From 30350cdc5785df745436d65175fb136676dd2a40 Mon Sep 17 00:00:00 2001 From: Matt Smith Date: Tue, 26 Sep 2017 21:59:07 -0400 Subject: [PATCH 001/258] added scope filtering to summaries.merge_all --- tensorflow/python/summary/summary.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/summary/summary.py b/tensorflow/python/summary/summary.py index 90afcc0a11..47d694d055 100644 --- a/tensorflow/python/summary/summary.py +++ b/tensorflow/python/summary/summary.py @@ -273,19 +273,20 @@ def merge(inputs, collections=None, name=None): return val -def merge_all(key=_ops.GraphKeys.SUMMARIES): +def merge_all(key=_ops.GraphKeys.SUMMARIES, scope=None): """Merges all summaries collected in the default graph. Args: key: `GraphKey` used to collect the summaries. Defaults to `GraphKeys.SUMMARIES`. + scope: Optional scope used to filter the summary ops, using `re.match` Returns: If no summaries were collected, returns None. Otherwise returns a scalar `Tensor` of type `string` containing the serialized `Summary` protocol buffer resulting from the merging. """ - summary_ops = _ops.get_collection(key) + summary_ops = _ops.get_collection(key, scope=scope) if not summary_ops: return None else: -- GitLab From c8bdebe33ed66966f668a530334de06623466a0e Mon Sep 17 00:00:00 2001 From: m-smith Date: Fri, 29 Sep 2017 13:42:36 -0400 Subject: [PATCH 002/258] updated goldens to reflect change to summaries.merge_all api --- tensorflow/tools/api/golden/tensorflow.summary.pbtxt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/tools/api/golden/tensorflow.summary.pbtxt b/tensorflow/tools/api/golden/tensorflow.summary.pbtxt index 326e077d39..871ebb5247 100644 --- a/tensorflow/tools/api/golden/tensorflow.summary.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.summary.pbtxt @@ -50,7 +50,7 @@ tf_module { } member_method { name: "merge_all" - argspec: "args=[\'key\'], varargs=None, keywords=None, defaults=[\'summaries\'], " + argspec: "args=[\'key\', \'scope\'], varargs=None, keywords=None, defaults=[\'summaries\', \'None\'], " } member_method { name: "scalar" -- GitLab From 9fe609d2f675a30c2dbc286dc827342399cbe39f Mon Sep 17 00:00:00 2001 From: Scott Tseng Date: Wed, 20 Dec 2017 03:38:16 +0800 Subject: [PATCH 003/258] Enables 0-D indexing for Gather() in TFLite This patch enables using scalar (0-D) index for Gather() in TFLite. --- tensorflow/contrib/lite/kernels/gather.cc | 7 +++--- .../contrib/lite/kernels/gather_test.cc | 25 +++++++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/tensorflow/contrib/lite/kernels/gather.cc b/tensorflow/contrib/lite/kernels/gather.cc index f8df797daf..0e4187d1ea 100644 --- a/tensorflow/contrib/lite/kernels/gather.cc +++ b/tensorflow/contrib/lite/kernels/gather.cc @@ -42,9 +42,10 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { TF_LITE_ENSURE_EQ(context, positions->type, kTfLiteInt32); // Check that input and output types match. TF_LITE_ENSURE_EQ(context, input->type, output->type); - // TODO(mgubin): only 1D positions are currently supported. - TF_LITE_ENSURE_EQ(context, NumDimensions(positions), 1); + // TODO(mgubin): only 0D or 1D positions are currently supported. + TF_LITE_ENSURE(context, NumDimensions(positions) <= 1); // TODO(mgubin): Only default axis == 0 is supported. + TF_LITE_ENSURE_EQ(context, params->axis, 0); // Check conditions for different types. switch (input->type) { case kTfLiteFloat32: @@ -64,7 +65,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { } const int num_dimensions = NumDimensions(input) + NumDimensions(positions) - 1; - TF_LITE_ENSURE(context, params->axis < num_dimensions); + TF_LITE_ENSURE(context, params->axis <= num_dimensions); TfLiteIntArray* output_shape = TfLiteIntArrayCreate(num_dimensions); int output_index = 0; for (int i = 0; i < params->axis; ++i) { diff --git a/tensorflow/contrib/lite/kernels/gather_test.cc b/tensorflow/contrib/lite/kernels/gather_test.cc index 6343d3b4ef..1a196583d4 100644 --- a/tensorflow/contrib/lite/kernels/gather_test.cc +++ b/tensorflow/contrib/lite/kernels/gather_test.cc @@ -48,8 +48,8 @@ class GatherOpModel : public SingleOpModel { PopulateStringTensor(input_, data); } - void SetPositions(std::initializer_list data) { - PopulateTensor(positions_, data); + void SetPositions(std::initializer_list data) { + PopulateTensor(positions_, data); } std::vector GetOutputFloat() { return ExtractVector(output_); } @@ -76,6 +76,27 @@ TEST(GatherOpTest, Shuffle) { ElementsAreArray(ArrayFloatNear({0.7, 0.8, -2, 0.2}))); } +TEST(GatherOpTest, Index) { + GatherOpModel m({2, 2}, TensorType_FLOAT32, {}); + m.SetInputFloat({-2.0, 0.2, 0.7, 0.8}); + m.SetPositions({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputFloat(), + ElementsAreArray(ArrayFloatNear({0.7, 0.8}))); + EXPECT_THAT(m.GetOutputShape(), + ElementsAreArray({2})); +} + +TEST(GatherOpTest, IndexToCornerCase) { + GatherOpModel m({3}, TensorType_FLOAT32, {}); + m.SetInputFloat({1.0, 2.0, 3.0}); + m.SetPositions({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputFloat(), + ElementsAreArray(ArrayFloatNear({2.0}))); + EXPECT_TRUE(m.GetOutputShape().empty()); +} + TEST(FloatGatherOpTest, Duplicate) { GatherOpModel m({1, 2, 2}, TensorType_FLOAT32, {2}); m.SetInputFloat({-2.0, 0.2, 0.7, 0.8}); -- GitLab From c16be5b553d744ca592e8ebcff212e0a3af9be0f Mon Sep 17 00:00:00 2001 From: Scott Tseng Date: Fri, 29 Dec 2017 13:00:39 +0800 Subject: [PATCH 004/258] Update in response to review comments --- tensorflow/contrib/lite/kernels/gather_test.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/lite/kernels/gather_test.cc b/tensorflow/contrib/lite/kernels/gather_test.cc index 1a196583d4..658d977b8d 100644 --- a/tensorflow/contrib/lite/kernels/gather_test.cc +++ b/tensorflow/contrib/lite/kernels/gather_test.cc @@ -48,8 +48,8 @@ class GatherOpModel : public SingleOpModel { PopulateStringTensor(input_, data); } - void SetPositions(std::initializer_list data) { - PopulateTensor(positions_, data); + void SetPositions(std::initializer_list data) { + PopulateTensor(positions_, data); } std::vector GetOutputFloat() { return ExtractVector(output_); } @@ -76,7 +76,7 @@ TEST(GatherOpTest, Shuffle) { ElementsAreArray(ArrayFloatNear({0.7, 0.8, -2, 0.2}))); } -TEST(GatherOpTest, Index) { +TEST(GatherOpTest, Test0DIndex) { GatherOpModel m({2, 2}, TensorType_FLOAT32, {}); m.SetInputFloat({-2.0, 0.2, 0.7, 0.8}); m.SetPositions({1}); @@ -87,7 +87,9 @@ TEST(GatherOpTest, Index) { ElementsAreArray({2})); } -TEST(GatherOpTest, IndexToCornerCase) { +TEST(GatherOpTest, Test0DIndexWith0DResult) { + // 0D tensor is special case in current TFLite. Test it once to make sure + // existing workarounds are fine with it. GatherOpModel m({3}, TensorType_FLOAT32, {}); m.SetInputFloat({1.0, 2.0, 3.0}); m.SetPositions({1}); -- GitLab From 581da65a1134db2de78db058ca42cee33eae3414 Mon Sep 17 00:00:00 2001 From: Daniel Trebbien Date: Wed, 3 Jan 2018 12:33:33 -0800 Subject: [PATCH 005/258] Fix a pessimizing-move warning in GetDeviceLapackInfo() clang reports: ./tensorflow/core/kernels/cuda_solvers.h:430:10: warning: moving a local object in a return statement prevents copy elision [-Wpessimizing-move] return std::move(new_dev_info); ^ ./tensorflow/core/kernels/cuda_solvers.h:430:10: note: remove std::move call here return std::move(new_dev_info); ^~~~~~~~~~ ~ --- tensorflow/core/kernels/cuda_solvers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/kernels/cuda_solvers.h b/tensorflow/core/kernels/cuda_solvers.h index 3c389a82ab..ecfa23750c 100644 --- a/tensorflow/core/kernels/cuda_solvers.h +++ b/tensorflow/core/kernels/cuda_solvers.h @@ -427,7 +427,7 @@ inline DeviceLapackInfo CudaSolver::GetDeviceLapackInfo( int64 size, const string& debug_info) { DeviceLapackInfo new_dev_info(context_, size, debug_info); scratch_tensor_refs_.emplace_back(new_dev_info.tensor()); - return std::move(new_dev_info); + return new_dev_info; } } // namespace tensorflow -- GitLab From 612b176cf3f8f751743b35438b24dadfb1668db2 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sat, 13 Jan 2018 15:48:42 +0000 Subject: [PATCH 006/258] Add stream selection support for `tf.contrib.ffmpeg.decode_audio` This fix tries to address the issue raised in 16073 where it was not possible to selectively decode a perticular stream with `tf.contrib.ffmpeg.decode_audio`. This fix adds an additional attribute `stream` which could be used to specify the stream to decode. By default stream='' which leaves the decision to ffmpeg. This fix fixes 16073. Signed-off-by: Yong Tang --- tensorflow/contrib/ffmpeg/decode_audio_op.cc | 18 +++++++++++---- .../contrib/ffmpeg/default/ffmpeg_lib.cc | 23 ++++++++++++------- tensorflow/contrib/ffmpeg/ffmpeg_lib.h | 2 +- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/tensorflow/contrib/ffmpeg/decode_audio_op.cc b/tensorflow/contrib/ffmpeg/decode_audio_op.cc index 92fad70b1f..9e43774cc4 100644 --- a/tensorflow/contrib/ffmpeg/decode_audio_op.cc +++ b/tensorflow/contrib/ffmpeg/decode_audio_op.cc @@ -44,7 +44,7 @@ const char* kValidFileFormats[] = {"mp3", "mp4", "ogg", "wav"}; void Decode(OpKernelContext* context, const tensorflow::StringPiece& file_contents, const string& file_format, const int32 samples_per_second, - const int32 channel_count) { + const int32 channel_count, const string& stream) { // Write the input data to a temp file. const string temp_filename = io::GetTempFilename(file_format); OP_REQUIRES_OK(context, WriteFile(temp_filename, file_contents)); @@ -54,7 +54,7 @@ void Decode(OpKernelContext* context, std::vector output_samples; Status result = ffmpeg::ReadAudioFile(temp_filename, file_format, samples_per_second, - channel_count, &output_samples); + channel_count, stream, &output_samples); if (result.code() == error::Code::NOT_FOUND) { OP_REQUIRES( context, result.ok(), @@ -99,7 +99,12 @@ void Decode(OpKernelContext* context, */ class DecodeAudioOpV2 : public OpKernel { public: - explicit DecodeAudioOpV2(OpKernelConstruction* context) : OpKernel(context) {} + explicit DecodeAudioOpV2(OpKernelConstruction* context) : OpKernel(context) { + string stream; + if (context->GetAttr("stream", &stream).ok()) { + stream_ = stream; + } + } void Compute(OpKernelContext* context) override { OP_REQUIRES( @@ -153,8 +158,10 @@ class DecodeAudioOpV2 : public OpKernel { errors::InvalidArgument("channel_count must be positive, but got: ", channel_count)); - Decode(context, contents, file_format, samples_per_second, channel_count); + Decode(context, contents, file_format, samples_per_second, channel_count, stream_); } +private: + string stream_; }; REGISTER_KERNEL_BUILDER(Name("DecodeAudioV2").Device(DEVICE_CPU), @@ -166,6 +173,7 @@ REGISTER_OP("DecodeAudioV2") .Input("samples_per_second: int32") .Input("channel_count: int32") .Output("sampled_audio: float") + .Attr("stream: string = ''") .SetShapeFn([](shape_inference::InferenceContext* c) { const Tensor* channels_tensor = c->input_tensor(3); if (channels_tensor == nullptr) { @@ -237,7 +245,7 @@ class DecodeAudioOp : public OpKernel { const tensorflow::StringPiece file_contents = contents.scalar()(); Decode(context, file_contents, file_format_, samples_per_second_, - channel_count_); + channel_count_, ""); } private: diff --git a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc index 1e8af1458c..e31d88b40f 100644 --- a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc +++ b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc @@ -44,8 +44,10 @@ std::vector FfmpegAudioCommandLine(const string& input_filename, const string& output_filename, const string& input_format_id, int32 samples_per_second, - int32 channel_count) { - return {"-nostats", // No additional progress display. + int32 channel_count, + const string& stream) { + std::vector command({ + "-nostats", // No additional progress display. "-nostdin", // No interactive commands accepted. "-f", input_format_id, // eg: "mp3" "-probesize", StrCat(kDefaultProbeSize), "-i", input_filename, @@ -58,8 +60,15 @@ std::vector FfmpegAudioCommandLine(const string& input_filename, // Output set (in several ways) to signed 16-bit little-endian ints. "-codec:a:0", "pcm_s16le", "-sample_fmt", "s16", "-f", "s16le", "-sn", // No subtitle recording. - "-y", // Overwrite output file. - StrCat(output_filename)}; + "-y" // Overwrite output file. + }); + if (!stream.empty()) { + command.emplace_back("-map"); + command.emplace_back(StrCat("0:", stream)); + } + command.emplace_back(StrCat(output_filename)); + + return command; } std::vector FfmpegVideoCommandLine(const string& input_filename, @@ -123,7 +132,6 @@ bool IsBinaryInstalled(const string& binary_name) { std::transform(args.begin(), args.end(), std::back_inserter(args_chars), [](const string& s) { return const_cast(s.c_str()); }); args_chars.push_back(nullptr); - ::execvp(kFfmpegExecutable, args_chars.data()); // exec only returns on error. const int error = errno; @@ -308,13 +316,13 @@ Status WriteFile(const string& filename, StringPiece contents) { Status ReadAudioFile(const string& filename, const string& audio_format_id, int32 samples_per_second, int32 channel_count, + const string& stream, std::vector* output_samples) { // Create an argument list. string output_filename = io::GetTempFilename("raw"); const std::vector args = FfmpegAudioCommandLine(filename, output_filename, audio_format_id, - samples_per_second, channel_count); - + samples_per_second, channel_count, stream); // Unfortunately, it's impossible to differentiate an exec failure due to the // binary being missing and an error from the binary's execution. Therefore, // check to see if the binary *should* be available. If not, return an error @@ -368,7 +376,6 @@ Status ReadVideoFile(const string& filename, std::vector* output_data, // Create an argument list. const std::vector args = FfmpegVideoCommandLine(filename, output_filename); - // Execute ffmpeg and report errors. pid_t child_pid = ::fork(); if (child_pid < 0) { diff --git a/tensorflow/contrib/ffmpeg/ffmpeg_lib.h b/tensorflow/contrib/ffmpeg/ffmpeg_lib.h index c5ea1432bf..bc1733ead8 100644 --- a/tensorflow/contrib/ffmpeg/ffmpeg_lib.h +++ b/tensorflow/contrib/ffmpeg/ffmpeg_lib.h @@ -42,7 +42,7 @@ Status WriteFile(const string& filename, tensorflow::StringPiece contents); // contain a separate sample for each channel. Frames are ordered by time. Status ReadAudioFile(const string& filename, const string& audio_format_id, int32 samples_per_second, int32 channel_count, - std::vector* output_samples); + const string& stream, std::vector* output_samples); // Creates an audio file using ffmpeg in a specific format. The samples are in // [-1.0, 1.0]. If there are multiple channels in the audio then each frame will -- GitLab From 8f39ea7a97da3cee999f8832a9f299915597749e Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sat, 13 Jan 2018 15:48:49 +0000 Subject: [PATCH 007/258] Update python wrapper for ffmpeg.decode_audio with `stream` attribute Signed-off-by: Yong Tang --- tensorflow/contrib/ffmpeg/ffmpeg_ops.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/ffmpeg/ffmpeg_ops.py b/tensorflow/contrib/ffmpeg/ffmpeg_ops.py index 08b5a6ea48..020b5c99c6 100644 --- a/tensorflow/contrib/ffmpeg/ffmpeg_ops.py +++ b/tensorflow/contrib/ffmpeg/ffmpeg_ops.py @@ -31,7 +31,7 @@ _ffmpeg_so = loader.load_op_library( def decode_audio(contents, file_format=None, samples_per_second=None, - channel_count=None): + channel_count=None, stream=None): """Create an op that decodes the contents of an audio file. Note that ffmpeg is free to select the "best" audio track from an mp4. @@ -51,6 +51,9 @@ def decode_audio(contents, file_format=None, samples_per_second=None, `contents` have more than this number, then some channels will be merged or dropped. If `contents` has fewer than this, then additional channels will be created from the existing ones. + stream: A string specifying which stream from the content file + should be decoded, e.g., '0' means the 0-th stream. + The default value is '' which leaves the decision to ffmpeg. Returns: A rank-2 tensor that has time along dimension 0 and channels along @@ -61,7 +64,7 @@ def decode_audio(contents, file_format=None, samples_per_second=None, """ return gen_decode_audio_op_py.decode_audio_v2( contents, file_format=file_format, samples_per_second=samples_per_second, - channel_count=channel_count) + channel_count=channel_count, stream=stream) ops.NotDifferentiable('DecodeAudio') -- GitLab From 8890abb0fc34720f6025f8e1bb2eb0df8f643038 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sat, 13 Jan 2018 15:48:56 +0000 Subject: [PATCH 008/258] Add additional test case and test samples Signed-off-by: Yong Tang --- .../contrib/ffmpeg/decode_audio_op_test.py | 19 ++++++++++++++++-- .../testdata/mono_16khz_mp3_32khz_aac.mp4 | Bin 0 -> 69357 bytes 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3_32khz_aac.mp4 diff --git a/tensorflow/contrib/ffmpeg/decode_audio_op_test.py b/tensorflow/contrib/ffmpeg/decode_audio_op_test.py index 0d7c9cb99e..a0f8d6787b 100644 --- a/tensorflow/contrib/ffmpeg/decode_audio_op_test.py +++ b/tensorflow/contrib/ffmpeg/decode_audio_op_test.py @@ -33,7 +33,8 @@ class DecodeAudioOpTest(test.TestCase): def _loadFileAndTest(self, filename, file_format, duration_sec, samples_per_second, channel_count, - samples_per_second_tensor=None, feed_dict=None): + samples_per_second_tensor=None, feed_dict=None, + stream=None): """Loads an audio file and validates the output tensor. Args: @@ -49,6 +50,9 @@ class DecodeAudioOpTest(test.TestCase): feed_dict: Used when evaluating the `decode_audio` op. If not provided, will be empty. Useful when providing a placeholder for `samples_per_second_tensor`. + stream: A string specifying which stream from the content file + should be decoded. The default value is '' which leaves the + decision to ffmpeg. """ if samples_per_second_tensor is None: samples_per_second_tensor = samples_per_second @@ -62,7 +66,7 @@ class DecodeAudioOpTest(test.TestCase): contents, file_format=file_format, samples_per_second=samples_per_second_tensor, - channel_count=channel_count) + channel_count=channel_count, stream=stream) audio = audio_op.eval(feed_dict=feed_dict or {}) self.assertEqual(len(audio.shape), 2) self.assertNear( @@ -72,6 +76,17 @@ class DecodeAudioOpTest(test.TestCase): 0.1 * audio.shape[0]) self.assertEqual(audio.shape[1], channel_count) + def testStreamIdentifier(self): + # mono_16khz_mp3_32khz_aac.mp4 was generated from: + # ffmpeg -i tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3.mp4 \ + # -i tensorflow/contrib/ffmpeg/testdata/mono_32khz_aac.mp4 \ + # -strict -2 -map 0:a -map 1:a \ + # tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3_32khz_aac.mp4 + self._loadFileAndTest('mono_16khz_mp3_32khz_aac.mp4', 'mp4', 2.77, 20000, + 1, stream="0") + self._loadFileAndTest('mono_16khz_mp3_32khz_aac.mp4', 'mp4', 2.77, 20000, + 1, stream="1") + def testMonoMp3(self): self._loadFileAndTest('mono_16khz.mp3', 'mp3', 0.57, 20000, 1) self._loadFileAndTest('mono_16khz.mp3', 'mp3', 0.57, 20000, 2) diff --git a/tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3_32khz_aac.mp4 b/tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3_32khz_aac.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..2485da86d60837800fbb0b390c440e674de25993 GIT binary patch literal 69357 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 ZQxd_NL5Y*WC$TKe)J)IBK+n*?5CER*t;qlY literal 0 HcmV?d00001 -- GitLab From 6e56e195d29f33c42b4b58f83c508544e2bb59a7 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sat, 13 Jan 2018 19:48:57 +0000 Subject: [PATCH 009/258] Fix crash in `tf.contrib.ffmpeg.decode_video` This fix fixes the crash in `tf.contrib.ffmpeg.decode_video`. The reason for the crash was that, `decode_video` dumps the information about streaming etc. (as opposed to dump to stderr) info a file and read from it. As the loglevel was `error` the file was empty. This fix addresses the issue. The fix could be verifed by manually running ``` bazel test -s --config=opt --cache_test_results=no //tensorflow/contrib/ffmpeg:decode_video_op_test ``` With this fix, the above test works. Signed-off-by: Yong Tang --- tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc index 1e8af1458c..373f26869a 100644 --- a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc +++ b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc @@ -73,7 +73,9 @@ std::vector FfmpegVideoCommandLine(const string& input_filename, "-probesize", StrCat(kDefaultProbeSize), "-loglevel", - "error", // Print errors only. + // Info is needed to get the information about stream, etc. + // It is generated to a separate file, not stdout/stderr. + "info", "-hide_banner", // Skip printing build options, version, etc. "-vcodec", "rawvideo", -- GitLab From 26891cccd3fad36fdfd19254435d6aec72397808 Mon Sep 17 00:00:00 2001 From: lspvic Date: Thu, 18 Jan 2018 19:39:45 +0800 Subject: [PATCH 010/258] Fix result shape of tf.tensordot unknown --- tensorflow/python/ops/math_ops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index cd07dad613..88260e2687 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -2768,7 +2768,8 @@ def tensordot(a, b, axes, name=None): if axes < 1: raise ValueError("'axes' must be at least 1.") if a_shape.ndims is not None: - return range(a_shape.ndims - axes, a_shape.ndims), range(axes) + return (list(xrange(a_shape.ndims - axes, a_shape.ndims)), + list(xrange(axes))) else: rank = array_ops.rank(a) return (range(rank - axes, rank, dtype=dtypes.int32), -- GitLab From 211e5a42a842dde39068cb2de83689c80de3485b Mon Sep 17 00:00:00 2001 From: cph Date: Fri, 19 Jan 2018 10:52:21 +0800 Subject: [PATCH 011/258] fix pooling1D channels_first test case --- tensorflow/python/layers/pooling_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/layers/pooling_test.py b/tensorflow/python/layers/pooling_test.py index 589fee5f71..e4d4ed4a2a 100644 --- a/tensorflow/python/layers/pooling_test.py +++ b/tensorflow/python/layers/pooling_test.py @@ -110,19 +110,19 @@ class PoolingTest(test.TestCase): def testCreateMaxPooling1DChannelsFirst(self): width = 7 - images = random_ops.random_uniform((5, width, 4)) + images = random_ops.random_uniform((5, 4, width)) layer = pooling_layers.MaxPooling1D( 2, strides=2, data_format='channels_first') output = layer.apply(images) - self.assertListEqual(output.get_shape().as_list(), [5, 3, 4]) + self.assertListEqual(output.get_shape().as_list(), [5, 4, 3]) def testCreateAveragePooling1DChannelsFirst(self): width = 7 - images = random_ops.random_uniform((5, width, 4)) + images = random_ops.random_uniform((5, 4, width)) layer = pooling_layers.AveragePooling1D( 2, strides=2, data_format='channels_first') output = layer.apply(images) - self.assertListEqual(output.get_shape().as_list(), [5, 3, 4]) + self.assertListEqual(output.get_shape().as_list(), [5, 4, 3]) def testCreateMaxPooling3D(self): depth, height, width = 6, 7, 9 -- GitLab From a71b2861d48d082de707ab8833b17295c2a860ae Mon Sep 17 00:00:00 2001 From: cph Date: Fri, 19 Jan 2018 16:16:11 +0800 Subject: [PATCH 012/258] fix layers pooling1D dim bug --- tensorflow/python/layers/pooling.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tensorflow/python/layers/pooling.py b/tensorflow/python/layers/pooling.py index c6bd7aae07..ab06a3a408 100644 --- a/tensorflow/python/layers/pooling.py +++ b/tensorflow/python/layers/pooling.py @@ -63,14 +63,18 @@ class _Pooling1D(base.Layer): def call(self, inputs): # There is no TF op for 1D pooling, hence we make the inputs 4D. if self.data_format == 'channels_last': - inputs = array_ops.expand_dims(inputs, 2) - pool_shape = (1,) + self.pool_size + (1, 1) - strides = (1,) + self.strides + (1, 1) - data_format = 'NHWC' - else: + # input is NWC, make it NHWC inputs = array_ops.expand_dims(inputs, 1) + # pool on the W dim pool_shape = (1, 1) + self.pool_size + (1,) strides = (1, 1) + self.strides + (1,) + data_format = 'NHWC' + else: + # input is NCW, make it NCHW + inputs = array_ops.expand_dims(inputs, 2) + # pool on the W dim + pool_shape = (1, 1, 1) + self.pool_size + strides = (1, 1, 1) + self.strides data_format = 'NCHW' outputs = self.pool_function( @@ -81,9 +85,9 @@ class _Pooling1D(base.Layer): data_format=data_format) if self.data_format == 'channels_last': - return array_ops.squeeze(outputs, 2) - else: return array_ops.squeeze(outputs, 1) + else: + return array_ops.squeeze(outputs, 2) def compute_output_shape(self, input_shape): input_shape = tensor_shape.TensorShape(input_shape).as_list() -- GitLab From f063d85cf74e7ad5943d614f7ac4b7404d1ed32f Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 20 Jan 2018 00:52:59 +0900 Subject: [PATCH 013/258] fix typo --- tensorflow/contrib/eager/python/g3doc/guide.md | 2 +- tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/eager/python/g3doc/guide.md b/tensorflow/contrib/eager/python/g3doc/guide.md index 0095ffa0db..7eea93ce1f 100644 --- a/tensorflow/contrib/eager/python/g3doc/guide.md +++ b/tensorflow/contrib/eager/python/g3doc/guide.md @@ -292,7 +292,7 @@ def loss(weight, bias): error = prediction(training_inputs, weight, bias) - training_outputs return tf.reduce_mean(tf.square(error)) -# Function that returns the the derivative of loss with respect to +# Function that returns the derivative of loss with respect to # weight and bias grad = tfe.gradients_function(loss) diff --git a/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h b/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h index 3cda4bcccc..7019c29959 100644 --- a/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h +++ b/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h @@ -370,7 +370,7 @@ enum { * Looks up items from a given tensor. * * Each item in the output is a raw copy of the corresponding item in - * the input “values”. If the the given “lookup” indices are out of bounds, + * the input “values”. If the given “lookup” indices are out of bounds, * the op will fail and an error will be reported. * * Inputs: -- GitLab From a58524fa602829459aa7eb0335a33afe1f28382a Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Fri, 19 Jan 2018 14:01:29 -0800 Subject: [PATCH 014/258] [XLA] Simplify trivial pad/reduce-window combos into broadcasts. PiperOrigin-RevId: 182585236 --- tensorflow/compiler/xla/service/BUILD | 1 + .../xla/service/algebraic_simplifier.cc | 59 +++++++- .../xla/service/algebraic_simplifier_test.cc | 139 ++++++++++++++++++ .../compiler/xla/service/gpu/pad_insertion.cc | 8 +- .../compiler/xla/service/hlo_instruction.cc | 52 +++++++ .../compiler/xla/service/hlo_instruction.h | 14 ++ .../compiler/xla/service/hlo_verifier.cc | 3 +- .../compiler/xla/service/user_computation.cc | 47 +----- tensorflow/compiler/xla/window_util.cc | 31 +++- tensorflow/compiler/xla/window_util.h | 18 ++- 10 files changed, 322 insertions(+), 50 deletions(-) diff --git a/tensorflow/compiler/xla/service/BUILD b/tensorflow/compiler/xla/service/BUILD index 16d227a00f..926bcfa1b8 100644 --- a/tensorflow/compiler/xla/service/BUILD +++ b/tensorflow/compiler/xla/service/BUILD @@ -1086,6 +1086,7 @@ tf_cc_test( "//tensorflow/compiler/xla:test", "//tensorflow/compiler/xla:types", "//tensorflow/compiler/xla:util", + "//tensorflow/compiler/xla:window_util", "//tensorflow/compiler/xla:xla_data_proto", "//tensorflow/compiler/xla/tests:hlo_verified_test_base", "//tensorflow/compiler/xla/tests:xla_internal_test_main", # fixdeps: keep diff --git a/tensorflow/compiler/xla/service/algebraic_simplifier.cc b/tensorflow/compiler/xla/service/algebraic_simplifier.cc index 90a3f0b674..ba82e822b2 100644 --- a/tensorflow/compiler/xla/service/algebraic_simplifier.cc +++ b/tensorflow/compiler/xla/service/algebraic_simplifier.cc @@ -1741,6 +1741,63 @@ Status AlgebraicSimplifierVisitor::HandleReduceWindow( } } + // If the pad puts a single non-identity value in each window that we're + // reducing, then this is a broadcast. + HloInstruction* pad_operand = operand->mutable_operand(0); + auto is_effective_broadcast = [&] { + if (window_util::HasStride(window)) { + VLOG(10) << "Window has stride."; + return false; + } + if (!window_util::HasSymmetricPadding(pad_config)) { + VLOG(10) << "Window has uneven padding."; + return false; + } + for (int64 i = 0; i < pad_config.dimensions_size(); ++i) { + const auto& pad_dimension = pad_config.dimensions(i); + if ((pad_dimension.edge_padding_low() != 0 || + pad_dimension.edge_padding_high() != 0) && + pad_operand->shape().dimensions(i) != 1) { + VLOG(10) << "Found non-trivial dimension being padded: " << i; + return false; + } + } + VLOG(10) << "Found to be padding trivial dimensions only."; + + for (int64 i = 0; i < window.dimensions_size(); ++i) { + const auto& pad_dimension = pad_config.dimensions(i); + const WindowDimension& window_dimension = window.dimensions(i); + bool dimension_has_padding = (pad_dimension.edge_padding_low() != 0 || + pad_dimension.edge_padding_high() != 0); + if (dimension_has_padding && + window_dimension.size() < pad_dimension.edge_padding_low() + 1) { + VLOG(10) << "Found window did not cover single unpadded element in " + "dimension: " + << i; + return false; + } + if (pad_operand->shape().dimensions(i) != 1 && + window_dimension.size() != 1) { + VLOG(10) << "Found window covers more than one element in non-trivial " + "dimension: " + << i; + return false; + } + } + VLOG(10) << "Found window covers a single unpadded element."; + return true; + }; + if (is_effective_broadcast()) { + VLOG(10) << "Replacing pad/reduce-window with (implicit) broadcast."; + auto fadd = [this](std::unique_ptr x) { + return computation_->AddInstruction(std::move(x)); + }; + return ReplaceWithNewInstruction( + reduce_window, HloInstruction::CreateBroadcastSequence( + /*output_shape=*/reduce_window->shape(), + /*operand=*/pad_operand, fadd)); + } + // Carry out the folding of the pad into reduce_window. VLOG(10) << "Folding pad into reduce-window."; Window new_window = window; @@ -1758,7 +1815,7 @@ Status AlgebraicSimplifierVisitor::HandleReduceWindow( return ReplaceWithNewInstruction( reduce_window, HloInstruction::CreateReduceWindow( /*shape=*/reduce_window->shape(), - /*operand=*/operand->mutable_operand(0), + /*operand=*/pad_operand, /*init_value=*/reduce_window->mutable_operand(1), /*window=*/new_window, /*reduce_computation=*/function)); diff --git a/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc b/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc index e7c4dfb0a1..e43ea50af4 100644 --- a/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc +++ b/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc @@ -30,6 +30,7 @@ limitations under the License. #include "tensorflow/compiler/xla/test.h" #include "tensorflow/compiler/xla/tests/hlo_verified_test_base.h" #include "tensorflow/compiler/xla/types.h" +#include "tensorflow/compiler/xla/window_util.h" #include "tensorflow/compiler/xla/xla_data.pb.h" #include "tensorflow/core/lib/core/status_test_util.h" #include "tensorflow/core/lib/strings/str_util.h" @@ -2495,6 +2496,144 @@ TEST_F(AlgebraicSimplifierTest, TrivialDynamicUpdateSlice) { op::DynamicSlice(op::Parameter(), op::Parameter())); } +struct PadReduceWindowEffectiveBroadcastCase { + std::vector input_spatials; + std::vector symmetric_pad_spatials; + std::vector reduce_window_spatials; + // Whether to use `B F S0 S1` form vs `B S0 S1 F` form. + // + // This doesn't test any different functionality but is useful for making sure + // kBroadcast nodes are well formed. + bool prepend_a; + bool should_become_broadcast; + + string ToTestCaseName() const { + return tensorflow::strings::StrCat( + tensorflow::str_util::Join(input_spatials, ","), ";", + tensorflow::str_util::Join(symmetric_pad_spatials, ","), ";", + tensorflow::str_util::Join(reduce_window_spatials, ","), ";", prepend_a, + ";", should_become_broadcast); + } +}; + +void PrintTo(const PadReduceWindowEffectiveBroadcastCase& c, std::ostream* os) { + *os << c.ToTestCaseName(); +} + +class PadReduceWindowEffectiveBroadcastTest + : public AlgebraicSimplifierTest, + public ::testing::WithParamInterface< + PadReduceWindowEffectiveBroadcastCase> {}; + +TEST_P(PadReduceWindowEffectiveBroadcastTest, DoIt) { + const auto& param = GetParam(); + + // a and b are parallel bounds we can either turn into a B F S0 S1 or + // `B S0 S1 F` kind of pattern. + auto decorate_spatials = [¶m](tensorflow::gtl::ArraySlice spatials, + int64 a, int64 b) { + std::vector result; + if (param.prepend_a) { + result.push_back(a); + } + for (int64 s : spatials) { + result.push_back(s); + } + if (!param.prepend_a) { + result.push_back(a); + } + result.push_back(b); + return result; + }; + + HloComputation::Builder builder(TestName()); + const Shape input_shape = ShapeUtil::MakeShape( + F32, decorate_spatials(param.input_spatials, 128, 2048)); + HloInstruction* input = builder.AddInstruction( + HloInstruction::CreateParameter(0, input_shape, "input")); + + PaddingConfig padding = window_util::MakeSymmetricPadding( + decorate_spatials(param.symmetric_pad_spatials, 0, 0)); + HloInstruction* pad = builder.AddInstruction(HloInstruction::CreatePad( + ShapeUtil::MakeShape( + F32, decorate_spatials(param.reduce_window_spatials, 128, 2048)), + input, + builder.AddInstruction( + HloInstruction::CreateConstant(Literal::CreateR0(0.0f))), + padding)); + + std::unique_ptr module = CreateNewModule(); + HloComputation* add_computation = nullptr; + { + HloComputation::Builder builder(TestName() + ".add"); + const Shape scalar_shape = ShapeUtil::MakeShape(F32, {}); + HloInstruction* p0 = builder.AddInstruction( + HloInstruction::CreateParameter(0, scalar_shape, "p0")); + HloInstruction* p1 = builder.AddInstruction( + HloInstruction::CreateParameter(1, scalar_shape, "p1")); + builder.AddInstruction( + HloInstruction::CreateBinary(scalar_shape, HloOpcode::kAdd, p0, p1)); + add_computation = module->AddEmbeddedComputation(builder.Build()); + } + + TF_ASSERT_OK_AND_ASSIGN( + const Shape output_shape, + ShapeInference::InferPadShape(input_shape, ShapeUtil::MakeShape(F32, {}), + padding)); + Window window = window_util::MakeWindow( + decorate_spatials(param.reduce_window_spatials, 1, 1)); + auto zero = builder.AddInstruction( + HloInstruction::CreateConstant(Literal::CreateR0(0.0f))); + builder.AddInstruction(HloInstruction::CreateReduceWindow( + output_shape, pad, zero, window, add_computation)); + + auto computation = module->AddEntryComputation(builder.Build()); + AlgebraicSimplifier simplifier(/*is_layout_sensitive=*/false, + non_bitcasting_callback()); + TF_ASSERT_OK_AND_ASSIGN(bool run_successful, simplifier.Run(module.get())); + ASSERT_TRUE(run_successful); + + EXPECT_TRUE( + ShapeUtil::Equal(computation->root_instruction()->shape(), output_shape)); + + if (param.should_become_broadcast) { + EXPECT_THAT(computation->root_instruction(), op::Broadcast(::testing::_)); + } else { + EXPECT_THAT(computation->root_instruction(), + op::ReduceWindow(::testing::_, zero)); + } +} + +const std::vector& +PadReduceWindowEffectiveBroadcastCases() { + static auto* cases = new std::vector{ + {/*input_spatials=*/{1, 1}, /*symmetric_pad_amount=*/{6, 6}, + /*reduce_window_spatials=*/{7, 7}, /*prepend_a=*/true, + /*should_become_broadcast=*/true}, // + {/*input_spatials=*/{1, 1}, /*symmetric_pad_amount=*/{6, 6}, + /*reduce_window_spatials=*/{7, 7}, /*prepend_a=*/false, + /*should_become_broadcast=*/true}, // + {/*input_spatials=*/{2, 2}, /*symmetric_pad_amount=*/{6, 6}, + /*reduce_window_spatials=*/{7, 7}, /*prepend_a=*/true, + /*should_become_broadcast=*/false}, // + {/*input_spatials=*/{1, 1}, /*symmetric_pad_amount=*/{2, 2}, + /*reduce_window_spatials=*/{5, 5}, /*prepend_a=*/true, + /*should_become_broadcast=*/true}, // + {/*input_spatials=*/{1, 1}, /*symmetric_pad_amount=*/{2, 2}, + /*reduce_window_spatials=*/{1, 1}, /*prepend_a=*/true, + /*should_become_broadcast=*/false}, // + {/*input_spatials=*/{5, 1}, /*symmetric_pad_amount=*/{0, 2}, + /*reduce_window_spatials=*/{2, 5}, /*prepend_a=*/true, + /*should_become_broadcast=*/false}, // + }; + return *cases; +} + +INSTANTIATE_TEST_CASE_P( + PadReduceWindowEffectiveBroadcastInstantiation, + PadReduceWindowEffectiveBroadcastTest, + ::testing::ValuesIn(PadReduceWindowEffectiveBroadcastCases())); + class DotStrengthReductionTest : public AlgebraicSimplifierTest, public ::testing::WithParamInterface< diff --git a/tensorflow/compiler/xla/service/gpu/pad_insertion.cc b/tensorflow/compiler/xla/service/gpu/pad_insertion.cc index c29fee0879..2923a79af0 100644 --- a/tensorflow/compiler/xla/service/gpu/pad_insertion.cc +++ b/tensorflow/compiler/xla/service/gpu/pad_insertion.cc @@ -28,7 +28,7 @@ namespace gpu { namespace { bool IsForwardConvolutionCanonical(const HloInstruction& conv) { CHECK_EQ(HloOpcode::kConvolution, conv.opcode()); - return window_util::HasEvenPadding(conv.window()) && + return window_util::HasSymmetricPadding(conv.window()) && !window_util::HasNegativePadding(conv.window()) && !window_util::HasDilation(conv.window()); } @@ -43,7 +43,7 @@ HloInstruction* MaybePaddedAndSlicedInput( const Window& conv_window, const ConvolutionDimensionNumbers& conv_dnums, HloInstruction* input) { HloComputation* computation = input->parent(); - if (!window_util::HasEvenPadding(conv_window) || + if (!window_util::HasSymmetricPadding(conv_window) || window_util::HasBaseDilation(conv_window)) { // If padding is uneven or has dilation, we insert a kPad instruction that // applies positive padding and dilation. @@ -190,7 +190,7 @@ void IncreasePaddingHighBy(int64 delta, WindowDimension* window_dim) { bool PadInsertion::CanonicalizeBackwardFilterConvolution( HloInstruction* backward_conv) { - if (window_util::HasEvenPadding(backward_conv->window())) { + if (window_util::HasSymmetricPadding(backward_conv->window())) { return false; } @@ -285,7 +285,7 @@ bool PadInsertion::CanonicalizeBackwardFilterConvolution( bool PadInsertion::CanonicalizeBackwardInputConvolution( HloInstruction* backward_conv) { - if (window_util::HasEvenPadding(backward_conv->window())) { + if (window_util::HasSymmetricPadding(backward_conv->window())) { return false; } diff --git a/tensorflow/compiler/xla/service/hlo_instruction.cc b/tensorflow/compiler/xla/service/hlo_instruction.cc index 90121f7ffe..b2755b97bf 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.cc +++ b/tensorflow/compiler/xla/service/hlo_instruction.cc @@ -669,6 +669,58 @@ HloInstruction::CreateSelectAndScatter( return instruction; } +/* static */ std::unique_ptr +HloInstruction::CreateBroadcastSequence( + const Shape& output_shape, HloInstruction* operand, + const std::function)>& + adder) { + CHECK(ShapeUtil::IsScalar(operand->shape()) || + ShapeUtil::Rank(operand->shape()) == ShapeUtil::Rank(output_shape)); + Shape broadcast_shape = ShapeUtil::ChangeElementType( + output_shape, operand->shape().element_type()); + // Do explicit broadcast for scalar. + if (ShapeUtil::IsScalar(operand->shape())) { + auto broadcast = + HloInstruction::CreateBroadcast(broadcast_shape, operand, {}); + broadcast->set_metadata(operand->metadata()); + if (operand->has_sharding()) { + broadcast->set_sharding(operand->sharding()); + } + return broadcast; + } + // Do explicit broadcast for degenerate broadcast. + std::vector broadcast_dimensions; + std::vector reshaped_dimensions; + for (int i = 0; i < ShapeUtil::Rank(operand->shape()); i++) { + if (operand->shape().dimensions(i) == output_shape.dimensions(i)) { + broadcast_dimensions.push_back(i); + reshaped_dimensions.push_back(operand->shape().dimensions(i)); + } else { + CHECK_EQ(operand->shape().dimensions(i), 1) + << "An explicit broadcast sequence requires the broadcasted " + "dimensions to be trivial; operand: " + << operand->ToString() << "; output_shape: " << output_shape; + } + } + // Eliminate the size one dimensions. + HloInstruction* reshaped_operand = adder(HloInstruction::CreateReshape( + ShapeUtil::MakeShape(operand->shape().element_type(), + reshaped_dimensions), + operand)); + reshaped_operand->set_metadata(operand->metadata()); + if (operand->has_sharding()) { + reshaped_operand->set_sharding(operand->sharding()); + } + // Broadcast 'reshape' up to the larger size. + auto broadcast = HloInstruction::CreateBroadcast( + broadcast_shape, reshaped_operand, broadcast_dimensions); + broadcast->set_metadata(operand->metadata()); + if (operand->has_sharding()) { + broadcast->set_sharding(operand->sharding()); + } + return broadcast; +} + /* static */ std::unique_ptr HloInstruction::CreatePad( const Shape& shape, HloInstruction* operand, HloInstruction* padding_value, const PaddingConfig& padding_config) { diff --git a/tensorflow/compiler/xla/service/hlo_instruction.h b/tensorflow/compiler/xla/service/hlo_instruction.h index e700ec1d29..5e89dc79be 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.h +++ b/tensorflow/compiler/xla/service/hlo_instruction.h @@ -409,6 +409,20 @@ class HloInstruction { const Shape& shape, HloInstruction* operand, tensorflow::gtl::ArraySlice broadcast_dimensions); + // Creates a sequence of instructions that performs an explicit broadcast of + // the operand to the target shape. + // + // Interior HLOs are passed to "adder", but the "root" HLO of the sequence is + // returned as a unique_ptr for API consistency with other factory methods in + // this interface. + // + // TODO(b/72173833) Ideally HloComputations would always be present, and so + // the adder being passed by the caller would not be necessary. + static std::unique_ptr CreateBroadcastSequence( + const Shape& output_shape, HloInstruction* operand, + const std::function)>& + adder); + // Creates a pad instruction, where the operand is padded on the edges and // between the elements with the given padding value. static std::unique_ptr CreatePad( diff --git a/tensorflow/compiler/xla/service/hlo_verifier.cc b/tensorflow/compiler/xla/service/hlo_verifier.cc index 9d9cf0c0f6..ce0eb1af92 100644 --- a/tensorflow/compiler/xla/service/hlo_verifier.cc +++ b/tensorflow/compiler/xla/service/hlo_verifier.cc @@ -159,7 +159,8 @@ Status ShapeVerifier::HandleBroadcast(HloInstruction* broadcast) { ++operand_dimension) { int64 output_dimension = broadcast->dimensions()[operand_dimension]; TF_RET_CHECK(broadcast->shape().dimensions(output_dimension) == - operand_shape.dimensions(operand_dimension)); + operand_shape.dimensions(operand_dimension)) + << broadcast->ToString() << " operand shape " << operand_shape; } return tensorflow::Status::OK(); } diff --git a/tensorflow/compiler/xla/service/user_computation.cc b/tensorflow/compiler/xla/service/user_computation.cc index 7882b70ab7..2ea6507900 100644 --- a/tensorflow/compiler/xla/service/user_computation.cc +++ b/tensorflow/compiler/xla/service/user_computation.cc @@ -2767,48 +2767,11 @@ HloComputation* ComputationLowerer::ResolveComputation( HloInstruction* ComputationLowerer::ImplicitBroadcastToExplicitBroadcast( HloInstruction* operand, const Shape& output_shape) { - CHECK(ShapeUtil::IsScalar(operand->shape()) || - ShapeUtil::Rank(operand->shape()) == ShapeUtil::Rank(output_shape)); - Shape broadcast_shape = ShapeUtil::MakeShape( - operand->shape().element_type(), AsInt64Slice(output_shape.dimensions())); - // Do explicit broadcast for scalar. - if (ShapeUtil::IsScalar(operand->shape())) { - HloInstruction* broadcast = hlo_builder_.AddInstruction( - HloInstruction::CreateBroadcast(broadcast_shape, operand, {})); - broadcast->set_metadata(operand->metadata()); - if (operand->has_sharding()) { - broadcast->set_sharding(operand->sharding()); - } - return broadcast; - } - // Do explicit broadcast for degenerate broadcast. - std::vector broadcast_dimensions; - std::vector reshaped_dimensions; - for (int i = 0; i < ShapeUtil::Rank(operand->shape()); i++) { - if (operand->shape().dimensions(i) == output_shape.dimensions(i)) { - broadcast_dimensions.push_back(i); - reshaped_dimensions.push_back(operand->shape().dimensions(i)); - } - } - // Eliminate the size one dimensions. - HloInstruction* reshaped_operand = - hlo_builder_.AddInstruction(HloInstruction::CreateReshape( - ShapeUtil::MakeShape(operand->shape().element_type(), - reshaped_dimensions), - operand)); - reshaped_operand->set_metadata(operand->metadata()); - if (operand->has_sharding()) { - reshaped_operand->set_sharding(operand->sharding()); - } - // Broadcast 'reshape' up to the larger size. - HloInstruction* broadcast = - hlo_builder_.AddInstruction(HloInstruction::CreateBroadcast( - broadcast_shape, reshaped_operand, broadcast_dimensions)); - broadcast->set_metadata(operand->metadata()); - if (operand->has_sharding()) { - broadcast->set_sharding(operand->sharding()); - } - return broadcast; + auto fadd = [this](std::unique_ptr x) { + return hlo_builder_.AddInstruction(std::move(x)); + }; + return fadd( + HloInstruction::CreateBroadcastSequence(output_shape, operand, fadd)); } void ComputationLowerer::Visit( diff --git a/tensorflow/compiler/xla/window_util.cc b/tensorflow/compiler/xla/window_util.cc index 224eb2a20c..55f42ed3a4 100644 --- a/tensorflow/compiler/xla/window_util.cc +++ b/tensorflow/compiler/xla/window_util.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include "tensorflow/compiler/xla/types.h" +#include "tensorflow/compiler/xla/xla_data.pb.h" #include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/lib/strings/stringprintf.h" @@ -25,6 +26,26 @@ limitations under the License. namespace xla { namespace window_util { +Window MakeWindow(tensorflow::gtl::ArraySlice sizes) { + Window window; + for (int64 size : sizes) { + auto* dimension = window.add_dimensions(); + dimension->set_size(size); + dimension->set_stride(1); + } + return window; +} + +PaddingConfig MakeSymmetricPadding(tensorflow::gtl::ArraySlice sizes) { + PaddingConfig config; + for (int64 size : sizes) { + auto* dimension = config.add_dimensions(); + dimension->set_edge_padding_low(size); + dimension->set_edge_padding_high(size); + } + return config; +} + /* static */ string ToString(const WindowDimension& dim) { using tensorflow::strings::StrAppend; using tensorflow::strings::StrCat; @@ -114,13 +135,21 @@ bool HasPadding(const Window& window) { return false; } -bool HasEvenPadding(const Window& window) { +bool HasSymmetricPadding(const Window& window) { return std::all_of(window.dimensions().begin(), window.dimensions().end(), [](const WindowDimension& dim) { return dim.padding_low() == dim.padding_high(); }); } +bool HasSymmetricPadding(const PaddingConfig& padding_config) { + return std::all_of(padding_config.dimensions().begin(), + padding_config.dimensions().end(), + [](const PaddingConfig::PaddingConfigDimension& dim) { + return dim.edge_padding_low() == dim.edge_padding_high(); + }); +} + bool HasNegativePadding(const Window& window) { return std::any_of(window.dimensions().begin(), window.dimensions().end(), [](const WindowDimension& dim) { diff --git a/tensorflow/compiler/xla/window_util.h b/tensorflow/compiler/xla/window_util.h index 17c388fc0b..ba473e2c8c 100644 --- a/tensorflow/compiler/xla/window_util.h +++ b/tensorflow/compiler/xla/window_util.h @@ -18,10 +18,21 @@ limitations under the License. #include "tensorflow/compiler/xla/types.h" #include "tensorflow/compiler/xla/xla_data.pb.h" +#include "tensorflow/core/lib/gtl/array_slice.h" namespace xla { namespace window_util { +// Creates a window with the given sizes in the dimensions and all strides set +// to 1. +Window MakeWindow(tensorflow::gtl::ArraySlice sizes); + +// Creates a padding config with symmetrical padding in each dimension, of value +// given by sizes; e.g. {0, 1, 2} would create a R3 padding config that had zero +// pixels of padding in dimension 0, one pixel of padding symmetrically, on each +// side of dimension 1, and two pixels of padding symmetrically on dimension 2. +PaddingConfig MakeSymmetricPadding(tensorflow::gtl::ArraySlice sizes); + string ToString(const WindowDimension& dim); string ToString(const Window& window); @@ -32,9 +43,14 @@ string ToString(const Window& window); bool HasStride(const Window& window); bool HasPadding(const Window& window); -bool HasEvenPadding(const Window& window); +bool HasSymmetricPadding(const Window& window); bool HasNegativePadding(const Window& window); +// As with HasSymmetricPadding(Window) above, returns whether the "padding low" +// is equivalent to the "padding high" for all dimensions, but works on a +// padding configuration. +bool HasSymmetricPadding(const PaddingConfig& padding_config); + bool HasBaseDilation(const Window& window); bool HasWindowDilation(const Window& window); bool HasDilation(const Window& window); -- GitLab From f0c0489fccbf26557e4a4d6512b50d347e4f9811 Mon Sep 17 00:00:00 2001 From: Brian Patton Date: Fri, 19 Jan 2018 14:03:27 -0800 Subject: [PATCH 015/258] Filling in some holes in C64 support with Literals. PiperOrigin-RevId: 182585597 --- tensorflow/compiler/xla/literal_util.cc | 10 ++++++++++ tensorflow/compiler/xla/tests/literal_test_util.cc | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/tensorflow/compiler/xla/literal_util.cc b/tensorflow/compiler/xla/literal_util.cc index 7f0201e74a..89279b659c 100644 --- a/tensorflow/compiler/xla/literal_util.cc +++ b/tensorflow/compiler/xla/literal_util.cc @@ -830,6 +830,16 @@ std::unique_ptr Literal::Slice( result_literal->Set(indices, value); }); return result_literal; + case C64: + result_literal->EachCell( + [&](tensorflow::gtl::ArraySlice indices, complex64 /*value*/) { + for (int64 i = 0; i < ShapeUtil::Rank(result_shape); ++i) { + new_indices[i] = indices[i] + start_indices[i]; + } + complex64 value = Get(new_indices); + result_literal->Set(indices, value); + }); + return result_literal; case S32: result_literal->EachCell( [&](tensorflow::gtl::ArraySlice indices, int32 /*value*/) { diff --git a/tensorflow/compiler/xla/tests/literal_test_util.cc b/tensorflow/compiler/xla/tests/literal_test_util.cc index e5b96c51ce..dd91dbe8b9 100644 --- a/tensorflow/compiler/xla/tests/literal_test_util.cc +++ b/tensorflow/compiler/xla/tests/literal_test_util.cc @@ -712,6 +712,7 @@ bool NearComparator::ExpectValuesNear(bfloat16 expected, new_num_elements *= new_dimensions[i]; } CHECK_EQ(ShapeUtil::ElementsIn(literal.shape()), new_num_elements); + CHECK_EQ(new_dimensions.size(), minor_to_major.size()); auto new_literal = MakeUnique( ShapeUtil::MakeShape(literal.shape().element_type(), new_dimensions)); @@ -761,6 +762,10 @@ bool NearComparator::ExpectValuesNear(bfloat16 expected, new_literal->Set(to_multi_index, literal.Get(from_multi_index)); break; + case C64: + new_literal->Set(to_multi_index, + literal.Get(from_multi_index)); + break; default: LOG(FATAL) << "Unhandled primitive element type: " << PrimitiveType_Name(literal.shape().element_type()); -- GitLab From f33f0996924a00631f7b344c6a289df3510a3db1 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 19 Jan 2018 14:05:20 -0800 Subject: [PATCH 016/258] Publish TPU Estimators Docs on github PiperOrigin-RevId: 182585909 --- tensorflow/contrib/tpu/tpu_estimator.md | 241 ++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 tensorflow/contrib/tpu/tpu_estimator.md diff --git a/tensorflow/contrib/tpu/tpu_estimator.md b/tensorflow/contrib/tpu/tpu_estimator.md new file mode 100644 index 0000000000..ca1255b16b --- /dev/null +++ b/tensorflow/contrib/tpu/tpu_estimator.md @@ -0,0 +1,241 @@ +# Using the Estimator API with TPUs + + +This document describes how to train a TensorFlow model on TPUs using the +Estimator API. If you are interested in the hardware itself, check out the +[Cloud TPU documentation](https://cloud.google.com/tpu/docs). + +The TPU Estimator simplifies running models on a Cloud TPU by automatically +handling numerous low-level hardware-specific details + +[TOC] + +## Introduction to Estimator + +[TensorFlow +tutorials](https://www.tensorflow.org/extend/estimators) cover the Estimator +API. At a high-level, the Estimator API provides: + +* `Estimator.train()` - train a model on a given input for a fixed number of + steps. +* `Estimator.evaluate()` - evaluate the model on a test set. +* `Estimator.predict()` - run inference using the trained model. +* `Estimator.export_savedmodel()` - export your model for serving. + +In addition, `Estimator` includes default behavior common to training jobs, +such as saving and restoring checkpoints, creating summaries for TensorBoard, +etc. + +`Estimator` requires you to write a `model_fn` and an `input_fn`, which +correspond to the model and input portions of your TensorFlow graph. + +The following code demonstrates using `TPUEstimator` with MNIST example to +handle training: + + def model_fn(features, labels, mode, params): + """A simple CNN.""" + del params # unused + + input_layer = tf.reshape(features, [-1, 28, 28, 1]) + conv1 = tf.layers.conv2d( + inputs=input_layer, filters=32, kernel_size=[5, 5], padding="same", + activation=tf.nn.relu) + pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2) + conv2 = tf.layers.conv2d( + inputs=pool1, filters=64, kernel_size=[5, 5], + padding="same", activation=tf.nn.relu) + pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2) + pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64]) + dense = tf.layers.dense(inputs=pool2_flat, units=128, activation=tf.nn.relu) + dropout = tf.layers.dropout( + inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN) + logits = tf.layers.dense(inputs=dropout, units=10) + onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=10) + + loss = tf.losses.softmax_cross_entropy( + onehot_labels=onehot_labels, logits=logits) + + learning_rate = tf.train.exponential_decay( + FLAGS.learning_rate, tf.train.get_global_step(), 100000, 0.96) + + optimizer = tpu_optimizer.CrossShardOptimizer( + tf.train.GradientDescentOptimizer(learning_rate=learning_rate)) + + train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step()) + return tpu_estimator.TPUEstimatorSpec(mode=mode, loss=loss, train_op=train_op) + + + def get_input_fn(filename): + """Returns an `input_fn` for train and eval.""" + + def input_fn(params): + """An input_fn to parse 28x28 images from filename using tf.data.""" + batch_size = params["batch_size"] + + def parser(serialized_example): + """Parses a single tf.Example into image and label tensors.""" + features = tf.parse_single_example( + serialized_example, + features={ + "image_raw": tf.FixedLenFeature([], tf.string), + "label": tf.FixedLenFeature([], tf.int64), + }) + image = tf.decode_raw(features["image_raw"], tf.uint8) + image.set_shape([28 * 28]) + # Normalize the values of the image from the range [0, 255] to [-0.5, 0.5] + image = tf.cast(image, tf.float32) * (1. / 255) - 0.5 + label = tf.cast(features["label"], tf.int32) + return image, label + + dataset = tf.contrib.data.TFRecordDataset( + filename, buffer_size=FLAGS.dataset_reader_buffer_size) + dataset = dataset.map(parser).cache().repeat().batch(batch_size) + images, labels = dataset.make_one_shot_iterator().get_next() + # set_shape to give inputs statically known shapes. + images.set_shape([batch_size, 28 * 28]) + labels.set_shape([batch_size]) + return images, labels + return input_fn + + + def main(unused_argv): + + tf.logging.set_verbosity(tf.logging.INFO) + + run_config = tpu_config.RunConfig( + master=FLAGS.master, + model_dir=FLAGS.model_dir, + session_config=tf.ConfigProto( + allow_soft_placement=True, log_device_placement=True), + tpu_config=tpu_config.TPUConfig(FLAGS.iterations, FLAGS.num_shards),) + + estimator = tpu_estimator.TPUEstimator( + model_fn=model_fn, + use_tpu=FLAGS.use_tpu, + train_batch_size=FLAGS.batch_size, + eval_batch_size=FLAGS.batch_size, + config=run_config) + + estimator.train(input_fn=get_input_fn(FLAGS.train_file), + max_steps=FLAGS.train_steps) + + +Although this code is quite simple by appearance, there are some new +concepts to learn for using `TPU`s. The next section will cover the most +important details. + +## New Concepts Related to TPU/TPUEstimator + +TF programs run with `TPU Estimator` use an [in-graph +replication](https://www.tensorflow.org/deploy/distributed) approach. + +In-graph replication (also known as single-session replication) differs from +the between-graph replication (also known as multi-session replication) +training typically used in distributed TensorFlow. The major +differences include: + +1. The TensorFlow Session master is not local anymore. The user python program + creates one single graph that is replicated across all the cores in the Cloud + TPU. The typical configuration today sets the TensorFlow session master to be + the first worker. + +1. The input pipeline is placed on remote hosts (instead of local) to ensure the + training examples can be fed as fast as possible to TPU system. All queue-based + input pipelines do not work effectively. Dataset (tf.data) is + required. + +1. Workers in the TPU system operate in synchronous fashion, and each perform + the same step at the same time. + +Regarding programming model, _"The programmer picks a (large) batch size B and +writes the program (and sets hyperparameters) based on that batch size. The +system distributes the computation across the available devices." + +To align these, `TPUEstimator` wraps the computation (the `model_fn`) and +distributes it to all available TPU chips. + +To summarize: + +- The `input_fn` models the input pipeline running on remote host CPU. Use + `tf.data` to program the input Ops. `input_fn` is expected to be invoked + multiple times when using TPU pods. Each handles one device's input of the + global batch. The shard batch size should be retrieved from + `params['batch_size']`. We plan to provide better abstraction about the + sharding mechanism for `tf.data` to remove the `params['batch_size']`. + +- The `model_fn` models the computation which will be replicated and distributed + to all TPU chips. It should only contains ops that are supported by TPUs. + +## Convert from Vanilla Estimator to TPUEstimator + +It is always recommended to port a small, simple model first to make sure that +you are familiar with the basic concepts of `TPUEstimator` and test end-to-end +behavior. Once your simple model runs, gradually add more functionality. +In addition, there are several sample models, available at +[github.com/tensorflow/tpu-demos](https://github.com/tensorflow/tpu-demos). + +To convert your code from the vanilla `Estimator` class to use TPUs, change the +following (note some of the details may change over time): + +- Switch from `tf.estimator.RunConfig` to `tf.contrib.tpu.RunConfig`. +- Set the `TPUConfig` (part of the `tf.contrib.tpu.RunConfig`) to specify the + `iterations_per_loop`, number of iterations to run on the TPU device for one + `session.run` call (per training loop), and `num_shards`, the number of shards + (typically the number of TPU cores you’re running on). TPUs run a number of + iterations of the training loop before returning to host. Until all iterations + on the TPU device are run, no checkpoints or summaries will be saved. In the + future, we’ll choose a reasonable default. +- In `model_fn`, use `tf.contrib.tpu.CrossShardOptimizer` to wrap your + optimizer. Example: + + optimizer = tpu_optimizer.CrossShardOptimizer( + tf.train.GradientDescentOptimizer(learning_rate=learning_rate)) + +- Switch from `tf.estimator.Estimator` to `tf.contrib.tpu.TPUEstimator`. + +The default `RunConfig` will save summaries for TensorBoard every 100 steps and +write checkpoints every 10 minutes. + + +## FAQ + +### Why `tf.data` is Required for the Input Pipeline + +There are two reasons: + +1. The user code runs on the client, while the TPU computation is executed on + the `worker`. Input pipeline ops must be placed on the remote worker for + good performance. Only `tf.data` (Dataset) supports this. + +1. In order to amortize the TPU launch cost, the model train step is wrapped in + a `tf.while_loop`, such that one `Session.run` actually runs many iterations + for one train loop. To remove network back and forth, the input pipeline + in the future will be wrapped in a `tf.while_loop` and be placed on the + corresponding `worker`. Withou this, unnecessary network latency becomes + the performance bottleneck for models with short training-step times, or in + environments where network latency is higher. Only `tf.data` can be wrapped + by a `tf.while_loop`. + + +### How to add other CPU Ops into Graph +As `model_fn` only allows TPU Ops for computation, the easier workaround to add +CPU Ops into Graph is: + +1. Create a [SessionRunHook](https://www.tensorflow.org/api_docs/python/tf/train/SessionRunHook). +1. Modify the graph in the `def begin(self)`, +1. Pass the hook to `TPUEstimator.train`. + +### Running On GCP Cloud TPUs +To run your models on GCP Cloud TPUs refer to the [Cloud Documentation](https://cloud.google.com/tpu/docs/tutorials/mnist). +Refer to this link for all [Cloud TPU documentation](https://cloud.google.com/tpu/docs). + + +### Profiling +You can profile the `worker` by using instructions as spcified in the [Cloud TPU Tools](https://cloud.google.com/tpu/docs/cloud-tpu-tools). + + +### Is `int64` supported? +`int64` is not supported by TPU. Cast to int32 if applicable. The only exception +is global step, which relies on `assign_add`. `int64` support for global step +is added to ensure checkpoint compatibility between `TPUEstimator` and non-TPU +`Estimator`. -- GitLab From 87fb310d4cc6cea081ece27c621104dd6901ba33 Mon Sep 17 00:00:00 2001 From: Shivani Agrawal Date: Fri, 19 Jan 2018 14:38:45 -0800 Subject: [PATCH 017/258] [tf.data] Minor fix for saveable MapDataset and ParallelMapDataset. PiperOrigin-RevId: 182591174 --- .../python/kernel_tests/map_dataset_op_test.py | 18 ++++++++++++++++++ tensorflow/core/kernels/data/map_dataset_op.cc | 8 ++++---- .../kernels/data/parallel_map_dataset_op.cc | 8 ++++---- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/tensorflow/contrib/data/python/kernel_tests/map_dataset_op_test.py b/tensorflow/contrib/data/python/kernel_tests/map_dataset_op_test.py index 69252612a8..dd8247bfd4 100644 --- a/tensorflow/contrib/data/python/kernel_tests/map_dataset_op_test.py +++ b/tensorflow/contrib/data/python/kernel_tests/map_dataset_op_test.py @@ -765,6 +765,15 @@ class MapDatasetSerializationTest( self.verify_error_on_save(_build_ds, 15, errors.InvalidArgumentError) + def testCaptureConstantInMapFn(self): + + def _build_ds(): + constant_var = constant_op.constant(5) + return (contrib_dataset_ops.Dataset.from_tensors(0).repeat(10).map( + lambda x: x + constant_var)) + + self.run_core_tests(_build_ds, None, 10) + def testCaptureDefunInMapFn(self): num_outputs = 100 @@ -856,6 +865,15 @@ class ParallelMapDatasetSerializationTest( self.verify_error_on_save(_build_ds, 15, errors.InvalidArgumentError) + def testCaptureConstantInMapFn(self): + + def _build_ds(): + constant_var = constant_op.constant(5) + return (contrib_dataset_ops.Dataset.from_tensors(0).repeat(10).map( + lambda x: x + constant_var)) + + self.run_core_tests(_build_ds, None, 10) + def testCaptureDefunInMapFn(self): num_outputs = 100 diff --git a/tensorflow/core/kernels/data/map_dataset_op.cc b/tensorflow/core/kernels/data/map_dataset_op.cc index 01f9b9fa09..89360d1cd9 100644 --- a/tensorflow/core/kernels/data/map_dataset_op.cc +++ b/tensorflow/core/kernels/data/map_dataset_op.cc @@ -95,10 +95,10 @@ class MapDatasetOp : public UnaryDatasetOpKernel { Node* input_graph_node = nullptr; TF_RETURN_IF_ERROR(b->AddParentDataset(ctx, input_, &input_graph_node)); - DataTypeVector other_arguments_types( - captured_func_->captured_inputs().size()); - std::vector other_arguments( - captured_func_->captured_inputs().size()); + DataTypeVector other_arguments_types; + other_arguments_types.reserve(captured_func_->captured_inputs().size()); + std::vector other_arguments; + other_arguments.reserve(captured_func_->captured_inputs().size()); for (const Tensor& t : captured_func_->captured_inputs()) { Node* node; TF_RETURN_IF_ERROR(b->AddTensor(t, &node)); diff --git a/tensorflow/core/kernels/data/parallel_map_dataset_op.cc b/tensorflow/core/kernels/data/parallel_map_dataset_op.cc index f09871d98d..bc4426a9fd 100644 --- a/tensorflow/core/kernels/data/parallel_map_dataset_op.cc +++ b/tensorflow/core/kernels/data/parallel_map_dataset_op.cc @@ -109,10 +109,10 @@ class ParallelMapDatasetOp : public UnaryDatasetOpKernel { TF_RETURN_IF_ERROR(b->AddParentDataset(ctx, input_, &input_graph_node)); // Input: other_arguments - DataTypeVector other_arguments_types( - captured_func_->captured_inputs().size()); - std::vector other_arguments( - captured_func_->captured_inputs().size()); + DataTypeVector other_arguments_types; + other_arguments_types.reserve(captured_func_->captured_inputs().size()); + std::vector other_arguments; + other_arguments.reserve(captured_func_->captured_inputs().size()); for (const Tensor& t : captured_func_->captured_inputs()) { Node* node; TF_RETURN_IF_ERROR(b->AddTensor(t, &node)); -- GitLab From 0c4c353690b0cec2e26e10abd59f66f7e61cc974 Mon Sep 17 00:00:00 2001 From: Zhixian Yan Date: Fri, 19 Jan 2018 14:51:11 -0800 Subject: [PATCH 018/258] TFLite export optional tensor as -1 id. PiperOrigin-RevId: 182592943 --- .../lite/toco/graph_transformations/dequantize.cc | 4 +++- .../propagate_array_data_types.cc | 3 ++- tensorflow/contrib/lite/toco/model.h | 12 ++++++++++++ tensorflow/contrib/lite/toco/tflite/export.cc | 5 +++-- tensorflow/contrib/lite/toco/tooling_util.cc | 10 ++++++++-- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/tensorflow/contrib/lite/toco/graph_transformations/dequantize.cc b/tensorflow/contrib/lite/toco/graph_transformations/dequantize.cc index b89e3f5310..79854cba34 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/dequantize.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/dequantize.cc @@ -214,7 +214,9 @@ bool Dequantize::Run(Model* model, std::size_t op_index) { } bool changed = false; for (const string& array : arrays) { - changed |= DequantizeArray(array, this, model); + if (!model->IsOptionalArray(array)) { + changed |= DequantizeArray(array, this, model); + } } return changed; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/propagate_array_data_types.cc b/tensorflow/contrib/lite/toco/graph_transformations/propagate_array_data_types.cc index c6f17cf319..29b55d9bfc 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/propagate_array_data_types.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/propagate_array_data_types.cc @@ -38,7 +38,8 @@ bool PropagateArrayDataTypes::Run(Model* model, std::size_t op_index) { // If the data type of some input is unknown, we need to yield. for (const auto& input : op->inputs) { - if (model->arrays[input]->data_type == ArrayDataType::kNone) { + if (!model->IsOptionalArray(input) && + model->arrays[input]->data_type == ArrayDataType::kNone) { return false; } } diff --git a/tensorflow/contrib/lite/toco/model.h b/tensorflow/contrib/lite/toco/model.h index 7b2235e275..b079750bed 100644 --- a/tensorflow/contrib/lite/toco/model.h +++ b/tensorflow/contrib/lite/toco/model.h @@ -1527,6 +1527,8 @@ struct Model { return *arrays.at(name); } Array& GetOrCreateArray(const string& name) { + // Make sure name is not used by an optional array + DCHECK(!optional_arrays.count(name)); if (!arrays.count(name)) { Array* ptr = new Array; arrays[name] = std::unique_ptr(ptr); @@ -1534,7 +1536,17 @@ struct Model { Array& result = GetArray(name); return result; } + void CreateOptionalArray(const string& name) { + DCHECK(!arrays.count(name) && !optional_arrays.count(name)); + optional_arrays.insert(name); + } + bool IsOptionalArray(const string& name) const { + return optional_arrays.count(name); + } + // Optional arrays are used for optional tensors, + // these tensors do not have data, but with reserved names as op inputs. + std::set optional_arrays; // The list of operators. Notice how it's a list of unique_ptr's, implying // that the Model is what owns Operator's and keeps them alive. std::vector> operators; diff --git a/tensorflow/contrib/lite/toco/tflite/export.cc b/tensorflow/contrib/lite/toco/tflite/export.cc index bec694a233..440353203e 100644 --- a/tensorflow/contrib/lite/toco/tflite/export.cc +++ b/tensorflow/contrib/lite/toco/tflite/export.cc @@ -235,9 +235,10 @@ Offset>> ExportOperators( for (const auto& op : model.operators) { std::vector inputs; for (const string& input : op->inputs) { - inputs.push_back(tensors_map.at(input)); + // -1 is the ID for optional tensor in TFLite output + int id = model.IsOptionalArray(input) ? -1 : tensors_map.at(input); + inputs.push_back(id); } - std::vector outputs; for (const string& output : op->outputs) { outputs.push_back(tensors_map.at(output)); diff --git a/tensorflow/contrib/lite/toco/tooling_util.cc b/tensorflow/contrib/lite/toco/tooling_util.cc index e09a469d55..f9093ab973 100644 --- a/tensorflow/contrib/lite/toco/tooling_util.cc +++ b/tensorflow/contrib/lite/toco/tooling_util.cc @@ -652,7 +652,7 @@ void CheckNonExistentIOArrays(const Model& model) { void CheckNoMissingArray(const Model& model) { for (const auto& op : model.operators) { for (const auto& input : op->inputs) { - CHECK(model.arrays.count(input)); + CHECK(model.arrays.count(input) || model.optional_arrays.count(input)); } for (const auto& output : op->outputs) { CHECK(model.arrays.count(output)); @@ -761,6 +761,8 @@ void CheckOperatorOrdering(const Model& model) { arrays_behind_us.insert(array_entry.first); } } + arrays_behind_us.insert(model.optional_arrays.begin(), + model.optional_arrays.end()); for (const auto& op : model.operators) { for (const auto& input : op->inputs) { if (!IsConstantParameterArray(model, input)) { @@ -784,6 +786,8 @@ void FixOperatorOrdering(Model* model) { arrays_behind_us.insert(array_entry.first); } } + arrays_behind_us.insert(model->optional_arrays.begin(), + model->optional_arrays.end()); std::vector> old_operators; std::swap(old_operators, model->operators); std::set remaining; @@ -1281,6 +1285,8 @@ void DropMinMax(Model* model, const string& array_name) { } bool IsAllocatableTransientArray(const Model& model, const string& array_name) { + // Optional array is not transient + if (model.IsOptionalArray(array_name)) return false; // The model's input and output arrays are externally allocated. // They are not transient arrays. if (IsInputArray(model, array_name)) { @@ -1304,7 +1310,7 @@ bool IsAllocatableTransientArray(const Model& model, const string& array_name) { } string AvailableArrayName(const Model& model, const string& name) { - if (!model.arrays.count(name)) { + if (!model.arrays.count(name) && !model.optional_arrays.count(name)) { return name; } const int kNumSuffixesToTry = 1000; -- GitLab From a141651809e17be5ebe02715074357a7c52c0220 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 19 Jan 2018 15:01:35 -0800 Subject: [PATCH 019/258] [XLA] Add xla_dump_prepass_hlo_proto_to debug flag Add xla_dump_prepass_hlo_proto_to debug flag for dumping HLO protos *BEFORE* running HLO passes, which will perform backend specific optimizations. PiperOrigin-RevId: 182594324 --- .../xla/legacy_flags/debug_options_flags.cc | 5 +++++ tensorflow/compiler/xla/service/BUILD | 1 + .../compiler/xla/service/compile_only_service.cc | 1 + tensorflow/compiler/xla/service/service.cc | 14 ++++++++++++++ tensorflow/compiler/xla/service/service.h | 2 ++ tensorflow/compiler/xla/xla.proto | 4 ++++ 6 files changed, 27 insertions(+) diff --git a/tensorflow/compiler/xla/legacy_flags/debug_options_flags.cc b/tensorflow/compiler/xla/legacy_flags/debug_options_flags.cc index e88bffd0ba..fe3a4d2f6d 100644 --- a/tensorflow/compiler/xla/legacy_flags/debug_options_flags.cc +++ b/tensorflow/compiler/xla/legacy_flags/debug_options_flags.cc @@ -223,6 +223,11 @@ void AllocateFlags() { tensorflow::Flag( "xla_dump_hlo_proto_to", flag_values->mutable_xla_dump_hlo_proto_to(), "Dump compilation artifacts as proto binary into this directory."), + tensorflow::Flag( + "xla_dump_prepass_hlo_proto_to", + flag_values->mutable_xla_dump_prepass_hlo_proto_to(), + "Dump compilation artifacts, before hlo passes are executed, as " + "proto binary into this directory."), tensorflow::Flag( "xla_test_all_output_layouts", bool_setter_for(&DebugOptions::set_xla_test_all_output_layouts), diff --git a/tensorflow/compiler/xla/service/BUILD b/tensorflow/compiler/xla/service/BUILD index 926bcfa1b8..426fead41b 100644 --- a/tensorflow/compiler/xla/service/BUILD +++ b/tensorflow/compiler/xla/service/BUILD @@ -454,6 +454,7 @@ cc_library( ":hlo_evaluator", ":hlo_execution_profile", ":hlo_module_config", + ":hlo_proto_util", ":platform_util", ":session_proto", ":transfer_manager", diff --git a/tensorflow/compiler/xla/service/compile_only_service.cc b/tensorflow/compiler/xla/service/compile_only_service.cc index 9e96898d9b..b9306a8bb0 100644 --- a/tensorflow/compiler/xla/service/compile_only_service.cc +++ b/tensorflow/compiler/xla/service/compile_only_service.cc @@ -107,6 +107,7 @@ CompileOnlyService::CompileAheadOfTime( computation_tracker_.BuildHloModule( versioned_handle, *module_config, /*include_unreachable_instructions=*/true)); + TF_RETURN_IF_ERROR(MaybeDumpHloModule(*hlo_module)); hlo_modules.push_back(std::move(hlo_module)); } diff --git a/tensorflow/compiler/xla/service/service.cc b/tensorflow/compiler/xla/service/service.cc index fc848bdb03..e230d25f1e 100644 --- a/tensorflow/compiler/xla/service/service.cc +++ b/tensorflow/compiler/xla/service/service.cc @@ -34,6 +34,7 @@ limitations under the License. #include "tensorflow/compiler/xla/service/hlo_instruction.h" #include "tensorflow/compiler/xla/service/hlo_module.h" #include "tensorflow/compiler/xla/service/hlo_module_config.h" +#include "tensorflow/compiler/xla/service/hlo_proto_util.h" #include "tensorflow/compiler/xla/service/platform_util.h" #include "tensorflow/compiler/xla/service/session.pb.h" #include "tensorflow/compiler/xla/service/transfer_manager.h" @@ -419,6 +420,8 @@ StatusOr> Service::BuildExecutable( /*include_unreachable_instructions=*/ true)); + TF_RETURN_IF_ERROR(MaybeDumpHloModule(*module)); + TF_ASSIGN_OR_RETURN( module, backend->compiler()->RunHloPasses(std::move(module), executor)); @@ -1597,4 +1600,15 @@ StatusOr> Service::Replicas( return replicas; } +Status Service::MaybeDumpHloModule(const HloModule& module) const { + const string xla_dump_prepass_hlo_proto_to = + module.config().debug_options().xla_dump_prepass_hlo_proto_to(); + if (xla_dump_prepass_hlo_proto_to.empty()) { + return Status::OK(); + } + HloProto proto = MakeHloProto(module); + return protobuf_util::DumpProtoToDirectory( + proto, xla_dump_prepass_hlo_proto_to, module.name()); +} + } // namespace xla diff --git a/tensorflow/compiler/xla/service/service.h b/tensorflow/compiler/xla/service/service.h index f962d0cdc7..0a7d0b3a7d 100644 --- a/tensorflow/compiler/xla/service/service.h +++ b/tensorflow/compiler/xla/service/service.h @@ -340,6 +340,8 @@ class Service : public ServiceInterface { StatusOr> Replicas( const Backend& backend, const DeviceHandle& device_handle) const; + Status MaybeDumpHloModule(const HloModule& module) const; + // Returns the device handle that represents the replicated device for a // single computation that is not model-parallelized. DeviceHandle SingleComputationDeviceHandle() const; diff --git a/tensorflow/compiler/xla/xla.proto b/tensorflow/compiler/xla/xla.proto index fda1a4c27b..e1ed08c848 100644 --- a/tensorflow/compiler/xla/xla.proto +++ b/tensorflow/compiler/xla/xla.proto @@ -179,6 +179,10 @@ message DebugOptions { // ops. bool xla_gpu_use_cudnn_batchnorm = 94; + // Dump compilation artifacts, before hlo passes are executed, in binary proto + // into this directory. + string xla_dump_prepass_hlo_proto_to = 95; + // Extra options to pass to the compilation backend; specific interpretation // of these values is left to the backend. map xla_backend_extra_options = 500; -- GitLab From dacb38ea3028f65b5d27c352110565183beacd1e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 19 Jan 2018 15:31:24 -0800 Subject: [PATCH 020/258] Automated g4 rollback of changelist 182559231 PiperOrigin-RevId: 182598631 --- tensorflow/python/ops/distributions/categorical.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/ops/distributions/categorical.py b/tensorflow/python/ops/distributions/categorical.py index 2046a08d61..84ca6db4c4 100644 --- a/tensorflow/python/ops/distributions/categorical.py +++ b/tensorflow/python/ops/distributions/categorical.py @@ -263,12 +263,11 @@ class Categorical(distribution.Distribution): logits_2d = self.logits else: logits_2d = array_ops.reshape(self.logits, [-1, self.event_size]) - draws = random_ops.multinomial( - logits_2d, n, seed=seed, output_dtype=self.dtype) + draws = random_ops.multinomial(logits_2d, n, seed=seed) draws = array_ops.reshape( array_ops.transpose(draws), array_ops.concat([[n], self.batch_shape_tensor()], 0)) - return draws + return math_ops.cast(draws, self.dtype) def _cdf(self, k): k = ops.convert_to_tensor(k, name="k") -- GitLab From 677d733e8449580c77b57566c94e71224ffcfad0 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Fri, 19 Jan 2018 15:42:39 -0800 Subject: [PATCH 021/258] Report incompatible shapes in case of check failure. PiperOrigin-RevId: 182600051 --- tensorflow/compiler/xla/service/layout_assignment.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tensorflow/compiler/xla/service/layout_assignment.cc b/tensorflow/compiler/xla/service/layout_assignment.cc index f80dace877..bbea6bee56 100644 --- a/tensorflow/compiler/xla/service/layout_assignment.cc +++ b/tensorflow/compiler/xla/service/layout_assignment.cc @@ -81,7 +81,10 @@ OperandLayoutConstraint::OperandLayoutConstraint( operand_no_(operand_no) { CHECK(shape_layout_.LayoutIsSet()); CHECK(ShapeUtil::Compatible(shape_layout.shape(), - instruction->operand(operand_no)->shape())); + instruction->operand(operand_no)->shape())) + << shape_layout.shape() << " is not compatible with " + << instruction->operand(operand_no)->shape() << " (for operand " + << operand_no << " of instruction " << instruction->ToString() << ")"; } string OperandLayoutConstraint::ToString() const { -- GitLab From f448189df9b62b6dd141ce14224dbfc0d8f0d11b Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 19 Jan 2018 16:54:39 -0800 Subject: [PATCH 022/258] Make sure the same rewrite is not performed multiple times in ArithmeticOptimizer, and that added nodes are unique. A couple of minor cleanups. PiperOrigin-RevId: 182609552 --- .../optimizers/arithmetic_optimizer.cc | 72 +++++++++++-------- .../optimizers/arithmetic_optimizer.h | 8 ++- .../optimizers/arithmetic_optimizer_test.cc | 46 ++++++------ .../grappler/optimizers/constant_folding.h | 1 - 4 files changed, 73 insertions(+), 54 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc index 990a07c86c..9c544c82bf 100644 --- a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc @@ -436,23 +436,31 @@ bool UniqueNodes::SameNode(const NodeDef& node1, const NodeDef& node2) const { return true; } +NodeDef* ArithmeticOptimizer::AddNode(const NodeDef& node, StringPiece suffix, + bool copy_node) { + return AddNode(OptimizedNodeName(node, suffix), copy_node ? &node : nullptr); +} + NodeDef* ArithmeticOptimizer::AddNode(const string& name, const NodeDef* node_to_copy) { NodeDef* new_node = optimized_graph_->add_node(); - const string name_with_prefix = - AddPrefixToNodeName(name, kArithmeticOptimizer); - node_map_->AddNode(NodeName(name_with_prefix), new_node); + node_map_->AddNode(NodeName(name), new_node); if (node_to_copy != nullptr) { *new_node = *node_to_copy; } - new_node->set_name(name_with_prefix); + new_node->set_name(name); return new_node; } -bool ArithmeticOptimizer::OptimizedNodeExists(const string& name) { - const string name_with_prefix = - AddPrefixToNodeName(name, kArithmeticOptimizer); - return node_map_->NodeExists(name_with_prefix); +string ArithmeticOptimizer::OptimizedNodeName(const NodeDef& node, + StringPiece suffix) const { + return AddPrefixToNodeName(strings::StrCat(node.name(), "_", suffix), + kArithmeticOptimizer); +} + +bool ArithmeticOptimizer::OptimizedNodeExists(const NodeDef& node, + StringPiece suffix) const { + return node_map_->NodeExists(OptimizedNodeName(node, suffix)); } bool ArithmeticOptimizer::CanDedup(const NodeDef& node) const { @@ -668,17 +676,19 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( const DataType src_type = GetSourceDataType(*cast); const DataType dst_type = GetDestinationDataType(*cast); if (IsNumberType(src_type) && IsNumberType(dst_type) && - DataTypeSize(src_type) < DataTypeSize(dst_type)) { - NodeDef* new_transpose = - AddNode(StrCat(transpose->name(), "_", DataTypeString(src_type)), - transpose); + DataTypeSize(src_type) < DataTypeSize(dst_type) && + !OptimizedNodeExists(*cast, DataTypeString(dst_type)) && + !OptimizedNodeExists(*transpose, DataTypeString(src_type))) { + NodeDef* new_transpose = AddNode(*transpose, DataTypeString(src_type), + /*copy_node=*/true); (*new_transpose->mutable_attr())["T"].set_type(src_type); new_transpose->set_input(0, cast->input(0)); node_map_->AddOutput(input->name(), new_transpose->name()); node_map_->AddOutput(NodeName(new_transpose->input(1)), new_transpose->name()); - NodeDef* new_cast = AddNode(StrCat(cast->name(), "_new"), cast); + NodeDef* new_cast = + AddNode(*cast, DataTypeString(dst_type), /*copy_node=*/true); new_cast->set_input(0, new_transpose->name()); node_map_->AddOutput(new_transpose->name(), new_cast->name()); @@ -754,7 +764,8 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( // multiply can be constant-folded. TODO(jingyue): When the weights aren't // constant, this should also help performance a bit and memory usage a lot, // since the weights tend to be smaller than the activations. - if (weights->op() == "Const") { + if (weights->op() == "Const" && + !OptimizedNodeExists(*weights, StrCat("scaled_", conv->name()))) { const NodeDef* source = node_map_->GetNode( GetTailOfValuePreservingChain(*node, *node_map_, nodes_to_preserve_) ->input(0)); @@ -773,7 +784,7 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( scale_tensor.tensor_shape().dim_size() == 0) { // Create new node `scaled_weights`. NodeDef* scaled_weights = AddNode( - StrCat(weights->name(), "_scaled_", conv->name()), nullptr); + *weights, StrCat("scaled_", conv->name()), /*copy_node=*/false); scaled_weights->set_op("Mul"); scaled_weights->set_device(weights->device()); (*scaled_weights->mutable_attr())["T"] = @@ -810,9 +821,8 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( } if (node->op() == "Mul" && node->input(0) == node->input(1) && - !OptimizedNodeExists(StrCat(node->name(), "_square"))) { - NodeDef* new_square_node = - AddNode(strings::StrCat(node->name(), "_square"), node); + !OptimizedNodeExists(*node, "square")) { + NodeDef* new_square_node = AddNode(*node, "square", /*copy_node=*/true); new_square_node->set_op("Square"); for (int i = 1; i < new_square_node->input_size(); ++i) { new_square_node->set_input(i - 1, new_square_node->input(i)); @@ -847,8 +857,8 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( break; } } - const string mul_node_name = StrCat(node->name(), "_mul"); - if (all_equal && !OptimizedNodeExists(mul_node_name)) { + if (all_equal && !OptimizedNodeExists(*node, "const") && + !OptimizedNodeExists(*node, "mul")) { // 1. Create constant node with value N. const auto type = GetDataTypeFromAttr(*node, "T"); Tensor t(type, TensorShape({})); @@ -859,15 +869,14 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( return ""; } TensorValue value(&t); - NodeDef* new_const_node = - AddNode(StrCat(node->name(), "_const"), nullptr); + NodeDef* new_const_node = AddNode(*node, "const", /*copy_node=*/false); *new_const_node = ConstantFolding::CreateNodeDef(new_const_node->name(), value); new_const_node->set_device(node->device()); nodes_to_simplify->PushBack(new_const_node); // 2. Replace the aggregate node with Mul(Const(N), x). - NodeDef* new_mul_node = AddNode(mul_node_name, nullptr); + NodeDef* new_mul_node = AddNode(*node, "mul", /*copy_node=*/false); new_mul_node->set_op("Mul"); new_mul_node->set_device(node->device()); SetDataTypeToAttr(type, "T", new_mul_node); @@ -892,7 +901,8 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( // to the following: // Mul(x, AddN(y1, y2, y3, ... yn)) if (IsAggregate(*node) && NumNonControlInputs(*node) > 1 && - !OptimizedNodeExists(StrCat(node->name(), "_hoist_add"))) { + !OptimizedNodeExists(*node, "hoist_add") && + !OptimizedNodeExists(*node, "hoist_mul")) { // Determine the set of common factors if the input nodes are all Mul nodes. std::set common_factors; for (int i = 0; i < node->input_size(); ++i) { @@ -946,10 +956,9 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( if (shapes_match) { // 1. Use a copy of the first Mul node for the outer multiplication. - NodeDef* new_mul_node = AddNode(StrCat(node->name(), "_hoist_mul"), + NodeDef* new_mul_node = AddNode(OptimizedNodeName(*node, "hoist_mul"), node_map_->GetNode(node->input(0))); - NodeDef* new_add_node = - AddNode(StrCat(node->name(), "_hoist_add"), node); + NodeDef* new_add_node = AddNode(*node, "hoist_add", /*copy_node=*/true); new_mul_node->set_device(node->device()); new_mul_node->set_input(0, common_factor); node_map_->AddOutput(common_factor, new_mul_node->name()); @@ -978,7 +987,7 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( // Fold Transpose into matrix multiplication. if ((node->op() == "MatMul" || node->op() == "SparseMatMul" || node->op() == "BatchMatMul") && - !OptimizedNodeExists(StrCat(node->name(), "_fused"))) { + !OptimizedNodeExists(*node, "fused")) { const NodeDef* a = node_map_->GetNode(node->input(0)); const NodeDef* b = node_map_->GetNode(node->input(1)); bool is_complex = false; @@ -996,7 +1005,7 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( const bool b_is_foldable = foldable_transpose_ops.count(b->op()) > 0 && IsInnerMatrixTransposeNode(*b, node_map_.get()); if (a_is_foldable || b_is_foldable) { - NodeDef* new_op = AddNode(StrCat(node->name(), "_fused"), node); + NodeDef* new_op = AddNode(*node, "fused", /*copy_node=*/true); if (a_is_foldable) { const string attr_a = node->op() == "BatchMatMul" ? "adj_x" : "transpose_a"; @@ -1021,7 +1030,7 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( // Fold Conj into Transpose or ConjugateTranspose. if ((node->op() == "Conj" || node->op() == "Transpose" || node->op() == "ConjugateTranspose") && - !OptimizedNodeExists(StrCat(node->name(), "_fused"))) { + !OptimizedNodeExists(*node, "fused")) { const NodeDef* input = node_map_->GetNode(node->input(0)); const NodeDef* transpose_op = node->op() == "Conj" ? input : node; const NodeDef* conj_op = node->op() == "Conj" ? node : input; @@ -1029,7 +1038,8 @@ string ArithmeticOptimizer::TrySimplifyAndReplaceUses( if ((transpose_op->op() == "Transpose" || transpose_op->op() == "ConjugateTranspose") && conj_op->op() == "Conj") { - NodeDef* new_op = AddNode(StrCat(node->name(), "_fused"), transpose_op); + NodeDef* new_op = + AddNode(OptimizedNodeName(*node, "fused"), transpose_op); // Flip the type of transpose op to absorb the conjugation. new_op->set_op(transpose_op->op() == "Transpose" ? "ConjugateTranspose" : "Transpose"); diff --git a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.h b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.h index ec26979238..afd538db40 100644 --- a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.h +++ b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.h @@ -48,7 +48,13 @@ class ArithmeticOptimizer : public GraphOptimizer { private: // Returns true is a node with given name and the optimizer prefix already // exists. - bool OptimizedNodeExists(const string& name); + string OptimizedNodeName(const NodeDef& node, StringPiece suffix) const; + bool OptimizedNodeExists(const NodeDef& node, StringPiece suffix) const; + + // Creates a new node in the graph, with name equal to that of node, prefixed + // with "ArithmeticOptimizer/" and the given suffix. Also updates node_map_, + // and optionally copies node into the new node if copy_node is true. + NodeDef* AddNode(const NodeDef& node, StringPiece suffix, bool copy_node); // Creates a new node in the graph, prefixed with "ArithmeticOptimizer/", // updates node_map_, and optionally copies *node_to_copy into the new diff --git a/tensorflow/core/grappler/optimizers/arithmetic_optimizer_test.cc b/tensorflow/core/grappler/optimizers/arithmetic_optimizer_test.cc index b5b1ec7021..2a82b25058 100644 --- a/tensorflow/core/grappler/optimizers/arithmetic_optimizer_test.cc +++ b/tensorflow/core/grappler/optimizers/arithmetic_optimizer_test.cc @@ -627,7 +627,7 @@ TEST_F(ArithmeticOptimizerTest, IdentityReshape) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); EXPECT_EQ(0, std::count_if( @@ -651,7 +651,7 @@ TEST_F(ArithmeticOptimizerTest, NotIdentityReshape) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); EXPECT_EQ(1, std::count_if( @@ -673,7 +673,7 @@ TEST_F(ArithmeticOptimizerTest, NotIdentityReshapeTooManyUnknownDimSizes) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); EXPECT_EQ(1, std::count_if( @@ -706,7 +706,7 @@ TEST_F(ArithmeticOptimizerTest, CombineReshapes) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); EXPECT_EQ(1, std::count_if( @@ -730,7 +730,7 @@ TEST_F(ArithmeticOptimizerTest, ReorderTransposeCast) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); const NodeDef* transpose_node = nullptr; @@ -766,7 +766,7 @@ TEST_F(ArithmeticOptimizerTest, NoReorderTransposeCast) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); int num_transposes = 0; @@ -800,7 +800,7 @@ TEST_F(ArithmeticOptimizerTest, RemoveInverseTransposes) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); std::set nodes_after_optimization; @@ -833,7 +833,7 @@ TEST_F(ArithmeticOptimizerTest, RemoveInverseTransposesMultipleOutputs) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); for (const NodeDef& node : output.node()) { @@ -860,7 +860,7 @@ TEST_F(ArithmeticOptimizerTest, RemoveTransposesWithControlDependency) { TF_CHECK_OK(s.ToGraphDef(&item.graph)); GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); NodeMap node_map(&output); @@ -889,7 +889,7 @@ TEST_F(ArithmeticOptimizerTest, NotRemoveTransposes) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); EXPECT_EQ(6, output.node_size()); @@ -920,7 +920,7 @@ TEST_F(ArithmeticOptimizerTest, FoldMulToTransposeConv) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); NodeMap node_map(&output); @@ -962,7 +962,7 @@ TEST_F(ArithmeticOptimizerTest, NotFoldMulAcrossPreservedTranspose) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); NodeMap node_map(&output); @@ -992,7 +992,7 @@ TEST_F(ArithmeticOptimizerTest, FoldMulToConv) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); NodeMap node_map(&output); @@ -1031,11 +1031,15 @@ TEST_F(ArithmeticOptimizerTest, OptimizeCastMulTransposeConv) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + // Run the optimizer twice to make sure the rewrite is idempotent. + item.graph.Swap(&output); + TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); + + item.graph.Swap(&output); TF_EXPECT_OK( ConstantFolding(/*cpu_device=*/nullptr).Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); NodeMap node_map(&output); @@ -1043,7 +1047,7 @@ TEST_F(ArithmeticOptimizerTest, OptimizeCastMulTransposeConv) { const NodeDef* transpose_node = CHECK_NOTNULL(node_map.GetNode(OptimizedName("Transpose_uint8"))); const NodeDef* cast_node = - CHECK_NOTNULL(node_map.GetNode(OptimizedName("Cast_new"))); + CHECK_NOTNULL(node_map.GetNode(OptimizedName("Cast_float"))); const NodeDef* weights_node = CHECK_NOTNULL(node_map.GetNode(OptimizedName("weights_scaled_Conv2D"))); const NodeDef* conv_node = CHECK_NOTNULL(node_map.GetNode("Conv2D")); @@ -1080,11 +1084,11 @@ TEST_F(ArithmeticOptimizerTest, OptimizeMultipleMulTransposeConv) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK( ConstantFolding(/*cpu_device=*/nullptr).Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); NodeMap node_map(&output); @@ -1113,7 +1117,7 @@ TEST_F(ArithmeticOptimizerTest, CombineBitcasts) { GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); EXPECT_EQ(1, std::count_if( @@ -1133,7 +1137,7 @@ TEST_F(ArithmeticOptimizerTest, CombineAndRemoveBitcasts) { TF_CHECK_OK(s.ToGraphDef(&item.graph)); GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); EXPECT_EQ(0, std::count_if( @@ -1152,7 +1156,7 @@ TEST_F(ArithmeticOptimizerTest, RemoveRedundantCast) { TF_CHECK_OK(s.ToGraphDef(&item.graph)); GraphDef output; TF_EXPECT_OK(ArithmeticOptimizer().Optimize(nullptr, item, &output)); - item.graph = output; + item.graph.Swap(&output); TF_EXPECT_OK(ModelPruner().Optimize(nullptr, item, &output)); EXPECT_EQ(0, std::count_if( diff --git a/tensorflow/core/grappler/optimizers/constant_folding.h b/tensorflow/core/grappler/optimizers/constant_folding.h index 6aadd97508..18acc91e8a 100644 --- a/tensorflow/core/grappler/optimizers/constant_folding.h +++ b/tensorflow/core/grappler/optimizers/constant_folding.h @@ -52,7 +52,6 @@ class ConstantFolding : public GraphOptimizer { private: string OptimizedNodeName(const NodeDef& node, StringPiece suffix) const; - string OptimizedNodeName(const NodeDef& node) const; bool OptimizedNodeExists(const NodeDef& node, StringPiece suffix) const; bool IsReallyConstant(const NodeDef& node) const; -- GitLab From ce76b3e5e34b58d3e295c824ae2e43fe63bc1680 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Fri, 19 Jan 2018 16:55:11 -0800 Subject: [PATCH 023/258] Add clif rules for function.proto. PiperOrigin-RevId: 182609604 --- tensorflow/core/BUILD | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 0b1d549459..5a58eb31ea 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -1316,6 +1316,13 @@ tf_pyclif_proto_library( visibility = ["//visibility:public"], ) +tf_pyclif_proto_library( + name = "framework/function_pyclif", + proto_lib = ":protos_all_cc", + proto_srcfile = "framework/function.proto", + visibility = ["//visibility:public"], +) + tf_pyclif_proto_library( name = "framework/graph_pyclif", proto_lib = ":protos_all_cc", -- GitLab From 723e98328b71c6f8121f85571dc7f8dc9c9cbfda Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 19 Jan 2018 17:18:25 -0800 Subject: [PATCH 024/258] [XLA] Update R4 reduce window test cases. PiperOrigin-RevId: 182612106 --- .../compiler/xla/tests/reduce_window_test.cc | 88 +++++++++++++++++-- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/tensorflow/compiler/xla/tests/reduce_window_test.cc b/tensorflow/compiler/xla/tests/reduce_window_test.cc index 01f23efcd5..51e0765f7f 100644 --- a/tensorflow/compiler/xla/tests/reduce_window_test.cc +++ b/tensorflow/compiler/xla/tests/reduce_window_test.cc @@ -533,6 +533,7 @@ struct R4ReduceWindowTestData { int64 strides[4]; int64 pad_low[4]; int64 pad_high[4]; + int64 layout[4]; Reducer reducer; }; @@ -548,7 +549,8 @@ string R4ReduceWindowTestDataToString( "__strides_", tensorflow::str_util::Join(param.strides, "x"), // "__pad_low_", tensorflow::str_util::Join(param.pad_low, "x"), // "__pad_high_", tensorflow::str_util::Join(param.pad_high, "x"), // - (param.reducer == kAdd) ? "add" : "max"); + "__layout_", tensorflow::str_util::Join(param.layout, "_"), // + (param.reducer == kAdd) ? "_add" : "_max"); CHECK(param.reducer == kAdd || param.reducer == kMax); // Test names are not allowed to contain the '-' character. @@ -575,7 +577,8 @@ class R4ReduceWindowTest : public ReduceWindowTestBase, param.base_bounds[2], param.base_bounds[3]); input.FillIota(1); std::unique_ptr input_literal = - Literal::CreateR4FromArray4D(input); + Literal::CreateR4FromArray4DWithLayout( + input, LayoutUtil::MakeLayout(param.layout)); ComputationDataHandle parameter; auto input_arg = CreateParameterAndTransferLiteral(0, *input_literal, "p0", &b, ¶meter); @@ -611,8 +614,13 @@ class R4ReduceWindowTest : public ReduceWindowTestBase, /*window=*/param.window_bounds, /*stride=*/param.strides, /*padding=*/padding); - ComputeAndCompareLiteral(&b, *Literal::CreateFromArray(*expected), - {input_arg.get()}, DefaultErrorSpec()); + std::unique_ptr expected_literal = + Literal::CreateFromArray(*expected); + const Shape& expected_shape_with_layout = ShapeUtil::MakeShapeWithLayout( + input_literal->shape().element_type(), + AsInt64Slice(expected_literal->shape().dimensions()), param.layout); + ComputeAndCompareLiteral(&b, *expected_literal, {input_arg.get()}, + DefaultErrorSpec(), &expected_shape_with_layout); } }; @@ -626,6 +634,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // Arbitrary padding (not kSame or kValid). @@ -634,6 +643,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{2, 2, 1, 1}, /*pad_low=*/{4, 4, 0, 0}, /*pad_high=*/{4, 4, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // Zero base bound edge case. @@ -642,6 +652,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With non-1x1 window. @@ -650,6 +661,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With max instead of add. @@ -658,6 +670,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kMax}, // With stride. @@ -666,6 +679,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{2, 4, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With low padding. @@ -674,6 +688,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{2, 2, 1, 1}, /*pad_low=*/{3, 2, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With high padding. @@ -682,6 +697,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{2, 2, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{2, 3, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // Window touches both sides of the padding simultaneously. @@ -690,6 +706,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{1, 1, 0, 0}, /*pad_high=*/{1, 1, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // Window is entirely in the padding for some positions. @@ -698,6 +715,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{4, 4, 0, 0}, /*pad_high=*/{4, 4, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // Zero base bound with padding edge case. @@ -706,6 +724,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{0, 1, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With stride, low padding and high padding. @@ -714,6 +733,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{3, 1, 1, 1}, /*pad_low=*/{10, 1, 0, 0}, /*pad_high=*/{2, 3, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With second minor dimension == 9. @@ -722,6 +742,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With minor dimension == 129. @@ -730,6 +751,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With minor dims reduction and non-overlapped stride. @@ -738,6 +760,7 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*strides=*/{1, 1, 2, 2}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, // With minor dims reduction and overlapped stride. @@ -745,7 +768,8 @@ const R4ReduceWindowTestData kR4ReduceWindowTestValues[] = { /*window_bounds=*/{1, 1, 4, 4}, /*strides=*/{1, 1, 2, 2}, /*pad_low=*/{0, 0, 0, 0}, - /*pad_high=*/{0, 0, 0, 0}, + /*pad_high=*/{1, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, }; @@ -762,10 +786,11 @@ XLA_TEST_P(R4ReduceWindowLargeTest, DISABLED_ON_INTERPRETER(DoIt)) { DoIt(); } // Test cases that are large/slow/failed. const R4ReduceWindowTestData kR4ReduceWindowLargeTestValues[] = { R4ReduceWindowTestData{/*base_bounds=*/{28, 28, 256, 128}, - /*window_bounds=*/{3, 3, 1, 1}, - /*strides=*/{1, 1, 1, 1}, + /*window_bounds=*/{3, 3, 1, 5}, + /*strides=*/{1, 1, 1, 5}, /*pad_low=*/{1, 1, 0, 0}, /*pad_high=*/{1, 1, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kMax}, R4ReduceWindowTestData{/*base_bounds=*/{112, 112, 64, 128}, @@ -773,6 +798,7 @@ const R4ReduceWindowTestData kR4ReduceWindowLargeTestValues[] = { /*strides=*/{2, 2, 1, 1}, /*pad_low=*/{0, 0, 0, 0}, /*pad_high=*/{1, 1, 0, 0}, + /*layout=*/{3, 2, 1, 0}, /*reducer=*/kAdd}, }; @@ -782,6 +808,54 @@ INSTANTIATE_TEST_CASE_P( ::testing::ValuesIn(use_bfloat16_params)), R4ReduceWindowTestDataToString); +class R4ReduceWindowAnyDimsTest : public R4ReduceWindowTest {}; + +// TODO(b/72234705): Fix the test cases failed on CPU. +XLA_TEST_P(R4ReduceWindowAnyDimsTest, + DISABLED_ON_CPU_PARALLEL(DISABLED_ON_CPU(DoIt))) { + DoIt(); +} + +const R4ReduceWindowTestData kR4ReduceWindowAnyDimsTestValues[] = { + R4ReduceWindowTestData{/*base_bounds=*/{4, 6, 17, 140}, + /*window_bounds=*/{2, 3, 4, 5}, + /*strides=*/{1, 1, 1, 1}, + /*pad_low=*/{0, 0, 0, 0}, + /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, + /*reducer=*/kAdd}, + R4ReduceWindowTestData{/*base_bounds=*/{4, 6, 17, 140}, + /*window_bounds=*/{2, 3, 1, 1}, + /*strides=*/{1, 1, 1, 1}, + /*pad_low=*/{0, 0, 0, 0}, + /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{3, 2, 1, 0}, + /*reducer=*/kMax}, + // With 0321 layout. + R4ReduceWindowTestData{/*base_bounds=*/{4, 6, 17, 140}, + /*window_bounds=*/{2, 3, 4, 5}, + /*strides=*/{1, 2, 3, 4}, + /*pad_low=*/{0, 0, 0, 0}, + /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{0, 3, 2, 1}, + /*reducer=*/kAdd}, + + // With 0123 layout. + R4ReduceWindowTestData{/*base_bounds=*/{4, 6, 17, 23}, + /*window_bounds=*/{2, 3, 7, 9}, + /*strides=*/{1, 2, 5, 8}, + /*pad_low=*/{0, 0, 0, 0}, + /*pad_high=*/{0, 0, 0, 0}, + /*layout=*/{0, 1, 2, 3}, + /*reducer=*/kAdd}, +}; + +INSTANTIATE_TEST_CASE_P( + R4ReduceWindowAnyDimsTestInstantiation, R4ReduceWindowAnyDimsTest, + ::testing::Combine(::testing::ValuesIn(kR4ReduceWindowAnyDimsTestValues), + ::testing::ValuesIn(use_bfloat16_params)), + R4ReduceWindowTestDataToString); + struct R3ReduceWindowTestData { int64 base_bounds[3]; int64 window_bounds[3]; -- GitLab From 1ebcfc1da181ba19f21fa0da655dbf247e054cfb Mon Sep 17 00:00:00 2001 From: Mark Heffernan Date: Fri, 19 Jan 2018 18:05:19 -0800 Subject: [PATCH 025/258] Add check for valid outfeed shape on outfeed creation and in HloVerifier. PiperOrigin-RevId: 182616345 --- .../compiler/xla/service/hlo_instruction.cc | 3 +++ .../compiler/xla/service/hlo_instruction_test.cc | 4 ++-- tensorflow/compiler/xla/service/hlo_verifier.cc | 16 ++++++++++++++-- .../compiler/xla/tools/parser/hlo_parser.cc | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_instruction.cc b/tensorflow/compiler/xla/service/hlo_instruction.cc index b2755b97bf..a889c35aeb 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.cc +++ b/tensorflow/compiler/xla/service/hlo_instruction.cc @@ -404,6 +404,9 @@ HloInstruction::CreateCrossReplicaSum( tensorflow::StringPiece outfeed_config) { std::unique_ptr instruction = WrapUnique(new HloInstruction(HloOpcode::kOutfeed, ShapeUtil::MakeNil())); + CHECK(ShapeUtil::Compatible(operand->shape(), shape)) + << "Outfeed shape " << shape << " must be compatible with operand shape " + << operand->shape(); instruction->AppendOperand(operand); instruction->outfeed_config_ = outfeed_config.ToString(); instruction->outfeed_shape_ = shape; diff --git a/tensorflow/compiler/xla/service/hlo_instruction_test.cc b/tensorflow/compiler/xla/service/hlo_instruction_test.cc index 3af3b29ced..1038ab5555 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction_test.cc +++ b/tensorflow/compiler/xla/service/hlo_instruction_test.cc @@ -712,8 +712,8 @@ TEST_F(HloInstructionTest, PreserveOutfeedShapeThroughClone) { {1, 2}, {3, 4}, }))); - auto shape10 = ShapeUtil::MakeShapeWithLayout(F32, {2, 3}, {1, 0}); - auto shape01 = ShapeUtil::MakeShapeWithLayout(F32, {2, 3}, {0, 1}); + auto shape10 = ShapeUtil::MakeShapeWithLayout(F32, {2, 2}, {1, 0}); + auto shape01 = ShapeUtil::MakeShapeWithLayout(F32, {2, 2}, {0, 1}); auto outfeed10 = builder.AddInstruction( HloInstruction::CreateOutfeed(shape10, constant, "")); auto outfeed01 = builder.AddInstruction( diff --git a/tensorflow/compiler/xla/service/hlo_verifier.cc b/tensorflow/compiler/xla/service/hlo_verifier.cc index ce0eb1af92..6e46f945e0 100644 --- a/tensorflow/compiler/xla/service/hlo_verifier.cc +++ b/tensorflow/compiler/xla/service/hlo_verifier.cc @@ -107,8 +107,20 @@ Status ShapeVerifier::HandleInfeed(HloInstruction*) { return tensorflow::Status::OK(); } -Status ShapeVerifier::HandleOutfeed(HloInstruction*) { - return tensorflow::Status::OK(); +Status ShapeVerifier::HandleOutfeed(HloInstruction* outfeed) { + // Outfeed has a separate shape field for the value which is outfed to the + // host. The shape of the instruction itself is always nil because the outfeed + // produces no HLO value in the graph. + if (!ShapeUtil::Compatible(outfeed->outfeed_shape(), + outfeed->operand(0)->shape())) { + return InvalidArgument( + "Expected outfeed to have shape compatible with operand's shape %s, " + "actual shape is %s:\n%s", + ShapeUtil::HumanString(outfeed->operand(0)->shape()).c_str(), + ShapeUtil::HumanString(outfeed->outfeed_shape()).c_str(), + outfeed->ToString().c_str()); + } + return CheckShape(outfeed, ShapeUtil::MakeNil()); } Status ShapeVerifier::HandleRng(HloInstruction*) { diff --git a/tensorflow/compiler/xla/tools/parser/hlo_parser.cc b/tensorflow/compiler/xla/tools/parser/hlo_parser.cc index 1c68e271e0..42e7f91f26 100644 --- a/tensorflow/compiler/xla/tools/parser/hlo_parser.cc +++ b/tensorflow/compiler/xla/tools/parser/hlo_parser.cc @@ -931,7 +931,7 @@ bool HloParser::ParseInstruction(HloComputation::Builder* builder, return false; } instruction = builder->AddInstruction(HloInstruction::CreateOutfeed( - shape, operands[0], config ? *config : "")); + operands[0]->shape(), operands[0], config ? *config : "")); break; } case HloOpcode::kRng: { -- GitLab From 76d33554c72f9bd193362a86aab6c91b5fceb234 Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Fri, 19 Jan 2018 19:13:43 -0800 Subject: [PATCH 026/258] Turn the op_performance_data proto lib into a header only library by default PiperOrigin-RevId: 182621348 --- tensorflow/core/BUILD | 6 +++-- tensorflow/core/grappler/costs/BUILD | 24 +++++++++---------- .../core/platform/default/build_config.bzl | 8 +++++++ tensorflow/python/BUILD | 4 ++-- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 5a58eb31ea..9738a6bb95 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -136,6 +136,8 @@ load( "tf_nano_proto_library", "tf_protos_all", "tf_protos_all_impl", + "tf_protos_grappler", + "tf_protos_grappler_impl", ) load( "//tensorflow/core:platform/default/build_config_root.bzl", @@ -1534,7 +1536,7 @@ cc_library( "@snappy", "@zlib_archive//:zlib", "@protobuf_archive//:protobuf", - ] + tf_protos_all_impl(), + ] + tf_protos_all_impl() + tf_protos_grappler_impl(), ) # File compiled with extra flags to get cpu-specific acceleration. @@ -2099,7 +2101,7 @@ tf_cuda_library( ":core_cpu_base", ":proto_text", "//tensorflow/core/grappler:grappler_item", - ] + if_static([":core_cpu_impl"]) + tf_protos_all(), + ] + if_static([":core_cpu_impl"]) + tf_protos_all() + tf_protos_grappler(), ) tf_cuda_library( diff --git a/tensorflow/core/grappler/costs/BUILD b/tensorflow/core/grappler/costs/BUILD index 7abc155c19..0fe01e9c9e 100644 --- a/tensorflow/core/grappler/costs/BUILD +++ b/tensorflow/core/grappler/costs/BUILD @@ -1,6 +1,10 @@ licenses(["notice"]) # Apache 2.0 load("//tensorflow:tensorflow.bzl", "tf_cuda_library", "tf_cc_test") +load( + "//tensorflow/core:platform/default/build_config.bzl", + "tf_protos_grappler", +) filegroup( name = "all_files", @@ -37,6 +41,7 @@ tf_proto_library( name = "op_performance_data", srcs = ["op_performance_data.proto"], cc_api_version = 2, + default_header = True, protodeps = tf_additional_all_protos(), visibility = ["//visibility:public"], ) @@ -47,7 +52,6 @@ cc_library( hdrs = ["graph_properties.h"], visibility = ["//visibility:public"], deps = [ - ":op_performance_data_cc", ":utils", "//tensorflow/core:core_cpu_base", "//tensorflow/core:framework", @@ -55,7 +59,7 @@ cc_library( "//tensorflow/core/grappler:grappler_item", "//tensorflow/core/grappler:utils", "//tensorflow/core/grappler/clusters:cluster", - ], + ] + tf_protos_grappler(), ) tf_cc_test( @@ -135,7 +139,7 @@ tf_cuda_library( hdrs = ["utils.h"], visibility = ["//visibility:public"], deps = [ - ":op_performance_data_cc", + "//third_party/eigen3", "//tensorflow/core:framework", "//tensorflow/core:graph", "//tensorflow/core:lib", @@ -143,8 +147,7 @@ tf_cuda_library( "//tensorflow/core:protos_all_cc", "//tensorflow/core/grappler:utils", "//tensorflow/core/grappler/clusters:utils", - "//third_party/eigen3", - ], + ] + tf_protos_grappler(), ) tf_cc_test( @@ -207,9 +210,8 @@ cc_library( hdrs = ["op_context.h"], visibility = ["//visibility:public"], deps = [ - ":op_performance_data_cc", "//tensorflow/core:protos_all_cc", - ], + ] + tf_protos_grappler(), ) cc_library( @@ -276,12 +278,11 @@ cc_library( deps = [ ":cost_estimator", ":op_context", - ":op_performance_data_cc", + "//third_party/eigen3", "//tensorflow/core:framework", "//tensorflow/core:protos_all_cc", "//tensorflow/core/grappler/clusters:utils", - "//third_party/eigen3", - ], + ] + tf_protos_grappler(), ) tf_cc_test( @@ -305,7 +306,6 @@ cc_library( ":cost_estimator", ":graph_properties", ":op_level_cost_estimator", - ":op_performance_data_cc", ":utils", ":virtual_placer", ":virtual_scheduler", @@ -314,7 +314,7 @@ cc_library( "//tensorflow/core:lib", "//tensorflow/core:protos_all_cc", "//tensorflow/core/grappler:grappler_item", - ], + ] + tf_protos_grappler(), ) tf_cc_test( diff --git a/tensorflow/core/platform/default/build_config.bzl b/tensorflow/core/platform/default/build_config.bzl index e9c510c93c..2102c5cca3 100644 --- a/tensorflow/core/platform/default/build_config.bzl +++ b/tensorflow/core/platform/default/build_config.bzl @@ -378,6 +378,14 @@ def tf_protos_all(): extra_deps=tf_protos_all_impl(), otherwise=["//tensorflow/core:protos_all_cc"]) +def tf_protos_grappler_impl(): + return ["//tensorflow/core/grappler/costs:op_performance_data_cc_impl"] + +def tf_protos_grappler(): + return if_static( + extra_deps=tf_protos_grappler_impl(), + otherwise=["//tensorflow/core/grappler/costs:op_performance_data_cc"]) + def tf_env_time_hdrs(): return [ "platform/env_time.h", diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 3493ed76f3..dbb29d9878 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -32,6 +32,7 @@ load("//tensorflow/core:platform/default/build_config.bzl", "tf_proto_library") load("//tensorflow/core:platform/default/build_config.bzl", "tf_proto_library_py") load("//tensorflow/core:platform/default/build_config.bzl", "tf_additional_lib_deps") load("//tensorflow/core:platform/default/build_config.bzl", "tf_additional_all_protos") +load("//tensorflow/core:platform/default/build_config.bzl", "tf_protos_grappler") load("//tensorflow/core:platform/default/build_config_root.bzl", "tf_additional_plugin_deps") load("//tensorflow/python:build_defs.bzl", "tf_gen_op_wrapper_private_py") load("//tensorflow/core:platform/default/build_config_root.bzl", "tf_additional_verbs_deps") @@ -209,9 +210,8 @@ cc_library( "//tensorflow/core/grappler/costs:analytical_cost_estimator", "//tensorflow/core/grappler/costs:cost_estimator", "//tensorflow/core/grappler/costs:measuring_cost_estimator", - "//tensorflow/core/grappler/costs:op_performance_data_cc", "//tensorflow/core/grappler/costs:utils", - ], + ] + tf_protos_grappler(), ) cc_library( -- GitLab From b3e464e0d658c7039b621ef86b1c725ad7f81eac Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 19 Jan 2018 20:52:19 -0800 Subject: [PATCH 027/258] Added BeamRoot to manage instances of BeamEntry for CTCBeamSearchDecoder to avoid recursive destructor call. PiperOrigin-RevId: 182625992 --- tensorflow/core/util/ctc/ctc_beam_entry.h | 51 +++++++++++++++++----- tensorflow/core/util/ctc/ctc_beam_search.h | 17 +++++--- tensorflow/core/util/ctc/ctc_decoder.h | 3 ++ 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/tensorflow/core/util/ctc/ctc_beam_entry.h b/tensorflow/core/util/ctc/ctc_beam_entry.h index d30ab3f4da..53087821d7 100644 --- a/tensorflow/core/util/ctc/ctc_beam_entry.h +++ b/tensorflow/core/util/ctc/ctc_beam_entry.h @@ -52,26 +52,25 @@ struct BeamProbability { float label; }; +template +class BeamRoot; + template struct BeamEntry { - // Default constructor does not create a vector of children. - BeamEntry() : parent(nullptr), label(-1) {} - // Constructor giving parent, label, and number of children does - // create a vector of children. The object pointed to by p - // cannot be copied and should not be moved, otherwise parent will - // become invalid. - BeamEntry(BeamEntry* p, int l) : parent(p), label(l) {} + // BeamRoot::AddEntry() serves as the factory method. + friend BeamEntry* BeamRoot::AddEntry( + BeamEntry* p, int l); inline bool Active() const { return newp.total != kLogZero; } // Return the child at the given index, or construct a new one in-place if // none was found. BeamEntry& GetChild(int ind) { auto entry = children.emplace(ind, nullptr); auto& child_entry = entry.first->second; - // If this is a new child, populate the uniqe_ptr. + // If this is a new child, populate the BeamEntry*. if (entry.second) { - child_entry.reset(new BeamEntry(this, ind)); + child_entry = beam_root->AddEntry(this, ind); } - return *(child_entry.get()); + return *child_entry; } std::vector LabelSeq(bool merge_repeated) const { std::vector labels; @@ -90,15 +89,45 @@ struct BeamEntry { BeamEntry* parent; int label; - gtl::FlatMap>> children; + // All instances of child BeamEntry are owned by *beam_root. + gtl::FlatMap*> children; BeamProbability oldp; BeamProbability newp; CTCBeamState state; private: + // Constructor giving parent, label, and the beam_root. + // The object pointed to by p cannot be copied and should not be moved, + // otherwise parent will become invalid. + // This private constructor is only called through the factory method + // BeamRoot::AddEntry(). + BeamEntry(BeamEntry* p, int l, BeamRoot* beam_root) + : parent(p), label(l), beam_root(beam_root) {} + BeamRoot* beam_root; TF_DISALLOW_COPY_AND_ASSIGN(BeamEntry); }; +// This class owns all instances of BeamEntry. This is used to avoid recursive +// destructor call during destruction. +template +class BeamRoot { + public: + BeamRoot(BeamEntry* p, int l) { root_entry_ = AddEntry(p, l); } + BeamRoot(const BeamRoot&) = delete; + BeamRoot& operator=(const BeamRoot&) = delete; + + BeamEntry* AddEntry(BeamEntry* p, int l) { + auto* new_entry = new BeamEntry(p, l, this); + beam_entries_.emplace_back(new_entry); + return new_entry; + } + BeamEntry* RootEntry() const { return root_entry_; } + + private: + BeamEntry* root_entry_ = nullptr; + std::vector>> beam_entries_; +}; + // BeamComparer is the default beam comparer provided in CTCBeamSearch. template class BeamComparer { diff --git a/tensorflow/core/util/ctc/ctc_beam_search.h b/tensorflow/core/util/ctc/ctc_beam_search.h index 372f25a143..709c65fc96 100644 --- a/tensorflow/core/util/ctc/ctc_beam_search.h +++ b/tensorflow/core/util/ctc/ctc_beam_search.h @@ -16,11 +16,15 @@ limitations under the License. #ifndef TENSORFLOW_CORE_UTIL_CTC_CTC_BEAM_SEARCH_H_ #define TENSORFLOW_CORE_UTIL_CTC_CTC_BEAM_SEARCH_H_ +#include #include +#include #include +#include #include "third_party/eigen3/Eigen/Core" #include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/gtl/top_n.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/macros.h" @@ -69,6 +73,7 @@ class CTCBeamSearchDecoder : public CTCDecoder { // P(l=abc? @ t=3) = P(a @ 0)*P(b @ 1)*P(c @ 2)*P(? @ 3) // but we calculate it recursively for speed purposes. typedef ctc_beam_search::BeamEntry BeamEntry; + typedef ctc_beam_search::BeamRoot BeamRoot; typedef ctc_beam_search::BeamProbability BeamProbability; public: @@ -142,7 +147,7 @@ class CTCBeamSearchDecoder : public CTCDecoder { float label_selection_margin_ = -1; // -1 means unlimited. gtl::TopN leaves_; - std::unique_ptr beam_root_; + std::unique_ptr beam_root_; BaseBeamScorer* beam_scorer_; TF_DISALLOW_COPY_AND_ASSIGN(CTCBeamSearchDecoder); @@ -367,15 +372,15 @@ void CTCBeamSearchDecoder::Reset() { // This beam root, and all of its children, will be in memory until // the next reset. - beam_root_.reset(new BeamEntry(nullptr, -1)); - beam_root_->newp.total = 0.0; // ln(1) - beam_root_->newp.blank = 0.0; // ln(1) + beam_root_.reset(new BeamRoot(nullptr, -1)); + beam_root_->RootEntry()->newp.total = 0.0; // ln(1) + beam_root_->RootEntry()->newp.blank = 0.0; // ln(1) // Add the root as the initial leaf. - leaves_.push(beam_root_.get()); + leaves_.push(beam_root_->RootEntry()); // Call initialize state on the root object. - beam_scorer_->InitializeState(&beam_root_->state); + beam_scorer_->InitializeState(&beam_root_->RootEntry()->state); } template diff --git a/tensorflow/core/util/ctc/ctc_decoder.h b/tensorflow/core/util/ctc/ctc_decoder.h index 5b28aeb70a..b8bab69053 100644 --- a/tensorflow/core/util/ctc/ctc_decoder.h +++ b/tensorflow/core/util/ctc/ctc_decoder.h @@ -16,6 +16,9 @@ limitations under the License. #ifndef TENSORFLOW_CORE_UTIL_CTC_CTC_DECODER_H_ #define TENSORFLOW_CORE_UTIL_CTC_CTC_DECODER_H_ +#include +#include + #include "third_party/eigen3/Eigen/Core" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/core/status.h" -- GitLab From b23920670164e7ab19df8c165a703bc6c6782285 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sat, 20 Jan 2018 10:50:16 -0800 Subject: [PATCH 028/258] Update XLA for LLVM r323001 This will require an LLVM version bump PiperOrigin-RevId: 182661291 --- tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc b/tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc index 5403bf48b7..de5e9b4119 100644 --- a/tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc +++ b/tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc @@ -47,7 +47,7 @@ namespace cpu { namespace { // A simple SymbolResolver that delegates to the host dynamic linker. -class SimpleResolver : public llvm::JITSymbolResolver { +class SimpleResolver : public llvm::LegacyJITSymbolResolver { public: explicit SimpleResolver(ExternalConstantPool* external_constant_pool) : external_constant_pool_(external_constant_pool) {} -- GitLab From 8ba8051d05b99cac2b677f0713a11e74e4aac64c Mon Sep 17 00:00:00 2001 From: eladweiss <31474666+eladweiss@users.noreply.github.com> Date: Sun, 21 Jan 2018 01:41:28 +0300 Subject: [PATCH 029/258] Verbs w 0 copies (#16005) * Add RDMA_LOG macros. Will be used to quickly switch between log levels when debugging the protocol. Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 1 Changing the verbs implementation to use the 0 copies approach. For full details and design see 'patch_notes_verbs_with_0_copies.md' Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 2 - Remove RdmaAckBuffer Remove the RdmaAckBuffer completely, as it is no longer required. An Ack is now an empty RDMA write with immediate value 0x80000000. Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 2 - Remove RDMA_MESSAGE_BUFFER_IDLE Remove the RDMA_MESSAGE_BUFFER_IDLE message completely. It is no longer required, since we no longer send the Tensor to a shared buffer. Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 2 - Remove RDMA_MESSAGE_ACK/RDMA_MESSAGE_TENSOR_WRITE The messages are no longer required. Use the immediate value instead. Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 2 - Rename RDMA_MESSAGE_BUFFER_REQUEST/RESPONSE. RDMA_MESSAGE_BUFFER_REQUEST ==> RDMA_MESSSAGE_META_DATA_UPDATE. RDMA_MESSAGE_BUFFER_RESPONSE ==> RDMA_MESSAGE_TENSOR_RE_REQUEST. Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 2 - Add data validation. Data validation can be enabled by compiling with -DRDMA_DATA_VALIDATION. The validation is done as follows: 1. Calculate checksum of the source Tensor on the sender side. 2. Send the checksum value in the META_DATA_RESPONSE message. The message will be sent for every request. 3. The receiver side receives the message and saves the checksum value. 4. When the Tensor content arrives on the receiver side, the receiver calculates its checksum right before invoking done(). If the value is different than the stored checksum value, the validation failed. Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 2 - Some code cleanup. 1. Remove some unused code and old comments. 2. Remove some parameters from PostCopyOpearions. Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 2 - Update README.md with the new design. Signed-off-by: Elad Weiss * Verbs with 0 copies - Phase 2 - Encapsulate sender logic under RdmaTensorResponse. - Move all the meta-data and content sending logic to RdmaTensorResponse methods. - Remove RdmaTensorBuffer. - Remove TensorBuffer base class and buffer types. - Remove ReItem. Delayed tensor is now saved inside the response object. Signed-off-by: Elad Weiss * Fix a synchronization issue when allocating a GPU result tensor. Signed-off-by: Elad Weiss * Move verbs_util.h inclusion (for debug purposes). Signed-off-by: Elad Weiss * [Verbs] - Solve a race condition issue when attempting to setup channels. The problem started when merging to latest master. The run would fail about 50% of the times when trying to execute Grpc GetRemoteAddress(), and return an "OS Error" message. Seems like a race condition between the stations. For now added a while loop with N retries. Signed-off-by: Elad Weiss * [Verbs] - PR review comment - Use SchedClosure() instead of WorkerEnv::compute_pool Signed-off-by: Elad Weiss * [Verbs] - PR review comment - Define and use RDMA_MAX_REQUEST_ID. Also requested internally to increase the number from 2G to 4G - 2. Signed-off-by: Elad Weiss * [Verbs] - PR review comment - Remove old/unused code & comments. Signed-off-by: Elad Weiss * [Verbs] - PR review comment - Change usleep() to Env::SleepForMicroseconds(). Signed-off-by: Elad Weiss * [Verbs] - PR review comment - Propagate error statuses to the higher level. Signed-off-by: Elad Weiss * [Verbs] - Nicify connection messages. Signed-off-by: Elad Weiss * [Verbs] - Dispose of SchedClosure. Using SchedClosure causes a real performance degradation (10-15% on inception3 and resnet152). Instead we will use synchronous calls for now, since ops are non-blocking anyway. Signed-off-by: Elad Weiss * [Verbs] - Enable sending content directly from source GPU tensor. This is a 0 copies requirement. It was implemented in the original prototype, however commiting it was delayed because: 1. It doesn't realy affect performance very much. 2. It requires the StreamGPUOp() function which in the prototype was implemented under GPUUtil, but in the mainstream should be kept under contrib code. I had a lot of techincal difficulties including "gpu_context.h" in my code, with the current Bazel configuration, so eventually I re-implemented it as an empty GPU-to-CPU copy. It is actually quiet elegant, fully reusing an existing code. Signed-off-by: Elad Weiss * [Verbs] - Replace the blocking Sync() call after GPU tensor allocation. Instead, queue the next operation on the GPU stream. Signed-off-by: Elad Weiss --- tensorflow/contrib/verbs/BUILD | 6 +- tensorflow/contrib/verbs/README.md | 174 ++- .../contrib/verbs/grpc_verbs_service.cc | 12 +- .../verbs/patch_notes_verbs_with_0_copies.md | 87 ++ tensorflow/contrib/verbs/rdma.cc | 1336 ++++++++++------- tensorflow/contrib/verbs/rdma.h | 503 ++++--- tensorflow/contrib/verbs/rdma_mgr.cc | 213 ++- tensorflow/contrib/verbs/rdma_mgr.h | 1 + .../contrib/verbs/rdma_rendezvous_mgr.cc | 114 +- tensorflow/contrib/verbs/verbs_server_lib.cc | 1 + tensorflow/contrib/verbs/verbs_service.proto | 6 + .../contrib/verbs/verbs_with_0_copies.png | Bin 0 -> 62862 bytes .../contrib/verbs/verbs_with_0_copies.xml | 1 + .../verbs_with_0_copies_phase1_protocol.jpg | Bin 0 -> 88799 bytes .../verbs_with_0_copies_phase1_protocol.xml | 1 + 15 files changed, 1574 insertions(+), 881 deletions(-) create mode 100644 tensorflow/contrib/verbs/patch_notes_verbs_with_0_copies.md create mode 100644 tensorflow/contrib/verbs/verbs_with_0_copies.png create mode 100644 tensorflow/contrib/verbs/verbs_with_0_copies.xml create mode 100644 tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.jpg create mode 100644 tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.xml diff --git a/tensorflow/contrib/verbs/BUILD b/tensorflow/contrib/verbs/BUILD index 38a84ffb10..80a5d07ea4 100644 --- a/tensorflow/contrib/verbs/BUILD +++ b/tensorflow/contrib/verbs/BUILD @@ -99,7 +99,7 @@ cc_library( alwayslink = 1, ) -tf_cuda_library( +cc_library( name = "rdma_rendezvous_mgr", srcs = ["rdma_rendezvous_mgr.cc"], hdrs = ["rdma_rendezvous_mgr.h"], @@ -114,7 +114,7 @@ tf_cuda_library( ], ) -cc_library( +tf_cuda_library( name = "rdma_mgr", srcs = ["rdma_mgr.cc"], hdrs = ["rdma_mgr.h"], @@ -141,6 +141,8 @@ tf_cuda_library( "//conditions:default": [], }), deps = [ + ":grpc_verbs_client", + ":verbs_service_proto_cc", ":verbs_util", "//tensorflow/core:core_cpu_internal", "//tensorflow/core:framework", diff --git a/tensorflow/contrib/verbs/README.md b/tensorflow/contrib/verbs/README.md index 7c1c8ea459..1b99f4ce4f 100644 --- a/tensorflow/contrib/verbs/README.md +++ b/tensorflow/contrib/verbs/README.md @@ -24,66 +24,144 @@ The design is based on TensorFlow r1.0. An RDMA path is added between servers fo During the server setup, an RDMA manager is created to manage low-level RDMA components such as RDMA channel and RDMA adapter, an RDMA rendezvous manager is created to oversee send/recv operations between servers. Following the distributed TensorFlow design philosophy, the send operation is passive, i.e. merely placing a tensor in the local out-going table. It is the receive operation that actually initiates the tensor transfer. -TensorFlow dynamically allocates memory for tensors that are to be sent or received. This causes difficulty for RDMA operations where pinned memory is required. Two remedies are possible, either the memory is pinned, transfer, then unpinned for each and every tensor to be transferred, or a buffer is pre-allocated and pinned for each tensor. The former incurs significant operation overhead since pinning and unpinning memory for each dynamically generated tensor is slow. The latter incurs large memory overhead and extra copying from the tensor to its pinned buffer, but may still be faster than the former. The second approach is adopted in this design. Each RDMA channel, representing a RDMA connection to a peer, contains a table of pinned buffers for all the seen tensors that requires transfer. It is assumed that the tensor size rarely changes across different steps. So only one buffer is created for the same tensor across all the steps. In the rare case when the tensor size does increases, the old buffer is discarded and new buffer of larger size is created and pinned. +TensorFlow dynamically allocates memory for tensors that are to be sent or received. This causes difficulty for RDMA operations where pinned memory is required. Few remedies are possible: +1. The memory is pinned, transfered, then unpinned for each and every tensor to be transferred. This incurs significant operation overhead since pinning and unpinning memory for each dynamically generated tensor is slow. +2. Buffer is pre-allocated and pinned for each tensor. This incurs large memory overhead and extra copying from the tensor to its pinned buffer, but may still be faster than the former. +3. Following HKUST research on the use of GPU direct, and their [GDR implementation](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/gdr/README.md), there is a smart way to benefit from the TensorFlow allocation theme which is mostly pool based, i.e allocators pre-allocate a large memory block, and allocate the tensors from there. By attaching a custom Visitor to relevant alloactors, we can do a single registration of the entire memory block, which zeros the registration overhead. Once the block is registered, each new tensor allocated will be at a registred address, which will allow us to do direct RDMA writes to it. -When a tensor is prepared for transfer, it is first converted to TensorProto, then the proto is serialized to byte array and copied to the pinned buffer. The content of the buffer is transferred to the remote node via RDMA write. On the remote side, the process is reversed. This is illustrated in the diagram below. The conversion of TensorProto is introduced to simplify transfer of string-tensors. Also since the TensorProto lives in host memory, even if the origin tensor lives in the device, the pinned buffers are all allocated in the host memory. -![TensorFlow RDMA path](./design_diagram.png) +For best performance, we will adopt HKUST 0 copies approach in our solution. This means: + +1. Tensor writes will be done directly from the source tensor to the **result** tensor, with no memory copies in between. This should be done for all DMAable tensors which are located either on CPU or on a RDMA compatible GPU device (GPU direct). +2. Non DMAable tensors (CanMemCopy == false) will be serialized to a TensorProto on the sender side, RDMA written to a registered buffer on the receiver side, and then deserialized by the receiver. +3. Tensors which are located on a non-RDMA-compatible GPU, will be RDMA written to a registered CPU **proxy** buffer on the receiver side, and then copied to GPU by the receiver. -The following improvements can be made in the future. First, conversion to TensorProto and serialization can be avoided for numeric (float/int) tensors since their internal buffer can be access directly as byte array. Second, the pinned buffer may be allocated on device if the tensor is located in the device. This avoids extra device-to-host copy at the expense of extra device memory consumption. ## Design details -### RDMA components +### Terminology -* **RDMA adapter:** The base for RDMA communications. It may contain multiple channels and buffers. It is responsible for handling various incoming RDMA messages. -* **RDMA channel:** Responsible for RDMA connection to a particular node. It manages multiple buffers. A channel has a callback table which stores all the callbacks for the requested tensors. -* **RDMA buffer:** Responsible for sending or receiving data. It has a fixed size memory to store the data. It has a queue to store the pending jobs. There are three types of buffers, message buffer, ACK buffer and tensor buffer. A channel has two message buffers, two ack buffers and many tensor buffers. -* **RDMA manager:** Manages the adapter and channels, including channel creation, channel setup via GRPC service, channel lookup, etc. -* **RDMA rendezvous manager:** manages multiple rdma rendezvous. -* **RDMA rendezvous:** a derived class of BaseRemoteRendezvous. This class is the back end for "send" and "recv" ops. When the sendrecv_op wants to send or receive a tensor, it calls the rendezvous' "send" and "recv" functions respectively. Rendezvous are identified by "step_id", a random number, so that tensors for different iterations don't get mixed up. +* **Sender** - The node which sends the tensor. +* **Receiver** - The node which receives the tensor. +* **Result tensor** - The destination tensor, allocated on its appropriate device. +* **Proxy tensor** - A CPU allocated tensor, which will be used in the case where the result tensor cannot be RDMA written to directly (GPU direct is disabled or not available). The RDMA write will therefore be done to the proxy tensor, and afterwards we will do a manual local copy from it to the result tensor. -### The SEND operation +### Messages -In TensorFlow, when rendezvous sends a tensor, it merely puts a tensor in a local table in the corresponding rendezvous. If the tensor has been requested, a callback exists in the table. "send" will activate the callback, which tries to send the tensor across the node. +* RDMA_MESSAGE_TENSOR_REQUEST +* RDMA_MESSAGE_META_DATA_RESPONSE +* RDMA_MESSAGE_TENSOR_RE_REQUEST +### Transport protocol -### The RECV operation +The tensor transfer process is initiated when the receiver requests a tensor. In code it is done by calling **Rendezvous::Recv()** or **Rendezvous::RecvAsync()**. The TensorFlow base implementation handles the case where the requested tensor is located on the same node. The more interesting case where the requested tensor is located on a remote node (receiver != sender) is to be handled in a derivation of the pure virtual **BaseRemoteRendezvous::RecvFromRemoteAsync()**. TensorFlow provides a default GRPC based implementation which comes in the vanilla version but suffers in scalability when running large models. Our RDMA based implementation presumes to be more scalable. HKUST's contrib GDR implementation is more scalable than GRPC, and less scalable than ours, only because we did our evolution based on it. -When a tensor is requested, rendezvous' recv function is called. The function first places a callback in the channel's callback table, which will be activated once the tensor is sent from the source. In the next step, a message is sent to notify the source of the requested tensor. Once the source receives the message, it will check locally for the tensor, if not found, a callback is placed in the table, otherwise, the tensor id will be placed at corresponding RDMA buffer's job queue for future transmission. When a tensor is scheduled to be transmitted, the RDMA buffer needs to have the memory allocated and initialized (registered with the remote buffer info). If the memory is not ready, the transmission is deferred, a message is sent to the destination to establish the memory first. The other case a transmission can be deferred is when the buffer is still being used by an on-going transmission. +Our entry point is the implementation of **RdmaRemoteRendezvous::RecvFromRemoteAsync()**, located in rdma_rendezvous_mgr.cc. The implementation creates a new **RdmaTensorRequest** object, keyed by request index (uint32_t), stores it in a list of pending requests, and calls its **Start()** method. The **Start()** method basically does 2 things: -### Three types of RDMA buffers +1. Allocate the result tensor (and the proxy tensor if required). +2. Send a **RDMA_MESSAGE_TENSOR_REQUEST** to the sender, containing the address of the destination tensor (result/proxy) for RDMA write. -* **Message buffer:** responsible for sending message only. -* **Ack buffer:** once a message is sent, the recipient needs to send an ack via the ack buffer to free up the message buffer. An ack buffer is exclusively for its coupled message buffer. -* **Tensor buffer:** responsible for sending tensors. The recipient needs to send back a message to free up the sending buffer. +In order to allocate the result and proxy tensors, we need to know the tensor's meta-data, i.e. shape and data-type for DMAable tensors, and proto-size for serialized tensors. Unfortunately, this information is only available on the sender side which complicates manners. In order to avoid sending extra messages for querying the meta-data at each step, we store a local meta-data cache per tensor, which will only be update upon changes. Based on the assumption that the meta-data of a tensor rarely changes between steps, we expect that on most times the cache will only be updated once. The sender is responsible to detect changes in the meta-data, and update the receiver. In order for the sender to know that the meta-data had changed, each **RDMA_MESSAGE_TENSOR_REQUEST** will contain the meta-data that the receiver had grabbed from the local cache. The sender will then compare the meta-data from the message to the tensor's new meta-data. -### RDMA packet format +When the sender receives an **RDMA_MESSAGE_TENSOR_REQUEST**, it will create a new **RdmaTensorResponse** object for the given request message, store it in a list of pending responses, and will invoke its **Start()** method. The **Start()** method does the following: -|type|name_size|name|step_id|buffer_size|remote_addr|rkey|is_dead|data_type|tensor_shape|tensor_bytes|tensor_buffer| +1. Grab the source tensor from the local table (In code, **RecvLocalAsync()**). +2. If the source tensor is not DMAable, serialize it to a TensorProto. +3. If the source tensor is located on a device which cannot be DMA written from, copy it to CPU. +4. If it is the first time this tensor is requested, or if the tensor's meta-data changed: + 1. Clone the tensor's data to be sent later. + 2. Send a **RDMA_MESSAGE_META_DATA_RESPONSE** containing the new meta-data. +5. Otherwise: + 1. RDMA write the tensor (or TensorProto) to the destination address and rkey specified in the request message. The immediate value for the write will be the request index. -### Six types of RDMA messages -* RDMA_MESSAGE_ACK -* RDMA_MESSAGE_BUFFER_IDLE -* RDMA_MESSAGE_BUFFER_REQUEST -* RDMA_MESSAGE_BUFFER_RESPONSE -* RDMA_MESSAGE_TENSOR_REQUEST -* RDMA_MESSAGE_TENSOR_WRITE - -### Actions upon receiving RDMA messages -* RDMA_MESSAGE_ACK - * sender: mark local ack buffer idle. - * receiver: mark remote message buffer idle, send next item. -* RDMA_MESSAGE_BUFFER_IDLE - * sender: mark local message buffer idle, send next item. - * receiver: send ack, set remote tensor buffer idle, send next item. -* RDMA_MESSAGE_BUFFER_REQUEST - * sender: mark local message buffer idle, send next item. - * receiver: send ack, find or create tensor buffer, send BUFFER_RESPONSE. -* RDMA_MESSAGE_BUFFER_RESPONSE - * sender: mark local message buffer idle, send next item. - * receiver: send ack, set remote buffer info, set local and remote buffer idle, send next item. -* RDMA_MESSAGE_TENSOR_REQUEST - * sender: mark local message buffer idle, send next item. - * receiver: send ack, find or create tensor buffer, enqueue tensor id, send next item. -* RDMA_MESSAGE_TENSOR_WRITE - * sender: mark local message buffer idle, send next item. - * receiver: run callback. + +When the receiver receives the **RDMA_MESSAGE_META_DATA_RESPONSE**, it will locate the relevant **RdmaTensorRequest** using the request index specified in the message, and invoke its **RecvTensorMetaData()** which does the following: + +1. Update the local meta-data cache. +2. Reallocate the result/proxy tensors. +3. Re-send the tensor request. For tracability, the new message has a different name: **RDMA_MESSAGE_TENSOR_RE_REQUEST**. + +When the sender receives a **RDMA_MESSAGE_TENSOR_RE_REQUEST**, it will locate the relevant **RdmaTensorResponse** using the request index specified in the message, and invoke its **Resume()** method, which will RDMA write the contents of the tensor that was cloned earlier, to the new remote address specified in the re-request. + +When the receiver receives the RDMA write, it will locate the relevant **RdmaTensorRequest** using the request index which is the immediate value. It will then invoke its **RecvTensorContent()** which does the following: + +1. Proxy copy/deserialize if required. +2. Invoke the done callback. +3. Deallocate the result/proxy tensors and remove the request from the pending list. + +![alt text](verbs_with_0_copies.png "Transport protocol") + +### Additional design notes + +1. When the sender receives a tensor request, the source tensor may or may not be ready yet. The situation is handled through a process of tag matching: + * If the request arrives before the tensor is ready, then a callback is put in a local table, and will be invoked once the tensor arrives. + * If the tensor is ready before the request arives, than the tensor is put in a local table. When the request arrives, it will invoke the callback immediatly. + In code it is done by calling **RecvLocalAsync()**, which receives the tensor's key, step-id, and the callback. +2. When the callback is invoked, the relevant tensor is removed from the tag matching table. In the case where we need to send the tensor's meta-data, the **RdmaTensorResponse** will store a copy of the tensor until the re-request arrives. +3. The sending of protocol messages (**RDMA_MESSAGE_TENSOR_REQUEST**, **RDMA_MESSAGE_META_DATA_RESPONSE** and **RDMA_MESSAGE_TENSOR_RE_REQUEST**) is done by the class **RdmaMessageBuffer**. All messages are sent using RDMA writes from/to fixed messages buffers. This implies that we cannot send on a specific channel more than one message at a time. In order to synchronize the messages, the **RdmaMessageBuffer** holds the a local and remote buffer statuses which can be either busy or idle. When a write is issued, both statuses will be changed to busy. When the write-complete event is received, the local status is changed to idle. When the write is received on the remote side, the remote side will parse the message, and return an ACK back to the sending side on which the sending side will update the remote status to idle. When both the local and remote statuses are idle, the next message can be sent. +5. ACK writes are empty writes (hence they require no buffer) with immediate value 0xFFFFFFFE. Message writes have the immediate value 0xFFFFFFFF. All other writes are tensor-content writes whose immediate value is the request-index. + +### RDMA components + +* **enum RdmaImmDataType** - Immediate types to distinguish between different RDMA writes on the remote side. Ack writes and control-message writes have a fixed immediate value. The rest of the writes are tensor writes and the immediate value is the relevant request index. +* **enum RdmaWriteIDType** - Types to distinguish between different RDMA write-complete events: Ack, control message and tensor writes. +* **class RdmaWriteID** - Context for RDMA write complete events. Holds the RdmaWriteIDType and additional data. +* **class RdmaTensorMetaData** - Meta-data for a tensor (type, shape, is_dead, proto_size). +* **class RdmaMemoryMgr** - Manages the meta-data cache, and the registered memory regions. +* **class RdmaTensorRequest** - Holds and manages information for a single tensor request throughout the entire receive cycle. API: + * **Start()** - Start the request sequence. + * Allocate the result tensor (and proxy tensor if required). + * Send RDMA_MESSAGE_TENSOR_REQUEST to the remote side. + * **RecvTensorMetaData()** - Receive meta-data from the remote side. + * Update the local meta-data cache. + * Reallocate the result tensor (and proxy tensor if required). + * Re-send the request to the remote side. + * **RecvTensorContent()** - Receive tensor content from the remote side (RDMA write was completed). + * Decode proto if required and/or move to GPU if the content was not written to it directly (GPU direct is not avaliable). + * Invoke the done callback. +* **class RdmaTensorResponse** - Holds and manages information for a single tensor response throughout the entire send cycle. API: + * **Start()** - Start the response sequence. + * Find the tensor in the local tag-match table. + * Compare the tensor's meta-data to the meta-data in the message (taken from the requester's local cache). + * If meta-data changed: + * Clone the tensor to be sent later. + * Send a meta-data update message and wait for re-request. + * Else: + * Send the tensor's content (using direct RDMA write). + * **Resume()** - Resume the response sequence after a re-request. Send the tensor's content that was cloned earlier. + * **Destroy()** - Destroy the response's resources and remove it form the pending list. +* **class RdmaAdapter** - The base for RDMA communications. It may contain multiple channels and buffers. It is responsible for handling various incoming RDMA messages. +* **class RdmaChannel** - Responsible for RDMA connection to a particular node. It manages messagee buffers. A channel has a request table which stores all the pending tensor requests. +* **class RdmaMessageBuffer** - Responsible for sending or receiving messages. It has a fixed size memory to store the data. It has a queue to store the pending jobs. A channel has two message buffers one for tx and one for rx. +* **class RdmaMgr** - Manages the adapter and channels, including channel creation, channel setup via GRPC service, channel lookup, etc. +* **class RdmaRendezvousMgr** - Manages multiple rdma rendezvous. +* **class RdmaRemoteRendezvous** - A derived class of BaseRemoteRendezvous. This class is the back end for "send" and "recv" ops. When the sendrecv_op wants to send or receive a tensor, it calls the rendezvous' "send" and "recv" functions respectively. Rendezvous are identified by "step_id", a random number, so that tensors for different iterations don't get mixed up. + +### Message structure: + +| type | name_size | name | step_id | request_index | remote_addr/checksum | rkey | is_dead | data_type | tensor_shape | tensor_bytes | error_status | +|------|---------- |------|---------|---------------|----------------------|------|---------|-----------|--------------|--------------|-----------------------| +| 1B | 2B | 512 | 8B | 8B | 8B | 4B | 1B | XB | XB | 8B | Size - 4B, proto - XB | + +* **RDMA_MESSAGE_TENSOR_REQUEST** - (receiver ==> sender) The original tensor request. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * remote_addr/rkey - Address/rkey of the result/proxy tensor. Irrelevant for first-time request. + * is_dead/data_type/tensor_shape/tensor_bytes - The current meta-data as stored in the receiver local cache. The sender will use that information to know if the receiver's cache requires updating. +* **RDMA_MESSAGE_META_DATA_RESPONSE** - (sender ==> receiver) The meta-data update message in case meta-data had changed (or if it is the first time the tensor is requested). + * type - The message type. + * request_index - Request index. + * is_dead/data_type/tensor_shape/tensor_bytes - The up-to-date meta-data. + * checksum - In data validation mode, this will hold the checksum of the source tensor. +* **RDMA_MESSAGE_TENSOR_RE_REQUEST** - (receiver ==> sender) Tensor re-requset after meta-data update and reallocation of result/proxy tensors. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * remote_addr/rkey - Address/rkey of the reallocated result/proxy tensor. +* **RDMA_MESSAGE_ERROR_STATUS** - (sender ==> receiver) Notify the receiver that an error had occured on the sender side, so it can propagate it to the upper levels. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * error_status - The error status (code, message, details). diff --git a/tensorflow/contrib/verbs/grpc_verbs_service.cc b/tensorflow/contrib/verbs/grpc_verbs_service.cc index f2af6b79fb..742f946c95 100644 --- a/tensorflow/contrib/verbs/grpc_verbs_service.cc +++ b/tensorflow/contrib/verbs/grpc_verbs_service.cc @@ -122,17 +122,15 @@ Status GrpcVerbsService::GetRemoteAddressSync( rc->SetRemoteAddress(ra, false); rc->Connect(); int i = 0; - int idx[] = {1, 0, 3, 2}; - std::vector mb(rc->message_buffers()); - CHECK_EQ(request->mr_size(), 4); + int idx[] = {1, 0}; + std::vector mb(rc->message_buffers()); + CHECK_EQ(request->mr_size(), RdmaChannel::kNumMessageBuffers); for (const auto& mr : request->mr()) { // the connections are crossed, i.e. // local tx_message_buffer <---> remote rx_message_buffer_ // local rx_message_buffer <---> remote tx_message_buffer_ - // local tx_ack_buffer <---> remote rx_ack_buffer_ - // local rx_ack_buffer <---> remote tx_ack_buffer_ - // hence idx[] = {1, 0, 3, 2}. - RdmaBuffer* rb = mb[idx[i]]; + // hence idx[] = {1, 0}. + RdmaMessageBuffer* rb = mb[idx[i]]; RemoteMR rmr; rmr.remote_addr = mr.remote_addr(); rmr.rkey = mr.rkey(); diff --git a/tensorflow/contrib/verbs/patch_notes_verbs_with_0_copies.md b/tensorflow/contrib/verbs/patch_notes_verbs_with_0_copies.md new file mode 100644 index 0000000000..956b8f2147 --- /dev/null +++ b/tensorflow/contrib/verbs/patch_notes_verbs_with_0_copies.md @@ -0,0 +1,87 @@ +## Verbs implementation to use direct tensor writes (0 copies) + +### Motivation: + +Following HKUST research on the use of GPU direct, and their [GDR implementation](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/gdr/README.md), we wish to adopt the 0 copies approach and apply it to the current verbs implementation, while keeping the current implementation advantages, such as configurability and the use of RDMA for control messages. + +### Performance: + +Compared with the current GRPC, verbs and GDR implementation, the result implementation gave the best performance for every model, with any number of nodes. For VGG16 on 8 nodes with 4 P100 GPUs each, the prototype beat the second place by over 15%. + +### Implementation requirements: + +1. Tensor writes need to be done directly from the source Tensor to the destination Tensor, with no memory copies in between. This should be done for all DMAble tensors which are located either on CPU or on a RDMA compatible GPU device (GPU direct). +2. Non DMAble tensors (CanMemCopy == false) will be serialized to proto on the sender side, RDMA written to a registered buffer on the receiver side, and then deserialized by the receiver. +3. Tensors which are located on a non-RDMA-compatible GPU, will be RDMA written to a registered CPU proxy buffer on the receiver side, and then copied to GPU by the receiver. + +### Implementation constrains: + +For best stability and proof of correctness, we will divide the implementation to two stages: +1. At first stage we will keep changes to the current implementation to the minimum possible. The expense will be that we may have unused or unnecessary code leftovers, which may also affect performance. +2. At second stage, we will re-iterate over the code and remove irrelevant code parts. +The design of the solution aims that we will achieve both stages with relative ease. + +### Design guidelines: + +1. Since we do not want to do any unnecessary memory copying, we will no longer allocate a fixed CPU buffer as the destination for the RDMA write. Instead we will do the writing directly to the result tensor, or if the result tensor is on a device which does not support RDMA, we will do the writing to a proxy CPU tensor and then copy its content to the result tensor. +2. The address of the destination Tensor needs to be sent to the sender side for writing, meaning that the result/proxy tensor should be pre-allocated on the receiver side, prior to sending the tensor request. In order to do that, we need to know its meta-data, i.e. shape and data-type for DMAble tensors, and proto-size for serialized tensors. Unfortunately, this information is only available on the sender side which complicates manners. In order to avoid sending extra messages for querying the meta-data on each step, we store a local meta-data cache per tensor. Based on the assumption that the meta-data of a tensor rarely changes between steps, we expect that on most times the cache will only be updated once. When the sender receives a request for a tensor, if it is the first time this tensor is requested, or in the rare case that the meta-data did change, the sender will first send a meta-data response, on which the receiver will update the local cache, and reallocate the result/proxy tensors if required. When the receiver sends the tensor request, it will contain also the meta-data currently stored in its local cache, so the sender can compare it to see if there was a change. +3. When the sender writes the tensor content to the result tensor, no additional data is being written with it. That means we need to reside on ibverbs immediate (uint32_t) to indicate which request we are responding to (in order to trigger the receive callback). The easiest and most elegant way is to key the recv callback with a unique request_index (uint32_t), instead of the current key_with_step_id (string). +4. Since the sender no longer writes the tensor from/to fixed buffers, we no longer need to schedule the writes using the local/remote status. In addition we no longer rely on the RmdaTensorBuffer members as the source/destination addresses and rkey/lkey. Instead, each RdmaTensorBuffer will hold multiple "Response" objects (one per step-id), from which we derive destination address and rkey. The source address and lkey are always the ones of the source Tensor. +5. With the addition of tensor pre-allocation, we noticed there is a large code similarity between sending the first tensor request and re-sending the request in case of meta-data changes. After implementing a common method for tensor pre-allocation, it turned out that implementation becomes much simpler by encapsulating the process of request sending/re-sending, meta-data response callback and content response callback, all in a single "Request" class. The request class holds all the relevant request information, which reduces excessive parameter passing and lambda capturing. This decision is purely for elegance and code simplicity, and we decided to implement it in first stage because it makes the implementation much easier. + +### New types/classes: + +* **enum RdmaImmDataType** - Immediate types to distinguish between different RDMA writes on the remote side. Ack writes and control-message writes have a fixed immediate value. The rest of the writes are tensor writes and the immediate value is the relevant request index. +* **enum RdmaWriteIDType** - Types to distinguish between different RDMA write-complete events: Ack, control message, tensor DMA write and tensor proto write. +* **class RdmaWriteID** - Context for RDMA write complete events. Holds the RdmaWriteIDType and additional data. +* **class RemoteAddressContext** - Remote address information (address + mr). Will be passed as write context for tensor proto writes. +* **class RdmaTensorMetaData** - Meta-data for a tensor (type, shape, is_dead, proto_size). +* **class RdmaMemoryMgr** - Manages the meta-data cache, and the registered memory regions. +* **class RdmaTensorRequest** - Holds and manages information for a single tensor request throughout the entire receive cycle. API: + * Start() - Start the request. + * RecvTensorMetaData() - Receive meta-data from the remote side. + * RecvTensorContent() - Receive tensor content from the remote side and invoke the done() callback. +* **class RdmaTensorResponse** - Holds information for a single tensor response, such as destination address and rkey. + +### Protocol changes: + +The protocol messages themselves will remain mostly unchanged at the first stage, but will be used differently, as described below. The current messages structures already have most of the required fields for the new implementation. The only change is the "buffer_size" field which is no longer used since we are no longer sending additional information with the tensor, and thus it is now always equal to the "tensor_bytes" field. Instead, we use that field to pass the "request_index". + +### Message structure: + +| type | name_size | name | step_id | request_index | remote_addr | rkey | is_dead | data_type | tensor_shape | tensor_bytes | +|------|---------- |------|---------|---------------|-------------|------|---------|-----------|--------------|--------------| +| 1B | 2B | 512 | 8B | 8B | 8B | 4B | 1B | XB | XB | 8B | + +* **RDMA_MESSAGE_TENSOR_REQUEST** - (receiver ==> sender) The original tensor request. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * remote_addr/rkey - Address/rkey of the result/proxy tensor. Irrelevant for first-time request. + * is_dead/data_type/tensor_shape/tensor_bytes - The current meta-data as stored in the receiver local cache. The sender will use that information to know if the receiver's cache requires updating. +* **RDMA_MESSAGE_BUFFER_REQUEST** - (sender ==> receiver) The meta-data update message in case meta-data had changed (or if it is the first time the tensor is requested). + * type - The message type. + * request_index - Request index. + * is_dead/data_type/tensor_shape/tensor_bytes - The up-to-date meta-data. +* **RDMA_MESSAGE_BUFFER_RESPONSE** - (receiver ==> sender) Tensor re-requset after meta-data update and reallocation of result/proxy tensors. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * remote_addr/rkey - Address/rkey of the reallocated result/proxy tensor. + * is_dead/data_type/tensor_shape/tensor_bytes - The new meta-data. Will be removed in the next phase. +* **RDMA_MESSAGE_TENSOR_WRITE** - (sender ==> receiver) No longer sent. There is only a direct write of the tensor content to the result/proxy tensor. Request index passed as the immediate value of the write. +* **RDMA_MESSAGE_TENSOR_IDLE** - (receiver ==> sender) No longer sent. + +![alt text](verbs_with_0_copies_phase1_protocol.jpg "Phase 1 message protocol") + +### Second stage optimizations: +1. Remove unused code leftovers. +2. Remove the ACK buffer completely, since we can rely completely on its immediate value. + +### Future optimizations: +1. Map the tensor names to indexes, to significantly reduce the request message size. +2. Understand the purpose of empty tensors and if we can skip remote fetching for them. +3. Consider concatenating multiple requests and/or using multiple message buffers. +4. Consider a no-request architecture. diff --git a/tensorflow/contrib/verbs/rdma.cc b/tensorflow/contrib/verbs/rdma.cc index ae9a384565..948398ec03 100644 --- a/tensorflow/contrib/verbs/rdma.cc +++ b/tensorflow/contrib/verbs/rdma.cc @@ -16,18 +16,19 @@ limitations under the License. #ifdef TENSORFLOW_USE_VERBS #include "tensorflow/contrib/verbs/rdma.h" -#include +#include "tensorflow/contrib/verbs/verbs_service.pb.h" #include #include -#include "tensorflow/contrib/verbs/verbs_util.h" #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/common_runtime/dma_helper.h" +#include "tensorflow/core/common_runtime/process_util.h" #if GOOGLE_CUDA #include "tensorflow/core/common_runtime/gpu/gpu_util.h" #include "tensorflow/core/common_runtime/gpu/process_state.h" #endif #include "tensorflow/core/distributed_runtime/rendezvous_mgr_interface.h" #include "tensorflow/core/distributed_runtime/session_mgr.h" +#include "tensorflow/core/distributed_runtime/rpc/grpc_util.h" #include "tensorflow/core/framework/rendezvous.h" #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/lib/core/status.h" @@ -41,32 +42,19 @@ namespace tensorflow { #define RoCE_V2 "RoCE v2" namespace { -// hash name to 32-bit integer -uint32_t NameHash(const string& name) { - return Hash32(name.data(), name.size(), 0x1234ABCD); -} // convenience function for printing message string MessageTypeToString(RdmaMessageType rmt) { switch (rmt) { - case RDMA_MESSAGE_ACK: - return "RDMA_MESSAGE_ACK"; - break; - case RDMA_MESSAGE_BUFFER_IDLE: - return "RDMA_MESSAGE_BUFFER_IDLE"; - break; - case RDMA_MESSAGE_BUFFER_REQUEST: - return "RDMA_MESSAGE_BUFFER_REQUEST"; + case RDMA_MESSAGE_META_DATA_UPDATE: + return "RDMA_MESSAGE_META_DATA_UPDATE"; break; - case RDMA_MESSAGE_BUFFER_RESPONSE: - return "RDMA_MESSAGE_BUFFER_RESPONSE"; + case RDMA_MESSAGE_TENSOR_RE_REQUEST: + return "RDMA_MESSAGE_TENSOR_RE_REQUEST"; break; case RDMA_MESSAGE_TENSOR_REQUEST: return "RDMA_MESSAGE_TENSOR_REQUEST"; break; - case RDMA_MESSAGE_TENSOR_WRITE: - return "RDMA_MESSAGE_TENSOR_WRITE"; - break; default: return "UNKNOWN MESSAGE"; } @@ -468,97 +456,70 @@ void RdmaAdapter::Process_CQ() { rc->Recv(); // imm_data is the index of RX buffer in the buffer table. uint32_t imm_data = wc_[i].imm_data; - RdmaBuffer* rb = rc->FindBuffer(imm_data); + RdmaMessageBuffer* rb; RdmaMessage rm; - RdmaMessage::ParseMessage(rm, rb->buffer_); - VLOG(2) << "recv RDMA message: " << MessageTypeToString(rm.type_); - if (rm.type_ == RDMA_MESSAGE_ACK) { + if (imm_data == RDMA_IMM_DATA_ACK) { // receive an ack to a message rb = rc->tx_message_buffer_; rb->SetBufferStatus(remote, idle); rb->SendNextItem(); - } else if (rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) { - // received a request-for-tensor message - // send ack to release remote tx message buffer - RdmaBuffer* ab = rc->tx_ack_buffer_; - ab->SendNextItem(); - // find or create buffer - RdmaBuffer* tb = rc->FindOrCreateBuffer(rm.name_); - string key_with_step_id = - VerbsUtil::AppendStepidToKey(rm.name_, rm.step_id_); - tb->EnqueueItem(key_with_step_id); - // send the next tensor - worker_env_->compute_pool->Schedule([tb]() { tb->SendNextItem(); }); - } else if (rm.type_ == RDMA_MESSAGE_BUFFER_IDLE) { - // receive tensor-buffer-ready message - // send ack to release remote tx message buffer - RdmaBuffer* ab = rc->tx_ack_buffer_; - ab->SendNextItem(); - // find buffer - RdmaTensorBuffer* tb = - reinterpret_cast(rc->FindBuffer(rm.name_)); - tb->SetBufferStatus(remote, idle); - worker_env_->compute_pool->Schedule([tb]() { tb->ReSendNextItem(); }); - } else if (rm.type_ == RDMA_MESSAGE_BUFFER_REQUEST) { - // remote host requests to create a tensor buffer; - // send ack to release remote tx message buffer - RdmaBuffer* ab = rc->tx_ack_buffer_; - ab->SendNextItem(); - // find or create the buffer - RdmaBuffer* tb = rc->FindOrCreateBuffer(rm.name_, TENSOR); - RemoteMR rmr; - rmr.remote_addr = rm.remote_addr_; - rmr.rkey = rm.rkey_; - tb->SetRemoteMR(rmr, true); - tb->CreateCPUBuffer(rm.buffer_size_); - // create RDMA_MESSAGE_BUFFER_RESPONSE message - RdmaMessage br; - br.type_ = RDMA_MESSAGE_BUFFER_RESPONSE; - br.name_size_ = rm.name_.size(); - br.name_ = rm.name_; - br.buffer_size_ = rm.buffer_size_; - br.remote_addr_ = reinterpret_cast(tb->buffer_); - br.rkey_ = tb->self_->rkey; - string message = RdmaMessage::CreateMessage(br); - RdmaBuffer* mb = rc->tx_message_buffer_; - mb->EnqueueItem(message); - mb->SendNextItem(); - } else if (rm.type_ == RDMA_MESSAGE_BUFFER_RESPONSE) { - // remote creates a buffer and responds - // send ack to release remote tx message buffer - RdmaBuffer* ab = rc->tx_ack_buffer_; - ab->SendNextItem(); - // find buffer - RdmaTensorBuffer* tb = - reinterpret_cast(rc->FindBuffer(rm.name_)); - CHECK(rm.buffer_size_ == tb->size_) - << "rm.buffer_size = " << rm.buffer_size_ - << "tb->size_ = " << tb->size_ << "rm.name_ = " << rm.name_; - RemoteMR rmr; - rmr.remote_addr = rm.remote_addr_; - rmr.rkey = rm.rkey_; - tb->SetRemoteMR(rmr, true); - tb->SetBufferStatus(local, idle); - tb->SetBufferStatus(remote, idle); - worker_env_->compute_pool->Schedule([tb]() { tb->ReSendNextItem(); }); - } else if (rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) { - // tensor RDMA write completed - worker_env_->compute_pool->Schedule([rm, rc]() { - string key_with_step_id = - VerbsUtil::AppendStepidToKey(rm.name_, rm.step_id_); - rc->RunRecvCallback(key_with_step_id); - }); + continue; } - } else if (wc_[i].opcode == IBV_WC_RDMA_WRITE) { - RdmaBuffer* rb = reinterpret_cast(wc_[i].wr_id); - rb->SetBufferStatus(local, idle); - RdmaMessage rm; + + if (imm_data <= RDMA_IMM_MAX_REQUEST_ID) { + // receive a tensor RDMA write + uint32_t request_index = imm_data; + RdmaTensorRequest* request = rc->GetTensorRequest(request_index); + request->RecvTensorContent(); + continue; + } + + // receive a control message + rb = rc->rx_message_buffer_; RdmaMessage::ParseMessage(rm, rb->buffer_); - VLOG(2) << "sent RDMA message: " << MessageTypeToString(rm.type_); - if (rm.type_ != RDMA_MESSAGE_ACK) { - worker_env_->compute_pool->Schedule([rb]() { rb->SendNextItem(); }); + RdmaMessageBuffer::SendAck(rc); + RDMA_LOG(1) << "Step 0x" << std::hex << rm.step_id_ << std::dec + << ": Received " << MessageTypeToString(rm.type_) << " " + << "#" << rm.request_index_ << ": " << rm.name_; + + if (rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) { + RdmaTensorResponse* response = rc->AddTensorResponse(rm); + response->Start(); + } else if (rm.type_ == RDMA_MESSAGE_META_DATA_UPDATE) { + RdmaTensorRequest* request = rc->GetTensorRequest(rm.request_index_); + request->RecvTensorMetaData(rm.data_type_, rm.tensor_shape_, + rm.is_dead_, rm.tensor_bytes_); +#ifdef RDMA_DATA_VALIDATION + request->RecvTensorChecksum(rm.checksum_); +#endif + } else if (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST) { + RdmaTensorResponse* response = rc->UpdateTensorResponse(rm); + response->Resume(); + } else if (rm.type_ == RDMA_MESSAGE_ERROR_STATUS) { + RdmaTensorRequest* request = rc->GetTensorRequest(rm.request_index_); + request->RecvErrorStatus(rm.status_); + } + } else if (wc_[i].opcode == IBV_WC_RDMA_WRITE) { + RdmaWriteID* wr_id = reinterpret_cast(wc_[i].wr_id); + RDMA_LOG(2) << "Write complete of type " << wr_id->write_type; + switch (wr_id->write_type) { + case RDMA_WRITE_ID_ACK: + break; + case RDMA_WRITE_ID_MESSAGE: { + RdmaMessageBuffer* rb = + reinterpret_cast(wr_id->write_context); + rb->SetBufferStatus(local, idle); + rb->SendNextItem(); + break; + } + case RDMA_WRITE_ID_TENSOR_WRITE: { + RdmaTensorResponse* response = + reinterpret_cast(wr_id->write_context); + response->Destroy(); + } } + delete wr_id; } } } @@ -588,8 +549,10 @@ int RdmaChannel::PingPostSend() { RdmaChannel::RdmaChannel(const RdmaAdapter* adapter, const string local_name, const string remote_name) - : adapter_(adapter), local_name_(local_name), remote_name_(remote_name) { - + : adapter_(adapter), + local_name_(local_name), + remote_name_(remote_name), + request_serial_(0) { struct ibv_sge list; mr_ = ibv_reg_mr(adapter_->pd_, ping_buff_, kPingBuffSize, @@ -651,29 +614,15 @@ RdmaChannel::RdmaChannel(const RdmaAdapter* adapter, const string local_name, // create message and ack buffers, then initialize the tables. { - const string buffer_names[] = {"tx_message_buffer", "rx_message_buffer", - "tx_ack_buffer", "rx_ack_buffer"}; + const string buffer_names[] = {"tx_message_buffer", "rx_message_buffer"}; tx_message_buffer_ = new RdmaMessageBuffer(this, buffer_names[0]); rx_message_buffer_ = new RdmaMessageBuffer(this, buffer_names[1]); - tx_ack_buffer_ = new RdmaAckBuffer(this, buffer_names[2]); - rx_ack_buffer_ = new RdmaAckBuffer(this, buffer_names[3]); message_buffers_.reserve(kNumMessageBuffers); message_buffers_.push_back(tx_message_buffer_); message_buffers_.push_back(rx_message_buffer_); - message_buffers_.push_back(tx_ack_buffer_); - message_buffers_.push_back(rx_ack_buffer_); // create buffer on host tx_message_buffer_->CreateCPUBuffer(RdmaMessage::kRdmaMessageBufferSize); rx_message_buffer_->CreateCPUBuffer(RdmaMessage::kRdmaMessageBufferSize); - tx_ack_buffer_->CreateCPUBuffer(RdmaMessage::kRdmaAckBufferSize); - rx_ack_buffer_->CreateCPUBuffer(RdmaMessage::kRdmaAckBufferSize); - // bt_mu_.lock() is not used in constructor. - for (int i = 0; i < kNumMessageBuffers; i++) { - uint32_t index = NameHash(buffer_names[i]); - buffer_table_.insert({index, message_buffers_[i]}); - buffer_index_name_table_.insert({index, buffer_names[i]}); - buffer_name_index_table_.insert({buffer_names[i], index}); - } } CHECK(PingPostRecv() == 0) << "Couldn't post receive from " << remote_name_ << " with error " << std::strerror(errno); @@ -684,8 +633,6 @@ RdmaChannel::~RdmaChannel() { CHECK(!ibv_destroy_qp(qp_)) << "Failed to destroy QP"; delete tx_message_buffer_; delete rx_message_buffer_; - delete tx_ack_buffer_; - delete rx_ack_buffer_; } void RdmaChannel::SetRemoteAddress(const RdmaAddress& ra, bool override) { @@ -716,114 +663,31 @@ void RdmaChannel::Recv() { CHECK(!ibv_post_recv(qp_, &wr, &bad_wr)) << "Failed to post recv"; } -// Lookup 32-bit buffer index from buffer name -// Args: -// buffer_name: name of the buffer -// Returns: -// 32-bit index -uint32_t RdmaChannel::LookupBufferIndex(const string& buffer_name) { - mutex_lock lock{bt_mu_}; - BufferNameIndexTable::iterator iter = - buffer_name_index_table_.find(buffer_name); - CHECK(iter != buffer_name_index_table_.end()); - return iter->second; -} - -// Find a buffer by its 32-bit index -// Args: -// index: 32-bit hash code of the tensor buffer name -// Returns: -// name of the tensor buffer -RdmaBuffer* RdmaChannel::FindBuffer(const uint32_t index) { - mutex_lock lock{bt_mu_}; - BufferTable::iterator iter = buffer_table_.find(index); - CHECK(iter != buffer_table_.end()); - return iter->second; -} - -// Find a buffer by its name -// Args: -// name: name of the buffer -// Returns: -// the named rdma buffer -RdmaBuffer* RdmaChannel::FindBuffer(const string& name) { - uint32_t index = LookupBufferIndex(name); - return FindBuffer(index); -} - -// Find a buffer if it exists, otherwise create one. -// The memory inside the created buffer is not allocated. -// Args: -// name: the name of the buffer -// buffer_type: TENSOR, MESSAGE or ACK. -// Returns: -// the named buffer -RdmaBuffer* RdmaChannel::FindOrCreateBuffer(const string& name, - BufferType buffer_type) { - mutex_lock lock{bt_mu_}; - RdmaBuffer* rb; - // find index - BufferNameIndexTable::iterator iter = buffer_name_index_table_.find(name); - if (iter != buffer_name_index_table_.end()) { - uint32_t index = iter->second; - // find buffer - BufferTable::iterator iter = buffer_table_.find(index); - CHECK(iter != buffer_table_.end()); - rb = iter->second; - } else { - uint32_t index = NameHash(name); - if (buffer_type == TENSOR) { - rb = new RdmaTensorBuffer(this, name); - } else if (buffer_type == MESSAGE) { - rb = new RdmaMessageBuffer(this, name); - } else if (buffer_type == ACK) { - rb = new RdmaAckBuffer(this, name); - } - buffer_name_index_table_.insert({name, index}); - buffer_index_name_table_.insert({index, name}); - buffer_table_.insert({index, rb}); +RdmaTensorRequest* RdmaChannel::InsertTensorRequest( + const string& key, int64 step_id, Device* dst_dev, + const Rendezvous::Args recv_args, + const RdmaTensorRequest::RecvDoneCallback& done) { + mutex_lock lock{ct_mu_}; + uint32_t request_index = request_serial_++; + if (request_serial_ > RDMA_IMM_MAX_REQUEST_ID) { + request_serial_ = 0; } - CHECK(rb); - return rb; + RdmaTensorRequest request(request_index, key, step_id, this, dst_dev, + recv_args, done); + auto it = request_table_.emplace(request_index, request); + return &it.first->second; } -// Insert callback to the callback_table. -// The callback is activated when the corresponding tensor is received. -// Arg: -// key: the name of the tensor -// recv_done: the callback associated with the tensor. -// Returns: -// None -void RdmaChannel::InsertRecvCallback(const string& key, - std::function recv_done) { +void RdmaChannel::RemoveTensorRequest(uint32_t request_index) { mutex_lock lock{ct_mu_}; - callback_table_.insert({key, recv_done}); + request_table_.erase(request_index); } -// Remove callback from the callback_table. -// Arg: -// key: the name of the tensor -// Returns: -// None -void RdmaChannel::RemoveRecvCallback(const string& key) { +RdmaTensorRequest* RdmaChannel::GetTensorRequest(uint32_t request_index) { mutex_lock lock{ct_mu_}; - callback_table_.erase(key); -} - -// Run named callback in the callback_table. -// Arg: -// key: the name of the tensor -// Returns: -// None -void RdmaChannel::RunRecvCallback(const string& key) { - std::function recv_done; - { - mutex_lock lock{ct_mu_}; - CallbackTable::iterator iter = callback_table_.find(key); - CHECK(iter != callback_table_.end()); - recv_done = iter->second; - } - recv_done(); + RequestTable::iterator iter = request_table_.find(request_index); + CHECK(iter != request_table_.end()); + return &iter->second; } void RdmaChannel::Connect() { @@ -888,25 +752,22 @@ void RdmaChannel::Connect(const RdmaAddress& remoteAddr) { connected_ = true; } else { - LOG(INFO) << "channel already connected"; + RDMA_LOG(2) << "channel already connected"; } } -RdmaBuffer::RdmaBuffer(RdmaChannel* channel, string name) +RdmaMessageBuffer::RdmaMessageBuffer(RdmaChannel* channel, string name) : channel_(channel), name_(name) {} -RdmaBuffer::~RdmaBuffer() { +RdmaMessageBuffer::~RdmaMessageBuffer() { CHECK(!ibv_dereg_mr(self_)) << "ibv_dereg_mr failed"; FreeBuffer(); } -void RdmaBuffer::FreeBuffer() { +void RdmaMessageBuffer::FreeBuffer() { if ((buffer_ != nullptr) && buffer_on_host_) { free(buffer_); } - // TODO - // release buffer if it is on device. - // We don't support RDMABuffer on device at this moment. } // Allocate CPU memory for the Rdma buffer @@ -915,7 +776,7 @@ void RdmaBuffer::FreeBuffer() { // lock: whether or not mutex_lock the process to protect concurrency. // Returns: // None -void RdmaBuffer::CreateCPUBuffer(size_t size, bool lock) { +void RdmaMessageBuffer::CreateCPUBuffer(size_t size, bool lock) { CHECK(size > 0); if (lock) { mu_.lock(); @@ -943,7 +804,7 @@ void RdmaBuffer::CreateCPUBuffer(size_t size, bool lock) { // override: whether override existing information // Returns: // None -void RdmaBuffer::SetRemoteMR(RemoteMR rmr, bool override) { +void RdmaMessageBuffer::SetRemoteMR(RemoteMR rmr, bool override) { mutex_lock lock{mu_}; if ((override) || (remote_status_ == none)) { remote_.remote_addr = rmr.remote_addr; @@ -956,63 +817,51 @@ void RdmaBuffer::SetRemoteMR(RemoteMR rmr, bool override) { } // Put a task in the buffer's job queue -void RdmaBuffer::EnqueueItem(string item) { +void RdmaMessageBuffer::EnqueueItem(string item) { mutex_lock lock{mu_}; queue_.push(item); } // Rdma-Write the content of the buffer -void RdmaBuffer::Write(uint32_t imm_data, size_t buffer_size) { +void RdmaMessageBuffer::Write(uint32_t imm_data, size_t buffer_size) { + Write(channel_, imm_data, buffer_size, (uint64_t)buffer_, self_->lkey, + remote_.remote_addr, remote_.rkey, RDMA_WRITE_ID_MESSAGE, this); +} + +// Generalized Write method +void RdmaMessageBuffer::Write(const RdmaChannel* channel, uint32_t imm_data, + size_t buffer_size, uint64_t src_addr, + uint32_t lkey, uint64_t remote_addr, + uint32_t rkey, RdmaWriteIDType write_type, + void* write_context) { struct ibv_sge list; - list.addr = (uint64_t)buffer_; + list.addr = src_addr; list.length = buffer_size; - list.lkey = self_->lkey; + list.lkey = lkey; struct ibv_send_wr wr; memset(&wr, 0, sizeof(wr)); - wr.wr_id = (uint64_t) this; + wr.wr_id = (uint64_t) new RdmaWriteID(write_type, write_context); wr.sg_list = &list; wr.num_sge = 1; wr.opcode = IBV_WR_RDMA_WRITE_WITH_IMM; wr.send_flags = IBV_SEND_SIGNALED; wr.imm_data = imm_data; - wr.wr.rdma.remote_addr = (uint64_t)remote_.remote_addr; - wr.wr.rdma.rkey = remote_.rkey; + wr.wr.rdma.remote_addr = remote_addr; + wr.wr.rdma.rkey = rkey; struct ibv_send_wr* bad_wr; - CHECK(!ibv_post_send(channel_->qp_, &wr, &bad_wr)) << "Failed to post send"; -} - -RdmaAckBuffer::RdmaAckBuffer(RdmaChannel* channel, string name) - : RdmaBuffer(channel, name) {} - -RdmaMessageBuffer::RdmaMessageBuffer(RdmaChannel* channel, string name) - : RdmaBuffer(channel, name) {} - -RdmaTensorBuffer::RdmaTensorBuffer(RdmaChannel* channel, string name) - : RdmaBuffer(channel, name) {} - -RdmaTensorBuffer::~RdmaTensorBuffer() { - for (Itable it = retable.begin(); it != retable.end(); ++it) { - delete (it->second); - } + CHECK(!ibv_post_send(channel->qp_, &wr, &bad_wr)) << "Failed to post send"; } // Send the next ack from the buffer's job queue. -void RdmaAckBuffer::SendNextItem() { - uint32_t imm_data = LookupBufferIndex("rx_ack_buffer"); - RdmaMessage rm; - rm.name_ = "rx_ack_buffer"; - rm.type_ = RDMA_MESSAGE_ACK; - rm.name_size_ = rm.name_.size(); - string message = RdmaMessage::CreateMessage(rm); - memcpy(buffer_, message.data(), message.size()); - Write(imm_data, message.size()); +void RdmaMessageBuffer::SendAck(const RdmaChannel* channel) { + Write(channel, RDMA_IMM_DATA_ACK, 0, 0, 0, 0, 0, RDMA_WRITE_ID_ACK, nullptr); } // Send the next message from the buffer's job queue. void RdmaMessageBuffer::SendNextItem() { - uint32_t imm_data = LookupBufferIndex("rx_message_buffer"); + uint32_t imm_data = RDMA_IMM_DATA_MESSAGE; mu_.lock(); if (!queue_.empty() && (local_status_ == idle) && (remote_status_ == idle)) { local_status_ = busy; @@ -1029,244 +878,385 @@ void RdmaMessageBuffer::SendNextItem() { } } -Rendezvous::DoneCallback RdmaTensorBuffer::getRecvTensorCallback( - const string& key_with_step_id, const string& key, int64 step_id, - const Rendezvous::ParsedKey& parsed) { - Rendezvous::DoneCallback cb = [this, key_with_step_id, key, step_id, parsed]( - const Status& status, const Rendezvous::Args& send_args, - const Rendezvous::Args& recv_args, const Tensor& in, bool is_dead) { - CHECK(status.ok()) << "RecvLocalAsync was not ok, key" << key_with_step_id - << " error message: " << status.error_message(); - size_t buffer_size = RdmaMessage::kMessageTotalBytes; - size_t tensor_bytes = 0; - // Figures out which device the tensor is hosted on. - Device* src_dev = nullptr; - Status s = channel_->adapter_->worker_env_->device_mgr->LookupDevice( - parsed.src_device, &src_dev); - CHECK(s.ok()) << "src device not found"; - // Does the device have the right incarnation number we expect? - CHECK(src_dev->attributes().incarnation() == parsed.src_incarnation) - << "RecvTensor expects a different device incarnation: " - << parsed.src_incarnation << " vs. " - << src_dev->attributes().incarnation() - << ". Your worker job was probably restarted. Check your " - << "worker job for the reason why it was restarted."; - Device* dst_dev = nullptr; - // destination is on CPU. - s = channel_->adapter_->worker_env_->device_mgr->LookupDevice("CPU:0", - &dst_dev); - CHECK(s.ok()) << "dst device not found"; - AllocatorAttributes dst_alloc_attr; - dst_alloc_attr.set_on_host(true); - - bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); - // string tensor needs to be serialized - Tensor copy; - TensorProto proto; - if (src_dev->tensorflow_gpu_device_info() && - (!send_args.alloc_attrs.on_host())) { +static void CountCopies(const std::string& key, void* src_addr, void* dst_addr, + size_t tensor_bytes, bool is_gpu_to_cpu) { +#ifdef RDMA_COUNT_COPIES + static uint64_t numGPUToCPUCopies = 0; + static uint64_t numGPUToCPUCopiedBytes = 0; + static uint64_t numCPUToGPUCopies = 0; + static uint64_t numCPUToGPUCopiedBytes = 0; + static uint64_t numTotalCopies = 0; + + if (is_gpu_to_cpu) { + ++numGPUToCPUCopies; + numGPUToCPUCopiedBytes += tensor_bytes; + } else { + ++numCPUToGPUCopies; + numCPUToGPUCopiedBytes += tensor_bytes; + } + if ((++numTotalCopies % 0x400) == 0) { + RDMA_LOG(0) << "Tensor copies:" + << " GPU to CPU: " << numGPUToCPUCopies + << " (" << numGPUToCPUCopiedBytes << " Bytes)" + << " CPU to GPU: " << numCPUToGPUCopies + << " (" << numCPUToGPUCopiedBytes << " Bytes)"; + } + RDMA_LOG(2) << "Copying tensor " << key + << " From: " << src_addr << " To: " << dst_addr; +#endif +} + +static uint64_t Checksum(Device* device, const DeviceContext* device_context, + const Tensor& in) { + uint64 checksum = 0; + if (DataTypeCanUseMemcpy(in.dtype())) { #if GOOGLE_CUDA - CHECK(send_args.device_context) << "send dev name: " << src_dev->name() - << " gpu_info: " - << src_dev->tensorflow_gpu_device_info(); - - if (can_memcpy) { - AllocatorAttributes host_alloc_attrs; - host_alloc_attrs.set_gpu_compatible(true); - host_alloc_attrs.set_on_host(true); - Allocator* alloc = ProcessState::singleton()->GetCUDAHostAllocator(0); - copy = Tensor(alloc, in.dtype(), in.shape()); - tensor_bytes = in.TotalBytes(); - buffer_size += tensor_bytes; - GPUUtil::CopyGPUTensorToCPU( - src_dev, send_args.device_context, &in, ©, - [this, copy, tensor_bytes, buffer_size, key, in, step_id, - key_with_step_id, is_dead, send_args, recv_args](const Status& s) { - CHECK(s.ok()) << "copy tensor from gpu sync"; - StringPiece copy_buf; - copy_buf = copy.tensor_data(); - PostCopyOperations(true, buffer_size, tensor_bytes, key, in, - step_id, is_dead, key_with_step_id, ©, - NULL, ©_buf, send_args, recv_args); - }); - } else { - // "val" is on a GPU. No longer uses GPUUtil to fill the proto, use - // aync instead - GPUUtil::SetProtoFromGPU( - in, src_dev, send_args.device_context, &proto, is_dead, - [this, proto, buffer_size, key, in, step_id, key_with_step_id, - is_dead, send_args, recv_args](const Status& s) mutable { - CHECK(s.ok()) << "copy proto from gpu sync"; - auto tensor_bytes = proto.ByteSize(); - buffer_size += tensor_bytes; - PostCopyOperations(false, buffer_size, tensor_bytes, key, in, - step_id, is_dead, key_with_step_id, NULL, - &proto, NULL, send_args, recv_args); - }); - } -#endif // GOOGLE_CUDA - } else { - // tensor is in CPU memory. - StringPiece copy_buf; - if (can_memcpy) { - copy_buf = in.tensor_data(); - tensor_bytes = in.TotalBytes(); - } else { - in.AsProtoTensorContent(&proto); - tensor_bytes = proto.ByteSize(); - } - buffer_size += tensor_bytes; - PostCopyOperations(can_memcpy, buffer_size, tensor_bytes, key, in, - step_id, is_dead, key_with_step_id, ©, &proto, - ©_buf, send_args, recv_args); + if (in.TotalBytes() == 0) { + return 0; } - }; - return cb; + checksum = (device_context != nullptr) + ? GPUUtil::Checksum(device, device_context, in) + : GPUUtil::Checksum(in); +#endif + } else { + string s = in.SummarizeValue(999999); + checksum = Hash64(s.c_str(), s.size(), 0); + } + return checksum; } -// Send the next tensor from the buffer's job queue. -void RdmaTensorBuffer::SendNextItem() { - // get the key - string key_with_step_id = ""; - { - mutex_lock lock{mu_}; - if (!queue_.empty()) { - key_with_step_id = queue_.front(); - queue_.pop(); +static void ValidateChecksum(uint64_t expected, uint64_t actual, + const Tensor& in, uint32_t request_index, + const std::string& key, const std::string& msg) { + RDMA_LOG(2) << "Request #" << request_index << ": " << key + << ": Checksum: " << std::hex << " Expected = 0x" << expected + << ". Actual = 0x" << actual << "."; + + if (expected != actual) { + // Checksum failed. There is one case where this is allowed - if the + // tensor is an AssignAdd of the global step. Since the data-validation + // always postpones the Tensor response in order to send a checksum message, + // it is possible that the global-step was updated while the response was + // still in queue. + if ((in.TotalBytes() == 8) && (in.dtype() == DT_INT64)) { + int64_t prev_val = *(int64_t*)DMAHelper::base(&in) - 1; + actual = Hash64((const char*)&prev_val, 8, 0); } + if (expected != actual) { + LOG(FATAL) << "[" << msg << "]: Checksum validation failed for request #" + << request_index << ": " << key << std::hex << " " + << DataTypeString(in.dtype()) << " " + << in.shape().DebugString() << " (0x" << in.TotalBytes() + << " bytes): " + << " Expected 0x" << expected << ". Got 0x" << actual << "."; + } + } +} + +// Sync the 'done' operation on the GPU stream, but without all the data +// copying. +static void StreamGPUOp(Device* gpu_device, + const DeviceContext* device_context, + StatusCallback done) { + Tensor dummy1, dummy2; + GPUUtil::CopyGPUTensorToCPU( + gpu_device, device_context, &dummy1, &dummy2, done); +} + +RdmaTensorResponse* RdmaChannel::AddTensorResponse(const RdmaMessage& rm) { + mutex_lock lock{mu_}; + auto it = + responses_table_.emplace(rm.request_index_, RdmaTensorResponse(this, rm)); + CHECK(it.second) << "Response with the ID " << rm.request_index_ + << " already exists."; + return &it.first->second; +} + +RdmaTensorResponse* RdmaChannel::UpdateTensorResponse(const RdmaMessage& rm) { + mutex_lock lock{mu_}; + auto it = responses_table_.find(rm.request_index_); + CHECK(it != responses_table_.end()) << "No response found."; + RdmaTensorResponse* response = &it->second; + response->Update(rm); + return response; +} + +void RdmaChannel::RemoveTensorResponse(uint32_t request_index) { + mutex_lock lock{mu_}; + responses_table_.erase(request_index); +} + +void RdmaTensorResponse::Start() { + Rendezvous::ParsedKey parsed; + Status s = Rendezvous::ParseKey(rm_.name_, &parsed); + if (!s.ok()) { + SendErrorStatus(s); + return; } - // send the tensor if a key is acquired. - if (key_with_step_id != "") { - VLOG(2) << "try to send tensor: " << key_with_step_id; - string key; - int64 step_id; - VerbsUtil::GetKeyAndStepId(key_with_step_id, key, step_id); - CHECK(key.compare(name_) == 0); - Rendezvous::ParsedKey parsed; - Rendezvous::ParseKey(key, &parsed); - Rendezvous::DoneCallback cb = - getRecvTensorCallback(key_with_step_id, key, step_id, parsed); - channel_->adapter_->worker_env_->rendezvous_mgr->RecvLocalAsync(step_id, - parsed, cb); + channel_->adapter_->worker_env_->rendezvous_mgr->RecvLocalAsync( + rm_.step_id_, parsed, + [this, parsed](const Status& status, const Rendezvous::Args& send_args, + const Rendezvous::Args& recv_args, const Tensor& in, + bool is_dead) { + CHECK(status.ok()) << "RecvLocalAsync was not ok." + << " error message: " << status.error_message(); + RecvHandler(parsed, send_args, recv_args, in, is_dead); + }); +} + +void RdmaTensorResponse::Resume() { SendContent(*tensor_, *proto_, is_dead_); } + +// Helper for RecvTensor. Validates "key" and returns the source +// device in "*src_dev". +Status RdmaTensorResponse::PrepareRecvTensor( + const Rendezvous::ParsedKey& parsed, Device** src_dev) { + // Figures out which device the tensor is hosted on. + string local_name = DeviceNameUtils::LocalName(parsed.src_device); + TF_RETURN_IF_ERROR(channel_->adapter_->worker_env_->device_mgr->LookupDevice( + local_name, src_dev)); + + // Does the device have the right incarnation number we expect? + if ((*src_dev)->attributes().incarnation() != parsed.src_incarnation) { + return errors::Aborted( + "RecvTensor expects a different device incarnation: ", + parsed.src_incarnation, " vs. ", (*src_dev)->attributes().incarnation(), + ". Your worker job was probably restarted. Check your " + "worker job for the reason why it was restarted."); } + + return Status::OK(); } -void RdmaTensorBuffer::ReSendNextItem() { - // get the key - string key_with_step_id = ""; - { - mutex_lock lock{mu_}; - if (!requeue.empty()) { - key_with_step_id = requeue.front(); - requeue.pop(); - } +void RdmaTensorResponse::RecvHandler(Rendezvous::ParsedKey parsed, + const Rendezvous::Args& send_args, + const Rendezvous::Args& recv_args, + const Tensor& in, bool is_dead) { + Device* src_dev = nullptr; + Status s = PrepareRecvTensor(parsed, &src_dev); + if (!s.ok()) { + SendErrorStatus(s); + return; } - // send the tensor if a key is acquired. - if (key_with_step_id != "") { - VLOG(2) << "try to send tensor: " << key_with_step_id; - string key; - int64 step_id; - VerbsUtil::GetKeyAndStepId(key_with_step_id, key, step_id); - CHECK(key.compare(name_) == 0); - Rendezvous::ParsedKey parsed; - Rendezvous::ParseKey(key, &parsed); - Rendezvous::DoneCallback cb = - getRecvTensorCallback(key_with_step_id, key, step_id, parsed); - ReItem* item; - { - mutex_lock lock{mu_}; - Itable it = retable.find(key_with_step_id); - CHECK(it != retable.end()) << "Could not find dup-recv context"; - item = it->second; - retable.erase(it); + meta_data_changed_ = TensorMetaDataChanged(in, is_dead); +#ifdef RDMA_DATA_VALIDATION + // Always send a meta data message with the source checksum + meta_data_changed_ = rm_.type_ == RDMA_MESSAGE_TENSOR_REQUEST; + checksum_ = Checksum(src_dev, send_args.device_context, in); +#endif + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + // string tensor needs to be serialized + Tensor copy; + TensorProto proto; + const bool on_host = send_args.alloc_attrs.on_host(); + if (src_dev->tensorflow_gpu_device_info() && !on_host) { +#if GOOGLE_CUDA + DeviceContext* send_dev_context = send_args.device_context; + CHECK(send_dev_context) + << "send dev name: " << src_dev->name() + << " gpu_info: " << src_dev->tensorflow_gpu_device_info(); + + if (can_memcpy) { + // If the tensor is located on a GDR compatible GPU, there is no need to + // copy it. We can send directly from the source, just need to make sure + // we are in sync with the GPU stream. + // If the tensor's meta-data changed however, we will need to clone it, + // so anyway we'll have to copy it from GPU to CPU first. If at some + // point in time Clone() is changed to only save a shallow copy, we can + // skip the copy here as well. + if ((in.TotalBytes() > 0) && !meta_data_changed_ && + (RdmaMemoryMgr::Singleton().FindMemoryRegion( + (void*)DMAHelper::base(&in), in.TotalBytes()) != nullptr)) { + StreamGPUOp(src_dev, send_dev_context, + [this, in, proto, is_dead](const Status& s) { + Send(in, proto, is_dead, s); + }); + return; + } + + // The tensor must be copied from GPU to CPU, because either: + // 1. The tensor is located on a non GDR compatible GPU. + // 2. The tensor's meta-data has changed. + Allocator* alloc = ProcessState::singleton()->GetCUDAHostAllocator(0); + copy = Tensor(alloc, in.dtype(), in.shape()); + CountCopies(rm_.name_, (void*)DMAHelper::base(&in), + (void*)DMAHelper::base(©), in.TotalBytes(), true); + GPUUtil::CopyGPUTensorToCPU( + src_dev, send_dev_context, &in, ©, + [this, copy, proto, is_dead](const Status& s) { + Send(copy, proto, is_dead, s); + }); + } else { + GPUUtil::SetProtoFromGPU( + in, src_dev, send_args.device_context, &proto, is_dead, + [this, in, proto, is_dead](const Status& s) mutable { + Send(in, proto, is_dead, s); + }); + } +#else + SendErrorStatus(errors::Internal("No GPU device in process")); +#endif // GOOGLE_CUDA + } else { + // tensor is in CPU memory. + if (!can_memcpy) { + in.AsProtoTensorContent(&proto); } - cb(Status::OK(), item->send_args, item->recv_args, item->in, item->is_dead); - delete (item); + Send(in, proto, is_dead, Status::OK()); } } -void RdmaTensorBuffer::PostCopyOperations( - bool can_memcpy, size_t buffer_size, size_t tensor_bytes, const string& key, - const Tensor& in, int64 step_id, bool is_dead, - const string& key_with_step_id, const Tensor* copy, - const TensorProto* proto, const StringPiece* copy_buf, - const Rendezvous::Args& send_args, const Rendezvous::Args& recv_args) { - // prepare message +void RdmaTensorResponse::Send(const Tensor& in, const TensorProto& proto, + bool is_dead, const Status& status) { + if (!status.ok()) { + SendErrorStatus(status); + return; + } + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + bool proto_size_changed = (!can_memcpy) && + (proto.ByteSize() != rm_.tensor_bytes_); + if (meta_data_changed_ || proto_size_changed) { + Clone(in, proto, is_dead); + SendMetaData(in, proto, is_dead); + } else { + SendContent(in, proto, is_dead); + } +} + +bool RdmaTensorResponse::TensorMetaDataChanged(const Tensor& in, bool is_dead) { + return (rm_.data_type_ != in.dtype()) || (rm_.tensor_shape_ != in.shape()) || + (rm_.is_dead_ != is_dead); +} + +void RdmaTensorResponse::Clone(const Tensor& in, const TensorProto& proto, + bool is_dead) { + // Clone the data to be sent later. For simplicity, we clone the tensor's + // data even if it is already a copy. Performance is less of a concern here + // since the meta-data hardly ever changes. The reason we create a copy, is + // that some tensors share their buffer between different step-ids, so the + // tensor content may change before re-request was completed. + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + if (can_memcpy && (in.TotalBytes() > 0)) { + Allocator* allocator = ProcessState::singleton()->GetCPUAllocator(0); + tensor_ = new Tensor(allocator, in.dtype(), in.shape()); + memcpy(DMAHelper::base(tensor_), DMAHelper::base(&in), in.TotalBytes()); + } else { + tensor_ = new Tensor(in.dtype(), in.shape()); + } + if (!can_memcpy) { + proto_ = new TensorProto(proto); + } + is_dead_ = is_dead; +} + +void RdmaTensorResponse::SendMetaData(const Tensor& in, + const TensorProto& proto, bool is_dead) { + RDMA_LOG(2) << "Request #" << rm_.request_index_ + << ": Meta data changed: " << rm_.name_; + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + size_t tensor_bytes = (can_memcpy) ? in.TotalBytes() : proto.ByteSize(); + + // Send meta-data update: RdmaMessage rm; - rm.name_size_ = key.size(); - rm.name_ = key; + rm.type_ = RDMA_MESSAGE_META_DATA_UPDATE; + rm.name_size_ = rm_.name_.size(); + rm.name_ = rm_.name_; rm.tensor_shape_ = in.shape(); rm.data_type_ = in.dtype(); - rm.step_id_ = step_id; + rm.step_id_ = rm_.step_id_; rm.is_dead_ = is_dead; rm.tensor_bytes_ = tensor_bytes; - rm.buffer_size_ = buffer_size; - mu_.lock(); - if (local_status_ == none || (buffer_size > size_ && local_status_ == idle && - remote_status_ == idle)) { - if ((local_status_ != none) && (buffer_size > size_)) { - VLOG(2) << "Extend RDMA buffer from " << size_ << " to " << buffer_size; - } - CreateCPUBuffer(buffer_size, false); - // Need to be received again, put into the re-recv queue and the table - requeue.push(key_with_step_id); - ReItem* item = new ReItem(send_args, recv_args, in, is_dead); - retable.insert(std::pair(key_with_step_id, item)); - mu_.unlock(); - // no longer used: put back the key since it is not sent; - // ask the remote to create the same buffer - rm.type_ = RDMA_MESSAGE_BUFFER_REQUEST; - rm.remote_addr_ = reinterpret_cast(buffer_); - rm.rkey_ = self_->rkey; - string message = RdmaMessage::CreateMessage(rm); - channel_->tx_message_buffer_->EnqueueItem(message); - channel_->tx_message_buffer_->SendNextItem(); - } else if ((local_status_ == idle) && (remote_status_ == idle)) { - // both buffers are ready, send the tensor - local_status_ = busy; - remote_status_ = busy; - // local/remote_status_ won't be set back to idle - // unitl Write() is successful - mu_.unlock(); - if (!((buffer_size == size_ && rm.data_type_ != DT_STRING) || - (buffer_size <= size_ && rm.data_type_ == DT_STRING))) { - VLOG(2) << "Tensor and buffer size do not agree," - << " buffer_size = " << size_ - << " requested tensor size = " << buffer_size << in.DebugString(); - } - uint32_t imm_data = LookupBufferIndex(key); - rm.type_ = RDMA_MESSAGE_TENSOR_WRITE; - string message = RdmaMessage::CreateMessage(rm); - memcpy(buffer_, message.data(), message.size()); - if (!is_dead) { - // copy the tensor buffer content - void* output = static_cast(static_cast(buffer_) + - RdmaMessage::kTensorBufferStartIndex); - CHECK(tensor_bytes + RdmaMessage::kTensorBufferStartIndex <= size_); - if (can_memcpy) { - CHECK(copy != NULL) << "callback missing pointer to copy tensor"; - CHECK(copy_buf != NULL) << "callback missing pointer to copy buffer"; - CHECK(copy_buf->size() == tensor_bytes) - << "unexpected tensor size: " << copy_buf->size() - << " != " << tensor_bytes; - memcpy(output, copy_buf->data(), tensor_bytes); - } else { - CHECK(proto != NULL) << "callback missing pointer to proto tensor"; - proto->SerializeToArray(output, tensor_bytes); + rm.request_index_ = rm_.request_index_; +#ifdef RDMA_DATA_VALIDATION + rm.checksum_ = checksum_; +#endif + RDMA_LOG(1) << "Step 0x" << std::hex << rm.step_id_ << std::dec + << ": Sending RDMA_MESSAGE_META_DATA_UPDATE #" + << rm.request_index_ << ": " << rm.name_ + << " (shape = " << rm.tensor_shape_.DebugString() << "." + << " data-type = " << DataTypeString(rm.data_type_) << "." + << " is-dead = " << rm.is_dead_ << ")"; + + string message = RdmaMessage::CreateMessage(rm); + channel_->tx_message_buffer_->EnqueueItem(message); + channel_->tx_message_buffer_->SendNextItem(); +} + +void RdmaTensorResponse::SendContent(const Tensor& in, const TensorProto& proto, + bool is_dead) { + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + size_t tensor_bytes = (can_memcpy) ? in.TotalBytes() : proto.ByteSize(); + uint32_t imm_data = rm_.request_index_; + if (!is_dead) { + if (can_memcpy) { + src_buffer_ = const_cast(DMAHelper::buffer(&in)); + if (src_buffer_ != nullptr) { + src_buffer_->Ref(); // Keep buffer alive until write is complete + src_addr_ = src_buffer_->data(); + mr_ = RdmaMemoryMgr::Singleton().FindMemoryRegion(src_addr_, + tensor_bytes); } } else { - buffer_size = RdmaMessage::kMessageTotalBytes; + RDMA_LOG(2) << "Encoding proto: " << rm_.name_ + << " (Size: " << tensor_bytes << ") " << in.DebugString(); + src_addr_ = malloc(tensor_bytes); + mr_ = ibv_reg_mr(channel_->adapter_->pd_, src_addr_, tensor_bytes, + IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); + proto.SerializeToArray(src_addr_, tensor_bytes); } - Write(imm_data, buffer_size); } else { - // Need to be received again, put into the re-recv queue and the table - requeue.push(key_with_step_id); - ReItem* item = new ReItem(send_args, recv_args, in, is_dead); - retable.insert(std::pair(key_with_step_id, item)); - mu_.unlock(); + tensor_bytes = 0; + } + + uint32_t lkey = (mr_ == nullptr) ? 0 : mr_->lkey; + RDMA_LOG(1) << "Step 0x" << std::hex << rm_.step_id_ << std::dec + << ": Sending tensor content #" << rm_.request_index_ << " from " + << std::hex << src_addr_ << " (0x" << lkey << ")" + << " to " << rm_.remote_addr_ << " (0x" << rm_.rkey_ + << "): " << rm_.name_ << " (size: 0x" << std::hex << tensor_bytes + << ")"; + + RdmaMessageBuffer::Write(channel_, imm_data, tensor_bytes, + (uint64_t)src_addr_, lkey, rm_.remote_addr_, + rm_.rkey_, RDMA_WRITE_ID_TENSOR_WRITE, this); +} + +void RdmaTensorResponse::SendErrorStatus(const Status& status) { + RdmaMessage rm; + rm.type_ = RDMA_MESSAGE_ERROR_STATUS; + rm.name_size_ = rm_.name_.size(); + rm.name_ = rm_.name_; + rm.step_id_ = rm_.step_id_; + rm.request_index_ = rm_.request_index_; + rm.status_ = status; + LOG(ERROR) << "Step 0x" << std::hex << rm.step_id_ << std::dec + << ": Sending RDMA_MESSAGE_ERROR_STATUS #" + << rm.request_index_ << ": " << rm.name_ + << ". Status: " << status.ToString(); + + string message = RdmaMessage::CreateMessage(rm); + channel_->tx_message_buffer_->EnqueueItem(message); + channel_->tx_message_buffer_->SendNextItem(); + + // Destroy the response. + Destroy(); +} + +void RdmaTensorResponse::Destroy() { + bool res = false; + if (src_buffer_ != nullptr) { + res = src_buffer_->Unref(); + } + if (tensor_ != nullptr) { + delete tensor_; + } + if (proto_ != nullptr) { + ibv_dereg_mr(mr_); + free(src_addr_); + delete proto_; } + // Remove response from the pending list: + channel_->RemoveTensorResponse(rm_.request_index_); } // Create a RdmaMessage according to the pre-defined format @@ -1276,43 +1266,46 @@ void RdmaTensorBuffer::PostCopyOperations( // message in string format string RdmaMessage::CreateMessage(const RdmaMessage& rm) { // Rdma Message format - // type|name_size|name|step_id|buffer_size|remote_addr|rkey|is_dead|... - // 1B| 2B | 512| 8B | 8B | 8B | 4B | 1B |... - // ...|data_type|tensor_shape|tensor_bytes|tensor_buffer - // ...| XB | XB | 8B |... + // type|name_size|name|step_id|request_index|remote_addr|rkey|is_dead|... + // 1B| 2B | 512| 8B | 8B | 8B | 4B | 1B |... + // ...|data_type|tensor_shape|tensor_bytes|error_status | + // ...| XB | XB | 8B |size - 4B, proto - XB | // - // ACK: type|13|"rx_ack_buffer" - // TENSOR_REQUEST: type|name_size|tensor_name|step_id - // TENSOR_WRITE: type|name_size|tensor_name|step_id|...|is_dead - // |data_type|tensor_shape|tensor_bytes - // BUFFER_IDLE: type|name_size|buffer_name - // BUFFER_REQUEST: - // type|name_size|buffer_name|...|buffer_size|remote_addr|rkey| - // BUFFER_RESPONSE: - // type|name_size|buffer_name|...|buffer_size|remote_addr|rkey| - char message[kMessageTotalBytes]; + // ACK: Imm-type: ACK + // TENSOR_REQUEST: Imm-type: MESSAGE + // Fields: type, request_index, name, step_id, remote_addr, + // rkey, is_dead, data_type, tensor_shape, tensor_bytes + // META_DATA_UPDATE: Imm-type: MESSAGE + // Fields: type, request_index, is_dead, data_type, + // tensor_shape, tensor_bytes + // TENSOR_RE_REQUST: Imm-type: MESSAGE + // Fields: type, request_index, name, step_id, remote_addr, + // rkey, is_dead, data_type, tensor_shape, tensor_bytes + // ERROR_STATUS: Imm-type: MESSAGE + // Fields: type, request_index, name, step_id, error_status + // Tensor content: Imm-type: request_index + size_t message_size = kMessageTotalBytes; + char message[kMessageTotalBytes + kErrorStatusMaxSize]; // type message[kTypeStartIndex] = static_cast(rm.type_) & 0xff; - // size of name - memcpy(&message[kNameSizeStartIndex], &rm.name_size_, sizeof(rm.name_size_)); - // name - memcpy(&message[kNameStartIndex], rm.name_.data(), rm.name_.size()); - // buffer_size, remote_addr, rkey - if ((rm.type_ == RDMA_MESSAGE_BUFFER_REQUEST) || - (rm.type_ == RDMA_MESSAGE_BUFFER_RESPONSE)) { - memcpy(&message[kBufferSizeStartIndex], &rm.buffer_size_, - sizeof(rm.buffer_size_)); + // request index + memcpy(&message[kRequestIndexStartIndex], &rm.request_index_, + sizeof(rm.request_index_)); + // name, step_id, remote_addr, rkey + if ((rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) || + (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST)) { + memcpy(&message[kNameSizeStartIndex], &rm.name_size_, + sizeof(rm.name_size_)); + memcpy(&message[kNameStartIndex], rm.name_.data(), rm.name_.size()); memcpy(&message[kRemoteAddrStartIndex], &rm.remote_addr_, sizeof(rm.remote_addr_)); memcpy(&message[kRkeyStartIndex], &rm.rkey_, sizeof(rm.rkey_)); - } - // step_id - if ((rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) || - (rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST)) { memcpy(&message[kStepIdStartIndex], &rm.step_id_, sizeof(rm.step_id_)); } // is_dead, data_type, tensor_shape, tensor_bytes - if (rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) { + if ((rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) || + (rm.type_ == RDMA_MESSAGE_META_DATA_UPDATE) || + (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST)) { memcpy(&message[kIsDeadStartIndex], &rm.is_dead_, sizeof(rm.is_dead_)); memcpy(&message[kDataTypeStartIndex], &rm.data_type_, @@ -1322,7 +1315,30 @@ string RdmaMessage::CreateMessage(const RdmaMessage& rm) { memcpy(&message[kTensorBytesStartIndex], &rm.tensor_bytes_, sizeof(rm.tensor_bytes_)); } - return string(message, kMessageTotalBytes); + // checksum +#ifdef RDMA_DATA_VALIDATION + memcpy(&message[kChecksumStartIndex], &rm.checksum_, sizeof(rm.checksum_)); +#endif + // error status + if (rm.type_ == RDMA_MESSAGE_ERROR_STATUS) { + ::grpc::Status gs = ToGrpcStatus(rm.status_); + ErrorStatusProto gsProto; + gsProto.set_error_code(gs.error_code()); + gsProto.set_error_message(gs.error_message()); + gsProto.set_error_details(gs.error_details()); + uint32_t gsProtoSize = gsProto.ByteSize(); + if (gsProtoSize + 4 > kErrorStatusMaxSize) { + LOG(ERROR) << "Error status (" << gsProtoSize + 4 << " bytes) " + << "is too big to fit in RDMA message (" + << kErrorStatusMaxSize << " bytes). Truncated."; + gsProtoSize = kErrorStatusMaxSize - 4; + } + *(uint32_t*)&message[kErrorStatusStartIndex] = gsProtoSize; + gsProto.SerializeToArray(&message[kErrorStatusStartIndex + 4], + gsProtoSize); + message_size += gsProtoSize + 4; + } + return string(message, message_size); } // Parse a RdmaMessage according to the pre-defined format @@ -1335,26 +1351,24 @@ void RdmaMessage::ParseMessage(RdmaMessage& rm, void* buffer) { char* message = static_cast(buffer); // type rm.type_ = static_cast(message[kTypeStartIndex]); - // name_size_ - memcpy(&rm.name_size_, &message[kNameSizeStartIndex], sizeof(rm.name_size_)); - // name - rm.name_ = string(&message[kNameStartIndex], rm.name_size_); - // buffer_size, remote_addr, rkey - if ((rm.type_ == RDMA_MESSAGE_BUFFER_REQUEST) || - (rm.type_ == RDMA_MESSAGE_BUFFER_RESPONSE)) { - memcpy(&rm.buffer_size_, &message[kBufferSizeStartIndex], - sizeof(rm.buffer_size_)); + // request index + memcpy(&rm.request_index_, &message[kRequestIndexStartIndex], + sizeof(rm.request_index_)); + // name, step_id, remote_addr, rkey + if ((rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) || + (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST)) { + memcpy(&rm.name_size_, &message[kNameSizeStartIndex], + sizeof(rm.name_size_)); + rm.name_ = string(&message[kNameStartIndex], rm.name_size_); memcpy(&rm.remote_addr_, &message[kRemoteAddrStartIndex], sizeof(rm.remote_addr_)); memcpy(&rm.rkey_, &message[kRkeyStartIndex], sizeof(rm.rkey_)); - } - // step_id - if ((rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) || - (rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST)) { memcpy(&rm.step_id_, &message[kStepIdStartIndex], sizeof(rm.step_id_)); } // data_type, tensor_bytes, tensor_shape, is_dead - if (rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) { + if ((rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) || + (rm.type_ == RDMA_MESSAGE_META_DATA_UPDATE) || + (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST)) { memcpy(&rm.is_dead_, &message[kIsDeadStartIndex], sizeof(rm.is_dead_)); memcpy(&rm.data_type_, &message[kDataTypeStartIndex], sizeof(rm.data_type_)); @@ -1363,6 +1377,292 @@ void RdmaMessage::ParseMessage(RdmaMessage& rm, void* buffer) { memcpy(&rm.tensor_bytes_, &message[kTensorBytesStartIndex], sizeof(rm.tensor_bytes_)); } + // checksum +#ifdef RDMA_DATA_VALIDATION + memcpy(&rm.checksum_, &message[kChecksumStartIndex], sizeof(rm.checksum_)); +#endif + // error status + if (rm.type_ == RDMA_MESSAGE_ERROR_STATUS) { + ErrorStatusProto gsProto; + uint32_t gsProtoSize = *(uint32_t*)&message[kErrorStatusStartIndex]; + CHECK(ParseProtoUnlimited( + &gsProto, &message[kErrorStatusStartIndex + 4], gsProtoSize)) + << "Failed to parse error status proto from message. Aborting."; + ::grpc::Status gs((::grpc::StatusCode)gsProto.error_code(), + gsProto.error_message(), gsProto.error_details()); + rm.status_ = FromGrpcStatus(gs); + } +} + +//***************************************************************************** +// RdmaMemoryMgr +//***************************************************************************** + +ibv_mr* RdmaMemoryMgr::FindMemoryRegion(void* addr, size_t length) { + mutex_lock l(mrs_mu_); + auto iter = std::upper_bound(mrs_.begin(), mrs_.end(), addr, &Comparator); + if (iter == std::end(mrs_) || iter->get()->addr > addr) { + return nullptr; + } else { + return iter->get(); + } +} + +void RdmaMemoryMgr::InsertMemoryRegion(void* addr, size_t length, + const std::string& allocator_name) { + if (length == 0) return; + ibv_mr* mr = ibv_reg_mr(pd_, addr, length, + IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); + RDMA_LOG(1) << "Insert memory region 0x" << std::hex << mr->rkey << ". [" + << addr << "-" << (void*)((uint64_t)addr + length - 1) << "]" + << " SIZE: 0x" << length << " (" << allocator_name << ")."; + if (mr != nullptr) { + mutex_lock l(mrs_mu_); + auto iter = std::upper_bound(mrs_.begin(), mrs_.end(), addr, &Comparator); + mrs_.insert(iter, {mr, &MRDeleter}); + } else { + LOG(WARNING) << "Cannot register memory region"; + } +} + +void RdmaMemoryMgr::EvictMemoryRegion(void* addr, size_t length) { + if (length == 0) return; + mutex_lock l(mrs_mu_); + auto iter = std::upper_bound(mrs_.begin(), mrs_.end(), addr, &Comparator); + if (iter != std::end(mrs_) && iter->get()->addr == addr) { + mrs_.erase(iter); + RDMA_LOG(1) << "Evict memory region 0x" << std::hex << iter->get()->rkey; + + } else { + LOG(WARNING) << "Failed to de-register memory region"; + } +} + +const TensorMetaData* RdmaMemoryMgr::GetTensorMetaData( + const std::string& tensor_name) { + mutex_lock l(tensor_meta_data_mu_); + auto it = tensors_meta_data_.find(tensor_name); + if (it == tensors_meta_data_.end()) { + return nullptr; + } + return &it->second; +} + +const TensorMetaData* RdmaMemoryMgr::SetTensorMetaData( + const std::string& tensor_name, DataType dtype, const TensorShape& shape, + bool is_dead, size_t proto_size) { + mutex_lock l(tensor_meta_data_mu_); + TensorMetaData& meta_data = tensors_meta_data_[tensor_name]; + meta_data.data_type_ = dtype; + meta_data.tensor_shape_ = shape; + meta_data.proto_size_ = proto_size; + meta_data.is_dead_ = is_dead; + return &meta_data; +} + +//***************************************************************************** +// RdmaTensorRequest +//***************************************************************************** + +RdmaTensorRequest::RdmaTensorRequest( + uint32_t index, const string& key, int64 step_id, RdmaChannel* channel, + Device* dst_dev, const Rendezvous::Args recv_args, + const RdmaTensorRequest::RecvDoneCallback& done) + : index_(index), + key_(key), + step_id_(step_id), + channel_(channel), + dst_dev_(dst_dev), + recv_args_(recv_args), + meta_data_(RdmaMemoryMgr::Singleton().GetTensorMetaData(key)), + result_tensor_(nullptr), + proxy_tensor_(nullptr), + rdma_addr_(nullptr), + mr_(nullptr), + done_(done) {} + +RdmaTensorRequest::~RdmaTensorRequest() { DeallocateTensors(); } + +void RdmaTensorRequest::Done(const Status& s) { + Tensor val = std::move(*result_tensor_); + +#ifdef RDMA_DATA_VALIDATION + // Validate checksum + // Unfortunately we can't always do a Checksum directly on the result tensor. + // If the result tensor is on GPU, then we need to copy it back to CPU. If + // we happen to be in the midst of a proxy callback, then the copying will + // get stuck. + uint64_t checksum = (proxy_tensor_ != nullptr) + ? Checksum(nullptr, nullptr, *proxy_tensor_) + : Checksum(dst_dev_, recv_args_.device_context, val); + ValidateChecksum(checksum_, checksum, val, index_, key_, "RDMA"); +#endif + + Rendezvous::Args recv_args = std::move(recv_args_); + bool is_dead = (meta_data_ == nullptr) ? false : meta_data_->is_dead_; + RecvDoneCallback done = done_; + DeallocateTensors(); + channel_->RemoveTensorRequest(index_); + done(s, Rendezvous::Args(), recv_args, val, is_dead); +} + +void RdmaTensorRequest::DeallocateTensors() { + if (result_tensor_ != nullptr) { + delete result_tensor_; + result_tensor_ = nullptr; + } + if (proxy_tensor_ != nullptr) { + delete proxy_tensor_; + proxy_tensor_ = nullptr; + } +} + +bool RdmaTensorRequest::AllocateTensors() { + result_tensor_ = + new Tensor(dst_dev_->GetAllocator(recv_args_.alloc_attrs), + meta_data_->data_type_, meta_data_->tensor_shape_); + + size_t tensor_size = result_tensor_->TotalBytes(); + bool can_memcpy = DataTypeCanUseMemcpy(result_tensor_->dtype()); + if (can_memcpy) { + if (tensor_size == 0) { + return true; + } + rdma_addr_ = DMAHelper::base(result_tensor_); + mr_ = RdmaMemoryMgr::Singleton().FindMemoryRegion(rdma_addr_, tensor_size); +#if GOOGLE_CUDA + if (mr_ == nullptr) { + // Can't RDMA directly to result. Use a proxy. + proxy_tensor_ = + new Tensor(ProcessState::singleton()->GetCUDAHostAllocator(0), + result_tensor_->dtype(), result_tensor_->shape()); + rdma_addr_ = DMAHelper::base(proxy_tensor_); + mr_ = + RdmaMemoryMgr::Singleton().FindMemoryRegion(rdma_addr_, tensor_size); + } +#endif + } else { + uint32_t proto_size = meta_data_->proto_size_; + rdma_addr_ = malloc(proto_size); + mr_ = ibv_reg_mr(RdmaMemoryMgr::Singleton().pd_, rdma_addr_, proto_size, + IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); + } + CHECK(mr_ != nullptr) << " No memory region found for address " << rdma_addr_ + << ": " << key_; + return true; +} + +void RdmaTensorRequest::AllocateTensorsAsync(StatusCallback done) { + AllocateTensors(); + bool on_host = recv_args_.alloc_attrs.on_host(); + if (dst_dev_->tensorflow_gpu_device_info() && !on_host && + (proxy_tensor_ == nullptr)) { + // We need to sync the memory allocation on the GPU: + StreamGPUOp(dst_dev_, recv_args_.device_context, done); + } else { + done(Status::OK()); + } +} + +void RdmaTensorRequest::Send(RdmaMessageType message_type) { + RdmaMessageBuffer* rb = channel_->tx_message_buffer_; + RdmaMessage rm; + rm.type_ = message_type; + rm.request_index_ = index_; + rm.name_size_ = key_.size(); + rm.name_ = key_; + rm.step_id_ = step_id_; + rm.remote_addr_ = (uint64_t)rdma_addr_; + if (meta_data_ != nullptr) { + rm.data_type_ = meta_data_->data_type_; + rm.tensor_shape_ = meta_data_->tensor_shape_; + rm.is_dead_ = meta_data_->is_dead_; + rm.tensor_bytes_ = meta_data_->proto_size_; + } else { + rm.data_type_ = DT_INVALID; + } + rm.rkey_ = (mr_ == nullptr) ? 0 : mr_->rkey; + + RDMA_LOG(1) << "Step 0x" << std::hex << rm.step_id_ << std::dec + << ": Sending " << MessageTypeToString(message_type) + << " #" << index_ << ": " + << rm.name_ << " on " << rdma_addr_ + << " (rkey: 0x" << std::hex << rm.rkey_ << ")"; + + string message = RdmaMessage::CreateMessage(rm); + rb->EnqueueItem(message); + rb->SendNextItem(); +} + +void RdmaTensorRequest::RecvTensorMetaData(DataType dtype, TensorShape shape, + bool is_dead, size_t proto_size) { + meta_data_ = RdmaMemoryMgr::Singleton().SetTensorMetaData( + key_, dtype, shape, is_dead, proto_size); + + DeallocateTensors(); + AllocateTensorsAsync([this](const Status& s) { + Send(RDMA_MESSAGE_TENSOR_RE_REQUEST); + }); +} + +void RdmaTensorRequest::RecvTensorContent() { + bool can_memcpy = DataTypeCanUseMemcpy(meta_data_->data_type_); + size_t message_size = + can_memcpy ? result_tensor_->TotalBytes() : meta_data_->proto_size_; + RDMA_LOG(1) << "Step 0x" << std::hex << step_id_ << std::dec + << ": Received tensor content #" << index_ << ": " + << key_ << " (Size: 0x" << std::hex << message_size << ")"; + + Tensor val; + +#if GOOGLE_CUDA + if (proxy_tensor_ != nullptr) { + CountCopies(key_, (void*)DMAHelper::base(proxy_tensor_), + (void*)DMAHelper::base(result_tensor_), + result_tensor_->TotalBytes(), false); + GPUUtil::CopyCPUTensorToGPU(proxy_tensor_, recv_args_.device_context, + dst_dev_, result_tensor_, + [this](const Status& s) { + CHECK(s.ok()) << "copy tensor to gpu sync"; + Done(s); + }); + return; + } +#endif + + if (can_memcpy) { + Done(Status::OK()); + } else { + RDMA_LOG(2) << "Decoding proto: " << key_ + << " (Size: " << meta_data_->proto_size_ << ")"; + TensorProto proto; + CHECK(ParseProtoUnlimited(&proto, rdma_addr_, meta_data_->proto_size_)) + << "fail to parse proto from array"; + ibv_dereg_mr(mr_); + free(rdma_addr_); + Status s = dst_dev_->MakeTensorFromProto(proto, recv_args_.alloc_attrs, + result_tensor_); + Done(s); + } +} + +void RdmaTensorRequest::RecvErrorStatus(const Status& status) { + if (result_tensor_ == nullptr) { + result_tensor_ = new Tensor(); + } + LOG(ERROR) << "Received RDMA_MESSAGE_ERROR_STATUS: " << status.ToString(); + Done(status); +} + +void RdmaTensorRequest::Start() { + meta_data_ = RdmaMemoryMgr::Singleton().GetTensorMetaData(key_); + if (meta_data_ != nullptr) { + AllocateTensorsAsync([this](const Status& s) { + Send(RDMA_MESSAGE_TENSOR_REQUEST); + }); + } else { + Send(RDMA_MESSAGE_TENSOR_REQUEST); + } } } // end namespace tensorflow diff --git a/tensorflow/contrib/verbs/rdma.h b/tensorflow/contrib/verbs/rdma.h index fea2327d77..dd7643de94 100644 --- a/tensorflow/contrib/verbs/rdma.h +++ b/tensorflow/contrib/verbs/rdma.h @@ -27,6 +27,7 @@ limitations under the License. #include #include +#include "tensorflow/contrib/verbs/verbs_util.h" #include "tensorflow/core/distributed_runtime/worker_env.h" #include "tensorflow/core/framework/rendezvous.h" #include "tensorflow/core/framework/tensor.h" @@ -43,6 +44,11 @@ namespace tensorflow { #define SL_DEFAULT 0 #define TRAFFIC_CLASS 0 +#define RDMA_LOG_0 LOG(INFO) +#define RDMA_LOG_1 VLOG(1) +#define RDMA_LOG_2 VLOG(2) +#define RDMA_LOG(LEVEL) RDMA_LOG_##LEVEL + struct RdmaParams { uint8_t port_num; uint8_t sgid_index; @@ -76,29 +82,302 @@ enum Location { local, remote }; -enum BufferType { - ACK, - MESSAGE, - TENSOR -}; + enum RdmaMessageType { - RDMA_MESSAGE_ACK, - RDMA_MESSAGE_BUFFER_IDLE, - RDMA_MESSAGE_BUFFER_REQUEST, - RDMA_MESSAGE_BUFFER_RESPONSE, + RDMA_MESSAGE_META_DATA_UPDATE, + RDMA_MESSAGE_TENSOR_RE_REQUEST, RDMA_MESSAGE_TENSOR_REQUEST, - RDMA_MESSAGE_TENSOR_WRITE + RDMA_MESSAGE_ERROR_STATUS, +}; + +struct RdmaMessage { + RdmaMessageType type_; + uint16_t name_size_; + string name_; + int64 step_id_; + uint64_t request_index_; + union { + uint64_t remote_addr_; +#ifdef RDMA_DATA_VALIDATION + uint64_t checksum_; +#endif + }; + uint32_t rkey_; + bool is_dead_; + DataType data_type_; + TensorShape tensor_shape_; + size_t tensor_bytes_; + + // For error status: + Status status_; + + // type|name_size|name|step_id|request_index|remote_addr/checksum|rkey|... + // 1B| 2B | 512| 8B | 8B | 8B | 4B |... + // ...|is_dead|data_type|tensor_shape|tensor_bytes|error_status | + // ...| 1B | XB | XB | 8B |size - 4B, proto - XB | + static const size_t kNameCapacity = 512; + static const size_t kTypeStartIndex = 0; + static const size_t kNameSizeStartIndex = kTypeStartIndex + sizeof(type_); + static const size_t kNameStartIndex = + kNameSizeStartIndex + sizeof(name_size_); + static const size_t kStepIdStartIndex = kNameStartIndex + kNameCapacity; + static const size_t kRequestIndexStartIndex = + kStepIdStartIndex + sizeof(step_id_); + static const size_t kRemoteAddrStartIndex = + kRequestIndexStartIndex + sizeof(request_index_); + static const size_t kChecksumStartIndex = kRemoteAddrStartIndex; + static const size_t kRkeyStartIndex = + kRemoteAddrStartIndex + sizeof(remote_addr_); + static const size_t kIsDeadStartIndex = kRkeyStartIndex + sizeof(rkey_); + static const size_t kDataTypeStartIndex = + kIsDeadStartIndex + sizeof(is_dead_); + static const size_t kTensorShapeStartIndex = + kDataTypeStartIndex + sizeof(data_type_); + static const size_t kTensorBytesStartIndex = + kTensorShapeStartIndex + sizeof(TensorShape); + static const size_t kErrorStatusStartIndex = + kTensorBytesStartIndex + sizeof(tensor_bytes_); + static const size_t kErrorStatusMaxSize = 4096; + + static const size_t kMessageTotalBytes = kErrorStatusStartIndex; + static const size_t kRdmaMessageBufferSize = + kMessageTotalBytes + kErrorStatusMaxSize; + static string CreateMessage(const RdmaMessage& rm); + static void ParseMessage(RdmaMessage& rm, void* buffer); +}; + +// Immediate types for RDMA write +enum RdmaImmDataType { + RDMA_IMM_MAX_REQUEST_ID = 0xFFFFFFFD, + RDMA_IMM_DATA_ACK = 0xFFFFFFFE, + RDMA_IMM_DATA_MESSAGE = 0xFFFFFFFF +}; + +// Write types for RDMA write-complete events +enum RdmaWriteIDType { + RDMA_WRITE_ID_ACK, + RDMA_WRITE_ID_MESSAGE, + RDMA_WRITE_ID_TENSOR_WRITE +}; + +// Context for RDMA write-complete events +class RdmaWriteID { + public: + RdmaWriteID(RdmaWriteIDType write_type, void* write_context) + : write_type(write_type), write_context(write_context) {} + + RdmaWriteIDType write_type; + void* write_context; +}; + +// Tensor meta-data +class TensorMetaData { + public: + TensorShape tensor_shape_; + DataType data_type_; + size_t proto_size_; + bool is_dead_; + + std::ostream& print(std::ostream& out) const { + out << "Dtype = " << DataTypeString(data_type_) + << ", Shape = " << tensor_shape_.DebugString() << ", Proto size = 0x" + << std::hex << proto_size_ << ", Is dead = " << is_dead_; + return out; + } +}; + +inline std::ostream& operator<<(std::ostream& out, + const TensorMetaData& meta_data) { + return meta_data.print(out); +} + +class RdmaChannel; + +void MRDeleter(ibv_mr* mr); +using MemoryRegionPtr = std::unique_ptr; + +// RdmaMemoryMgr +// Manages the local meta-data cache, and the registered RDMA memory regions. +class RdmaMemoryMgr { + public: + static RdmaMemoryMgr& Singleton() { + static RdmaMemoryMgr instance; + return instance; + } + + // Memory regions + ibv_mr* FindMemoryRegion(void* addr, size_t length); + void InsertMemoryRegion(void* addr, size_t length, + const std::string& allocator_name); + void EvictMemoryRegion(void* addr, size_t length); + + // Tensor meta-data cache + const TensorMetaData* GetTensorMetaData(const std::string& tensor_name); + const TensorMetaData* SetTensorMetaData(const std::string& tensor_name, + DataType dtype, + const TensorShape& shape, + bool is_dead, size_t proto_size); + + struct ibv_pd* pd_; + + protected: + RdmaMemoryMgr() : pd_(nullptr) {} + + static bool Comparator(const void* ptr, const MemoryRegionPtr& other) { + return ptr < reinterpret_cast(other->addr) + other->length; + } + + private: + mutex tensor_meta_data_mu_; + std::unordered_map tensors_meta_data_; + + // Managed memory regions + mutex mrs_mu_; + std::vector mrs_ GUARDED_BY(mrs_mu_); }; -class RdmaBuffer; + +// RdmaTensorRequest +// Represents a single tensor request. +class RdmaTensorRequest { + public: + typedef Rendezvous::DoneCallback RecvDoneCallback; + + // Creates a tensor request identified by index. + RdmaTensorRequest(uint32_t index, const string& key, int64 step_id, + RdmaChannel* channel, Device* dst_dev, + const Rendezvous::Args recv_args, + const RecvDoneCallback& done); + ~RdmaTensorRequest(); + + // Request unique index. + uint32_t index() { return index_; } + + // Start the tensor request sequence. + // + // 1. Allocate the result tensor (and proxy tensor if required). + // 2. Send RDMA_MESSAGE_TENSOR_REQUEST to the remote side. + void Start(); + + // Receive tensor meta-data. + // + // 1. Update the local meta-data cache. + // 2. Reallocate the result tensor (and proxy tensor if required). + // 3. Re-send the request to the remote side. + void RecvTensorMetaData(DataType dtype, TensorShape shape, bool is_dead, + size_t proto_size); + + // Receive tensor content (RDMA write was completed). + // + // Decode proto if required and/or move to GPU if the content was not + // written to it directly (GPU direct is not avaliable). Afterwards, + // invoke Done(). + void RecvTensorContent(); + + // Receive error status (in case of a remote error). + // Invoke Done() with the status code. + void RecvErrorStatus(const Status& status); + +#ifdef RDMA_DATA_VALIDATION + // Receive tensor checksum + // + // For validation: Get and store the Tensor's expected checksum for the + // current request. Compare the result Tensor's checksum with the stored + // checksum right before invoking Done(). + void RecvTensorChecksum(uint64_t checksum) { checksum_ = checksum; } +#endif + + private: + void Done(const Status& s); + void Send(RdmaMessageType message_type); + bool AllocateTensors(); + void AllocateTensorsAsync(StatusCallback done); + void DeallocateTensors(); + + uint32_t index_; + string key_; + int64 step_id_; + RdmaChannel* channel_; + Device* dst_dev_; + Rendezvous::Args recv_args_; + const TensorMetaData* meta_data_; + Tensor* result_tensor_; + Tensor* proxy_tensor_; + void* rdma_addr_; + ibv_mr* mr_; + RecvDoneCallback done_; +#ifdef RDMA_DATA_VALIDATION + uint64_t checksum_; +#endif +}; + +// RdmaTensorResponse +// Represents a single tensor response. +class RdmaTensorResponse { + public: + // Creates a response for request message. + RdmaTensorResponse(RdmaChannel* channel, const RdmaMessage& rm) + : channel_(channel), rm_(rm) {} + + void Update(const RdmaMessage& rm) { rm_ = rm; } + + // Start the tensor response sequence. + // + // 1. Find the tensor in the local tag-match table and invoke RecvHandler. + // (Using RecvLocalAsync()). + // 2. Compare the tensor's meta-data to the meta-data in the message (taken + // from the requester's local cache). + // If meta-data changed: + // a. Clone the tensor to be sent later. + // b. Send a meta-data update message and wait for re-request. + // Else: + // a. Send the tensor's content (using direct RDMA write). + void Start(); + + // Resume the response sequence, after a re-request. + // + // 1. Send the tensor's content that was cloned earlier. + void Resume(); + + // Destroy the response's resources and remove it from the pending list. + void Destroy(); + + private: + void RecvHandler(Rendezvous::ParsedKey parsed, + const Rendezvous::Args& send_args, + const Rendezvous::Args& recv_args, const Tensor& in, + bool is_dead); + void Clone(const Tensor& in, const TensorProto& proto, bool is_dead); + void Send(const Tensor& in, const TensorProto& proto, bool is_dead, + const Status& status); + bool TensorMetaDataChanged(const Tensor& in, bool is_dead); + Status PrepareRecvTensor(const Rendezvous::ParsedKey& parsed, + Device** src_dev); + void SendMetaData(const Tensor& in, const TensorProto& proto, bool is_dead); + void SendContent(const Tensor& in, const TensorProto& proto, bool is_dead); + void SendErrorStatus(const Status& status); + + RdmaChannel* channel_; + RdmaMessage rm_; // The request message + TensorBuffer* src_buffer_ = nullptr; + void* src_addr_ = nullptr; + ibv_mr* mr_ = nullptr; + uint64_t checksum_ = 0; + bool meta_data_changed_ = false; + + // Re-item: + TensorProto* proto_ = nullptr; + Tensor* tensor_ = nullptr; + bool is_dead_ = false; +}; + +class RdmaMessageBuffer; // Class that represents the Rdma Adapter. // Responsible for creation of the completion queue, and handling // of work completions. class RdmaAdapter { friend class RdmaChannel; - friend class RdmaBuffer; - friend class RdmaAckBuffer; friend class RdmaMessageBuffer; - friend class RdmaTensorBuffer; + friend class RdmaTensorResponse; friend class RdmaMgr; friend class RdmaRemoteRendezvous; @@ -133,10 +412,10 @@ class RdmaAdapter { // Responsible for connecting queue pairs. class RdmaChannel { friend class RdmaAdapter; - friend class RdmaBuffer; - friend class RdmaAckBuffer; friend class RdmaMessageBuffer; friend class RdmaTensorBuffer; + friend class RdmaTensorRequest; + friend class RdmaTensorResponse; friend class RdmaMgr; friend class RdmaRemoteRendezvous; @@ -146,22 +425,28 @@ class RdmaChannel { ~RdmaChannel(); inline const RdmaAddress& self() { return self_; } RdmaAddress address() const; - inline const std::vector& message_buffers() const { + inline const std::vector& message_buffers() const { return message_buffers_; } void Connect(const RdmaAddress& remoteAddr); void Connect(); void Recv(); - RdmaBuffer* FindBuffer(const uint32_t index); - RdmaBuffer* FindBuffer(const string& name); - RdmaBuffer* FindOrCreateBuffer(const string& name, - BufferType buffer_type = TENSOR); - uint32_t LookupBufferIndex(const string& buffer_name); void SetRemoteAddress(const RdmaAddress& ra, bool override); - void InsertRecvCallback(const string& key, std::function recv_done); - void RemoveRecvCallback(const string& key); - void RunRecvCallback(const string& key); - static const int kNumMessageBuffers = 4; + + // Requests: + RdmaTensorRequest* InsertTensorRequest( + const string& key, int64 step_id, Device* dst_dev, + const Rendezvous::Args recv_args, + const RdmaTensorRequest::RecvDoneCallback& done); + void RemoveTensorRequest(uint32_t request_index); + RdmaTensorRequest* GetTensorRequest(uint32_t request_index); + + // Responses: + RdmaTensorResponse* AddTensorResponse(const RdmaMessage& rm); + RdmaTensorResponse* UpdateTensorResponse(const RdmaMessage& rm); + void RemoveTensorResponse(uint32_t request_index); + + static const int kNumMessageBuffers = 2; static const int kPingRecvWrid = 0; private: @@ -179,36 +464,31 @@ class RdmaChannel { string remote_name_; ibv_qp* qp_; mutex mu_; - bool connected_ GUARDED_BY(bt_mu_) = false; - RdmaAddress remote_ GUARDED_BY(bt_mu_); - bool remote_set_ GUARDED_BY(bt_mu_) = false; + bool connected_ GUARDED_BY(mu_) = false; + RdmaAddress remote_ GUARDED_BY(mu_); + bool remote_set_ GUARDED_BY(mu_) = false; mutex ct_mu_; - typedef std::unordered_map > CallbackTable; - CallbackTable callback_table_ GUARDED_BY(ct_mu_); - mutex bt_mu_; - typedef std::unordered_map BufferTable; - BufferTable buffer_table_ GUARDED_BY(bt_mu_); - typedef std::unordered_map BufferIndexNameTable; - BufferIndexNameTable buffer_index_name_table_ GUARDED_BY(bt_mu_); - typedef std::unordered_map BufferNameIndexTable; - BufferNameIndexTable buffer_name_index_table_ GUARDED_BY(bt_mu_); - RdmaBuffer* tx_message_buffer_; - RdmaBuffer* rx_message_buffer_; - RdmaBuffer* tx_ack_buffer_; - RdmaBuffer* rx_ack_buffer_; - std::vector message_buffers_; + typedef std::unordered_map RequestTable; + RequestTable request_table_ GUARDED_BY(ct_mu_); + uint32_t request_serial_ GUARDED_BY(ct_mu_); + mutex responses_mu_; + typedef std::unordered_map ResponsesTable; + ResponsesTable responses_table_ GUARDED_BY(responses_mu_); + RdmaMessageBuffer* tx_message_buffer_; + RdmaMessageBuffer* rx_message_buffer_; + std::vector message_buffers_; }; -// Class that represents a buffer for Rdma writes and reads. -class RdmaBuffer { +// Class that represents a buffer for Rdma message sending. +class RdmaMessageBuffer { friend class RdmaChannel; friend class RdmaAdapter; friend class RdmaMgr; friend class RdmaRemoteRendezvous; public: - explicit RdmaBuffer(RdmaChannel* channel, string name); - virtual ~RdmaBuffer(); + explicit RdmaMessageBuffer(RdmaChannel* channel, string name); + ~RdmaMessageBuffer(); inline void* buffer() const { return buffer_; } inline ibv_mr* self() const { return self_; } @@ -223,13 +503,15 @@ class RdmaBuffer { } void FreeBuffer(); void EnqueueItem(string Item); - virtual void SendNextItem() {}; + void SendNextItem(); void CreateCPUBuffer(size_t size, bool lock = true); void SetRemoteMR(RemoteMR rmi, bool override); - uint32_t LookupBufferIndex(const string& buffer_name) { - return const_cast(channel_)->LookupBufferIndex(buffer_name); - } void Write(uint32_t imm_data, size_t buffer_size); + static void Write(const RdmaChannel* channel, uint32_t imm_data, + size_t buffer_size, uint64_t src_addr, uint32_t lkey, + uint64_t remote_addr, uint32_t rkey, + RdmaWriteIDType write_type, void* write_context); + static void SendAck(const RdmaChannel* channel); protected: const RdmaChannel* channel_; @@ -245,125 +527,6 @@ class RdmaBuffer { BufferStatus remote_status_ GUARDED_BY(mu_) = none; }; -class RdmaAckBuffer : public RdmaBuffer { - public: - explicit RdmaAckBuffer(RdmaChannel* channel, string name); - virtual ~RdmaAckBuffer() override {} - void SendNextItem() override; -}; - -class RdmaMessageBuffer : public RdmaBuffer { - friend class RdmaChannel; - friend class RdmaAapater; - - public: - explicit RdmaMessageBuffer(RdmaChannel* channel, string name); - virtual ~RdmaMessageBuffer() override {} - void SendNextItem() override; -}; - -class RdmaTensorBuffer : public RdmaBuffer { - public: - explicit RdmaTensorBuffer(RdmaChannel* channel, string name); - virtual ~RdmaTensorBuffer() override; - void SendNextItem() override; - void PostCopyOperations(bool can_memcpy, size_t buffer_size, - size_t tensor_bytes, const string& key, - const Tensor& in, int64 step_id, bool is_dead, - const string& key_with_step_id, const Tensor* copy, - const TensorProto* proto, const StringPiece* copy_buf, - const Rendezvous::Args& send_args, - const Rendezvous::Args& recv_args); - - void ReSendNextItem(); - - private: - Rendezvous::DoneCallback getRecvTensorCallback( - const string& key_with_step_id, const string& key, int64 step_id, - const Rendezvous::ParsedKey& parsed); - - struct ReItem { - Rendezvous::Args send_args; - Rendezvous::Args recv_args; - Tensor in; - bool is_dead; - - ReItem(const Rendezvous::Args& send_args_, - const Rendezvous::Args& recv_args_, const Tensor& in_, bool is_dead_) - : send_args(send_args_), - recv_args(recv_args_), - in(in_), - is_dead(is_dead_) { - if (send_args.device_context) { - send_args.device_context->Ref(); - } - if (recv_args.device_context) { - recv_args.device_context->Ref(); - } - } - - ~ReItem() { - if (send_args.device_context) { - send_args.device_context->Unref(); - } - if (recv_args.device_context) { - recv_args.device_context->Unref(); - } - } - }; - typedef std::map Table; - typedef Table::iterator Itable; - - std::queue requeue GUARDED_BY(mu_); - Table retable GUARDED_BY(mu_); -}; - -struct RdmaMessage { - RdmaMessageType type_; - uint16_t name_size_; - string name_; - int64 step_id_; - uint64_t buffer_size_; - uint64_t remote_addr_; - uint32_t rkey_; - bool is_dead_; - DataType data_type_; - TensorShape tensor_shape_; - size_t tensor_bytes_; - - // type|name_size|name|step_id|buffer_size|remote_addr|rkey|is_dead|... - // 1B| 2B | 512| 8B | 8B | 8B | 4B | 1B |... - // ...|data_type|tensor_shape|tensor_bytes|tensor_buffer - // ...| XB | XB | 8B |... - // - static const size_t kNameCapacity = 512; - static const size_t kTypeStartIndex = 0; - static const size_t kNameSizeStartIndex = kTypeStartIndex + sizeof(type_); - static const size_t kNameStartIndex = - kNameSizeStartIndex + sizeof(name_size_); - static const size_t kStepIdStartIndex = kNameStartIndex + kNameCapacity; - static const size_t kBufferSizeStartIndex = - kStepIdStartIndex + sizeof(step_id_); - static const size_t kRemoteAddrStartIndex = - kBufferSizeStartIndex + sizeof(buffer_size_); - static const size_t kRkeyStartIndex = - kRemoteAddrStartIndex + sizeof(remote_addr_); - static const size_t kIsDeadStartIndex = kRkeyStartIndex + sizeof(rkey_); - static const size_t kDataTypeStartIndex = - kIsDeadStartIndex + sizeof(is_dead_); - static const size_t kTensorShapeStartIndex = - kDataTypeStartIndex + sizeof(data_type_); - static const size_t kTensorBytesStartIndex = - kTensorShapeStartIndex + sizeof(TensorShape); - static const size_t kTensorBufferStartIndex = - kTensorBytesStartIndex + sizeof(tensor_bytes_); - static const size_t kMessageTotalBytes = kTensorBufferStartIndex; - static const size_t kRdmaMessageBufferSize = kMessageTotalBytes; - static const size_t kRdmaAckBufferSize = kMessageTotalBytes; - static string CreateMessage(const RdmaMessage& rm); - static void ParseMessage(RdmaMessage& rm, void* buffer); -}; - } // namespace tensorflow #endif // TENSORFLOW_USE_VERBS diff --git a/tensorflow/contrib/verbs/rdma_mgr.cc b/tensorflow/contrib/verbs/rdma_mgr.cc index 9cb307bcfa..f3644af0b4 100644 --- a/tensorflow/contrib/verbs/rdma_mgr.cc +++ b/tensorflow/contrib/verbs/rdma_mgr.cc @@ -16,11 +16,16 @@ limitations under the License. #ifdef TENSORFLOW_USE_VERBS #include "tensorflow/contrib/verbs/rdma_mgr.h" +#include #include #include "tensorflow/contrib/verbs/grpc_verbs_client.h" #include "tensorflow/contrib/verbs/verbs_service.pb.h" +#include "tensorflow/core/common_runtime/bfc_allocator.h" +#include "tensorflow/core/common_runtime/gpu/gpu_util.h" +#include "tensorflow/core/common_runtime/gpu/process_state.h" #include "tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.h" #include "tensorflow/core/distributed_runtime/session_mgr.h" +#include "tensorflow/core/framework/allocator_registry.h" #include "tensorflow/core/lib/core/status.h" namespace tensorflow { @@ -53,7 +58,7 @@ RdmaMgr::RdmaMgr(const WorkerEnv* const worker_env, void RdmaMgr::SetupChannels() { for (const auto& p : channel_table_) { string worker_name = p.first; - LOG(INFO) << "connecting to remote node " << worker_name; + RDMA_LOG(2) << "Connecting to remote node " << worker_name; RdmaChannel* rc = p.second; GetRemoteAddressRequest req; GetRemoteAddressResponse resp; @@ -78,39 +83,49 @@ void RdmaMgr::SetupChannels() { mr->set_rkey(rc->message_buffers_[i]->self_->rkey); } // synchronous call - Status s = client->GetRemoteAddress(&req, &resp); - // save obtained remote addresses - // connect to the remote channel - if (s.ok()) { - CHECK(worker_name.compare(resp.host_name()) == 0); - RdmaAddress ra; - ra.lid = resp.channel().lid(); - ra.qpn = resp.channel().qpn(); - ra.psn = resp.channel().psn(); - ra.snp = resp.channel().snp(); - ra.iid = resp.channel().iid(); - rc->SetRemoteAddress(ra, false); - rc->Connect(); - int i = 0; - int idx[] = {1, 0, 3, 2}; - for (const auto& mr : resp.mr()) { - // the connections are crossed, i.e. - // local tx_message_buffer <---> remote rx_message_buffer_ - // local rx_message_buffer <---> remote tx_message_buffer_ - // local tx_ack_buffer <---> remote rx_ack_buffer_ - // local rx_ack_buffer <---> remote tx_ack_buffer_ - // hence idx[] = {1, 0, 3, 2}. - RdmaBuffer* rb = rc->message_buffers_[idx[i]]; - RemoteMR rmr; - rmr.remote_addr = mr.remote_addr(); - rmr.rkey = mr.rkey(); - rb->SetRemoteMR(rmr, false); - i++; + Status s; + int attempts = 0; + static const int max_num_attempts = 5; + do { + s = client->GetRemoteAddress(&req, &resp); + // save obtained remote addresses + // connect to the remote channel + if (s.ok()) { + CHECK(worker_name.compare(resp.host_name()) == 0); + RdmaAddress ra; + ra.lid = resp.channel().lid(); + ra.qpn = resp.channel().qpn(); + ra.psn = resp.channel().psn(); + ra.snp = resp.channel().snp(); + ra.iid = resp.channel().iid(); + rc->SetRemoteAddress(ra, false); + rc->Connect(); + int i = 0; + int idx[] = {1, 0}; + for (const auto& mr : resp.mr()) { + // the connections are crossed, i.e. + // local tx_message_buffer <---> remote rx_message_buffer_ + // local rx_message_buffer <---> remote tx_message_buffer_ + // hence idx[] = {1, 0}. + RdmaMessageBuffer* rb = rc->message_buffers_[idx[i]]; + RemoteMR rmr; + rmr.remote_addr = mr.remote_addr(); + rmr.rkey = mr.rkey(); + rb->SetRemoteMR(rmr, false); + i++; + } + CHECK(i == RdmaChannel::kNumMessageBuffers); + } else { + LOG(ERROR) << "Connecting to " << worker_name + << ": Got " << s.error_message() << ". Retrying (" + << (attempts + 1) << "/" << max_num_attempts << ")..." ; + if (++attempts == max_num_attempts) { + break; + } + worker_env_->env->SleepForMicroseconds(2000000); } - CHECK(i == RdmaChannel::kNumMessageBuffers); - } else { - LOG(ERROR) << s.error_message(); - } + } while (!s.ok()); + RDMA_LOG(0) << "Connected to remote node " << worker_name; delete client; } } @@ -183,6 +198,138 @@ RdmaChannel* RdmaMgr::FindChannel(const string& name) { return iter->second; } +bool IsGDRAvailable() { +#if defined(__APPLE__) + return false; +#elif defined(PLATFORM_WINDOWS) + return false; +#else + std::ifstream ifs("/proc/modules"); + string line; + while (std::getline(ifs, line)) { + auto sep = line.find(' '); + CHECK_NE(sep, std::string::npos); + if (line.substr(0, sep) == "nv_peer_mem") { + return true; + } + } + return false; +#endif +} + +int TryToReadNumaNode(ibv_device* device) { +#if defined(__APPLE__) + LOG(INFO) << "OS X does not support NUMA - returning NUMA node 0"; + return 0; +#elif defined(PLATFORM_WINDOWS) + // Windows support for NUMA is not currently implemented. Return node 0. + return 0; +#else + VLOG(2) << "Trying to read NUMA node for device: " << device->name; + static const int kUnknownNumaNode = -1; + + auto filename = string(device->ibdev_path) + "/device/numa_node"; + + std::ifstream ifs(filename.c_str()); + string content; + CHECK(std::getline(ifs, content)); + + int32 value; + if (strings::safe_strto32(content, &value)) { + if (value < 0) { + LOG(INFO) << "Successful NUMA node read from SysFS had negative value (" + << value << "), but there must be at least one NUMA node" + ", so returning NUMA node zero"; + return 0; + } + LOG(INFO) << "NUMA node for device: " << device->name << " is " << value; + return value; + } + return kUnknownNumaNode; +#endif +} + +void MRDeleter(ibv_mr* mr) { + if (mr) { + ibv_dereg_mr(mr); + } +} + +// TODO(byronyi): remove this class duplicated from the one in +// common/runtime/gpu/pool_allocator.h when it is available in common_runtime +class BasicCPUAllocator : public SubAllocator { + public: + ~BasicCPUAllocator() override {} + + void* Alloc(size_t alignment, size_t num_bytes) override { + return port::AlignedMalloc(num_bytes, alignment); + } + void Free(void* ptr, size_t) override { port::AlignedFree(ptr); } +}; + +// TODO(byronyi): remove this class and its registration when the default +// cpu_allocator() returns visitable allocator +class BFCRdmaAllocator : public BFCAllocator { + public: + BFCRdmaAllocator() + : BFCAllocator(new BasicCPUAllocator(), 1LL << 36, true, "cpu_rdma_bfc") { + } +}; + +REGISTER_MEM_ALLOCATOR("BFCRdmaAllocator", 101, BFCRdmaAllocator); + +void RdmaMgr::InitAllocators() { + RdmaMemoryMgr::Singleton().pd_ = rdma_adapter_->pd_; + + Allocator* allocators[] = { +#if GOOGLE_CUDA + ProcessState::singleton()->GetCUDAHostAllocator(0), + ProcessState::singleton()->GetCPUAllocator(0), +#endif // GOOGLE_CUDA + cpu_allocator(), + }; + + using namespace std::placeholders; + + std::set instrumented_; + + // Host memory allocators + for (Allocator* allocator : allocators) { + VisitableAllocator::Visitor alloc_visitor = + std::bind(&RdmaMemoryMgr::InsertMemoryRegion, + &RdmaMemoryMgr::Singleton(), _1, _2, allocator->Name()); + VisitableAllocator::Visitor free_visitor = std::bind( + &RdmaMemoryMgr::EvictMemoryRegion, &RdmaMemoryMgr::Singleton(), _1, _2); + + auto* visitable_allocator = dynamic_cast(allocator); + CHECK(visitable_allocator) << "is not visitable for instrumentation" + << allocator->Name(); + // Make sure we don't instrument the same allocator twice + if (instrumented_.find(allocator) == std::end(instrumented_)) { + visitable_allocator->AddAllocVisitor(alloc_visitor); + visitable_allocator->AddFreeVisitor(free_visitor); + instrumented_.insert(allocator); + LOG(INFO) << "Instrumenting CPU allocator " << allocator->Name(); + } + } + +#if GOOGLE_CUDA + if (IsGDRAvailable()) { + // Note we don't free allocated GPU memory so there is no free visitor + int32_t bus_id = TryToReadNumaNode(rdma_adapter_->context_->device) + 1; + + char buf[8]; + sprintf(buf, "gpu"); + VisitableAllocator::Visitor cuda_alloc_visitor = + std::bind(&RdmaMemoryMgr::InsertMemoryRegion, + &RdmaMemoryMgr::Singleton(), _1, _2, std::string(buf)); + + ProcessState::singleton()->AddGPUAllocVisitor(bus_id, cuda_alloc_visitor); + LOG(INFO) << "Instrumenting GPU allocator with bus_id " << bus_id; + } +#endif // GOOGLE_CUDA +} + } // end namespace tensorflow #endif diff --git a/tensorflow/contrib/verbs/rdma_mgr.h b/tensorflow/contrib/verbs/rdma_mgr.h index e711e60478..29227a9544 100644 --- a/tensorflow/contrib/verbs/rdma_mgr.h +++ b/tensorflow/contrib/verbs/rdma_mgr.h @@ -38,6 +38,7 @@ class RdmaMgr { RdmaChannel* FindChannel(const string& key); void SetupChannels(); bool ConnectivityCheck(); + void InitAllocators(); const string& local_worker() { return local_worker_; } private: diff --git a/tensorflow/contrib/verbs/rdma_rendezvous_mgr.cc b/tensorflow/contrib/verbs/rdma_rendezvous_mgr.cc index 74f6681af3..ad3dce1784 100644 --- a/tensorflow/contrib/verbs/rdma_rendezvous_mgr.cc +++ b/tensorflow/contrib/verbs/rdma_rendezvous_mgr.cc @@ -21,10 +21,6 @@ limitations under the License. #include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/common_runtime/dma_helper.h" -#if GOOGLE_CUDA -#include "tensorflow/core/common_runtime/gpu/gpu_util.h" -#include "tensorflow/core/common_runtime/gpu/process_state.h" -#endif // GOOGLE_CUDA #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/strings/numbers.h" #include "tensorflow/core/lib/strings/str_util.h" @@ -36,11 +32,6 @@ class RdmaRemoteRendezvous : public BaseRemoteRendezvous { RdmaRemoteRendezvous(const WorkerEnv* env, int64 step_id, RdmaMgr* rdma_mgr) : BaseRemoteRendezvous(env, step_id), rdma_mgr_(rdma_mgr) {} - void RecvPostCopyOps(const string& key, const string& key_with_step_id, - const Rendezvous::Args& recv_args, - const DoneCallback& done, const RdmaMessage& rm, - RdmaChannel* rc, Tensor& val, const Status& s); - protected: void RecvFromRemoteAsync(const Rendezvous::ParsedKey& parsed, const Rendezvous::Args& args, @@ -74,101 +65,18 @@ void RdmaRemoteRendezvous::RecvFromRemoteAsync( RdmaChannel* rc = rdma_mgr_->FindChannel(src_name); string key(std::move(parsed.FullKey().ToString())); string key_with_step_id = VerbsUtil::AppendStepidToKey(key, step_id_); - // insert callback - rc->InsertRecvCallback(key_with_step_id, [this, key, key_with_step_id, rc, - recv_args, parsed, done]() { - Status src_s, dst_s, s; - Device* src_dev, *dst_dev; - src_s = env_->device_mgr->LookupDevice("CPU:0", &src_dev); - dst_s = env_->device_mgr->LookupDevice(parsed.dst_device, &dst_dev); - if (!src_s.ok() || !dst_s.ok()) { - s = src_s.ok() ? dst_s : src_s; - LOG(ERROR) << "s is not ok, error code " << s.error_message(); - done(s, Args(), recv_args, Tensor(), true); - return; - } - RdmaBuffer* rb = rc->FindBuffer(key); - RdmaMessage rm; - CHECK(rb->size_ >= RdmaMessage::kMessageTotalBytes); - RdmaMessage::ParseMessage(rm, rb->buffer_); - CHECK(rm.type_ == RDMA_MESSAGE_TENSOR_WRITE); - Tensor val; - if (!rm.is_dead_) { - void* input = static_cast(rb->buffer_) + - RdmaMessage::kTensorBufferStartIndex; - bool can_memcpy = DataTypeCanUseMemcpy(rm.data_type_); - if (can_memcpy) { - if (dst_dev->tensorflow_gpu_device_info() && - (!recv_args.alloc_attrs.on_host())) { -#if GOOGLE_CUDA - CHECK(recv_args.device_context) - << "send dev name: " << src_dev->name() - << " gpu_info: " << src_dev->tensorflow_gpu_device_info(); - Allocator* alloc = ProcessState::singleton()->GetCUDAHostAllocator(0); - Tensor copy(alloc, rm.data_type_, rm.tensor_shape_); - memcpy(DMAHelper::base(©), input, rm.tensor_bytes_); - - Allocator* dst_alloc = dst_dev->GetAllocator(recv_args.alloc_attrs); - Tensor gpu_copy(dst_alloc, rm.data_type_, rm.tensor_shape_); - - GPUUtil::CopyCPUTensorToGPU( - ©, recv_args.device_context, dst_dev, &gpu_copy, - [this, gpu_copy, key, key_with_step_id, recv_args, done, rm, rc]( - const Status& s) { - CHECK(s.ok()) << "copy tensor to gpu sync"; - Tensor val; - val = std::move(gpu_copy); - RecvPostCopyOps(key, key_with_step_id, recv_args, done, rm, rc, - val, s); - }); -#endif // GOOGLE_CUDA - return; - } else { - AllocatorAttributes host_alloc_attrs; - host_alloc_attrs.set_gpu_compatible(true); - host_alloc_attrs.set_on_host(true); - Allocator* alloc = dst_dev->GetAllocator(host_alloc_attrs); - Tensor copy(alloc, rm.data_type_, rm.tensor_shape_); - memcpy(DMAHelper::base(©), input, rm.tensor_bytes_); - val = std::move(copy); - } - } else { - TensorProto proto; - CHECK(rm.tensor_bytes_ + RdmaMessage::kTensorBufferStartIndex <= - rb->size_); - CHECK(ParseProtoUnlimited(&proto, input, rm.tensor_bytes_)) - << "fail to parse proto from array"; - s = dst_dev->MakeTensorFromProto(proto, recv_args.alloc_attrs, &val); - } - } - RecvPostCopyOps(key, key_with_step_id, recv_args, done, rm, rc, val, s); - }); - // append key to message queue - RdmaBuffer* rb = rc->tx_message_buffer_; - RdmaMessage rm; - rm.type_ = RDMA_MESSAGE_TENSOR_REQUEST; - rm.name_size_ = key.size(); - rm.name_ = key; - rm.step_id_ = step_id_; - string message = RdmaMessage::CreateMessage(rm); - rb->EnqueueItem(message); - rb->SendNextItem(); -} -void RdmaRemoteRendezvous::RecvPostCopyOps( - const string& key, const string& key_with_step_id, - const Rendezvous::Args& recv_args, const DoneCallback& done, - const RdmaMessage& rm, RdmaChannel* rc, Tensor& val, const Status& s) { - rc->RemoveRecvCallback(key_with_step_id); - RdmaMessage br; - br.type_ = RDMA_MESSAGE_BUFFER_IDLE; - br.name_size_ = key.size(); - br.name_ = key; - string message = RdmaMessage::CreateMessage(br); - RdmaBuffer* tb = rc->tx_message_buffer_; - tb->EnqueueItem(message); - tb->SendNextItem(); - done(s, Args(), recv_args, val, rm.is_dead_); + Device* dst_dev; + s = env_->device_mgr->LookupDevice(parsed.dst_device, &dst_dev); + CHECK(s.ok()) << "s is not ok, error code " << s.error_message(); + if (!s.ok()) { + done(s, Args(), recv_args, Tensor(), true); + return; + } + + RdmaTensorRequest* request = + rc->InsertTensorRequest(key, step_id_, dst_dev, recv_args, done); + request->Start(); } RdmaRendezvousMgr::RdmaRendezvousMgr(const WorkerEnv* env) diff --git a/tensorflow/contrib/verbs/verbs_server_lib.cc b/tensorflow/contrib/verbs/verbs_server_lib.cc index a606ef75a4..47ed83f521 100644 --- a/tensorflow/contrib/verbs/verbs_server_lib.cc +++ b/tensorflow/contrib/verbs/verbs_server_lib.cc @@ -104,6 +104,7 @@ Status VerbsServer::Start() { [this] { verbs_service_->HandleRPCsLoop(); })); rdma_mgr_->SetupChannels(); CHECK(rdma_mgr_->ConnectivityCheck()) << "Connectivity check failed!"; + rdma_mgr_->InitAllocators(); verbs_state_ = CONNECTED; } } diff --git a/tensorflow/contrib/verbs/verbs_service.proto b/tensorflow/contrib/verbs/verbs_service.proto index 0df1fed4b9..abdae1d84f 100644 --- a/tensorflow/contrib/verbs/verbs_service.proto +++ b/tensorflow/contrib/verbs/verbs_service.proto @@ -50,6 +50,12 @@ message GetRemoteAddressResponse { repeated MemoryRegion mr = 3; } +message ErrorStatusProto { + int32 error_code = 1; + string error_message = 2; + string error_details = 3; +} + //////////////////////////////////////////////////////////////////////////////// // // VerbsService diff --git a/tensorflow/contrib/verbs/verbs_with_0_copies.png b/tensorflow/contrib/verbs/verbs_with_0_copies.png new file mode 100644 index 0000000000000000000000000000000000000000..0641e2fd50da3738e3b8113f4324156063bf52a2 GIT binary patch literal 62862 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 \ No newline at end of file diff --git a/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.jpg b/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8bc69b889d68f0a6a8faa64f08eab22637646842 GIT binary patch literal 88799 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 z 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 literal 0 HcmV?d00001 diff --git a/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.xml b/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.xml new file mode 100644 index 0000000000..484e7c78ae --- /dev/null +++ b/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.xml @@ -0,0 +1 @@ +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 \ No newline at end of file -- GitLab From e69ede3f9206d29f9f412d2163629515d102ad85 Mon Sep 17 00:00:00 2001 From: David Norman Date: Sat, 20 Jan 2018 22:46:05 +0000 Subject: [PATCH 030/258] [XLA] Separate out the dynamic slice wrapping tests (#16067) * Separate out the wrapping tests, they are testing for undefined behaviour * Remove unnecessary extra line --- .../compiler/xla/tests/dynamic_ops_test.cc | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tensorflow/compiler/xla/tests/dynamic_ops_test.cc b/tensorflow/compiler/xla/tests/dynamic_ops_test.cc index ae3f887240..877dc7db0e 100644 --- a/tensorflow/compiler/xla/tests/dynamic_ops_test.cc +++ b/tensorflow/compiler/xla/tests/dynamic_ops_test.cc @@ -595,6 +595,11 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousSingleElement) { // Single element, no wrap. std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/1); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousSingleElementBF16) { + // Single element, no wrap. + std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/1); } @@ -602,6 +607,11 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousMultipleElements) { // Multiple element, no wrap. std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/2); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousMultipleElementsBF16) { + // Multiple element, no wrap. + std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/2); } @@ -609,6 +619,11 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousMultipleWrapping) { // Multiple element, wrapping. std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/3, /*size=*/2); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousMultipleWrappingBF16) { + // Multiple element, wrapping. + std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/3, /*size=*/2); } @@ -616,12 +631,21 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousTooLarge) { // Multiple element, update size larger than operand. std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/5, /*size=*/2); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousTooLargeBF16) { + // Multiple element, update size larger than operand. + std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/5, /*size=*/2); } XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousUnaligned) { std::vector operand_shape({3, 123, 247}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/1); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousUnalignedBF16) { + std::vector operand_shape({3, 123, 247}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/1); } @@ -629,6 +653,10 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousUnaligned) { XLA_TEST_F(DynamicUpdateSliceTest, DISABLED_ON_GPU(R3ContiguousLarger)) { std::vector operand_shape({32, 128, 1024}); RunR3Contiguous(operand_shape, /*index=*/7, /*size=*/1); +} + +XLA_TEST_F(DynamicUpdateSliceTest, DISABLED_ON_GPU(R3ContiguousLargerBF16)) { + std::vector operand_shape({32, 128, 1024}); RunR3Contiguous(operand_shape, /*index=*/7, /*size=*/1); } -- GitLab From 71d49e585d13869c478ad6b56aa64a5bc80eeed2 Mon Sep 17 00:00:00 2001 From: namrata-ibm Date: Sun, 21 Jan 2018 04:17:48 +0530 Subject: [PATCH 031/258] =?UTF-8?q?Converting=20the=20real=20and=20imagina?= =?UTF-8?q?ry=20float=20values=20from=20short=5Ftest=5Fsegmen=E2=80=A6=20(?= =?UTF-8?q?#14569)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Converting the real and imaginary float values from short_test_segment_spectrogram.csv.bin on big endian for spectrogram_test * Incorporating review comments --- tensorflow/core/kernels/spectrogram_test_utils.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tensorflow/core/kernels/spectrogram_test_utils.cc b/tensorflow/core/kernels/spectrogram_test_utils.cc index 046f6344df..bc30330d61 100644 --- a/tensorflow/core/kernels/spectrogram_test_utils.cc +++ b/tensorflow/core/kernels/spectrogram_test_utils.cc @@ -70,10 +70,24 @@ bool ReadRawFloatFileToComplexVector( int offset = 0; const int end = data_string.size(); while (offset < end) { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + char arr[4]; + for (int i = 0; i < kBytesPerValue; ++i ) { + arr[3 - i] = *(data_string.data() + offset + i); + } + memcpy(&real_out, arr, kBytesPerValue); + offset += kBytesPerValue; + for (int i = 0; i < kBytesPerValue; ++i ) { + arr[3 - i] = *(data_string.data() + offset + i); + } + memcpy(&imag_out, arr, kBytesPerValue); + offset += kBytesPerValue; +#else memcpy(&real_out, data_string.data() + offset, kBytesPerValue); offset += kBytesPerValue; memcpy(&imag_out, data_string.data() + offset, kBytesPerValue); offset += kBytesPerValue; +#endif if (row_counter >= row_length) { data->push_back(data_row); data_row.clear(); -- GitLab From cf0c0e7d265692a28a0f2d3266ed238d72a6fff8 Mon Sep 17 00:00:00 2001 From: Parth P Panchal Date: Sun, 21 Jan 2018 05:06:14 +0530 Subject: [PATCH 032/258] Accepts `PathLike` objects for `model_dir` (#16200) * Accepts `PathLike` objects for `model_dir` * Retrieves the file system path representation if `PathLike` object is passed to `Estimator` or `RunConfig` for `model_dir`, instead of `str`. * Closes #15784 * Renames `as_path_repr` to `path_to_str` * Adds `path_to_str` to "compat.py"'s top level docstring * Updates golden on addition of a new method * commit 5242790 adds method `path_to_str` in "compat.py" --- tensorflow/python/estimator/estimator.py | 8 +++++--- tensorflow/python/estimator/run_config.py | 6 ++++-- tensorflow/python/util/compat.py | 15 +++++++++++++++ .../tools/api/golden/tensorflow.compat.pbtxt | 4 ++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/estimator/estimator.py b/tensorflow/python/estimator/estimator.py index 90eecc1fda..bd65d565b5 100644 --- a/tensorflow/python/estimator/estimator.py +++ b/tensorflow/python/estimator/estimator.py @@ -128,9 +128,10 @@ class Estimator(object): model_dir: Directory to save model parameters, graph and etc. This can also be used to load checkpoints from the directory into a estimator to - continue training a previously saved model. If `None`, the model_dir in - `config` will be used if set. If both are set, they must be same. If - both are `None`, a temporary directory will be used. + continue training a previously saved model. If `PathLike` object, the + path will be resolved. If `None`, the model_dir in `config` will be used + if set. If both are set, they must be same. If both are `None`, a + temporary directory will be used. config: Configuration object. params: `dict` of hyper parameters that will be passed into `model_fn`. Keys are names of parameters, values are basic python types. @@ -158,6 +159,7 @@ class Estimator(object): self._config = config # Model directory. + model_dir = compat.path_to_str(model_dir) if (model_dir is not None) and (self._config.model_dir is not None): if model_dir != self._config.model_dir: # TODO(alanyee): remove this suppression after it is no longer needed diff --git a/tensorflow/python/estimator/run_config.py b/tensorflow/python/estimator/run_config.py index dc714d4d22..db30329897 100644 --- a/tensorflow/python/estimator/run_config.py +++ b/tensorflow/python/estimator/run_config.py @@ -27,6 +27,7 @@ import six from tensorflow.core.protobuf import config_pb2 from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training import server_lib +from tensorflow.python.util import compat _USE_DEFAULT = object() @@ -399,7 +400,8 @@ class RunConfig(object): Args: model_dir: directory where model parameters, graph, etc are saved. If - `None`, will use a default value set by the Estimator. + `PathLike` object, the path will be resolved. If `None`, will use a + default value set by the Estimator. tf_random_seed: Random seed for TensorFlow initializers. Setting this value allows consistency between reruns. save_summary_steps: Save summaries every this many steps. @@ -442,7 +444,7 @@ class RunConfig(object): if tf_config: logging.info('TF_CONFIG environment variable: %s', tf_config) - model_dir = _get_model_dir(tf_config, model_dir) + model_dir = _get_model_dir(tf_config, compat.path_to_str(model_dir)) RunConfig._replace( self, diff --git a/tensorflow/python/util/compat.py b/tensorflow/python/util/compat.py index 07382d93df..3ab0bd16fa 100644 --- a/tensorflow/python/util/compat.py +++ b/tensorflow/python/util/compat.py @@ -21,6 +21,7 @@ In addition to the functions below, `as_str` converts an object to a `str`. @@as_bytes @@as_text @@as_str_any +@@path_to_str ## Types The compatibility module also provides the following types: @@ -108,6 +109,20 @@ def as_str_any(value): return str(value) +def path_to_str(path): + """Returns the file system path representation of a `PathLike` object, else as it is. + + Args: + path: An object that can be converted to path representation. + + Returns: + A `str` object. + """ + if hasattr(path, "__fspath__"): + path = as_str_any(path.__fspath__()) + return path + + # Numpy 1.8 scalars don't inherit from numbers.Integral in Python 3, so we # need to check them specifically. The same goes from Real and Complex. integral_types = (_numbers.Integral, _np.integer) diff --git a/tensorflow/tools/api/golden/tensorflow.compat.pbtxt b/tensorflow/tools/api/golden/tensorflow.compat.pbtxt index ccc6031400..bab480ff9b 100644 --- a/tensorflow/tools/api/golden/tensorflow.compat.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.compat.pbtxt @@ -32,4 +32,8 @@ tf_module { name: "as_text" argspec: "args=[\'bytes_or_text\', \'encoding\'], varargs=None, keywords=None, defaults=[\'utf-8\'], " } + member_method { + name: "path_to_str" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } } -- GitLab From 9563c0938ef718fa33426ce070b3f26ecda90c76 Mon Sep 17 00:00:00 2001 From: JxKing Date: Sun, 21 Jan 2018 07:39:19 +0800 Subject: [PATCH 033/258] Model Average Optimizer (#15299) * model average optimizer * zip in py2andpy3 * rename a map variable --- tensorflow/contrib/opt/BUILD | 19 ++ tensorflow/contrib/opt/__init__.py | 5 +- .../training/model_average_optimizer.py | 299 ++++++++++++++++++ .../training/model_average_optimizer_test.py | 200 ++++++++++++ 4 files changed, 522 insertions(+), 1 deletion(-) create mode 100644 tensorflow/contrib/opt/python/training/model_average_optimizer.py create mode 100644 tensorflow/contrib/opt/python/training/model_average_optimizer_test.py diff --git a/tensorflow/contrib/opt/BUILD b/tensorflow/contrib/opt/BUILD index 9c961f2b9c..7974621fbc 100644 --- a/tensorflow/contrib/opt/BUILD +++ b/tensorflow/contrib/opt/BUILD @@ -19,6 +19,7 @@ py_library( "python/training/elastic_average_optimizer.py", "python/training/external_optimizer.py", "python/training/lazy_adam_optimizer.py", + "python/training/model_average_optimizer.py", "python/training/moving_average_optimizer.py", "python/training/multitask_optimizer_wrapper.py", "python/training/nadam_optimizer.py", @@ -193,6 +194,24 @@ tf_py_test( ], ) +tf_py_test( + name = "model_average_optimizer_test", + srcs = ["python/training/model_average_optimizer_test.py"], + additional_deps = [ + ":opt_py", + "//tensorflow/python:client", + "//tensorflow/python:client_testlib", + "//tensorflow/python:array_ops", + "//tensorflow/python:variables", + "//tensorflow/python:framework", + "//tensorflow/python:platform", + "//tensorflow/python:training", + "//tensorflow/python:ops", + "//tensorflow/python:framework_for_generated_wrappers", + "//third_party/py/numpy", + ], +) + py_test( name = "sign_decay_test", srcs = ["python/training/sign_decay_test.py"], diff --git a/tensorflow/contrib/opt/__init__.py b/tensorflow/contrib/opt/__init__.py index 90d2f92462..6c1bb1adc0 100644 --- a/tensorflow/contrib/opt/__init__.py +++ b/tensorflow/contrib/opt/__init__.py @@ -29,6 +29,7 @@ from tensorflow.contrib.opt.python.training.nadam_optimizer import * from tensorflow.contrib.opt.python.training.powersign import * from tensorflow.contrib.opt.python.training.variable_clipping_optimizer import * from tensorflow.contrib.opt.python.training.elastic_average_optimizer import * +from tensorflow.contrib.opt.python.training.model_average_optimizer import * # pylint: enable=wildcard-import from tensorflow.python.util.all_util import remove_undocumented @@ -48,7 +49,9 @@ _allowed_symbols = [ 'MultitaskOptimizerWrapper', 'clip_gradients_by_global_norm', 'ElasticAverageOptimizer', - 'ElasticAverageCustomGetter' + 'ElasticAverageCustomGetter', + 'ModelAverageOptimizer', + 'ModelAverageCustomGetter' ] remove_undocumented(__name__, _allowed_symbols) diff --git a/tensorflow/contrib/opt/python/training/model_average_optimizer.py b/tensorflow/contrib/opt/python/training/model_average_optimizer.py new file mode 100644 index 0000000000..47509ecca6 --- /dev/null +++ b/tensorflow/contrib/opt/python/training/model_average_optimizer.py @@ -0,0 +1,299 @@ +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== + +"""Wrapper optimizer for Model Average """ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import constant_op +from tensorflow.python.training import optimizer +from tensorflow.python.training import session_run_hook +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import variable_scope +from tensorflow.python.ops import variables +from tensorflow.python.ops import state_ops +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import data_flow_ops + +GLOBAL_VARIABLE_NAME = 'global_center_variable' + + +class ModelAverageCustomGetter(object): + """Custom_getter class is used to do: + 1. Change trainable variables to local collection and place them at worker + device + 2. Generate global variables + Notice that the class should be used with tf.replica_device_setter, + so that the global center variables and global step variable can be placed + at ps device. Besides, use 'tf.get_variable' instead of 'tf.Variable' to + use this custom getter. + + For example, + ma_custom_getter = ModelAverageCustomGetter(worker_device) + with tf.device( + tf.train.replica_device_setter( + worker_device=worker_device, + ps_device="/job:ps/cpu:0", + cluster=cluster)), + tf.variable_scope('',custom_getter=ma_custom_getter): + hid_w = tf.get_variable( + initializer=tf.truncated_normal( + [IMAGE_PIXELS * IMAGE_PIXELS, FLAGS.hidden_units], + stddev=1.0 / IMAGE_PIXELS), + name="hid_w") + hid_b = tf.get_variable(initializer=tf.zeros([FLAGS.hidden_units]), + name="hid_b") + """ + + def __init__(self, worker_device): + """Create a new `ElasticAverageCustomGetter`. + + Args: + worker_device: String. Name of the `worker` job. + """ + self._worker_device = worker_device + self._local_2_global = {} + + def __call__(self, getter, name, trainable, collections, *args, **kwargs): + if trainable: + with ops.device(self._worker_device): + local_var = getter(name, trainable=True, + collections=[ops.GraphKeys.LOCAL_VARIABLES], + *args, **kwargs) + + global_variable = variable_scope.variable( + name='%s/%s' % (GLOBAL_VARIABLE_NAME, name), + initial_value=local_var.initialized_value(), + trainable=False, + collections=[ops.GraphKeys.GLOBAL_VARIABLES]) + + self._local_2_global[local_var] = global_variable + return local_var + else: + return getter(name, trainable, collections, *args, **kwargs) + + +class ModelAverageOptimizer(optimizer.Optimizer): + """Wrapper optimizer that implements the Model Average algorithm. + This is a sync optimizer. During the training, each worker will update + the local variables and maintains its own local_step, which starts from 0 + and is incremented by 1 after each update of local variables. Whenever the + interval_steps divides the local step, the local variables from all the + workers will be averaged and assigned to global center variables. Then the + local variables will be assigned by global center variables. + """ + + def __init__( + self, + opt, + num_worker, + is_chief, + ma_custom_getter, + interval_steps=100, + use_locking=True, + name="ModelAverageOptimizer"): + """Construct a new model average optimizer. + + Args: + opt: The actual optimizer that will be used to update local variables + num_worker: The number of workers + is_chief: whether chief worker + ma_custom_getter: ModelAverageCustomGetter + interval_steps: An int point value to controls the frequency of the + average of local variables + use_locking: If True use locks for update operations + name: string. Optional name of the returned operation + """ + super(ModelAverageOptimizer, self).__init__(use_locking, name) + self._opt = opt + self._num_worker = num_worker + self._is_chief = is_chief + self._local_2_global = ma_custom_getter._local_2_global + self._interval_steps = interval_steps + self._accumulator_list = [] + self._chief_init_op = None + + self._local_step = variable_scope.get_variable( + initializer=0, + trainable=False, + collections=[ops.GraphKeys.LOCAL_VARIABLES], + name="local_step") + + self._opt._prepare() + + def compute_gradients(self, *args, **kwargs): + """Compute gradients of "loss" for the variables in "var_list". + + This simply wraps the compute_gradients() from the real optimizer. + + Args: + *args: Arguments for compute_gradients(). + **kwargs: Keyword arguments for compute_gradients(). + + Returns: + A list of (gradient, variable) pairs. + """ + return self._opt.compute_gradients(*args, **kwargs) + + def _local_vars_update(self, var_list): + """Get the update ops for the local variables in "var_list". + + Args: + var_list: Optional list or tuple of 'tf.Variable' to update + + Returns: + An update op + """ + if not var_list: + raise ValueError( + 'The list of local_variables should not be empty') + update_ops = [] + global_center_vars = [self._local_2_global[var] for var in var_list] + for lvar, gvar in zip(var_list, global_center_vars): + with ops.device(lvar.device): + update_ops.append(state_ops.assign(lvar, gvar.read_value())) + return control_flow_ops.group(*(update_ops)) + + def apply_gradients(self, grads_and_vars, global_step=None, name=None): + """Apply gradients to variables. + + This contains most of the synchronization implementation and also wraps the + apply_gradients() from the real optimizer. The chief work updates global + variables. + + Args: + grads_and_vars: List of (gradient, variable) pairs as returned by + compute_gradients(). + global_step: Optional Variable to increment by one after the + variables have been updated. + name: Optional name for the returned operation. Default to the + name passed to the Optimizer constructor. + + Returns: + A conditional 'Operation' that update both local and global variables or + just local variables + + Raises: + ValueError: If the grads_and_vars is empty. + ValueError: If global step is not provided, the staleness cannot be + checked. + """ + + # update local variables + if not grads_and_vars: + raise ValueError("Must supply at least one variable") + if global_step is None: + raise ValueError("Global step is required") + + apply_updates = self._opt.apply_gradients(grads_and_vars) + with ops.control_dependencies([apply_updates]): + local_update = state_ops.assign_add( + self._local_step, 1, name='local_step_update').op + + # update global variables. + def _Update_global_variables(): + local_vars = [v for g, v in grads_and_vars if g is not None] + global_vars = [self._local_2_global[v] for v in local_vars] + # sync queue + with ops.colocate_with(global_step): + sync_queue = data_flow_ops.FIFOQueue(-1, [dtypes.bool], shapes=[[]], + shared_name='sync_queue') + train_ops = [] + aggregated_vars = [] + with ops.name_scope(None, self._name + '/global'): + for var, gvar in zip(local_vars, global_vars): + with ops.device(gvar.device): + if isinstance(var._ref(), ops.Tensor): + var_accum = data_flow_ops.ConditionalAccumulator( + var.dtype, + shape=var.get_shape(), + shared_name=gvar.name + "/var_accum") + train_ops.append( + var_accum.apply_grad(var._ref(), local_step=global_step)) + aggregated_vars.append(var_accum.take_grad(self._num_worker)) + else: + raise ValueError("Unknown local variable type!") + self._accumulator_list.append((var_accum, gvar.device)) + # chief worker updates global vars and enqueues tokens to the sync queue + if self._is_chief: + update_ops = [] + with ops.control_dependencies(train_ops): + for avg_var, gvar in zip(aggregated_vars, global_vars): + with ops.device(gvar.device): + update_ops.append(state_ops.assign(gvar, avg_var)) + with ops.device(global_step.device): + update_ops.append(state_ops.assign_add(global_step, 1)) + with ops.control_dependencies(update_ops), ops.device( + global_step.device): + tokens = array_ops.fill([self._num_worker - 1], + constant_op.constant(False)) + sync_op = sync_queue.enqueue_many(tokens) + else: + with ops.control_dependencies(train_ops), ops.device( + global_step.device): + sync_op = sync_queue.dequeue() + + with ops.control_dependencies([sync_op]): + local_update_op = self._local_vars_update(local_vars) + return local_update_op + + with ops.control_dependencies([local_update]): + condition = math_ops.equal(math_ops.mod( + self._local_step, self._interval_steps), 0) + conditional_update = control_flow_ops.cond( + condition, _Update_global_variables, control_flow_ops.no_op) + + chief_init_ops = [] + for accum, dev in self._accumulator_list: + with ops.device(dev): + chief_init_ops.append( + accum.set_global_step( + global_step, name="SetGlobalStep")) + self._chief_init_op = control_flow_ops.group(*(chief_init_ops)) + + return conditional_update + + def get_init_op(self): + """Returns the op to let all the local variables equal to the global + variables before the training begins""" + return self._local_vars_update(variables.trainable_variables()) + + def make_session_run_hook(self): + """Creates a hook to handle ModelAverage ops such as initialization.""" + return _ModelAverageOptimizerHook(self, self._is_chief) + + +class _ModelAverageOptimizerHook(session_run_hook.SessionRunHook): + def __init__(self, ma_optimizer, is_chief): + """Creates hook to handle ModelAverageOptimizer initialization ops. + + Args: + ea_optimizer: `ModelAverageOptimizer` which this hook will initialize. + is_chief: `Bool`, whether is this a chief replica or not. + """ + self._ma_optimizer = ma_optimizer + self._is_chief = is_chief + + def begin(self): + self._local_init_op = variables.local_variables_initializer() + self._global_init_op = None + if self._is_chief: + self._global_init_op = variables.global_variables_initializer() + self._chief_init_op = self._ma_optimizer._chief_init_op + self._variable_init_op = self._ma_optimizer.get_init_op() diff --git a/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py b/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py new file mode 100644 index 0000000000..a73aa772bb --- /dev/null +++ b/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py @@ -0,0 +1,200 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for ModelAverageOptimizer.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import portpicker +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import ops +from tensorflow.python.ops import variables +from tensorflow.python.platform import test +from tensorflow.python.training import gradient_descent +from tensorflow.python.training import server_lib +from tensorflow.python.training import training +from tensorflow.python.training import training_util +from tensorflow.python.ops import variable_scope +from tensorflow.python.training import device_setter +from tensorflow.contrib.opt.python.training.model_average_optimizer import \ + ModelAverageOptimizer, ModelAverageCustomGetter, GLOBAL_VARIABLE_NAME + + +def create_local_cluster(num_workers, num_ps, protocol="grpc"): + """Create local GRPC servers and return them.""" + worker_ports = [portpicker.pick_unused_port() for _ in range(num_workers)] + ps_ports = [portpicker.pick_unused_port() for _ in range(num_ps)] + cluster_dict = { + "worker": ["localhost:%s" % port for port in worker_ports], + "ps": ["localhost:%s" % port for port in ps_ports] + } + cs = server_lib.ClusterSpec(cluster_dict) + + workers = [ + server_lib.Server( + cs, job_name="worker", protocol=protocol, task_index=ix, start=True) + for ix in range(num_workers) + ] + ps_servers = [ + server_lib.Server( + cs, job_name="ps", protocol=protocol, task_index=ix, start=True) + for ix in range(num_ps) + ] + + return cluster_dict, workers, ps_servers + + +# Creates the workers and return their sessions, graphs, train_ops. +# Cheif worker will update at last +def _get_workers(num_workers, steps, workers): + sessions = [] + graphs = [] + train_ops = [] + for worker_id in range(num_workers): + graph = ops.Graph() + is_chief = (worker_id == 0) + with graph.as_default(): + worker_device = "/job:worker/task:%d/cpu:0" % (worker_id) + ma_coustom = ModelAverageCustomGetter( + worker_device=worker_device) + with variable_scope.variable_scope('', + custom_getter=ma_coustom), ops.device( + device_setter.replica_device_setter(worker_device=worker_device, + ps_device="/job:ps/task:0/cpu:0", + ps_tasks=1)): + + global_step = variables.Variable(0, name='global_step', + trainable=False) + var_0 = variable_scope.get_variable(initializer=0.0, name="v0") + var_1 = variable_scope.get_variable(initializer=1.0, name="v1") + + with ops.device("/job:worker/task:" + str(worker_id)): + if worker_id == 0: + grads_0 = constant_op.constant(-1.0) + grads_1 = constant_op.constant(-1.0) + else: + grads_0 = constant_op.constant(-2.0) + grads_1 = constant_op.constant(-2.0) + sgd_opt = gradient_descent.GradientDescentOptimizer(1.0) + opt = ModelAverageOptimizer( + opt=sgd_opt, + num_worker=num_workers, + ma_custom_getter=ma_coustom, + is_chief=is_chief, + interval_steps=steps + ) + train_op = [ + opt.apply_gradients( + [[grads_0, var_0], + [grads_1, var_1]], global_step) + ] + easgd_hook = opt.make_session_run_hook() + # Creates MonitoredSession + sess = training.MonitoredTrainingSession(workers[worker_id].target, + hooks=[easgd_hook]) + + sessions.append(sess) + graphs.append(graph) + train_ops.append(train_op) + return sessions, graphs, train_ops + + +class ModelAverageOptimizerTest(test.TestCase): + def _run(self, train_op, sess): + sess.run(train_op) + + def test1Workers2Period(self): + num_workers = 2 + steps = 2 + num_ps = 1 + cluster, workers, _ = create_local_cluster(num_workers=num_workers, + num_ps=num_ps) + + sessions, graphs, train_ops = _get_workers(num_workers, + steps, + workers) + + var_0 = graphs[0].get_tensor_by_name('v0:0') + var_1 = graphs[0].get_tensor_by_name('v1:0') + global_step = training_util.get_global_step(graphs[0]) + global_var_0 = graphs[0].get_tensor_by_name(GLOBAL_VARIABLE_NAME + "/v0:0") + global_var_1 = graphs[0].get_tensor_by_name(GLOBAL_VARIABLE_NAME + "/v1:0") + + # Verify the initialized value. + self.assertAllEqual(0.0, sessions[0].run(var_0)) + self.assertAllEqual(1.0, sessions[0].run(var_1)) + self.assertAllEqual(0.0, sessions[0].run(global_var_0)) + self.assertAllEqual(1.0, sessions[0].run(global_var_1)) + self.assertAllEqual(0, sessions[0].run(global_step)) + + sessions[0].run(train_ops[0]) + sessions[1].run(train_ops[1]) + + self.assertAllEqual(1.0, sessions[0].run(var_0)) + self.assertAllEqual(2.0, sessions[0].run(var_1)) + self.assertAllEqual(0.0, sessions[0].run(global_var_0)) + self.assertAllEqual(1.0, sessions[0].run(global_var_1)) + self.assertAllEqual(0, sessions[0].run(global_step)) + + # iteration 2, global varibale update + thread_0 = self.checkedThread( + target=self._run, args=(train_ops[0], sessions[0])) + thread_1 = self.checkedThread( + target=self._run, args=(train_ops[1], sessions[1])) + thread_0.start() + thread_1.start() + thread_0.join() + thread_1.join() + + self.assertAllEqual(3.0, sessions[0].run(var_0)) + self.assertAllEqual(4.0, sessions[0].run(var_1)) + self.assertAllEqual(3.0, sessions[0].run(global_var_0)) + self.assertAllEqual(4.0, sessions[0].run(global_var_1)) + self.assertAllEqual(1, sessions[0].run(global_step)) + + # iteration 3 + sessions[0].run(train_ops[0]) + + self.assertAllEqual(4.0, sessions[0].run(var_0)) + self.assertAllEqual(5.0, sessions[0].run(var_1)) + self.assertAllEqual(3.0, sessions[0].run(global_var_0)) + self.assertAllEqual(4.0, sessions[0].run(global_var_1)) + self.assertAllEqual(1, sessions[0].run(global_step)) + + def testPS2TasksWithClusterSpecClass(self): + cluster_spec = server_lib.ClusterSpec({ + "ps": ["ps0:2222", "ps1:2222"], + "worker": ["worker0:2222", "worker1:2222", "worker2:2222"] + }) + worker_device = "/job:worker/task:0" + ma_coustom = ModelAverageCustomGetter( + worker_device=worker_device) + from tensorflow.python.training import device_setter + with ops.device( + device_setter.replica_device_setter(cluster=cluster_spec, + worker_device=worker_device, + ps_device="/job:ps")), \ + variable_scope.variable_scope('', custom_getter=ma_coustom): + v = variable_scope.get_variable(initializer=[1, 2], name="v") + w = variable_scope.get_variable(initializer=[2, 1], name='w') + v_g, w_g = ma_coustom._local_2_global[v], ma_coustom._local_2_global[w] + self.assertDeviceEqual("/job:worker/task:0", v.device) + self.assertDeviceEqual("job:ps/task:0", v_g.device) + self.assertDeviceEqual("/job:worker/task:0", w.device) + self.assertDeviceEqual("job:ps/task:1", w_g.device) + + +if __name__ == '__main__': + test.main() -- GitLab From 81265711afcdec35f82ce19d47fb5cf3b4baf336 Mon Sep 17 00:00:00 2001 From: Ozge Yalcinkaya Date: Sun, 21 Jan 2018 02:39:54 +0300 Subject: [PATCH 034/258] TensorBoard Modifications for Word2Vec Example (#14908) * TensorBoard modifications are added to visualize loss graph and embeddings. * Update word2vec_basic.py * Flag is added for log directory. --- .../tutorials/word2vec/word2vec_basic.py | 104 ++++++++++++++---- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/tensorflow/examples/tutorials/word2vec/word2vec_basic.py b/tensorflow/examples/tutorials/word2vec/word2vec_basic.py index 87cd95165e..7d1650f05e 100644 --- a/tensorflow/examples/tutorials/word2vec/word2vec_basic.py +++ b/tensorflow/examples/tutorials/word2vec/word2vec_basic.py @@ -21,6 +21,8 @@ from __future__ import print_function import collections import math import os +import sys +import argparse import random from tempfile import gettempdir import zipfile @@ -30,6 +32,24 @@ from six.moves import urllib from six.moves import xrange # pylint: disable=redefined-builtin import tensorflow as tf +from tensorflow.contrib.tensorboard.plugins import projector + +# Give a folder path as an argument with '--log_dir' to save +# TensorBoard summaries. Default is a log folder in current directory. +current_path = os.path.dirname(os.path.realpath(sys.argv[0])) + +parser = argparse.ArgumentParser() +parser.add_argument( + '--log_dir', + type=str, + default=os.path.join(current_path, 'log'), + help='The log directory for TensorBoard summaries.') +FLAGS, unparsed = parser.parse_known_args() + +# Create the directory for TensorBoard variables if there is not. +if not os.path.exists(FLAGS.log_dir): + os.makedirs(FLAGS.log_dir) + # Step 1: Download the data. url = 'http://mattmahoney.net/dc/' @@ -156,38 +176,47 @@ graph = tf.Graph() with graph.as_default(): # Input data. - train_inputs = tf.placeholder(tf.int32, shape=[batch_size]) - train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1]) - valid_dataset = tf.constant(valid_examples, dtype=tf.int32) + with tf.name_scope('inputs'): + train_inputs = tf.placeholder(tf.int32, shape=[batch_size]) + train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1]) + valid_dataset = tf.constant(valid_examples, dtype=tf.int32) # Ops and variables pinned to the CPU because of missing GPU implementation with tf.device('/cpu:0'): # Look up embeddings for inputs. - embeddings = tf.Variable( - tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0)) - embed = tf.nn.embedding_lookup(embeddings, train_inputs) + with tf.name_scope('embeddings'): + embeddings = tf.Variable( + tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0)) + embed = tf.nn.embedding_lookup(embeddings, train_inputs) # Construct the variables for the NCE loss - nce_weights = tf.Variable( - tf.truncated_normal([vocabulary_size, embedding_size], - stddev=1.0 / math.sqrt(embedding_size))) - nce_biases = tf.Variable(tf.zeros([vocabulary_size])) + with tf.name_scope('weights'): + nce_weights = tf.Variable( + tf.truncated_normal([vocabulary_size, embedding_size], + stddev=1.0 / math.sqrt(embedding_size))) + with tf.name_scope('biases'): + nce_biases = tf.Variable(tf.zeros([vocabulary_size])) # Compute the average NCE loss for the batch. # tf.nce_loss automatically draws a new sample of the negative labels each # time we evaluate the loss. # Explanation of the meaning of NCE loss: # http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/ - loss = tf.reduce_mean( - tf.nn.nce_loss(weights=nce_weights, - biases=nce_biases, - labels=train_labels, - inputs=embed, - num_sampled=num_sampled, - num_classes=vocabulary_size)) + with tf.name_scope('loss'): + loss = tf.reduce_mean( + tf.nn.nce_loss(weights=nce_weights, + biases=nce_biases, + labels=train_labels, + inputs=embed, + num_sampled=num_sampled, + num_classes=vocabulary_size)) + + # Add the loss value as a scalar to summary. + tf.summary.scalar('loss', loss) # Construct the SGD optimizer using a learning rate of 1.0. - optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss) + with tf.name_scope('optimizer'): + optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss) # Compute the cosine similarity between minibatch examples and all embeddings. norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True)) @@ -197,13 +226,22 @@ with graph.as_default(): similarity = tf.matmul( valid_embeddings, normalized_embeddings, transpose_b=True) + # Merge all summaries. + merged = tf.summary.merge_all() + # Add variable initializer. init = tf.global_variables_initializer() + # Create a saver. + saver = tf.train.Saver() + # Step 5: Begin training. num_steps = 100001 with tf.Session(graph=graph) as session: + # Open a writer to write summaries. + writer = tf.summary.FileWriter(FLAGS.log_dir, session.graph) + # We must initialize all variables before we use them. init.run() print('Initialized') @@ -214,10 +252,21 @@ with tf.Session(graph=graph) as session: batch_size, num_skips, skip_window) feed_dict = {train_inputs: batch_inputs, train_labels: batch_labels} + # Define metadata variable. + run_metadata = tf.RunMetadata() + # We perform one update step by evaluating the optimizer op (including it # in the list of returned values for session.run() - _, loss_val = session.run([optimizer, loss], feed_dict=feed_dict) + # Also, evaluate the merged op to get all summaries from the returned "summary" variable. + # Feed metadata variable to session for visualizing the graph in TensorBoard. + _, summary, loss_val = session.run([optimizer, merged, loss], feed_dict=feed_dict, run_metadata=run_metadata) average_loss += loss_val + + # Add returned summaries to writer in each step. + writer.add_summary(summary, step) + # Add metadata to visualize the graph for the last run. + if step == (num_steps - 1): + writer.add_run_metadata(run_metadata, 'step%d' % step) if step % 2000 == 0: if step > 0: @@ -240,6 +289,23 @@ with tf.Session(graph=graph) as session: print(log_str) final_embeddings = normalized_embeddings.eval() + # Write corresponding labels for the embeddings. + with open(FLAGS.log_dir + '/metadata.tsv', 'w') as f: + for i in xrange(vocabulary_size): + f.write(reverse_dictionary[i] + '\n') + + # Save the model for checkpoints. + saver.save(session, os.path.join(FLAGS.log_dir, "model.ckpt")) + + # Create a configuration for visualizing embeddings with the labels in TensorBoard. + config = projector.ProjectorConfig() + embedding_conf = config.embeddings.add() + embedding_conf.tensor_name = embeddings.name + embedding_conf.metadata_path = os.path.join(FLAGS.log_dir, 'metadata.tsv') + projector.visualize_embeddings(writer, config) + +writer.close() + # Step 6: Visualize the embeddings. -- GitLab From 9fb9ac66ce5236ff045630cad6793f0531bf9d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yan=20Facai=20=28=E9=A2=9C=E5=8F=91=E6=89=8D=29?= Date: Sun, 21 Jan 2018 07:43:08 +0800 Subject: [PATCH 035/258] Fix bug: leaky relu supports float64 (#15399) * TST: add test case * BUG: fix unmatched dtype * DOC: add document * ENH: support integer * TST: add test case for int * DOC: modify document for int * TST: lose precision for float16 * CLN: clean code --- tensorflow/python/ops/nn_ops.py | 7 +++++-- tensorflow/python/ops/nn_test.py | 12 +++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 865e459e90..bd8d02fec1 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -1546,7 +1546,8 @@ def leaky_relu(features, alpha=0.2, name=None): http://web.stanford.edu/~awni/papers/relu_hybrid_icml2013_final.pdf Args: - features: A `Tensor` representing preactivation values. + features: A `Tensor` representing preactivation values. Must be one of + the following types: `float16`, `float32`, `float64`, `int32`, `int64`. alpha: Slope of the activation function at x < 0. name: A name for the operation (optional). @@ -1555,7 +1556,9 @@ def leaky_relu(features, alpha=0.2, name=None): """ with ops.name_scope(name, "LeakyRelu", [features, alpha]): features = ops.convert_to_tensor(features, name="features") - alpha = ops.convert_to_tensor(alpha, name="alpha") + if features.dtype.is_integer: + features = math_ops.to_float(features) + alpha = ops.convert_to_tensor(alpha, dtype=features.dtype, name="alpha") return math_ops.maximum(alpha * features, features) diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py index 66bc0803b7..6767564024 100644 --- a/tensorflow/python/ops/nn_test.py +++ b/tensorflow/python/ops/nn_test.py @@ -878,11 +878,13 @@ class LeakyReluTest(test_lib.TestCase): self.assertAllClose(inputs, outputs) def testValues(self): - np_values = np.array([-1.0, 0.0, 0.5, 1.0, 2.0], dtype=np.float32) - outputs = nn_ops.leaky_relu(constant_op.constant(np_values)) - with self.test_session() as sess: - outputs = sess.run(outputs) - self.assertAllClose(outputs, [-0.2, 0.0, 0.5, 1.0, 2.0]) + for dtype in [np.int32, np.int64, np.float16, np.float32, np.float64]: + np_values = np.array([-2, -1, 0, 1, 2], dtype=dtype) + outputs = nn_ops.leaky_relu(constant_op.constant(np_values)) + with self.test_session() as sess: + outputs = sess.run(outputs) + tol = 2e-3 if dtype == np.float16 else 1e-6 + self.assertAllClose(outputs, [-0.4, -0.2, 0.0, 1.0, 2.0], rtol=tol, atol=tol) class SwishTest(test_lib.TestCase): -- GitLab From e00ba24c4038e7644da417ddc639169b6ea59122 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Sat, 20 Jan 2018 18:13:15 -0800 Subject: [PATCH 036/258] [XLA:GPU] Warn on more broken CUDA versions. We've received additional data on which CUDA versions contain a ptx assembler bug that affects XLA. Warn if you're using any of these. PiperOrigin-RevId: 182675055 --- .../compiler/xla/service/gpu/gpu_compiler.cc | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc b/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc index 89acac2c3f..8ba6f48dcf 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc @@ -281,14 +281,16 @@ void WarnIfBadPtxasVersion(const string& ptxas_path) { return; } - // ptxas 9.0 before 9.0.276 miscompiles some address calculations with large - // offsets (e.g. "load ptr + large_constant"), b/70245379. - if (vmaj == 9 && vmin == 0 && vdot < 276) { + // ptxas 9.0 before 9.0.276 and ptxas 9.1 before 9.1.121 miscompile some + // address calculations with large offsets (e.g. "load ptr + large_constant"), + // b/70245379. + if ((vmaj == 9 && vmin == 0 && vdot < 276) || + (vmaj == 9 && vmin == 1 && vdot < 121)) { LOG(WARNING) << "*** WARNING *** You are using ptxas " << vmaj << "." << vmin << "." << vdot - << ", which is in range [9.0.0, 9.0.276). These versions are " - "known to miscompile XLA code, leading to incorrect " - "results or invalid-address errors."; + << ", which is in range [9.0.0, 9.0.276) + [9.1.0, 9.1.121). " + "These versions are known to miscompile XLA code, leading " + "to incorrect results or invalid-address errors."; } } @@ -309,16 +311,24 @@ void WarnIfBadDriverJITVersion() { } se::cuda::DriverVersion version = version_or_status.ValueOrDie(); - // The driver JIT in 384 before 384.108 miscompiles some address + // The following versions of the driver JIT miscompile some address // calculations with large offsets (e.g. "load ptr + large_constant"), - // b/70245379. - if (std::get<0>(version) == 384 && std::get<1>(version) < 108) { + // b/70245379: + // + // - 384.x before 384.108 + // - 387.x before 387.40 + // - 390.x before 390.10. + auto vmaj = std::get<0>(version); + auto vmin = std::get<1>(version); + if ((vmaj == 384 && vmin < 108) || // + (vmaj == 387 && vmin < 40) || // + (vmaj == 390 && vmin < 10)) { LOG(WARNING) << "*** WARNING *** Invoking the PTX->SASS JIT from driver version " << se::cuda::DriverVersionToString(version) - << ", which is in range [384.0.0, 384.108.0). These versions are " - "known to miscompile XLA code, leading to incorrect results or " - "invalid-address errors."; + << ", which is in range [384.0.0, 384.108.0) + [387.0.0, 387.40.0) + " + "[390.0.0, 390.10.0). These versions are known to miscompile XLA " + "code, leading to incorrect results or invalid-address errors."; } }); } -- GitLab From 79a16a847caf845055239a43e3163f3f825afdab Mon Sep 17 00:00:00 2001 From: Anna R Date: Sat, 20 Jan 2018 20:34:12 -0800 Subject: [PATCH 037/258] Improve error message in create_python_api.py. The new message would print exact filenames that need to be added to the tensorflow/tools/api/generator/BUILD file. PiperOrigin-RevId: 182679235 --- tensorflow/tools/api/generator/create_python_api.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tensorflow/tools/api/generator/create_python_api.py b/tensorflow/tools/api/generator/create_python_api.py index aab856b723..2c9a2fa731 100644 --- a/tensorflow/tools/api/generator/create_python_api.py +++ b/tensorflow/tools/api/generator/create_python_api.py @@ -157,15 +157,20 @@ def create_api_files(output_files): for module, exports in module_imports.items(): # Make sure genrule output file list is in sync with API exports. if module not in module_name_to_file_path: - missing_output_files.append(module) + module_without_tf = module[len('tf.'):] + module_file_path = '"api/%s/__init__.py"' % ( + module_without_tf.replace('.', '/')) + missing_output_files.append(module_file_path) continue with open(module_name_to_file_path[module], 'w') as fp: fp.write(_GENERATED_FILE_HEADER + '\n'.join(exports)) if missing_output_files: raise ValueError( - 'Missing outputs for python_api_gen genrule:\n%s' % - ',\n'.join(missing_output_files)) + 'Missing outputs for python_api_gen genrule:\n%s.' + 'Make sure all required outputs are in the ' + 'tensorflow/tools/api/generator/BUILD file.' % + ',\n'.join(sorted(missing_output_files))) def main(output_files): -- GitLab From c2f75aea52b0dd5c3623d96cb2334f5d7e90e69c Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sun, 21 Jan 2018 08:03:46 -0800 Subject: [PATCH 038/258] [TF:XLA] Bump open source llvm revision to r323005 PiperOrigin-RevId: 182703514 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index b27b1f21fb..a1af85aa4e 100644 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -473,11 +473,11 @@ def tf_workspace(path_prefix="", tf_repo_name=""): tf_http_archive( name = "llvm", urls = [ - "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/bfe367d1e2a3c75b8694967a83c7f05885e8f184.tar.gz", - "https://github.com/llvm-mirror/llvm/archive/bfe367d1e2a3c75b8694967a83c7f05885e8f184.tar.gz", + "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/4c73606e33bba4c18a77c28e5a853adfea421951.tar.gz", + "https://github.com/llvm-mirror/llvm/archive/4c73606e33bba4c18a77c28e5a853adfea421951.tar.gz", ], - sha256 = "916c82948687f6be82dbb7764f707abc319e6e4ebaef868f745bd5f44b0f281c", - strip_prefix = "llvm-bfe367d1e2a3c75b8694967a83c7f05885e8f184", + sha256 = "4e179ad9a7de252602b58e109ff00aad9662e1e83334791b56dafdb580a1e850", + strip_prefix = "llvm-4c73606e33bba4c18a77c28e5a853adfea421951", build_file = str(Label("//third_party/llvm:llvm.BUILD")), ) -- GitLab From f31c1acda127e361b797b6f61b6ed3d30d7ea2af Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sun, 21 Jan 2018 09:22:43 -0800 Subject: [PATCH 039/258] Fix a bug in the associative & commutative rewrite in constant folding: I finally tracked it down to the case where we do the transformation: // // + + = parent // / \ / \ // C + -- > X + = children // / \ / \ // X Y C Y = leaves when there exists a control dependency from the child '+' to C. This control dependency creates a cycle in the graph when X and C are simply swapped. We can fix it by moving the control dependency and anchoring it on Y instead (We still need it in case we are inside a frame). PiperOrigin-RevId: 182705910 --- .../grappler/optimizers/constant_folding.cc | 87 +++++++++++++++---- .../optimizers/constant_folding_test.cc | 47 ++++++---- 2 files changed, 100 insertions(+), 34 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/constant_folding.cc b/tensorflow/core/grappler/optimizers/constant_folding.cc index 6860447fb8..0aeff6222c 100644 --- a/tensorflow/core/grappler/optimizers/constant_folding.cc +++ b/tensorflow/core/grappler/optimizers/constant_folding.cc @@ -128,6 +128,42 @@ bool AllValuesAre(const TensorProto& tensor, const T& value) { return false; } +// Add new_input as a control input to node if it does not already depend on it. +// TODO(rmlarsen): Move the following two utility functions to utils.{h,cc} and +// clean up code that should be using them. +bool MaybeAddControlInput(const string& new_input, NodeDef* node, + GraphDef* graph, NodeMap* node_map) { + bool already_exists = false; + for (const string& input : node->input()) { + if (input == new_input || AsControlDependency(input) == new_input) { + already_exists = true; + break; + } + } + if (!already_exists) { + const string ctrl_dep = + ConstantFolding::AddControlDependency(new_input, graph, node_map); + node->add_input(ctrl_dep); + node_map->AddOutput(NodeName(new_input), node->name()); + } + return !already_exists; +} + +// Remove old_input as a control input to node. +bool MaybeRemoveControlInput(const string& old_input, NodeDef* node, + GraphDef* graph, NodeMap* node_map) { + for (int i = 0; i < node->input_size(); ++i) { + const string& input = node->input(i); + if (IsControlInput(input) && AsControlDependency(old_input) == input) { + node->mutable_input()->SwapElements(i, node->input_size() - 1); + node->mutable_input()->RemoveLast(); + node_map->RemoveOutput(NodeName(old_input), node->name()); + return true; + } + } + return false; +} + } // namespace ConstantFolding::ConstantFolding(RewriterConfig::Toggle opt_level, @@ -1524,14 +1560,15 @@ Status ConstantFolding::SimplifyGraph(GraphDef* output, // // + + = parent // / \ / \ - // Const + -- > X + = children + // C + -- > X + = children // / \ / \ - // X Y Const Y = leaves + // X Y C Y = leaves // - // where '+' denotes an associative and commutative operator like addition - // or multiplication. This optimization pushes constants down in the tree - // to canonicalize it. Moreoever, in cases where the child node has a - // constant input we will create a node that can be folded, e.g. + // where C is constant and X is non-constant, and '+' denotes an + // associative and commutative operator like addition or multiplication. + // This optimization pushes constants down in the tree to canonicalize it. + // Moreoever, in cases where the child node has a second constant input Y + // we will create a leaf node that can be folded, e.g. // // Add(C1, Add(C2, X)) -> Add(X, Add(C1, C2)) -> Add(X, C1 + C2) // @@ -1540,7 +1577,8 @@ Status ConstantFolding::SimplifyGraph(GraphDef* output, // division/multiplication. // Don't touch BiasAdd since they can't handle vectors as their first // inputs. - if ((IsAdd(*node) || is_mul) && NumNonControlInputs(*node) == 2) { + if (has_fetch_ && (IsAdd(*node) || is_mul) && + NumNonControlInputs(*node) == 2) { NodeDef* left_child = node_map_->GetNode(node->input(0)); NodeDef* right_child = node_map_->GetNode(node->input(1)); // One child must be constant, and the other the same op as the parent. @@ -1556,18 +1594,21 @@ Status ConstantFolding::SimplifyGraph(GraphDef* output, node->device() != right_child->device()) { continue; } - NodeDef* child_node = left_child_is_constant ? right_child : left_child; + NodeDef* op_child_node = + left_child_is_constant ? right_child : left_child; + NodeDef* const_child_node = + left_child_is_constant ? left_child : right_child; // Make sure that it is safe to change the value of the child node-> - if (child_node->input_size() < 2 || - NumNonControlOutputs(*child_node, *node_map_) > 1 || !has_fetch_ || - nodes_to_preserve_.find(child_node->name()) != + if (op_child_node->input_size() < 2 || + NumNonControlOutputs(*op_child_node, *node_map_) > 1 || + nodes_to_preserve_.find(op_child_node->name()) != nodes_to_preserve_.end()) { continue; } // Identify the nodes to swap. - const NodeDef* left_leaf = node_map_->GetNode(child_node->input(0)); - const NodeDef* right_leaf = node_map_->GetNode(child_node->input(1)); + NodeDef* left_leaf = node_map_->GetNode(op_child_node->input(0)); + NodeDef* right_leaf = node_map_->GetNode(op_child_node->input(1)); const bool left_leaf_is_constant = IsReallyConstant(*left_leaf); const bool right_leaf_is_constant = IsReallyConstant(*right_leaf); if (left_leaf_is_constant && right_leaf_is_constant) { @@ -1576,15 +1617,27 @@ Status ConstantFolding::SimplifyGraph(GraphDef* output, } const int non_const_leaf_input = left_leaf_is_constant ? 1 : 0; const int parent_const_input = left_child_is_constant ? 0 : 1; + const auto& child_output = node_map_->GetOutputs(op_child_node->name()); + if (child_output.find(const_child_node) != child_output.end()) { + // If there is a control edge from the child op to C, the transformation + // would create a cycle in the graph. We know that it must be a control + // edge. We can replace such a control edge with a control edge from A + // to C. + CHECK(MaybeRemoveControlInput(op_child_node->name(), const_child_node, + graph_, node_map_.get())); + NodeDef* other_leaf = left_leaf_is_constant ? left_leaf : right_leaf; + MaybeAddControlInput(other_leaf->name(), const_child_node, graph_, + node_map_.get()); + } // Swap the constant child with a non-constant leaf node. node_map_->UpdateInput(node->name(), node->input(parent_const_input), - child_node->input(non_const_leaf_input)); - node_map_->UpdateInput(child_node->name(), - child_node->input(non_const_leaf_input), + op_child_node->input(non_const_leaf_input)); + node_map_->UpdateInput(op_child_node->name(), + op_child_node->input(non_const_leaf_input), node->input(parent_const_input)); std::swap(*node->mutable_input(parent_const_input), - *child_node->mutable_input(non_const_leaf_input)); + *op_child_node->mutable_input(non_const_leaf_input)); graph_modified_ = true; } } diff --git a/tensorflow/core/grappler/optimizers/constant_folding_test.cc b/tensorflow/core/grappler/optimizers/constant_folding_test.cc index 2db3dc6993..849a88770a 100644 --- a/tensorflow/core/grappler/optimizers/constant_folding_test.cc +++ b/tensorflow/core/grappler/optimizers/constant_folding_test.cc @@ -80,18 +80,25 @@ TEST_F(ConstantFoldingTest, SimpleFolding) { TEST_F(ConstantFoldingTest, AddTree) { tensorflow::Scope s = tensorflow::Scope::NewRootScope(); - Output c1 = ops::Const(s.WithOpName("c1"), 2.0f, {1}); Output c2 = ops::Const(s.WithOpName("c2"), 2.0f, {2}); - Output c4 = ops::Const(s.WithOpName("c4"), 4.0f, {2}); + Output c3 = ops::Const(s.WithOpName("c3"), 3.0f, {2}); Output x = ops::Placeholder(s.WithOpName("x"), DT_FLOAT, ops::Placeholder::Shape(TensorShape({2, 2}))); Output add_child = ops::Add(s.WithOpName("add_child"), c2, x); + Output c1 = ops::Const(s.WithOpName("c1").WithControlDependencies(add_child), + 1.0f, {1}); Output add_parent = ops::Add(s.WithOpName("add_parent"), c1, add_child); - Output mul_child = ops::Mul(s.WithOpName("mul_child"), c2, x); - Output mul_parent = ops::Mul(s.WithOpName("mul_parent"), c1, mul_child); - Output addmul_child = ops::Add(s.WithOpName("addmul_child"), c2, x); + + Output y = ops::Placeholder(s.WithOpName("y"), DT_FLOAT, + ops::Placeholder::Shape(TensorShape({2, 2}))); + Output c4 = ops::Const(s.WithOpName("c4"), 4.0f, {2}); + Output c5 = ops::Const(s.WithOpName("c5"), 5.0f, {2}); + Output c20 = ops::Const(s.WithOpName("c20"), 20.0f, {2}); + Output mul_child = ops::Mul(s.WithOpName("mul_child"), c4, y); + Output mul_parent = ops::Mul(s.WithOpName("mul_parent"), c5, mul_child); + Output addmul_child = ops::Add(s.WithOpName("addmul_child"), c4, x); Output addmul_parent = - ops::Mul(s.WithOpName("addmul_parent"), c1, addmul_child); + ops::Mul(s.WithOpName("addmul_parent"), c5, addmul_child); GrapplerItem item; item.fetch = {"add_parent", "mul_parent", "addmul_parent"}; @@ -102,15 +109,21 @@ TEST_F(ConstantFoldingTest, AddTree) { Status status = fold.Optimize(nullptr, item, &output); TF_EXPECT_OK(status); - EXPECT_EQ(9, output.node_size()); - - // We expect the following rewrite(s) to occur (for both Add and Mul): + // We expect the following rewrite(s) to occur: + // // + + + // / \ / \ / \ - // 2.0 + --> x + --> x 4.0 - // / \ / \ - // 2.0 x 2.0 2.0 + // 1.0 + --> x + --> x 3.0 + // / \ / \ + // 2.0 x 1.0 2.0 + // + // * * * + // / \ / \ / \ + // 4.0 * --> y * --> y 20.0 + // / \ / \ + // 5.0 y 4.0 5.0 + EXPECT_EQ(11, output.node_size()); for (const auto& node : output.node()) { if (node.name() == "add_child") { EXPECT_EQ("Const", node.op()); @@ -130,26 +143,26 @@ TEST_F(ConstantFoldingTest, AddTree) { } else if (node.name() == "mul_parent") { EXPECT_EQ("Mul", node.op()); EXPECT_EQ(2, node.input_size()); - EXPECT_EQ("x", node.input(0)); + EXPECT_EQ("y", node.input(0)); EXPECT_EQ("mul_child", node.input(1)); } else if (node.name() == "addmul_child") { // Unchanged. EXPECT_EQ("Add", node.op()); EXPECT_EQ(2, node.input_size()); - EXPECT_EQ("c2", node.input(0)); + EXPECT_EQ("c4", node.input(0)); EXPECT_EQ("x", node.input(1)); } } - // Check that the reciprocals have the expected value. - std::vector fetch = {"c4"}; + // Check that the result nodes have the expected value. + std::vector fetch = {"c3", "c20"}; auto tensor_expected = EvaluateNodes(item.graph, fetch); EXPECT_EQ(fetch.size(), tensor_expected.size()); fetch = {"add_child", "mul_child"}; auto tensors = EvaluateNodes(output, fetch); EXPECT_EQ(fetch.size(), tensors.size()); for (int i = 0; i < fetch.size(); i++) { - test::ExpectTensorEqual(tensor_expected[0], tensors[i]); + test::ExpectTensorEqual(tensor_expected[i], tensors[i]); } } -- GitLab From 056d69f262a64d219998e245427c7e8524233a5e Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Mon, 22 Jan 2018 08:54:25 +0900 Subject: [PATCH 040/258] fix typo (#16243) --- tensorflow/contrib/eager/python/g3doc/guide.md | 2 +- tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/eager/python/g3doc/guide.md b/tensorflow/contrib/eager/python/g3doc/guide.md index 0095ffa0db..7eea93ce1f 100644 --- a/tensorflow/contrib/eager/python/g3doc/guide.md +++ b/tensorflow/contrib/eager/python/g3doc/guide.md @@ -292,7 +292,7 @@ def loss(weight, bias): error = prediction(training_inputs, weight, bias) - training_outputs return tf.reduce_mean(tf.square(error)) -# Function that returns the the derivative of loss with respect to +# Function that returns the derivative of loss with respect to # weight and bias grad = tfe.gradients_function(loss) diff --git a/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h b/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h index 3cda4bcccc..7019c29959 100644 --- a/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h +++ b/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h @@ -370,7 +370,7 @@ enum { * Looks up items from a given tensor. * * Each item in the output is a raw copy of the corresponding item in - * the input “values”. If the the given “lookup” indices are out of bounds, + * the input “values”. If the given “lookup” indices are out of bounds, * the op will fail and an error will be reported. * * Inputs: -- GitLab From 57b32eabca4597241120cb4aba8308a431853c30 Mon Sep 17 00:00:00 2001 From: Ashwini Shukla Date: Mon, 22 Jan 2018 00:22:30 +0000 Subject: [PATCH 041/258] Weight normalization for RNN Cells. (#11573) * Weight normalization for RNN Cells. The class `WeightNormLSTMCell` is added in contrib/rnn. This implements most of the functionality provided by `LSTMCell` with one additional constructor argument `norm`. If set to `True`, this will normalize the state transition and projection (if used via the `num_proj` argument) matrices. If set to `False`, the outputs are identical to that of `LSTMCell`. Tests are added for checking this equivalence and correctness of the normalization operation. * fixed pylint formatting errors --- .../rnn/python/kernel_tests/rnn_cell_test.py | 95 +++++++ tensorflow/contrib/rnn/python/ops/rnn_cell.py | 255 ++++++++++++++++++ 2 files changed, 350 insertions(+) diff --git a/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py b/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py index 73789206f3..70aaba1728 100644 --- a/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py +++ b/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py @@ -1549,5 +1549,100 @@ class BenchmarkLSTMCellXLA(test.Benchmark): benchmark_results["wall_time"]]])) +class WeightNormLSTMCellTest(test.TestCase): + """Compared cell output with pre-calculated values.""" + + def _cell_output(self, cell): + """Calculate cell output""" + + with self.test_session() as sess: + init = init_ops.constant_initializer(0.5) + with variable_scope.variable_scope("root", + initializer=init): + x = array_ops.zeros([1, 2]) + c0 = array_ops.zeros([1, 2]) + h0 = array_ops.zeros([1, 2]) + + state0 = rnn_cell.LSTMStateTuple(c0, h0) + + xout, sout = cell()(x, state0) + + sess.run([variables.global_variables_initializer()]) + res = sess.run([xout, sout], { + x.name: np.array([[1., 1.]]), + c0.name: 0.1 * np.asarray([[0, 1]]), + h0.name: 0.1 * np.asarray([[2, 3]]), + }) + + actual_state_c = res[1].c + actual_state_h = res[1].h + + return actual_state_c, actual_state_h + + def testBasicCell(self): + """Tests cell w/o peepholes and w/o normalisation""" + + def cell(): + return contrib_rnn_cell.WeightNormLSTMCell(2, + norm=False, + use_peepholes=False) + + actual_c, actual_h = self._cell_output(cell) + + expected_c = np.array([[0.65937078, 0.74983585]]) + expected_h = np.array([[0.44923624, 0.49362513]]) + + self.assertAllClose(expected_c, actual_c, 1e-5) + self.assertAllClose(expected_h, actual_h, 1e-5) + + def testNonbasicCell(self): + """Tests cell with peepholes and w/o normalisation""" + + def cell(): + return contrib_rnn_cell.WeightNormLSTMCell(2, + norm=False, + use_peepholes=True) + + actual_c, actual_h = self._cell_output(cell) + + expected_c = np.array([[0.65937084, 0.7574988]]) + expected_h = np.array([[0.4792085, 0.53470564]]) + + self.assertAllClose(expected_c, actual_c, 1e-5) + self.assertAllClose(expected_h, actual_h, 1e-5) + + + def testBasicCellWithNorm(self): + """Tests cell w/o peepholes and with normalisation""" + + def cell(): + return contrib_rnn_cell.WeightNormLSTMCell(2, + norm=True, + use_peepholes=False) + + actual_c, actual_h = self._cell_output(cell) + + expected_c = np.array([[0.50125383, 0.58805949]]) + expected_h = np.array([[0.32770363, 0.37397948]]) + + self.assertAllClose(expected_c, actual_c, 1e-5) + self.assertAllClose(expected_h, actual_h, 1e-5) + + def testNonBasicCellWithNorm(self): + """Tests cell with peepholes and with normalisation""" + + def cell(): + return contrib_rnn_cell.WeightNormLSTMCell(2, + norm=True, + use_peepholes=True) + + actual_c, actual_h = self._cell_output(cell) + + expected_c = np.array([[0.50125383, 0.59587258]]) + expected_h = np.array([[0.35041603, 0.40873795]]) + + self.assertAllClose(expected_c, actual_c, 1e-5) + self.assertAllClose(expected_h, actual_h, 1e-5) + if __name__ == "__main__": test.main() diff --git a/tensorflow/contrib/rnn/python/ops/rnn_cell.py b/tensorflow/contrib/rnn/python/ops/rnn_cell.py index e4667828cd..6dccf1775e 100644 --- a/tensorflow/contrib/rnn/python/ops/rnn_cell.py +++ b/tensorflow/contrib/rnn/python/ops/rnn_cell.py @@ -38,6 +38,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops import rnn_cell_impl from tensorflow.python.ops import variable_scope as vs from tensorflow.python.ops import partitioned_variables +from tensorflow.python.ops import nn_impl from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import nest @@ -2723,3 +2724,257 @@ class SRUCell(rnn_cell_impl._LayerRNNCell): h = r * self._activation(c) + (1.0 - r) * inputs return h, c + + +class WeightNormLSTMCell(rnn_cell_impl.RNNCell): + """Weight normalized LSTM Cell. Adapted from `rnn_cell_impl.LSTMCell`. + + The weight-norm implementation is based on: + https://arxiv.org/abs/1602.07868 + Tim Salimans, Diederik P. Kingma. + Weight Normalization: A Simple Reparameterization to Accelerate + Training of Deep Neural Networks + + The default LSTM implementation based on: + http://www.bioinf.jku.at/publications/older/2604.pdf + S. Hochreiter and J. Schmidhuber. + "Long Short-Term Memory". Neural Computation, 9(8):1735-1780, 1997. + + The class uses optional peephole connections, optional cell clipping + and an optional projection layer. + + The optional peephole implementation is based on: + https://research.google.com/pubs/archive/43905.pdf + Hasim Sak, Andrew Senior, and Francoise Beaufays. + "Long short-term memory recurrent neural network architectures for + large scale acoustic modeling." INTERSPEECH, 2014. + """ + + def __init__(self, num_units, norm=True, use_peepholes=False, + cell_clip=None, initializer=None, num_proj=None, + proj_clip=None, forget_bias=1, activation=None, + reuse=None): + """Initialize the parameters of a weight-normalized LSTM cell. + + Args: + num_units: int, The number of units in the LSTM cell + norm: If `True`, apply normalization to the weight matrices. If False, + the result is identical to that obtained from `rnn_cell_impl.LSTMCell` + use_peepholes: bool, set `True` to enable diagonal/peephole connections. + cell_clip: (optional) A float value, if provided the cell state is clipped + by this value prior to the cell output activation. + initializer: (optional) The initializer to use for the weight matrices. + num_proj: (optional) int, The output dimensionality for the projection + matrices. If None, no projection is performed. + proj_clip: (optional) A float value. If `num_proj > 0` and `proj_clip` is + provided, then the projected values are clipped elementwise to within + `[-proj_clip, proj_clip]`. + forget_bias: Biases of the forget gate are initialized by default to 1 + in order to reduce the scale of forgetting at the beginning of + the training. + activation: Activation function of the inner states. Default: `tanh`. + reuse: (optional) Python boolean describing whether to reuse variables + in an existing scope. If not `True`, and the existing scope already has + the given variables, an error is raised. + """ + super(WeightNormLSTMCell, self).__init__(_reuse=reuse) + + self._scope = 'wn_lstm_cell' + self._num_units = num_units + self._norm = norm + self._initializer = initializer + self._use_peepholes = use_peepholes + self._cell_clip = cell_clip + self._num_proj = num_proj + self._proj_clip = proj_clip + self._activation = activation or math_ops.tanh + self._forget_bias = forget_bias + + self._weights_variable_name = "kernel" + self._bias_variable_name = "bias" + + if num_proj: + self._state_size = rnn_cell_impl.LSTMStateTuple(num_units, num_proj) + self._output_size = num_proj + else: + self._state_size = rnn_cell_impl.LSTMStateTuple(num_units, num_units) + self._output_size = num_units + + @property + def state_size(self): + return self._state_size + + @property + def output_size(self): + return self._output_size + + def _normalize(self, weight, name): + """Apply weight normalization. + + Args: + weight: a 2D tensor with known number of columns. + name: string, variable name for the normalizer. + Returns: + A tensor with the same shape as `weight`. + """ + + output_size = weight.get_shape().as_list()[1] + g = vs.get_variable(name, [output_size], dtype=weight.dtype) + return nn_impl.l2_normalize(weight, dim=0) * g + + def _linear(self, args, + output_size, + norm, + bias, + bias_initializer=None, + kernel_initializer=None): + """Linear map: sum_i(args[i] * W[i]), where W[i] is a variable. + + Args: + args: a 2D Tensor or a list of 2D, batch x n, Tensors. + output_size: int, second dimension of W[i]. + bias: boolean, whether to add a bias term or not. + bias_initializer: starting value to initialize the bias + (default is all zeros). + kernel_initializer: starting value to initialize the weight. + + Returns: + A 2D Tensor with shape [batch x output_size] equal to + sum_i(args[i] * W[i]), where W[i]s are newly created matrices. + + Raises: + ValueError: if some of the arguments has unspecified or wrong shape. + """ + if args is None or (nest.is_sequence(args) and not args): + raise ValueError("`args` must be specified") + if not nest.is_sequence(args): + args = [args] + + # Calculate the total size of arguments on dimension 1. + total_arg_size = 0 + shapes = [a.get_shape() for a in args] + for shape in shapes: + if shape.ndims != 2: + raise ValueError("linear is expecting 2D arguments: %s" % shapes) + if shape[1].value is None: + raise ValueError("linear expects shape[1] to be provided for shape %s, " + "but saw %s" % (shape, shape[1])) + else: + total_arg_size += shape[1].value + + dtype = [a.dtype for a in args][0] + + # Now the computation. + scope = vs.get_variable_scope() + with vs.variable_scope(scope) as outer_scope: + weights = vs.get_variable( + self._weights_variable_name, [total_arg_size, output_size], + dtype=dtype, + initializer=kernel_initializer) + if norm: + wn = [] + st = 0 + with ops.control_dependencies(None): + for i in range(len(args)): + en = st + shapes[i][1].value + wn.append(self._normalize(weights[st:en, :], + name='norm_{}'.format(i))) + st = en + + weights = array_ops.concat(wn, axis=0) + + if len(args) == 1: + res = math_ops.matmul(args[0], weights) + else: + res = math_ops.matmul(array_ops.concat(args, 1), weights) + if not bias: + return res + + with vs.variable_scope(outer_scope) as inner_scope: + inner_scope.set_partitioner(None) + if bias_initializer is None: + bias_initializer = init_ops.constant_initializer(0.0, dtype=dtype) + + biases = vs.get_variable( + self._bias_variable_name, [output_size], + dtype=dtype, + initializer=bias_initializer) + + return nn_ops.bias_add(res, biases) + + def call(self, inputs, state): + """Run one step of LSTM. + + Args: + inputs: input Tensor, 2D, batch x num_units. + state: A tuple of state Tensors, both `2-D`, with column sizes + `c_state` and `m_state`. + + Returns: + A tuple containing: + + - A `2-D, [batch x output_dim]`, Tensor representing the output of the + LSTM after reading `inputs` when previous state was `state`. + Here output_dim is: + num_proj if num_proj was set, + num_units otherwise. + - Tensor(s) representing the new state of LSTM after reading `inputs` when + the previous state was `state`. Same type and shape(s) as `state`. + + Raises: + ValueError: If input size cannot be inferred from inputs via + static shape inference. + """ + dtype = inputs.dtype + num_units = self._num_units + sigmoid = math_ops.sigmoid + c, h = state + + input_size = inputs.get_shape().with_rank(2)[1] + if input_size.value is None: + raise ValueError("Could not infer input size from inputs.get_shape()[-1]") + + with vs.variable_scope(self._scope, initializer=self._initializer): + + concat = self._linear([inputs, h], 4 * num_units, + norm=self._norm, bias=True) + + # i = input_gate, j = new_input, f = forget_gate, o = output_gate + i, j, f, o = array_ops.split(value=concat, num_or_size_splits=4, axis=1) + + if self._use_peepholes: + w_f_diag = vs.get_variable("w_f_diag", shape=[num_units], dtype=dtype) + w_i_diag = vs.get_variable("w_i_diag", shape=[num_units], dtype=dtype) + w_o_diag = vs.get_variable("w_o_diag", shape=[num_units], dtype=dtype) + + new_c = (c * sigmoid(f + self._forget_bias + w_f_diag * c) + + sigmoid(i + w_i_diag * c) * self._activation(j)) + else: + new_c = (c * sigmoid(f + self._forget_bias) + + sigmoid(i) * self._activation(j)) + + if self._cell_clip is not None: + # pylint: disable=invalid-unary-operand-type + new_c = clip_ops.clip_by_value(new_c, -self._cell_clip, self._cell_clip) + # pylint: enable=invalid-unary-operand-type + if self._use_peepholes: + new_h = sigmoid(o + w_o_diag * new_c) * self._activation(new_c) + else: + new_h = sigmoid(o) * self._activation(new_c) + + if self._num_proj is not None: + with vs.variable_scope("projection"): + new_h = self._linear(new_h, + self._num_proj, + norm=self._norm, + bias=False) + + if self._proj_clip is not None: + # pylint: disable=invalid-unary-operand-type + new_h = clip_ops.clip_by_value(new_h, + -self._proj_clip, + self._proj_clip) + # pylint: enable=invalid-unary-operand-type + + new_state = rnn_cell_impl.LSTMStateTuple(new_c, new_h) + return new_h, new_state -- GitLab From 63bc130497fd128f903308a946a9a09681f24625 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 06:39:21 -0800 Subject: [PATCH 042/258] Replace "Google Container Engine" by "Google Kubernetes Engine" in README.md. PiperOrigin-RevId: 182771284 --- tensorflow/tools/dist_test/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/tools/dist_test/README.md b/tensorflow/tools/dist_test/README.md index 39c040e051..c1b1f79bbd 100644 --- a/tensorflow/tools/dist_test/README.md +++ b/tensorflow/tools/dist_test/README.md @@ -17,7 +17,7 @@ cesnsu model: ./local_test.sh --model_name CENSUS_WIDENDEEP -**2) Launch a remote k8s cluster on Google Container Engine (GKE) and run the +**2) Launch a remote k8s cluster on Google Kubernetes Engine (GKE) and run the test suite on it** For example: -- GitLab From 53b10c92a6ab96f41e883da90e342e11da67cb4f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 07:47:48 -0800 Subject: [PATCH 043/258] Internal cleanup PiperOrigin-RevId: 182777782 --- tensorflow/contrib/lite/toco/args.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/lite/toco/args.h b/tensorflow/contrib/lite/toco/args.h index eb2d7ba916..e988cbda33 100644 --- a/tensorflow/contrib/lite/toco/args.h +++ b/tensorflow/contrib/lite/toco/args.h @@ -147,12 +147,12 @@ class Arg final { if (!TryStripPrefixString(outer_member, "{", &outer_member)) return false; if (!TryStripSuffixString(outer_member, "}", &outer_member)) return false; const std::vector inner_fields_vector = - strings::Split(outer_member, ','); + absl::StrSplit(outer_member, ','); std::unordered_map element; for (const string& member_field : inner_fields_vector) { std::vector outer_member_key_value = - strings::Split(member_field, ':'); + absl::StrSplit(member_field, ':'); if (outer_member_key_value.size() != 2) return false; string& key = outer_member_key_value[0]; string& value = outer_member_key_value[1]; -- GitLab From 6972d7091825e8f609dbcb958128a53ea1b5e8eb Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 08:19:56 -0800 Subject: [PATCH 044/258] Implement native support of CycleGAN in tf.contrib.gan PiperOrigin-RevId: 182782072 --- tensorflow/contrib/gan/BUILD | 5 + .../gan/python/eval/python/summaries_impl.py | 33 ++++ .../gan/python/eval/python/summaries_test.py | 69 ++++++-- .../gan/python/losses/python/losses_impl.py | 61 +++++++ .../python/losses/python/losses_impl_test.py | 27 ++++ .../python/losses/python/tuple_losses_impl.py | 31 ++++ .../python/losses/python/tuple_losses_test.py | 38 ++++- tensorflow/contrib/gan/python/namedtuples.py | 33 ++++ tensorflow/contrib/gan/python/train.py | 153 ++++++++++++++++++ tensorflow/contrib/gan/python/train_test.py | 78 +++++++++ 10 files changed, 514 insertions(+), 14 deletions(-) diff --git a/tensorflow/contrib/gan/BUILD b/tensorflow/contrib/gan/BUILD index b355a79b1a..5db34f0f8d 100644 --- a/tensorflow/contrib/gan/BUILD +++ b/tensorflow/contrib/gan/BUILD @@ -177,6 +177,7 @@ py_library( srcs_version = "PY2AND3", deps = [ ":losses_impl", + ":namedtuples", "//tensorflow/python:util", ], ) @@ -188,6 +189,9 @@ py_test( deps = [ ":tuple_losses", "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", + "//tensorflow/python:dtypes", + "//tensorflow/python:variables", "//third_party/py/numpy", ], ) @@ -395,6 +399,7 @@ py_library( srcs_version = "PY2AND3", deps = [ ":eval_utils", + ":namedtuples", "//tensorflow/python:array_ops", "//tensorflow/python:framework_ops", "//tensorflow/python:math_ops", diff --git a/tensorflow/contrib/gan/python/eval/python/summaries_impl.py b/tensorflow/contrib/gan/python/eval/python/summaries_impl.py index 508b4d20d8..74811ff409 100644 --- a/tensorflow/contrib/gan/python/eval/python/summaries_impl.py +++ b/tensorflow/contrib/gan/python/eval/python/summaries_impl.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.contrib.gan.python import namedtuples from tensorflow.contrib.gan.python.eval.python import eval_utils from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops @@ -48,6 +49,15 @@ def add_gan_model_image_summaries(gan_model, grid_size=4): Raises: ValueError: If real and generated data aren't images. """ + if isinstance(gan_model, namedtuples.CycleGANModel): + saved_params = locals() + saved_params.pop('gan_model', None) + with ops.name_scope('cyclegan_x2y_image_summaries'): + add_gan_model_image_summaries(gan_model.model_x2y, **saved_params) + with ops.name_scope('cyclegan_y2x_image_summaries'): + add_gan_model_image_summaries(gan_model.model_y2x, **saved_params) + return + _assert_is_image(gan_model.real_data) _assert_is_image(gan_model.generated_data) @@ -96,6 +106,15 @@ def add_image_comparison_summaries(gan_model, num_comparisons=2, ValueError: If the generator input, real, and generated data aren't all the same size. """ + if isinstance(gan_model, namedtuples.CycleGANModel): + saved_params = locals() + saved_params.pop('gan_model', None) + with ops.name_scope('cyclegan_x2y_image_comparison_summaries'): + add_image_comparison_summaries(gan_model.model_x2y, **saved_params) + with ops.name_scope('cyclegan_y2x_image_comparison_summaries'): + add_image_comparison_summaries(gan_model.model_y2x, **saved_params) + return + _assert_is_image(gan_model.generator_inputs) _assert_is_image(gan_model.generated_data) _assert_is_image(gan_model.real_data) @@ -133,6 +152,13 @@ def add_gan_model_summaries(gan_model): Args: gan_model: A GANModel tuple. """ + if isinstance(gan_model, namedtuples.CycleGANModel): + with ops.name_scope('cyclegan_x2y_summaries'): + add_gan_model_summaries(gan_model.model_x2y) + with ops.name_scope('cyclegan_y2x_summaries'): + add_gan_model_summaries(gan_model.model_y2x) + return + with ops.name_scope('generator_variables'): for var in gan_model.generator_variables: summary.histogram(var.name, var) @@ -147,6 +173,13 @@ def add_regularization_loss_summaries(gan_model): Args: gan_model: A GANModel tuple. """ + if isinstance(gan_model, namedtuples.CycleGANModel): + with ops.name_scope('cyclegan_x2y_regularization_loss_summaries'): + add_regularization_loss_summaries(gan_model.model_x2y) + with ops.name_scope('cyclegan_y2x_regularization_loss_summaries'): + add_regularization_loss_summaries(gan_model.model_y2x) + return + if gan_model.generator_scope: summary.scalar( 'generator_regularization_loss', diff --git a/tensorflow/contrib/gan/python/eval/python/summaries_test.py b/tensorflow/contrib/gan/python/eval/python/summaries_test.py index a3b02bcefc..a02d8772e1 100644 --- a/tensorflow/contrib/gan/python/eval/python/summaries_test.py +++ b/tensorflow/contrib/gan/python/eval/python/summaries_test.py @@ -57,40 +57,83 @@ def get_gan_model(): discriminator_fn=discriminator_model) +def get_cyclegan_model(): + with variable_scope.variable_scope('x2y'): + model_x2y = get_gan_model() + with variable_scope.variable_scope('y2x'): + model_y2x = get_gan_model() + return namedtuples.CycleGANModel( + model_x2y=model_x2y, + model_y2x=model_y2x, + reconstructed_x=array_ops.zeros([3, 30, 35, 6]), + reconstructed_y=array_ops.zeros([3, 30, 35, 6])) + + class SummariesTest(test.TestCase): - def testAddGanModelImageSummaries(self): - summaries.add_gan_model_image_summaries(get_gan_model(), grid_size=2) + def _test_add_gan_model_image_summaries_impl(self, get_model_fn, + expected_num_summary_ops): + summaries.add_gan_model_image_summaries(get_model_fn(), grid_size=2) - self.assertEquals(5, len(ops.get_collection(ops.GraphKeys.SUMMARIES))) + self.assertEquals(expected_num_summary_ops, + len(ops.get_collection(ops.GraphKeys.SUMMARIES))) with self.test_session(use_gpu=True): variables.global_variables_initializer().run() summary.merge_all().eval() - def testAddGanModelSummaries(self): - summaries.add_gan_model_summaries(get_gan_model()) + def test_add_gan_model_image_summaries(self): + self._test_add_gan_model_image_summaries_impl(get_gan_model, 5) + + def test_add_gan_model_image_summaries_for_cyclegan(self): + self._test_add_gan_model_image_summaries_impl(get_cyclegan_model, 10) - self.assertEquals(3, len(ops.get_collection(ops.GraphKeys.SUMMARIES))) + def _test_add_gan_model_summaries_impl(self, get_model_fn, + expected_num_summary_ops): + summaries.add_gan_model_summaries(get_model_fn()) + + self.assertEquals(expected_num_summary_ops, + len(ops.get_collection(ops.GraphKeys.SUMMARIES))) with self.test_session(use_gpu=True): variables.global_variables_initializer().run() summary.merge_all().eval() - def testAddRegularizationLossSummaries(self): - summaries.add_regularization_loss_summaries(get_gan_model()) + def test_add_gan_model_summaries(self): + self._test_add_gan_model_summaries_impl(get_gan_model, 3) + + def test_add_gan_model_summaries_for_cyclegan(self): + self._test_add_gan_model_summaries_impl(get_cyclegan_model, 6) - self.assertEquals(2, len(ops.get_collection(ops.GraphKeys.SUMMARIES))) + def _test_add_regularization_loss_summaries_impl(self, get_model_fn, + expected_num_summary_ops): + summaries.add_regularization_loss_summaries(get_model_fn()) + + self.assertEquals(expected_num_summary_ops, + len(ops.get_collection(ops.GraphKeys.SUMMARIES))) with self.test_session(use_gpu=True): summary.merge_all().eval() + def test_add_regularization_loss_summaries(self): + self._test_add_regularization_loss_summaries_impl(get_gan_model, 2) + + def test_add_regularization_loss_summaries_for_cyclegan(self): + self._test_add_regularization_loss_summaries_impl(get_cyclegan_model, 4) + # TODO(joelshor): Add correctness test. - def testAddImageComparisonSummaries(self): - summaries.add_image_comparison_summaries( - get_gan_model(), display_diffs=True) + def _test_add_image_comparison_summaries_impl(self, get_model_fn, + expected_num_summary_ops): + summaries.add_image_comparison_summaries(get_model_fn(), display_diffs=True) - self.assertEquals(1, len(ops.get_collection(ops.GraphKeys.SUMMARIES))) + self.assertEquals(expected_num_summary_ops, + len(ops.get_collection(ops.GraphKeys.SUMMARIES))) with self.test_session(use_gpu=True): summary.merge_all().eval() + def test_add_image_comparison_summaries(self): + self._test_add_image_comparison_summaries_impl(get_gan_model, 1) + + def test_add_image_comparison_summaries_for_cyclegan(self): + self._test_add_image_comparison_summaries_impl(get_cyclegan_model, 2) + if __name__ == '__main__': test.main() diff --git a/tensorflow/contrib/gan/python/losses/python/losses_impl.py b/tensorflow/contrib/gan/python/losses/python/losses_impl.py index 940762cf2a..23a3b60cc0 100644 --- a/tensorflow/contrib/gan/python/losses/python/losses_impl.py +++ b/tensorflow/contrib/gan/python/losses/python/losses_impl.py @@ -67,6 +67,7 @@ __all__ = [ 'wasserstein_gradient_penalty', 'mutual_information_penalty', 'combine_adversarial_loss', + 'cycle_consistency_loss', ] @@ -915,3 +916,63 @@ def combine_adversarial_loss(main_loss, array_ops.stop_gradient(adv_coeff) * adversarial_loss) return final_loss + + +def cycle_consistency_loss(data_x, + reconstructed_data_x, + data_y, + reconstructed_data_y, + scope=None, + add_summaries=False): + """Defines the cycle consistency loss. + + The cyclegan model has two partial models where `model_x2y` generator F maps + data set X to Y, `model_y2x` generator G maps data set Y to X. For a `data_x` + in data set X, we could reconstruct it by + * reconstructed_data_x = G(F(data_x)) + Similarly + * reconstructed_data_y = F(G(data_y)) + + The cycle consistency loss is about the difference between data and + reconstructed data, namely + * loss_x2x = |data_x - G(F(data_x))| (L1-norm) + * loss_y2y = |data_y - F(G(data_y))| (L1-norm) + * loss = (loss_x2x + loss_y2y) / 2 + where `loss` is the final result. + + See https://arxiv.org/abs/1703.10593 for more details. + + Args: + data_x: A `Tensor` of data X. + reconstructed_data_x: A `Tensor` of reconstructed data X. + data_y: A `Tensor` of data Y. + reconstructed_data_y: A `Tensor` of reconstructed data Y. + scope: The scope for the operations performed in computing the loss. + Defaults to None. + add_summaries: Whether or not to add detailed summaries for the loss. + Defaults to False. + + Returns: + A scalar `Tensor` of cycle consistency loss. + """ + + def _partial_cycle_consistency_loss(data, reconstructed_data): + # Following the original implementation + # https://github.com/junyanz/CycleGAN/blob/master/models/cycle_gan_model.lua + # use L1-norm of pixel-wise error normalized by data size so that + # `cycle_loss_weight` can be specified independent of image size. + return math_ops.reduce_mean(math_ops.abs(data - reconstructed_data)) + + with ops.name_scope( + scope, + 'cycle_consistency_loss', + values=[data_x, reconstructed_data_x, data_y, reconstructed_data_y]): + loss_x2x = _partial_cycle_consistency_loss(data_x, reconstructed_data_x) + loss_y2y = _partial_cycle_consistency_loss(data_y, reconstructed_data_y) + loss = (loss_x2x + loss_y2y) / 2.0 + if add_summaries: + summary.scalar('cycle_consistency_loss_x2x', loss_x2x) + summary.scalar('cycle_consistency_loss_y2y', loss_y2y) + summary.scalar('cycle_consistency_loss', loss) + + return loss diff --git a/tensorflow/contrib/gan/python/losses/python/losses_impl_test.py b/tensorflow/contrib/gan/python/losses/python/losses_impl_test.py index b5cd8c92ba..7d2a7a254f 100644 --- a/tensorflow/contrib/gan/python/losses/python/losses_impl_test.py +++ b/tensorflow/contrib/gan/python/losses/python/losses_impl_test.py @@ -623,5 +623,32 @@ class CombineAdversarialLossTest(test.TestCase): self.assertNear(gnorm_np, precond_gnorm_np, 1e-5) +class CycleConsistencyLossTest(test.TestCase): + """Tests for cycle_consistency_loss.""" + + def setUp(self): + super(CycleConsistencyLossTest, self).setUp() + + self._data_x_np = [[1.0, 2, 3], [4, 5, 6]] + self._reconstructed_data_x_np = [[7.0, 8, 9], [10, 11, 12]] + self._data_y_np = [1.0, 9] + self._reconstructed_data_y_np = [-2.0, 3] + + self._data_x = constant_op.constant(self._data_x_np, dtype=dtypes.float32) + self._reconstructed_data_x = constant_op.constant( + self._reconstructed_data_x_np, dtype=dtypes.float32) + self._data_y = constant_op.constant(self._data_y_np, dtype=dtypes.float32) + self._reconstructed_data_y = constant_op.constant( + self._reconstructed_data_y_np, dtype=dtypes.float32) + + def test_correct_loss(self): + loss = tfgan_losses.cycle_consistency_loss( + self._data_x, self._reconstructed_data_x, self._data_y, + self._reconstructed_data_y) + with self.test_session(use_gpu=True): + variables.global_variables_initializer().run() + self.assertNear(5.25, loss.eval(), 1e-5) + + if __name__ == '__main__': test.main() diff --git a/tensorflow/contrib/gan/python/losses/python/tuple_losses_impl.py b/tensorflow/contrib/gan/python/losses/python/tuple_losses_impl.py index b341f03a0d..dcc3f94c2d 100644 --- a/tensorflow/contrib/gan/python/losses/python/tuple_losses_impl.py +++ b/tensorflow/contrib/gan/python/losses/python/tuple_losses_impl.py @@ -60,6 +60,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.contrib.gan.python import namedtuples from tensorflow.contrib.gan.python.losses.python import losses_impl from tensorflow.python.util import tf_inspect @@ -78,6 +79,7 @@ __all__ = [ 'wasserstein_gradient_penalty', 'mutual_information_penalty', 'combine_adversarial_loss', + 'cycle_consistency_loss', ] @@ -246,3 +248,32 @@ def combine_adversarial_loss(gan_loss, scalar_summaries, gradient_summaries) return gan_loss._replace(generator_loss=combined_loss) + + +def cycle_consistency_loss(cyclegan_model, scope=None, add_summaries=False): + """Defines the cycle consistency loss. + + Uses `cycle_consistency_loss` to compute the cycle consistency loss for a + `cyclegan_model`. + + Args: + cyclegan_model: A `CycleGANModel` namedtuple. + scope: The scope for the operations performed in computing the loss. + Defaults to None. + add_summaries: Whether or not to add detailed summaries for the loss. + Defaults to False. + + Returns: + A scalar `Tensor` of cycle consistency loss. + + Raises: + ValueError: If `cyclegan_model` is not a `CycleGANModel` namedtuple. + """ + if not isinstance(cyclegan_model, namedtuples.CycleGANModel): + raise ValueError( + '`cyclegan_model` must be a `CycleGANModel`. Instead, was %s.' % + type(cyclegan_model)) + return losses_impl.cycle_consistency_loss( + cyclegan_model.model_x2y.generator_inputs, cyclegan_model.reconstructed_x, + cyclegan_model.model_y2x.generator_inputs, cyclegan_model.reconstructed_y, + scope, add_summaries) diff --git a/tensorflow/contrib/gan/python/losses/python/tuple_losses_test.py b/tensorflow/contrib/gan/python/losses/python/tuple_losses_test.py index 215b15ef69..aa1ef11172 100644 --- a/tensorflow/contrib/gan/python/losses/python/tuple_losses_test.py +++ b/tensorflow/contrib/gan/python/losses/python/tuple_losses_test.py @@ -22,8 +22,11 @@ import collections import numpy as np +from tensorflow.contrib.gan.python import namedtuples from tensorflow.contrib.gan.python.losses.python import tuple_losses_impl as tfgan_losses - +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -125,6 +128,7 @@ manual_tests = [ 'combine_adversarial_loss', 'mutual_information_penalty', 'wasserstein_gradient_penalty', + 'cycle_consistency_loss', ] discriminator_keyword_args = { @@ -139,6 +143,38 @@ generator_keyword_args = { } +class CycleConsistencyLossTest(test.TestCase): + + def setUp(self): + super(CycleConsistencyLossTest, self).setUp() + + def _partial_model(generator_inputs_np): + model = namedtuples.GANModel(*[None] * 11) + return model._replace( + generator_inputs=constant_op.constant( + generator_inputs_np, dtype=dtypes.float32)) + + self._model_x2y = _partial_model([1, 2]) + self._model_y2x = _partial_model([5, 6]) + + def test_model_type(self): + """Test the input model type for `cycle_consistency_loss`.""" + with self.assertRaises(ValueError): + tfgan_losses.cycle_consistency_loss(self._model_x2y) + + def test_correct_loss(self): + """Test the output of `cycle_consistency_loss`.""" + loss = tfgan_losses.cycle_consistency_loss( + namedtuples.CycleGANModel( + model_x2y=self._model_x2y, + model_y2x=self._model_y2x, + reconstructed_x=constant_op.constant([9, 8], dtype=dtypes.float32), + reconstructed_y=constant_op.constant([7, 2], dtype=dtypes.float32))) + with self.test_session(use_gpu=True): + variables.global_variables_initializer().run() + self.assertNear(5.0, loss.eval(), 1e-5) + + if __name__ == '__main__': for loss_name in tfgan_losses.__all__: if loss_name in manual_tests: continue diff --git a/tensorflow/contrib/gan/python/namedtuples.py b/tensorflow/contrib/gan/python/namedtuples.py index 3d4e315ebd..25cfeafeec 100644 --- a/tensorflow/contrib/gan/python/namedtuples.py +++ b/tensorflow/contrib/gan/python/namedtuples.py @@ -30,7 +30,9 @@ __all__ = [ 'GANModel', 'InfoGANModel', 'ACGANModel', + 'CycleGANModel', 'GANLoss', + 'CycleGANLoss', 'GANTrainOps', 'GANTrainSteps', ] @@ -115,6 +117,25 @@ class ACGANModel( """ +class CycleGANModel( + collections.namedtuple( + 'CycleGANModel', + ('model_x2y', 'model_y2x', 'reconstructed_x', 'reconstructed_y'))): + """An CycleGANModel contains all the pieces needed for CycleGAN training. + + The model `model_x2y` generator F maps data set X to Y, while the model + `model_y2x` generator G maps data set Y to X. + + See https://arxiv.org/abs/1703.10593 for more details. + + Args: + model_x2y: A `GANModel` namedtuple whose generator maps data set X to Y. + model_y2x: A `GANModel` namedtuple whose generator maps data set Y to X. + reconstructed_x: A `Tensor` of reconstructed data X which is G(F(X)). + reconstructed_y: A `Tensor` of reconstructed data Y which is F(G(Y)). + """ + + class GANLoss( collections.namedtuple('GANLoss', ( 'generator_loss', @@ -128,6 +149,18 @@ class GANLoss( """ +class CycleGANLoss( + collections.namedtuple('CycleGANLoss', ('loss_x2y', 'loss_y2x'))): + """CycleGANLoss contains the losses for `CycleGANModel`. + + See https://arxiv.org/abs/1703.10593 for more details. + + Args: + loss_x2y: A `GANLoss` namedtuple representing the loss of `model_x2y`. + loss_y2x: A `GANLoss` namedtuple representing the loss of `model_y2x`. + """ + + class GANTrainOps( collections.namedtuple('GANTrainOps', ( 'generator_train_op', diff --git a/tensorflow/contrib/gan/python/train.py b/tensorflow/contrib/gan/python/train.py index c429ec4831..a32ddd7a06 100644 --- a/tensorflow/contrib/gan/python/train.py +++ b/tensorflow/contrib/gan/python/train.py @@ -52,7 +52,9 @@ __all__ = [ 'gan_model', 'infogan_model', 'acgan_model', + 'cyclegan_model', 'gan_loss', + 'cyclegan_loss', 'gan_train_ops', 'gan_train', 'get_sequential_train_hooks', @@ -305,6 +307,76 @@ def acgan_model( discriminator_gen_classification_logits) +def cyclegan_model( + # Lambdas defining models. + generator_fn, + discriminator_fn, + # data X and Y. + data_x, + data_y, + # Optional scopes. + generator_scope='Generator', + discriminator_scope='Discriminator', + model_x2y_scope='ModelX2Y', + model_y2x_scope='ModelY2X', + # Options. + check_shapes=True): + """Returns a CycleGAN model outputs and variables. + + See https://arxiv.org/abs/1703.10593 for more details. + + Args: + generator_fn: A python lambda that takes `data_x` or `data_y` as inputs and + returns the outputs of the GAN generator. + discriminator_fn: A python lambda that takes `real_data`/`generated data` + and `generator_inputs`. Outputs a Tensor in the range [-inf, inf]. + data_x: A `Tensor` of dataset X. Must be the same shape as `data_y`. + data_y: A `Tensor` of dataset Y. Must be the same shape as `data_x`. + generator_scope: Optional generator variable scope. Useful if you want to + reuse a subgraph that has already been created. Defaults to 'Generator'. + discriminator_scope: Optional discriminator variable scope. Useful if you + want to reuse a subgraph that has already been created. Defaults to + 'Discriminator'. + model_x2y_scope: Optional variable scope for model x2y variables. Defaults + to 'ModelX2Y'. + model_y2x_scope: Optional variable scope for model y2x variables. Defaults + to 'ModelY2X'. + check_shapes: If `True`, check that generator produces Tensors that are the + same shape as `data_x` (`data_y`). Otherwise, skip this check. + + Returns: + A `CycleGANModel` namedtuple. + + Raises: + ValueError: If `check_shapes` is True and `data_x` or the generator output + does not have the same shape as `data_y`. + """ + + # Create models. + def _define_partial_model(input_data, output_data): + return gan_model( + generator_fn=generator_fn, + discriminator_fn=discriminator_fn, + real_data=output_data, + generator_inputs=input_data, + generator_scope=generator_scope, + discriminator_scope=discriminator_scope, + check_shapes=check_shapes) + + with variable_scope.variable_scope(model_x2y_scope): + model_x2y = _define_partial_model(data_x, data_y) + with variable_scope.variable_scope(model_y2x_scope): + model_y2x = _define_partial_model(data_y, data_x) + + with variable_scope.variable_scope(model_y2x.generator_scope, reuse=True): + reconstructed_x = model_y2x.generator_fn(model_x2y.generated_data) + with variable_scope.variable_scope(model_x2y.generator_scope, reuse=True): + reconstructed_y = model_x2y.generator_fn(model_y2x.generated_data) + + return namedtuples.CycleGANModel(model_x2y, model_y2x, reconstructed_x, + reconstructed_y) + + def _validate_aux_loss_weight(aux_loss_weight, name='aux_loss_weight'): if isinstance(aux_loss_weight, ops.Tensor): aux_loss_weight.shape.assert_is_compatible_with([]) @@ -494,6 +566,69 @@ def gan_loss( return namedtuples.GANLoss(gen_loss + gen_reg_loss, dis_loss + dis_reg_loss) +def cyclegan_loss( + model, + # Loss functions. + generator_loss_fn=tfgan_losses.least_squares_generator_loss, + discriminator_loss_fn=tfgan_losses.least_squares_discriminator_loss, + # Auxiliary losses. + cycle_consistency_loss_fn=tfgan_losses.cycle_consistency_loss, + cycle_consistency_loss_weight=10.0, + # Options + **kwargs): + """Returns the losses for a `CycleGANModel`. + + See https://arxiv.org/abs/1703.10593 for more details. + + Args: + model: A `CycleGANModel` namedtuple. + generator_loss_fn: The loss function on the generator. Takes a `GANModel` + named tuple. + discriminator_loss_fn: The loss function on the discriminator. Takes a + `GANModel` namedtuple. + cycle_consistency_loss_fn: The cycle consistency loss function. Takes a + `CycleGANModel` namedtuple. + cycle_consistency_loss_weight: A non-negative Python number or a scalar + `Tensor` indicating how much to weigh the cycle consistency loss. + **kwargs: Keyword args to pass directly to `gan_loss` to construct the loss + for each partial model of `model`. + + Returns: + A `CycleGANLoss` namedtuple. + + Raises: + ValueError: If `model` is not a `CycleGANModel` namedtuple. + """ + # Sanity checks. + if not isinstance(model, namedtuples.CycleGANModel): + raise ValueError( + '`model` must be a `CycleGANModel`. Instead, was %s.' % type(model)) + + # Defines cycle consistency loss. + cycle_consistency_loss = cycle_consistency_loss_fn( + model, add_summaries=kwargs.get('add_summaries', True)) + cycle_consistency_loss_weight = _validate_aux_loss_weight( + cycle_consistency_loss_weight, 'cycle_consistency_loss_weight') + aux_loss = cycle_consistency_loss_weight * cycle_consistency_loss + + # Defines losses for each partial model. + def _partial_loss(partial_model): + partial_loss = gan_loss( + partial_model, + generator_loss_fn=generator_loss_fn, + discriminator_loss_fn=discriminator_loss_fn, + **kwargs) + return partial_loss._replace( + generator_loss=partial_loss.generator_loss + aux_loss) + + with ops.name_scope('cyclegan_loss_x2y'): + loss_x2y = _partial_loss(model.model_x2y) + with ops.name_scope('cyclegan_loss_y2x'): + loss_y2x = _partial_loss(model.model_y2x) + + return namedtuples.CycleGANLoss(loss_x2y, loss_y2x) + + def _get_update_ops(kwargs, gen_scope, dis_scope, check_for_unused_ops=True): """Gets generator and discriminator update ops. @@ -561,6 +696,24 @@ def gan_train_ops( A GANTrainOps tuple of (generator_train_op, discriminator_train_op) that can be used to train a generator/discriminator pair. """ + if isinstance(model, namedtuples.CycleGANModel): + saved_params = locals() + saved_params.pop('model', None) + saved_params.pop('loss', None) + kwargs = saved_params.pop('kwargs', {}) + saved_params.update(kwargs) + with ops.name_scope('cyclegan_x2y_train'): + train_ops_x2y = gan_train_ops(model.model_x2y, loss.loss_x2y, + **saved_params) + with ops.name_scope('cyclegan_y2x_train'): + train_ops_y2x = gan_train_ops(model.model_y2x, loss.loss_y2x, + **saved_params) + return namedtuples.GANTrainOps( + (train_ops_x2y.generator_train_op, train_ops_y2x.generator_train_op), + (train_ops_x2y.discriminator_train_op, + train_ops_y2x.discriminator_train_op), + training_util.get_or_create_global_step().assign_add(1)) + # Create global step increment op. global_step = training_util.get_or_create_global_step() global_step_inc = global_step.assign_add(1) diff --git a/tensorflow/contrib/gan/python/train_test.py b/tensorflow/contrib/gan/python/train_test.py index 58704e6859..f9bdaa74c9 100644 --- a/tensorflow/contrib/gan/python/train_test.py +++ b/tensorflow/contrib/gan/python/train_test.py @@ -210,6 +210,38 @@ def create_callable_acgan_model(): one_hot_labels=array_ops.one_hot([0, 1, 2], 10)) +def get_cyclegan_model(): + return namedtuples.CycleGANModel( + model_x2y=get_gan_model(), + model_y2x=get_gan_model(), + reconstructed_x=array_ops.ones([1, 2, 3]), + reconstructed_y=array_ops.zeros([1, 2, 3])) + + +def get_callable_cyclegan_model(): + return namedtuples.CycleGANModel( + model_x2y=get_callable_gan_model(), + model_y2x=get_callable_gan_model(), + reconstructed_x=array_ops.ones([1, 2, 3]), + reconstructed_y=array_ops.zeros([1, 2, 3])) + + +def create_cyclegan_model(): + return train.cyclegan_model( + generator_model, + discriminator_model, + data_x=array_ops.zeros([1, 2]), + data_y=array_ops.ones([1, 2])) + + +def create_callable_cyclegan_model(): + return train.cyclegan_model( + Generator(), + Discriminator(), + data_x=array_ops.zeros([1, 2]), + data_y=array_ops.ones([1, 2])) + + def get_sync_optimizer(): return sync_replicas_optimizer.SyncReplicasOptimizer( gradient_descent.GradientDescentOptimizer(learning_rate=1.0), @@ -261,6 +293,13 @@ class GANModelTest(test.TestCase): self._test_output_type_helper( get_callable_acgan_model, namedtuples.ACGANModel) + def test_output_type_cyclegan(self): + self._test_output_type_helper(get_cyclegan_model, namedtuples.CycleGANModel) + + def test_output_type_callable_cyclegan(self): + self._test_output_type_helper(get_callable_cyclegan_model, + namedtuples.CycleGANModel) + def test_no_shape_check(self): def dummy_generator_model(_): return (None, None) @@ -308,6 +347,17 @@ class GANLossTest(test.TestCase): def test_output_type_callable_acgan(self): self._test_output_type_helper(get_callable_acgan_model) + def test_output_type_cyclegan(self): + loss = train.cyclegan_loss(create_cyclegan_model(), add_summaries=True) + self.assertIsInstance(loss, namedtuples.CycleGANLoss) + self.assertGreater(len(ops.get_collection(ops.GraphKeys.SUMMARIES)), 0) + + def test_output_type_callable_cyclegan(self): + loss = train.cyclegan_loss( + create_callable_cyclegan_model(), add_summaries=True) + self.assertIsInstance(loss, namedtuples.CycleGANLoss) + self.assertGreater(len(ops.get_collection(ops.GraphKeys.SUMMARIES)), 0) + # Test gradient penalty option. def _test_grad_penalty_helper(self, create_gan_model_fn): model = create_gan_model_fn() @@ -431,6 +481,34 @@ class GANLossTest(test.TestCase): def test_callable_acgan(self): self._test_acgan_helper(create_callable_acgan_model) + # Test that CycleGan models work. + def _test_cyclegan_helper(self, create_gan_model_fn): + model = create_gan_model_fn() + loss = train.cyclegan_loss(model) + self.assertIsInstance(loss, namedtuples.CycleGANLoss) + + # Check values. + with self.test_session(use_gpu=True) as sess: + variables.global_variables_initializer().run() + (loss_x2y_gen_np, loss_x2y_dis_np, loss_y2x_gen_np, + loss_y2x_dis_np) = sess.run([ + loss.loss_x2y.generator_loss, loss.loss_x2y.discriminator_loss, + loss.loss_y2x.generator_loss, loss.loss_y2x.discriminator_loss + ]) + + self.assertGreater(loss_x2y_gen_np, loss_x2y_dis_np) + self.assertGreater(loss_y2x_gen_np, loss_y2x_dis_np) + self.assertTrue(np.isscalar(loss_x2y_gen_np)) + self.assertTrue(np.isscalar(loss_x2y_dis_np)) + self.assertTrue(np.isscalar(loss_y2x_gen_np)) + self.assertTrue(np.isscalar(loss_y2x_dis_np)) + + def test_cyclegan(self): + self._test_cyclegan_helper(create_cyclegan_model) + + def test_callable_cyclegan(self): + self._test_cyclegan_helper(create_callable_cyclegan_model) + def _check_tensor_pool_adjusted_model_outputs(self, tensor1, tensor2, pool_size): history_values = [] -- GitLab From 7ac2511d758047d41d2b0ffb236a19aad8421e2d Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Mon, 22 Jan 2018 08:31:23 -0800 Subject: [PATCH 045/258] Make array_ops_test.py work with the C API enabled. I only enabled the test class that other testing identified needed changes. PiperOrigin-RevId: 182783262 --- tensorflow/python/kernel_tests/array_ops_test.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py index 1dbe7deb97..ec6184aacd 100644 --- a/tensorflow/python/kernel_tests/array_ops_test.py +++ b/tensorflow/python/kernel_tests/array_ops_test.py @@ -975,6 +975,7 @@ class ShapeSizeRankTest(test_util.TensorFlowTestCase): self.assertEqual(2, array_ops.rank(sp).eval()) +@test_util.with_c_api class SequenceMaskTest(test_util.TensorFlowTestCase): def testExceptions(self): @@ -993,7 +994,10 @@ class SequenceMaskTest(test_util.TensorFlowTestCase): # test dtype and default maxlen: res = array_ops.sequence_mask( constant_op.constant([0, 1, 4]), dtype=dtypes.float32) - self.assertAllEqual(res.get_shape().as_list(), [3, None]) + if ops._USE_C_API: + self.assertAllEqual(res.get_shape().as_list(), [3, 4]) + else: + self.assertAllEqual(res.get_shape().as_list(), [3, None]) self.assertAllEqual(res.eval(), [[0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]]) @@ -1009,7 +1013,10 @@ class SequenceMaskTest(test_util.TensorFlowTestCase): # test dtype and default maxlen: res = array_ops.sequence_mask( constant_op.constant([[0, 1, 4], [1, 2, 3]]), dtype=dtypes.float32) - self.assertAllEqual(res.get_shape().as_list(), [2, 3, None]) + if ops._USE_C_API: + self.assertAllEqual(res.get_shape().as_list(), [2, 3, 4]) + else: + self.assertAllEqual(res.get_shape().as_list(), [2, 3, None]) self.assertAllEqual(res.eval(), [[[0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]], -- GitLab From f8e9bf408b2e27dfefe0811a735133082a1c7465 Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Mon, 22 Jan 2018 09:39:44 -0800 Subject: [PATCH 046/258] Reducing op overhead for eager. Benchmarks: (new) tfe_py_fastpath_execute_matmul: 7.86213080088 walltime (old) gen_math_ops_matmul: 11.2566947937 walltime (The slowdown is due to adding the record_gradient callback) This will be a 3-step process: 1. (This CL) Add a function that allows execution of an op on the fastpath. 2. Update python generation code to create 2 new python functions (_op/_op_gradient_callback and _op_slowpath_fallback): -- first function (_op) checks if it is in graph mode, if so, do the normal thing, else call out to the function added in step 1. -- second function does the else part similar to today (calling out to args_to_matching_eager etc.) 3. Rename the first function generated above to be the canonical _op function. PiperOrigin-RevId: 182791741 --- tensorflow/python/eager/BUILD | 19 +- tensorflow/python/eager/benchmarks_test.py | 36 +++- tensorflow/python/eager/pywrap_tfe.h | 22 +++ tensorflow/python/eager/pywrap_tfe_src.cc | 211 +++++++++++++++++++-- tensorflow/python/eager/pywrap_tfe_test.py | 109 +++++++++++ tensorflow/python/pywrap_tfe.i | 9 +- 6 files changed, 390 insertions(+), 16 deletions(-) create mode 100644 tensorflow/python/eager/pywrap_tfe_test.py diff --git a/tensorflow/python/eager/BUILD b/tensorflow/python/eager/BUILD index f470e18120..9e3382d4f3 100644 --- a/tensorflow/python/eager/BUILD +++ b/tensorflow/python/eager/BUILD @@ -1,8 +1,7 @@ licenses(["notice"]) # Apache 2.0 -load("//tensorflow:tensorflow.bzl", "py_test") +load("//tensorflow:tensorflow.bzl", "py_test", "tf_cc_binary") load("//tensorflow:tensorflow.bzl", "cuda_py_test") -load("//tensorflow:tensorflow.bzl", "tf_cc_binary") load( "//tensorflow/tools/test:performance.bzl", "tf_py_logged_benchmark", @@ -423,6 +422,22 @@ cuda_py_test( ], ) +py_test( + name = "pywrap_tfe_test", + srcs = ["pywrap_tfe_test.py"], + srcs_version = "PY2AND3", + deps = [ + ":backprop", + ":context", + ":test", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:math_ops", + "//tensorflow/python:pywrap_tensorflow", + "//tensorflow/python:random_ops", + "//third_party/py/numpy", + ], +) + # ----------------------------------------------------------------------------- # Google-internal targets. diff --git a/tensorflow/python/eager/benchmarks_test.py b/tensorflow/python/eager/benchmarks_test.py index 9849f0f322..75526ba9c1 100644 --- a/tensorflow/python/eager/benchmarks_test.py +++ b/tensorflow/python/eager/benchmarks_test.py @@ -42,11 +42,25 @@ from tensorflow.python.ops import gen_math_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops - CPU = "/device:CPU:0" GPU = "/device:GPU:0" +def record_gradient_callback(inputs, attrs, results): + return backprop._record_gradient("MatMul", inputs, attrs, results, None) + + +def c_tfe_py_fastpath_execute(a, b, transpose_a=False, transpose_b=False): + ctx = context.context() + assert not ctx.in_graph_mode( + ), "The prototype doesn't contain C code for graph construction" + ctx_handle = ctx._handle # pylint: disable=protected-access + + return pywrap_tensorflow.TFE_Py_FastPathExecute( + ctx_handle, None, "MatMul", record_gradient_callback, a, b, + "transpose_a", transpose_a, "transpose_b", transpose_b)[0] + + class MicroBenchmarks(test.Benchmark): def __init__(self): @@ -222,6 +236,14 @@ class MicroBenchmarks(test.Benchmark): gen_math_ops._mat_mul(m, m, transpose_b=transpose_b) self._run(func, num_iters) + def _benchmark_tfe_py_fastpath_execute_matmul(self, m, transpose_b, + num_iters): + + def func(): + c_tfe_py_fastpath_execute(m, m, transpose_b=transpose_b) + + self._run(func, num_iters) + def _benchmark_tfe_py_execute_matmul(self, m, transpose_b, num_iters): inputs = [m, m] # pylint: disable=protected-access @@ -257,6 +279,12 @@ class MicroBenchmarks(test.Benchmark): self._benchmark_gen_math_ops_matmul( m, transpose_b=False, num_iters=self._num_iters_2_by_2) + def benchmark_tfe_py_fastpath_execute_matmul_2_by_2_CPU(self): + with context.device(CPU): + m = self._m_2_by_2.cpu() + self._benchmark_tfe_py_fastpath_execute_matmul( + m, transpose_b=False, num_iters=self._num_iters_2_by_2) + def benchmark_tfe_py_execute_matmul_2_by_2_CPU(self): with context.device(CPU): m = self._m_2_by_2.cpu() @@ -320,6 +348,12 @@ class MicroBenchmarks(test.Benchmark): self._benchmark_gen_math_ops_matmul( m, transpose_b=True, num_iters=self._num_iters_100_by_784) + def benchmark_tfe_py_fastpath_execute_matmul_100_by_784_CPU(self): + with context.device(CPU): + m = self._m_100_by_784.cpu() + self._benchmark_tfe_py_fastpath_execute_matmul( + m, transpose_b=True, num_iters=self._num_iters_100_by_784) + def benchmark_tfe_py_execute_matmul_100_by_784_CPU(self): with context.device(CPU): m = self._m_100_by_784.cpu() diff --git a/tensorflow/python/eager/pywrap_tfe.h b/tensorflow/python/eager/pywrap_tfe.h index cecef42603..4aea134fa9 100644 --- a/tensorflow/python/eager/pywrap_tfe.h +++ b/tensorflow/python/eager/pywrap_tfe.h @@ -131,6 +131,28 @@ PyObject* TFE_Py_TapeGradient(PyObject* tape, PyObject* vspace, PyObject* target, PyObject* sources, PyObject* output_gradients, TF_Status* status); +// Execute a tensorflow operation assuming that all provided inputs are +// correctly formatted (i.e. EagerTensors). If it doesn't find EagerTensors, +// it will simply fail with a NotImplementedError. +// +// The first PyObject* is unused. +// The "args" PyObject* is meant to be a tuple with the following structure: +// Item 1: The TFE Context +// Item 2: device_name: Name of the device on which to execute the operation, +// or NULL for automatic selection. +// Item 3: op_name: Name of the TensorFlow op to execute. +// Item 4: record_gradient_callback: Callback that records the gradient of the +// result. +// The callback takes (inputs, attrs, result) - all sequences and +// records the gradient. +// Item 5 onwards: inputs - This is a list of inputs followed by a list of +// attrs. It is not necessary for type attrs to be present. +// +// This is named _C since there doesn't seem to be any way to make it visible +// in the SWIG interface without renaming due to the use of the %native +// directive. +PyObject* TFE_Py_FastPathExecute_C(PyObject*, PyObject* args); + // Returns the set of variables watched by the given tape. PyObject* TFE_Py_TapeWatchedVariables(PyObject* tape); diff --git a/tensorflow/python/eager/pywrap_tfe_src.cc b/tensorflow/python/eager/pywrap_tfe_src.cc index 38c3cb2174..a14b4aef5f 100644 --- a/tensorflow/python/eager/pywrap_tfe_src.cc +++ b/tensorflow/python/eager/pywrap_tfe_src.cc @@ -21,12 +21,15 @@ limitations under the License. #include "tensorflow/c/c_api_internal.h" #include "tensorflow/c/eager/c_api_internal.h" #include "tensorflow/c/eager/tape.h" +#include "tensorflow/core/lib/gtl/cleanup.h" #include "tensorflow/core/lib/strings/strcat.h" +#include "tensorflow/core/lib/strings/stringprintf.h" #include "tensorflow/core/platform/mutex.h" #include "tensorflow/core/platform/types.h" #include "tensorflow/python/eager/pywrap_tensor.h" using tensorflow::string; +using tensorflow::strings::Printf; namespace { @@ -289,14 +292,12 @@ bool SetOpAttrScalar(TFE_Context* ctx, TFE_Op* op, const char* key, return true; } -void SetOpAttrs(TFE_Context* ctx, TFE_Op* op, PyObject* attrs, +// start_index is the index at which the Tuple/List attrs will start getting +// processed. +void SetOpAttrs(TFE_Context* ctx, TFE_Op* op, PyObject* attrs, int start_index, TF_Status* out_status) { if (attrs == Py_None) return; - if (!PyTuple_Check(attrs)) { - TF_SetStatus(out_status, TF_INVALID_ARGUMENT, "Expecting an attrs tuple."); - return; - } - Py_ssize_t len = PyTuple_GET_SIZE(attrs); + Py_ssize_t len = PyTuple_GET_SIZE(attrs) - start_index; if ((len & 1) != 0) { TF_SetStatus(out_status, TF_INVALID_ARGUMENT, "Expecting attrs tuple to have even length."); @@ -304,8 +305,8 @@ void SetOpAttrs(TFE_Context* ctx, TFE_Op* op, PyObject* attrs, } // Parse attrs for (Py_ssize_t i = 0; i < len; i += 2) { - PyObject* py_key = PyTuple_GET_ITEM(attrs, i); - PyObject* py_value = PyTuple_GET_ITEM(attrs, i + 1); + PyObject* py_key = PyTuple_GET_ITEM(attrs, start_index + i); + PyObject* py_value = PyTuple_GET_ITEM(attrs, start_index + i + 1); #if PY_MAJOR_VERSION >= 3 const char* key = PyBytes_Check(py_key) ? PyBytes_AsString(py_key) : PyUnicode_AsUTF8(py_key); @@ -329,7 +330,6 @@ PyObject* exception_class GUARDED_BY(exception_class_mutex) = nullptr; static tensorflow::mutex _uid_mutex(tensorflow::LINKER_INITIALIZED); static tensorflow::int64 _uid GUARDED_BY(_uid_mutex) = 0; - } // namespace void TFE_Py_Execute(TFE_Context* ctx, const char* device_name, @@ -346,7 +346,7 @@ void TFE_Py_Execute(TFE_Context* ctx, const char* device_name, } } if (TF_GetCode(out_status) == TF_OK) { - SetOpAttrs(ctx, op, attrs, out_status); + SetOpAttrs(ctx, op, attrs, 0, out_status); } Py_BEGIN_ALLOW_THREADS; if (TF_GetCode(out_status) == TF_OK) { @@ -974,7 +974,6 @@ std::vector MakeTensorList(PyObject* tensors) { return list; } - PyObject* TFE_Py_TapeGradient(PyObject* tape, PyObject* vspace, PyObject* target, PyObject* sources, PyObject* output_gradients, TF_Status* status) { @@ -1029,3 +1028,193 @@ PyObject* TFE_Py_TapeGradient(PyObject* tape, PyObject* vspace, Py_INCREF(Py_None); return Py_None; } + +namespace { +static const int kFastPathExecuteInputStartIndex = 4; + +bool CheckEagerTensors(PyObject* seq, int start_index, int num_to_check) { + for (int i = start_index; i < start_index + num_to_check; i++) { + PyObject* item = PyTuple_GET_ITEM(seq, i); + if (!EagerTensor_CheckExact(item)) return false; + } + + return true; +} + +const tensorflow::OpDef* GetOpDef(PyObject* py_op_name) { + const char* op_name = TFE_GetPythonString(py_op_name); + if (op_name == nullptr) { + PyErr_SetString(PyExc_TypeError, + Printf("expected a string for op_name, got %s instead", + py_op_name->ob_type->tp_name) + .c_str()); + return nullptr; + } + + const tensorflow::OpRegistrationData* op_reg_data = nullptr; + const tensorflow::Status lookup_status = + tensorflow::OpRegistry::Global()->LookUp(op_name, &op_reg_data); + if (MaybeRaiseExceptionFromStatus(lookup_status, nullptr)) { + return nullptr; + } + return &op_reg_data->op_def; +} + +const char* GetDeviceName(PyObject* py_device_name) { + if (py_device_name != Py_None) { + return TFE_GetPythonString(py_device_name); + } + return nullptr; +} + +bool MaybeRunRecordGradientCallback(const tensorflow::OpDef* op_def, + PyObject* args, PyObject* result, + PyObject* record_gradient_callback) { + if (*ThreadTapeIsStopped() || GetTapeSet()->empty() || + record_gradient_callback == Py_None) { + return true; + } + if (!PyCallable_Check(record_gradient_callback)) { + PyErr_SetString( + PyExc_TypeError, + Printf( + "expected a function for record_gradient_callback, got %s instead", + record_gradient_callback->ob_type->tp_name) + .c_str()); + return false; + } + + PyObject* inputs = PyTuple_New(op_def->input_arg_size()); + for (int i = 0; i < op_def->input_arg_size(); i++) { + PyTuple_SET_ITEM( + inputs, i, PyTuple_GET_ITEM(args, kFastPathExecuteInputStartIndex + i)); + } + + int args_size = PyTuple_GET_SIZE(args); + int num_attrs = + args_size - op_def->input_arg_size() - kFastPathExecuteInputStartIndex; + PyObject* attrs = PyTuple_New(num_attrs); + for (int i = 0; i < num_attrs; i++) { + PyTuple_SET_ITEM(attrs, i, + PyTuple_GET_ITEM(args, kFastPathExecuteInputStartIndex + + op_def->input_arg_size() + i)); + } + + PyObject* callback_args = Py_BuildValue("OOO", inputs, attrs, result); + PyObject_CallObject(record_gradient_callback, callback_args); + + Py_DECREF(inputs); + Py_DECREF(callback_args); + Py_DECREF(attrs); + return true; +} +} // namespace + +PyObject* TFE_Py_FastPathExecute_C(PyObject*, PyObject* args) { + TFE_Context* ctx = reinterpret_cast( + PyCapsule_GetPointer(PyTuple_GET_ITEM(args, 0), nullptr)); + const tensorflow::OpDef* op_def = GetOpDef(PyTuple_GET_ITEM(args, 2)); + if (op_def == nullptr) return nullptr; + const char* device_name = GetDeviceName(PyTuple_GET_ITEM(args, 1)); + PyObject* record_gradient_callback = PyTuple_GET_ITEM(args, 3); + + Py_ssize_t args_size = PyTuple_GET_SIZE(args); + if (args_size < kFastPathExecuteInputStartIndex) { + PyErr_SetString( + PyExc_ValueError, + Printf("There must be at least %d items in the input tuple.", + kFastPathExecuteInputStartIndex) + .c_str()); + return nullptr; + } + + if (args_size < kFastPathExecuteInputStartIndex + op_def->input_arg_size()) { + PyErr_SetString( + PyExc_ValueError, + Printf("Tuple size smaller than intended. Expected to be at least %d, " + "was %ld", + kFastPathExecuteInputStartIndex + op_def->input_arg_size(), + args_size) + .c_str()); + return nullptr; + } + + if (!CheckEagerTensors(args, kFastPathExecuteInputStartIndex, + op_def->input_arg_size())) { + // TODO(nareshmodi): Maybe some other way of signalling that this should + // fall back? + PyErr_SetString(PyExc_NotImplementedError, + "This function does not handle the case of the path where " + "all inputs are not already EagerTensors."); + return nullptr; + } + + TF_Status* status = TF_NewStatus(); + TFE_Op* op = TFE_NewOp(ctx, op_def->name().c_str(), status); + auto cleaner = tensorflow::gtl::MakeCleanup([status, op] { + TF_DeleteStatus(status); + TFE_DeleteOp(op); + }); + if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) { + return nullptr; + } + + TFE_OpSetDevice(op, device_name, status); + if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) { + return nullptr; + } + + // Add non-type attrs. + SetOpAttrs(ctx, op, args, + kFastPathExecuteInputStartIndex + op_def->input_arg_size(), + status); + if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) { + return nullptr; + } + + // Add type attrs and inputs. + for (int i = 0; i < op_def->input_arg_size(); i++) { + const auto& input_arg = op_def->input_arg(i); + + PyObject* input = + PyTuple_GET_ITEM(args, kFastPathExecuteInputStartIndex + i); + TFE_TensorHandle* input_handle = EagerTensor_Handle(input); + + // The following code might set duplicate type attrs. This will result in + // the CacheKey for the generated AttrBuilder possibly differing from those + // where the type attrs are correctly set. Inconsistent CacheKeys for ops + // means that there might be unnecessarily duplicated kernels. + // TODO(nareshmodi): Fix this. + if (!input_arg.type_attr().empty()) { + TFE_OpSetAttrType(op, input_arg.type_attr().data(), + TFE_TensorHandleDataType(input_handle)); + } + + TFE_OpAddInput(op, input_handle, status); + if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) { + return nullptr; + } + } + + int num_retvals = op_def->output_arg_size(); + tensorflow::gtl::InlinedVector retvals(num_retvals); + + Py_BEGIN_ALLOW_THREADS; + TFE_Execute(op, retvals.data(), &num_retvals, status); + Py_END_ALLOW_THREADS; + if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) { + return nullptr; + } + + PyObject* result = PyTuple_New(num_retvals); + for (int i = 0; i < num_retvals; ++i) { + PyTuple_SET_ITEM(result, i, EagerTensorFromHandle(retvals[i])); + } + + if (!MaybeRunRecordGradientCallback(op_def, args, result, + record_gradient_callback)) { + return nullptr; + } + + return result; +} diff --git a/tensorflow/python/eager/pywrap_tfe_test.py b/tensorflow/python/eager/pywrap_tfe_test.py new file mode 100644 index 0000000000..d4f4ed592f --- /dev/null +++ b/tensorflow/python/eager/pywrap_tfe_test.py @@ -0,0 +1,109 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for low-level eager execution primitives.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python import pywrap_tensorflow +from tensorflow.python.eager import backprop +from tensorflow.python.eager import context +from tensorflow.python.eager import test +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import random_ops + + +def record_gradient_callback(inputs, attrs, results): + return backprop._record_gradient("MatMul", inputs, attrs, results, None) + + +def c_tfe_py_fastpath_execute(a, b, transpose_a=False, transpose_b=False): + ctx = context.context() + assert not ctx.in_graph_mode( + ), "The prototype doesn't contain C code for graph construction" + ctx_handle = ctx._handle # pylint: disable=protected-access + + return pywrap_tensorflow.TFE_Py_FastPathExecute( + ctx_handle, ctx.device_name, "MatMul", record_gradient_callback, a, b, + "transpose_a", transpose_a, "transpose_b", transpose_b)[0] + + +class Tests(test.TestCase): + + @test_util.assert_no_new_tensors + @test_util.assert_no_garbage_created + def testFastpathExecute_MatMulCorrectResponse(self): + a_2_by_2 = random_ops.random_uniform((2, 2)) + b_2_by_2 = random_ops.random_uniform((2, 2)) + + a_100_by_784 = random_ops.random_uniform((100, 784)) + b_100_by_784 = random_ops.random_uniform((100, 784)) + + self.assertAllClose( + math_ops.matmul(a_2_by_2, b_2_by_2), + c_tfe_py_fastpath_execute(a_2_by_2, b_2_by_2)) + self.assertAllClose( + math_ops.matmul(a_100_by_784, b_100_by_784, transpose_b=True), + c_tfe_py_fastpath_execute(a_100_by_784, b_100_by_784, transpose_b=True)) + + @test_util.assert_no_new_tensors + @test_util.assert_no_garbage_created + def testFastpathExecute_TapeWrite(self): + with backprop.GradientTape(persistent=True) as tape: + a_2_by_2 = constant_op.constant(1.0, shape=[2, 2]) + tape.watch(a_2_by_2) + z = c_tfe_py_fastpath_execute(a_2_by_2, a_2_by_2) + dz_dy = tape.gradient(z, [a_2_by_2])[0] + self.assertAllEqual(dz_dy.numpy(), + constant_op.constant(4.0, shape=[2, 2]).numpy()) + + @test_util.assert_no_new_tensors + @test_util.assert_no_garbage_created + def testFastpathExecute_MatMulSlowPath(self): + a_2_by_2 = random_ops.random_uniform((2, 2)).cpu().numpy() + + with self.assertRaises(NotImplementedError): + c_tfe_py_fastpath_execute(a_2_by_2, a_2_by_2) + + @test_util.assert_no_new_tensors + @test_util.assert_no_garbage_created + def testFastpathExecute_InvalidInputs(self): + a_2_by_2 = random_ops.random_uniform((2, 2)) + ctx = context.context() + assert not ctx.in_graph_mode( + ), "The prototype doesn't contain C code for graph construction" + ctx_handle = ctx._handle # pylint: disable=protected-access + + with self.assertRaisesRegexp(ValueError, + "at least 4 items in the input tuple"): + pywrap_tensorflow.TFE_Py_FastPathExecute(ctx_handle, ctx.device_name, + "Identity") + + with self.assertRaisesRegexp(ValueError, + "Expected to be at least 5, was 4"): + pywrap_tensorflow.TFE_Py_FastPathExecute( + ctx_handle, ctx_handle, "Identity", record_gradient_callback) + + with self.assertRaisesRegexp(TypeError, "expected a string for op_name"): + pywrap_tensorflow.TFE_Py_FastPathExecute( + ctx_handle, ctx.device_name, ctx_handle, record_gradient_callback, + a_2_by_2) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/pywrap_tfe.i b/tensorflow/python/pywrap_tfe.i index 083931aa83..de0e5856ff 100644 --- a/tensorflow/python/pywrap_tfe.i +++ b/tensorflow/python/pywrap_tfe.i @@ -28,6 +28,7 @@ limitations under the License. %rename("%s") TFE_Py_InitEagerTensor; %rename("%s") TFE_Py_RegisterExceptionClass; %rename("%s") TFE_Py_Execute; +%rename("%s") TFE_Py_FastPathExecute; %rename("%s") TFE_Py_UID; %rename("%s") TFE_Py_TapeSetNew; %rename("%s") TFE_Py_TapeSetRemove; @@ -155,7 +156,7 @@ limitations under the License. } $1 = &temp; $1->resize(PyInt_AsLong($input), nullptr); -} +} // Create new Status object. %typemap(in, numinputs=0) TF_Status *out_status { @@ -180,10 +181,14 @@ limitations under the License. } } +// SWIG usually unwraps the tuple that the native Python/C interface generates. +// Since we wanted to have a function with a variable length of arguments, we +// used the native Python/C interface directly (which by default supports +// passing all arguments as a tuple). +%native(TFE_Py_FastPathExecute) TFE_Py_FastPathExecute_C; %include "tensorflow/python/eager/pywrap_tfe.h" - // Clear all typemaps. %typemap(out) TF_DataType; %typemap(out) int64_t; -- GitLab From ad01defc7edaf4a644f17ec904ab68fd7ab42e35 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Mon, 22 Jan 2018 09:47:55 -0800 Subject: [PATCH 047/258] mnist and resnet eager examples avoiding optimizer.minimize PiperOrigin-RevId: 182792844 --- .../eager/python/examples/mnist/mnist.py | 22 ++++++++----------- .../python/examples/resnet50/resnet50_test.py | 7 +++--- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/tensorflow/contrib/eager/python/examples/mnist/mnist.py b/tensorflow/contrib/eager/python/examples/mnist/mnist.py index 82b3d3919c..2a7be95811 100644 --- a/tensorflow/contrib/eager/python/examples/mnist/mnist.py +++ b/tensorflow/contrib/eager/python/examples/mnist/mnist.py @@ -23,7 +23,6 @@ from __future__ import division from __future__ import print_function import argparse -import functools import os import sys import time @@ -124,21 +123,18 @@ def train_one_epoch(model, optimizer, dataset, log_interval=None): tf.train.get_or_create_global_step() - def model_loss(labels, images): - prediction = model(images, training=True) - loss_value = loss(prediction, labels) - tf.contrib.summary.scalar('loss', loss_value) - tf.contrib.summary.scalar('accuracy', - compute_accuracy(prediction, labels)) - return loss_value - for (batch, (images, labels)) in enumerate(tfe.Iterator(dataset)): with tf.contrib.summary.record_summaries_every_n_global_steps(10): - batch_model_loss = functools.partial(model_loss, labels, images) - optimizer.minimize( - batch_model_loss, global_step=tf.train.get_global_step()) + with tfe.GradientTape() as tape: + prediction = model(images, training=True) + loss_value = loss(prediction, labels) + tf.contrib.summary.scalar('loss', loss_value) + tf.contrib.summary.scalar('accuracy', + compute_accuracy(prediction, labels)) + grads = tape.gradient(loss_value, model.variables) + optimizer.apply_gradients(zip(grads, model.variables)) if log_interval and batch % log_interval == 0: - print('Batch #%d\tLoss: %.6f' % (batch, batch_model_loss())) + print('Batch #%d\tLoss: %.6f' % (batch, loss_value)) def test(model, dataset): diff --git a/tensorflow/contrib/eager/python/examples/resnet50/resnet50_test.py b/tensorflow/contrib/eager/python/examples/resnet50/resnet50_test.py index e2ae665a74..76e06269b6 100644 --- a/tensorflow/contrib/eager/python/examples/resnet50/resnet50_test.py +++ b/tensorflow/contrib/eager/python/examples/resnet50/resnet50_test.py @@ -52,14 +52,13 @@ def random_batch(batch_size): def train_one_step(model, images, labels, optimizer): - def model_loss(): + with tfe.GradientTape() as tape: logits = model(images, training=True) loss = tf.losses.softmax_cross_entropy( logits=logits, onehot_labels=labels) tf.contrib.summary.scalar(name='loss', tensor=loss) - return loss - - optimizer.minimize(model_loss) + grads = tape.gradient(loss, model.variables) + optimizer.apply_gradients(zip(grads, model.variables)) class ResNet50Test(tf.test.TestCase): -- GitLab From 066e356ce931d72bc582f98979d2d4e2f54eb105 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 10:19:07 -0800 Subject: [PATCH 048/258] Internal change PiperOrigin-RevId: 182797605 --- tensorflow/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/BUILD b/tensorflow/BUILD index 240a092ef0..84ef1447dd 100644 --- a/tensorflow/BUILD +++ b/tensorflow/BUILD @@ -376,6 +376,7 @@ package_group( "//learning/meta_rank/...", "//tensorflow/...", "//tensorflow_fold/llgtm/...", + "//third_party/py/tensor2tensor/...", ], ) -- GitLab From 25edaf3bf2e690a587f439ee0028af6aeace71a7 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 10:36:05 -0800 Subject: [PATCH 049/258] Allow whitespace after commas in hparam strings. E.g., allow 'a=b, c=d' or 'a=b,\nc=d' in addition to just 'a=b,c=d'. PiperOrigin-RevId: 182800230 --- tensorflow/contrib/training/python/training/hparam.py | 2 +- tensorflow/contrib/training/python/training/hparam_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/training/python/training/hparam.py b/tensorflow/contrib/training/python/training/hparam.py index 80de0f6eb7..fdfd27d6a4 100644 --- a/tensorflow/contrib/training/python/training/hparam.py +++ b/tensorflow/contrib/training/python/training/hparam.py @@ -40,7 +40,7 @@ PARAM_RE = re.compile(r""" ((?P[^,\[]*) # single value: "a" or None | \[(?P[^\]]*)\]) # list of values: None or "1,2,3" - ($|,)""", re.VERBOSE) + ($|,\s*)""", re.VERBOSE) def _parse_fail(name, var_type, value, values): diff --git a/tensorflow/contrib/training/python/training/hparam_test.py b/tensorflow/contrib/training/python/training/hparam_test.py index 28e4b4d01e..16397622ed 100644 --- a/tensorflow/contrib/training/python/training/hparam_test.py +++ b/tensorflow/contrib/training/python/training/hparam_test.py @@ -55,7 +55,7 @@ class HParamsTest(test.TestCase): self.assertEqual(12, hparams.aaa) self.assertEqual(2.0, hparams.b) self.assertEqual('relu6', hparams.c_c) - hparams.parse('c_c=relu4,b=-2.0e10') + hparams.parse('c_c=relu4, b=-2.0e10') self.assertDictEqual({ 'aaa': 12, 'b': -2.0e10, -- GitLab From d18f54b97ef678602e1ac91fdf4f997d0d057890 Mon Sep 17 00:00:00 2001 From: Yu-Cheng Ling Date: Mon, 22 Jan 2018 10:48:20 -0800 Subject: [PATCH 050/258] Fix TFLite Conv reference implementation PiperOrigin-RevId: 182802058 --- tensorflow/contrib/lite/kernels/conv.cc | 29 +++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tensorflow/contrib/lite/kernels/conv.cc b/tensorflow/contrib/lite/kernels/conv.cc index c75c04baea..37f499a4d0 100644 --- a/tensorflow/contrib/lite/kernels/conv.cc +++ b/tensorflow/contrib/lite/kernels/conv.cc @@ -322,22 +322,23 @@ void EvalFloat(TfLiteContext* context, TfLiteNode* node, CalculateActivationRangeFloat(params->activation, &output_activation_min, &output_activation_max); - const float* filter_data; - if (data->need_hwcn_weights) { - filter_data = GetTensorData(hwcn_weights); - } else { - filter_data = GetTensorData(filter); - } - if (kernel_type == kReference) { - reference_ops::Conv( - GetTensorData(input), GetTensorDims(input), filter_data, - GetTensorDims(filter), GetTensorData(bias), GetTensorDims(bias), - params->stride_width, params->stride_height, data->padding.width, - data->padding.height, output_activation_min, output_activation_max, - GetTensorData(output), GetTensorDims(output), - GetTensorData(im2col), GetTensorDims(im2col)); + reference_ops::Conv(GetTensorData(input), GetTensorDims(input), + GetTensorData(filter), GetTensorDims(filter), + GetTensorData(bias), GetTensorDims(bias), + params->stride_width, params->stride_height, + data->padding.width, data->padding.height, + output_activation_min, output_activation_max, + GetTensorData(output), GetTensorDims(output), + GetTensorData(im2col), GetTensorDims(im2col)); } else { + const float* filter_data; + if (data->need_hwcn_weights) { + filter_data = GetTensorData(hwcn_weights); + } else { + filter_data = GetTensorData(filter); + } + multithreaded_ops::Conv( GetTensorData(input), GetTensorDims(input), filter_data, GetTensorDims(filter), GetTensorData(bias), GetTensorDims(bias), -- GitLab From a93f40737d3a75ca81d679b531a5d210cbb64d28 Mon Sep 17 00:00:00 2001 From: Shanqing Cai Date: Mon, 22 Jan 2018 11:02:40 -0800 Subject: [PATCH 051/258] tf.keras recurrent Layers: Fix doc strings on default activations * The default activation for input is `tanh`, not `linear`, as the previous doc string might mislead readers to think. * Also clarify that the default activation for recurrent is `hard_sigmoid`. PiperOrigin-RevId: 182804493 --- .../keras/_impl/keras/layers/recurrent.py | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/tensorflow/python/keras/_impl/keras/layers/recurrent.py b/tensorflow/python/keras/_impl/keras/layers/recurrent.py index 6e38cf2f41..9ea21c9c36 100644 --- a/tensorflow/python/keras/_impl/keras/layers/recurrent.py +++ b/tensorflow/python/keras/_impl/keras/layers/recurrent.py @@ -790,7 +790,8 @@ class SimpleRNNCell(Layer): units: Positive integer, dimensionality of the output space. activation: Activation function to use (see [activations](../activations.md)). - If you pass None, no activation is applied + Default: hyperbolic tangent (`tanh`). + If you pass `None`, no activation is applied (ie. "linear" activation: `a(x) = x`). use_bias: Boolean, whether the layer uses a bias vector. kernel_initializer: Initializer for the `kernel` weights matrix, @@ -946,7 +947,8 @@ class SimpleRNN(RNN): units: Positive integer, dimensionality of the output space. activation: Activation function to use (see [activations](../activations.md)). - If you pass None, no activation is applied + Default: hyperbolic tangent (`tanh`). + If you pass `None`, no activation is applied (ie. "linear" activation: `a(x) = x`). use_bias: Boolean, whether the layer uses a bias vector. kernel_initializer: Initializer for the `kernel` weights matrix, @@ -1155,11 +1157,15 @@ class GRUCell(Layer): units: Positive integer, dimensionality of the output space. activation: Activation function to use (see [activations](../activations.md)). - If you pass None, no activation is applied + Default: hyperbolic tangent (`tanh`). + If you pass `None`, no activation is applied (ie. "linear" activation: `a(x) = x`). recurrent_activation: Activation function to use for the recurrent step (see [activations](../activations.md)). + Default: hard sigmoid (`hard_sigmoid`). + If you pass `None`, no activation is applied + (ie. "linear" activation: `a(x) = x`). use_bias: Boolean, whether the layer uses a bias vector. kernel_initializer: Initializer for the `kernel` weights matrix, used for the linear transformation of the inputs. @@ -1392,11 +1398,15 @@ class GRU(RNN): units: Positive integer, dimensionality of the output space. activation: Activation function to use (see [activations](../activations.md)). - If you pass None, no activation is applied + Default: hyperbolic tangent (`tanh`). + If you pass `None`, no activation is applied (ie. "linear" activation: `a(x) = x`). recurrent_activation: Activation function to use for the recurrent step (see [activations](../activations.md)). + Default: hard sigmoid (`hard_sigmoid`). + If you pass `None`, no activation is applied + (ie. "linear" activation: `a(x) = x`). use_bias: Boolean, whether the layer uses a bias vector. kernel_initializer: Initializer for the `kernel` weights matrix, used for the linear transformation of the inputs. @@ -1630,11 +1640,15 @@ class LSTMCell(Layer): units: Positive integer, dimensionality of the output space. activation: Activation function to use (see [activations](../activations.md)). - If you pass None, no activation is applied + Default: hyperbolic tangent (`tanh`). + If you pass `None`, no activation is applied (ie. "linear" activation: `a(x) = x`). recurrent_activation: Activation function to use for the recurrent step (see [activations](../activations.md)). + Default: hard sigmoid (`hard_sigmoid`). + If you pass `None`, no activation is applied + (ie. "linear" activation: `a(x) = x`). use_bias: Boolean, whether the layer uses a bias vector. kernel_initializer: Initializer for the `kernel` weights matrix, used for the linear transformation of the inputs. @@ -1896,11 +1910,16 @@ class LSTM(RNN): units: Positive integer, dimensionality of the output space. activation: Activation function to use (see [activations](../activations.md)). - If you pass None, no activation is applied + Default: hyperbolic tangent (`tanh`). + If you pass `None`, no activation is applied (ie. "linear" activation: `a(x) = x`). recurrent_activation: Activation function to use for the recurrent step (see [activations](../activations.md)). + Default: hyperbolic tangent (`tanh`). + Default: hard sigmoid (`hard_sigmoid`). + If you pass `None`, no activation is applied + (ie. "linear" activation: `a(x) = x`). use_bias: Boolean, whether the layer uses a bias vector. kernel_initializer: Initializer for the `kernel` weights matrix, used for the linear transformation of the inputs. -- GitLab From 436cac9a5bfee30f1dd8ea0773000153e920cc0c Mon Sep 17 00:00:00 2001 From: Yifei Feng Date: Mon, 22 Jan 2018 11:07:28 -0800 Subject: [PATCH 052/258] Add support for tf.Example to saved_model_cli. You can now pass tf.Example as inputs to with option --input_examples, for example: --input_examples 'input_key=[{"age":[25],"education":["11th"]}]' PiperOrigin-RevId: 182805401 --- .../docs_src/programmers_guide/saved_model.md | 17 ++- tensorflow/python/tools/saved_model_cli.py | 108 +++++++++++++++--- .../python/tools/saved_model_cli_test.py | 75 ++++++++++-- 3 files changed, 172 insertions(+), 28 deletions(-) diff --git a/tensorflow/docs_src/programmers_guide/saved_model.md b/tensorflow/docs_src/programmers_guide/saved_model.md index fa7a94cc06..9f50be5b31 100644 --- a/tensorflow/docs_src/programmers_guide/saved_model.md +++ b/tensorflow/docs_src/programmers_guide/saved_model.md @@ -736,6 +736,7 @@ The `run` command provides the following two ways to pass inputs to the model: * `--inputs` option enables you to pass numpy ndarray in files. * `--input_exprs` option enables you to pass Python expressions. +* `--input_examples` option enables you to pass `tf.train.Example`. #### `--inputs` @@ -789,19 +790,31 @@ inputs that match the dtype and shape of the model's `SignatureDef`s. For example: ```bsh -`input_key=[[1], [2], [3]]` +`=[[1],[2],[3]]` ``` In addition to Python expressions, you may also pass numpy functions. For example: ```bsh -input_key=np.ones((32, 32, 3)) +`=np.ones((32,32,3))` ``` (Note that the `numpy` module is already available to you as `np`.) +#### `--inputs_examples` + +To pass `tf.train.Example` as inputs, specify the `--input_examples` option. +For each input key, it takes a list of dictionary, where each dictionary is an +instance of `tf.train.Example`. The dictionary keys are the features and the +values are the value lists for each feature. +For example: + +```bsh +`=[{"age":[22,24],"education":["BS","MS"]}]` +``` + #### Save Output By default, the SavedModel CLI writes output to stdout. If a directory is diff --git a/tensorflow/python/tools/saved_model_cli.py b/tensorflow/python/tools/saved_model_cli.py index ce64fdf709..21e8e803fc 100644 --- a/tensorflow/python/tools/saved_model_cli.py +++ b/tensorflow/python/tools/saved_model_cli.py @@ -33,6 +33,7 @@ import numpy as np from tensorflow.contrib.saved_model.python.saved_model import reader from tensorflow.contrib.saved_model.python.saved_model import signature_def_utils +from tensorflow.core.example import example_pb2 from tensorflow.core.framework import types_pb2 from tensorflow.python.client import session from tensorflow.python.debug.wrappers import local_cli_wrapper @@ -377,7 +378,7 @@ def preprocess_input_exprs_arg_string(input_exprs_str): 'input_key=' Returns: - A dictionary that maps input keys to python expressions. + A dictionary that maps input keys to their values. Raises: RuntimeError: An error when the given input string is in a bad format. @@ -388,17 +389,75 @@ def preprocess_input_exprs_arg_string(input_exprs_str): if '=' not in input_exprs_str: raise RuntimeError('--input_exprs "%s" format is incorrect. Please follow' '"="' % input_exprs_str) - input_key, expr = input_raw.split('=') - input_dict[input_key] = expr + input_key, expr = input_raw.split('=', 1) + # ast.literal_eval does not work with numpy expressions + input_dict[input_key] = eval(expr) # pylint: disable=eval-used + return input_dict + +def preprocess_input_examples_arg_string(input_examples_str): + """Parses input into dict that maps input keys to lists of tf.Example. + + Parses input string in the format of 'input_key1=[{feature_name: + feature_list}];input_key2=[{feature_name:feature_list}];' into a dictionary + that maps each input_key to its list of serialized tf.Example. + + Args: + input_examples_str: A string that specifies a list of dictionaries of + feature_names and their feature_lists for each input. + Each input is separated by semicolon. For each input key: + 'input=[{feature_name1: feature_list1, feature_name2:feature_list2}]' + items in feature_list can be the type of float, int, long or str. + + Returns: + A dictionary that maps input keys to lists of serialized tf.Example. + + Raises: + ValueError: An error when the given tf.Example is not a list. + """ + input_dict = preprocess_input_exprs_arg_string(input_examples_str) + for input_key, example_list in input_dict.items(): + if not isinstance(example_list, list): + raise ValueError( + 'tf.Example input must be a list of dictionaries, but "%s" is %s' % + (example_list, type(example_list))) + input_dict[input_key] = [ + _create_example_string(example) for example in example_list + ] return input_dict -def load_inputs_from_input_arg_string(inputs_str, input_exprs_str): +def _create_example_string(example_dict): + """Create a serialized tf.example from feature dictionary.""" + example = example_pb2.Example() + for feature_name, feature_list in example_dict.items(): + if not isinstance(feature_list, list): + raise ValueError('feature value must be a list, but %s: "%s" is %s' % + (feature_name, feature_list, type(feature_list))) + if isinstance(feature_list[0], float): + example.features.feature[feature_name].float_list.value.extend( + feature_list) + elif isinstance(feature_list[0], str): + example.features.feature[feature_name].bytes_list.value.extend( + feature_list) + elif isinstance(feature_list[0], (int, long)): + example.features.feature[feature_name].int64_list.value.extend( + feature_list) + else: + raise ValueError( + 'Type %s for value %s is not supported for tf.train.Feature.' % + (type(feature_list[0]), feature_list[0])) + return example.SerializeToString() + + +def load_inputs_from_input_arg_string(inputs_str, input_exprs_str, + input_examples_str): """Parses input arg strings and create inputs feed_dict. Parses '--inputs' string for inputs to be loaded from file, and parses '--input_exprs' string for inputs to be evaluated from python expression. + '--input_examples' string for inputs to be created from tf.example feature + dictionary list. Args: inputs_str: A string that specified where to load inputs. Each input is @@ -424,9 +483,11 @@ def load_inputs_from_input_arg_string(inputs_str, input_exprs_str): to the specified input tensor, else SavedModel CLI will assume a dictionary is stored in the pickle file and the value corresponding to the variable_name will be used. - input_exprs_str: A string that specified python expressions for inputs. + input_exprs_str: A string that specifies python expressions for inputs. * In the format of: '='. * numpy module is available as np. + input_examples_str: A string that specifies tf.Example with dictionary. + * In the format of: '=<[{feature:value list}]>' Returns: A dictionary that maps input tensor keys to numpy ndarrays. @@ -441,6 +502,7 @@ def load_inputs_from_input_arg_string(inputs_str, input_exprs_str): inputs = preprocess_inputs_arg_string(inputs_str) input_exprs = preprocess_input_exprs_arg_string(input_exprs_str) + input_examples = preprocess_input_examples_arg_string(input_examples_str) for input_tensor_key, (filename, variable_name) in inputs.items(): data = np.load(filename) @@ -474,15 +536,20 @@ def load_inputs_from_input_arg_string(inputs_str, input_exprs_str): tensor_key_feed_dict[input_tensor_key] = data # When input is a python expression: - for input_tensor_key, py_expr in input_exprs.items(): + for input_tensor_key, py_expr_evaluated in input_exprs.items(): if input_tensor_key in tensor_key_feed_dict: warnings.warn( 'input_key %s has been specified with both --inputs and --input_exprs' ' options. Value in --input_exprs will be used.' % input_tensor_key) + tensor_key_feed_dict[input_tensor_key] = py_expr_evaluated - # ast.literal_eval does not work with numpy expressions - tensor_key_feed_dict[input_tensor_key] = eval(py_expr) # pylint: disable=eval-used - + # When input is a tf.Example: + for input_tensor_key, example in input_examples.items(): + if input_tensor_key in tensor_key_feed_dict: + warnings.warn( + 'input_key %s has been specified in multiple options. Value in ' + '--input_examples will be used.' % input_tensor_key) + tensor_key_feed_dict[input_tensor_key] = example return tensor_key_feed_dict @@ -518,11 +585,12 @@ def run(args): AttributeError: An error when neither --inputs nor --input_exprs is passed to run command. """ - if not args.inputs and not args.input_exprs: + if not args.inputs and not args.input_exprs and not args.input_examples: raise AttributeError( - 'At least one of --inputs and --input_exprs must be required') + 'At least one of --inputs, --input_exprs or --input_examples must be ' + 'required') tensor_key_feed_dict = load_inputs_from_input_arg_string( - args.inputs, args.input_exprs) + args.inputs, args.input_exprs, args.input_examples) run_saved_model_with_feed_dict(args.dir, args.tag_set, args.signature_def, tensor_key_feed_dict, args.outdir, args.overwrite, tf_debug=args.tf_debug) @@ -589,10 +657,12 @@ def create_parser(): run_msg = ('Usage example:\n' 'To run input tensors from files through a MetaGraphDef and save' ' the output tensors to files:\n' - '$saved_model_cli show --dir /tmp/saved_model --tag_set serve' + '$saved_model_cli show --dir /tmp/saved_model --tag_set serve ' '--signature_def serving_default ' - '--inputs input1_key=/tmp/124.npz[x],input2_key=/tmp/123.npy' - '--input_exprs \'input3_key=np.ones(2)\' --outdir=/out\n\n' + '--inputs input1_key=/tmp/124.npz[x],input2_key=/tmp/123.npy ' + '--input_exprs \'input3_key=np.ones(2)\' --input_examples ' + '\'input4_key=[{"id":[26],"weights":[0.5, 0.5]}]\' ' + '--outdir=/out\n\n' 'For more information about input file format, please see:\n' 'https://www.tensorflow.org/programmers_guide/saved_model_cli\n') parser_run = subparsers.add_parser( @@ -620,8 +690,14 @@ def create_parser(): msg = ('Specifying inputs by python expressions, in the format of' ' "=\'\'", separated by \';\'. ' 'numpy module is available as \'np\'. ' - 'Will override duplicate input_keys from --inputs option.') + 'Will override duplicate input keys from --inputs option.') parser_run.add_argument('--input_exprs', type=str, default='', help=msg) + msg = ( + 'Specifying tf.Example inputs as list of dictionaries. For example: ' + '=[{feature0:value_list,feature1:value_list}]. Use ";" to ' + 'separate input keys. Will override duplicate input keys from --inputs ' + 'and --input_exprs option.') + parser_run.add_argument('--input_examples', type=str, default='', help=msg) parser_run.add_argument( '--outdir', type=str, diff --git a/tensorflow/python/tools/saved_model_cli_test.py b/tensorflow/python/tools/saved_model_cli_test.py index 0789e1e107..d6cbc49ba1 100644 --- a/tensorflow/python/tools/saved_model_cli_test.py +++ b/tensorflow/python/tools/saved_model_cli_test.py @@ -218,8 +218,9 @@ Method name is: tensorflow/serving/predict""" input_expr_str) self.assertTrue(input_dict['input1'] == ('/path/file.txt', 'ab3')) self.assertTrue(input_dict['input2'] == ('file2', None)) - self.assertTrue(input_expr_dict['input3'] == 'np.zeros([2,2])') - self.assertTrue(input_expr_dict['input4'] == '[4,5]') + print(input_expr_dict['input3']) + self.assertAllClose(input_expr_dict['input3'], np.zeros([2, 2])) + self.assertAllClose(input_expr_dict['input4'], [4, 5]) self.assertTrue(len(input_dict) == 2) self.assertTrue(len(input_expr_dict) == 2) @@ -250,7 +251,8 @@ Method name is: tensorflow/serving/predict""" np.save(input0_path, x0) np.save(input1_path, x1) input_str = 'x0=' + input0_path + '[x0];x1=' + input1_path - feed_dict = saved_model_cli.load_inputs_from_input_arg_string(input_str, '') + feed_dict = saved_model_cli.load_inputs_from_input_arg_string( + input_str, '', '') self.assertTrue(np.all(feed_dict['x0'] == x0)) self.assertTrue(np.all(feed_dict['x1'] == x1)) @@ -259,7 +261,8 @@ Method name is: tensorflow/serving/predict""" input_path = os.path.join(test.get_temp_dir(), 'input.npz') np.savez(input_path, a=x0) input_str = 'x=' + input_path + '[a];y=' + input_path - feed_dict = saved_model_cli.load_inputs_from_input_arg_string(input_str, '') + feed_dict = saved_model_cli.load_inputs_from_input_arg_string( + input_str, '', '') self.assertTrue(np.all(feed_dict['x'] == x0)) self.assertTrue(np.all(feed_dict['y'] == x0)) @@ -278,7 +281,8 @@ Method name is: tensorflow/serving/predict""" pickle.dump(pkl2, f) input_str = 'x=' + input_path0 + '[b];y=' + input_path1 + '[c];' input_str += 'z=' + input_path2 - feed_dict = saved_model_cli.load_inputs_from_input_arg_string(input_str, '') + feed_dict = saved_model_cli.load_inputs_from_input_arg_string( + input_str, '', '') self.assertTrue(np.all(feed_dict['x'] == pkl0['b'])) self.assertTrue(np.all(feed_dict['y'] == pkl1)) self.assertTrue(np.all(feed_dict['z'] == pkl2)) @@ -291,7 +295,7 @@ Method name is: tensorflow/serving/predict""" input_expr_str = ('x1=np.ones([2,10]);x2=np.array([[1],[2],[3]]);' 'x3=np.mgrid[0:5,0:5];x4=[[3],[4]]') feed_dict = saved_model_cli.load_inputs_from_input_arg_string( - '', input_expr_str) + '', input_expr_str, '') self.assertTrue(np.all(feed_dict['x1'] == x1)) self.assertTrue(np.all(feed_dict['x2'] == x2)) self.assertTrue(np.all(feed_dict['x3'] == x3)) @@ -305,7 +309,7 @@ Method name is: tensorflow/serving/predict""" input_str = 'x0=' + input_path + '[a]' input_expr_str = 'x1=np.ones([2,10])' feed_dict = saved_model_cli.load_inputs_from_input_arg_string( - input_str, input_expr_str) + input_str, input_expr_str, '') self.assertTrue(np.all(feed_dict['x0'] == x0)) self.assertTrue(np.all(feed_dict['x1'] == x1)) @@ -317,7 +321,7 @@ Method name is: tensorflow/serving/predict""" input_str = 'x0=' + input_path + '[a]' input_expr_str = 'x0=np.ones([2,10])' feed_dict = saved_model_cli.load_inputs_from_input_arg_string( - input_str, input_expr_str) + input_str, input_expr_str, '') self.assertTrue(np.all(feed_dict['x0'] == x1)) def testInputParserErrorNoName(self): @@ -327,7 +331,7 @@ Method name is: tensorflow/serving/predict""" np.savez(input_path, a=x0, b=x1) input_str = 'x=' + input_path with self.assertRaises(RuntimeError): - saved_model_cli.load_inputs_from_input_arg_string(input_str, '') + saved_model_cli.load_inputs_from_input_arg_string(input_str, '', '') def testInputParserErrorWrongName(self): x0 = np.array([[1], [2]]) @@ -336,7 +340,22 @@ Method name is: tensorflow/serving/predict""" np.savez(input_path, a=x0, b=x1) input_str = 'x=' + input_path + '[c]' with self.assertRaises(RuntimeError): - saved_model_cli.load_inputs_from_input_arg_string(input_str, '') + saved_model_cli.load_inputs_from_input_arg_string(input_str, '', '') + + def testRunCommandInputExamples(self): + self.parser = saved_model_cli.create_parser() + base_path = test.test_src_dir_path(SAVED_MODEL_PATH) + output_dir = os.path.join(test.get_temp_dir(), 'new_dir') + args = self.parser.parse_args([ + 'run', '--dir', base_path, '--tag_set', 'serve', '--signature_def', + 'regress_x_to_y', '--input_examples', + 'inputs=[{"x":[8.0],"x2":[5.0]}, {"x":[4.0],"x2":[3.0]}]', '--outdir', + output_dir + ]) + saved_model_cli.run(args) + y_actual = np.load(os.path.join(output_dir, 'outputs.npy')) + y_expected = np.array([[6.0], [4.0]]) + self.assertAllEqual(y_expected, y_actual) def testRunCommandExistingOutdir(self): self.parser = saved_model_cli.create_parser() @@ -410,6 +429,42 @@ Method name is: tensorflow/serving/predict""" with self.assertRaises(ValueError): saved_model_cli.run(args) + def testRunCommandInputExamplesNotListError(self): + self.parser = saved_model_cli.create_parser() + base_path = test.test_src_dir_path(SAVED_MODEL_PATH) + output_dir = os.path.join(test.get_temp_dir(), 'new_dir') + args = self.parser.parse_args([ + 'run', '--dir', base_path, '--tag_set', 'serve', '--signature_def', + 'regress_x_to_y', '--input_examples', 'inputs={"x":8.0,"x2":5.0}', + '--outdir', output_dir + ]) + with self.assertRaisesRegexp(ValueError, 'must be a list'): + saved_model_cli.run(args) + + def testRunCommandInputExamplesFeatureValueNotListError(self): + self.parser = saved_model_cli.create_parser() + base_path = test.test_src_dir_path(SAVED_MODEL_PATH) + output_dir = os.path.join(test.get_temp_dir(), 'new_dir') + args = self.parser.parse_args([ + 'run', '--dir', base_path, '--tag_set', 'serve', '--signature_def', + 'regress_x_to_y', '--input_examples', 'inputs=[{"x":8.0,"x2":5.0}]', + '--outdir', output_dir + ]) + with self.assertRaisesRegexp(ValueError, 'feature value must be a list'): + saved_model_cli.run(args) + + def testRunCommandInputExamplesFeatureBadType(self): + self.parser = saved_model_cli.create_parser() + base_path = test.test_src_dir_path(SAVED_MODEL_PATH) + output_dir = os.path.join(test.get_temp_dir(), 'new_dir') + args = self.parser.parse_args([ + 'run', '--dir', base_path, '--tag_set', 'serve', '--signature_def', + 'regress_x_to_y', '--input_examples', 'inputs=[{"x":[[1],[2]]}]', + '--outdir', output_dir + ]) + with self.assertRaisesRegexp(ValueError, 'is not supported'): + saved_model_cli.run(args) + def testRunCommandOutputFileExistError(self): self.parser = saved_model_cli.create_parser() base_path = test.test_src_dir_path(SAVED_MODEL_PATH) -- GitLab From 8451cee9722f11b3d28d234e2c383d59562eec15 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 11:18:44 -0800 Subject: [PATCH 053/258] Add new src targets for C API and native TF PiperOrigin-RevId: 182807258 --- tensorflow/c/BUILD | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tensorflow/c/BUILD b/tensorflow/c/BUILD index f258bcd956..c46cb32aa4 100644 --- a/tensorflow/c/BUILD +++ b/tensorflow/c/BUILD @@ -26,6 +26,18 @@ filegroup( visibility = ["//tensorflow:__subpackages__"], ) +filegroup( + name = "srcs", + srcs = glob( + [ + "*.cc", + "*.h", + ], + exclude = ["*test*"], + ), + visibility = ["//visibility:public"], +) + tf_cuda_library( name = "c_api_internal", srcs = ["c_api.h"], -- GitLab From 398852bb70a64a03465cb712a9616a0d56c4c3de Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 11:27:33 -0800 Subject: [PATCH 054/258] Extend the API with a pair of decorators that can convert functions inline. Add logic to detect these decorators and treat them appropriately (e.g. when converting recursively, do all decorated functions as they are). PiperOrigin-RevId: 182808673 --- tensorflow/contrib/py2tf/api.py | 134 ++++++++++++++++- tensorflow/contrib/py2tf/api_test.py | 140 +++++++++++++++++- tensorflow/contrib/py2tf/conversion.py | 54 +++++-- tensorflow/contrib/py2tf/conversion_test.py | 6 +- tensorflow/contrib/py2tf/convert/BUILD | 1 + .../contrib/py2tf/convert/call_trees.py | 109 ++++++++++++-- .../contrib/py2tf/convert/call_trees_test.py | 6 +- .../contrib/py2tf/convert/decorators.py | 56 +++++++ tensorflow/contrib/py2tf/naming.py | 9 +- tensorflow/contrib/py2tf/naming_test.py | 12 +- 10 files changed, 477 insertions(+), 50 deletions(-) create mode 100644 tensorflow/contrib/py2tf/convert/decorators.py diff --git a/tensorflow/contrib/py2tf/api.py b/tensorflow/contrib/py2tf/api.py index 3a36720969..9a2b70c53c 100644 --- a/tensorflow/contrib/py2tf/api.py +++ b/tensorflow/contrib/py2tf/api.py @@ -18,6 +18,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from functools import wraps + import gast import six @@ -32,7 +34,111 @@ from tensorflow.python.util import tf_inspect # (currently we require (module + class name, type)) -def to_graph(o, arg_value_hints=None): +def graph_ready(f): + """No-op decorator that explicitly marks a function as graph-ready. + + Graph-ready functions are assumed to not need any conversion. + + Args: + f: Any callable. + Returns: + f itself. + """ + setattr(f, '__pyct_is_compile_decorator', True) + return f + + +def convert_inline(f, *args, **kwargs): + """Shorthand to convert and call a function. + + For example, the following two statements are equivalent: + + @convert() + def foo(): + ... + foo(bar) + + def foo(): + ... + convert_inline(foo, bar) + + Args: + f: Function to convert. Only this call will be converted. + *args: Passed through to f. + **kwargs: Passed through to f, with the following exceptions: + * arg_value_hints: A dict mapping parameter names to objects that can + hint at the type of those parameters. + + Returns: + The result of the converted f applied to args and kwargs. + """ + if 'arg_value_hints' in kwargs: + arg_value_hints = kwargs['arg_value_hints'] + del kwargs['arg_value_hints'] + else: + arg_value_hints = None + if tf_inspect.ismethod(f): + # When converting methods, the result is still an unbound function. + args = (f.__self__,) + args + return convert(arg_value_hints)(f)(*args, **kwargs) + + +def convert(recursive=False, arg_value_hints=None): + """Decorator that compiles a function to graph mode. + + The decorator is dynamic - invoking compilation whenever the decorated fuction + is called. This means the parameter values are known at compilation. + + Args: + recursive: Whether to recusrively convert any functions that the decorator + function may call. + arg_value_hints: A dict mapping parameter names to objects that can hint + at the type of those parameters. + + Returns: + A decorator that compiles the given function to graph mode. + + Raises: + ValueError: If any of the arguments are illegal. + """ + if arg_value_hints is None: + arg_value_hints = {} + + def decorator(f): + """Decorator implementation.""" + + @wraps(f) + def wrapper(*args, **kwargs): + """Wrapper that calls the compiled version of the wrapped function.""" + partial_types = () + arg_names = tf_inspect.getargspec(f)[0] + for name, arg in zip(arg_names, args): + arg_class = arg.__class__ + if tf_inspect.isclass(arg_class): + # If arg_value_hints specifies any name, use that instead. + # TODO(mdan): Shouldn't this just be in the func's globals? + if name not in arg_value_hints: + arg_value_hints[name] = (arg_class.__name__, arg_class) + # Annotated methods need to specify that their owner type is partial, + # otherwise other members they call will not be converted. + if name == 'self': + partial_types = (arg_class,) + wrapped = to_graph( + f, + recursive=recursive, + arg_value_hints=arg_value_hints, + partial_types=partial_types) + return wrapped(*args, **kwargs) + + # Sometimes the decorator is just desugared, making it impossible to detect. + # This attribute makes detection easier. + setattr(wrapper, '__pyct_is_compile_decorator', True) + return wrapper + + return decorator + + +def to_graph(o, recursive=True, arg_value_hints=None, partial_types=None): """Compile a Python entity into equivalent TensorFlow code. Currently supported entities: @@ -43,14 +149,22 @@ def to_graph(o, arg_value_hints=None): Args: o: A Python function or class. + recursive: Whether to recusrively convert any functions that the decorator + function may call. arg_value_hints: A dict mapping parameter names to objects that can hint at the type of those parameters. + partial_types: A set of types (e.g. classes) that will not be converted + entirely. Calls to member functions for these types will be renamed + independently. Returns: A function with a signature identical to `o`, but which when executed it creates TF a graph that has the same functionality as the original entity. """ - conversion_map = conversion.ConversionMap() + conversion_map = conversion.ConversionMap( + recursive=recursive, + nocompile_decorators=(convert, graph_ready, convert_inline), + partial_types=partial_types) _, name = conversion.object_to_graph(o, conversion_map, arg_value_hints) module = gast.Module([]) @@ -69,21 +183,33 @@ def to_graph(o, arg_value_hints=None): return compiled_fn -def to_code(o, arg_value_hints=None, indentation=' '): +def to_code(o, + recursive=True, + arg_value_hints=None, + partial_types=None, + indentation=' '): """Return the equivalent of an entity in TensorFlow code. See `to_graph` for more details. Args: o: A Python function or class. + recursive: Whether to recusrively convert any functions that the decorator + function may call. arg_value_hints: A dict mapping parameter names to objects that can hint at the type of those parameters. + partial_types: A set of types (e.g. classes) that will not be converted + entirely. Calls to member functions for these types will be renamed + independently. indentation: String, when to use for each level of indentation. Returns: String. """ - conversion_map = conversion.ConversionMap() + conversion_map = conversion.ConversionMap( + recursive=recursive, + nocompile_decorators=(convert, graph_ready, convert_inline), + partial_types=partial_types) conversion.object_to_graph(o, conversion_map, arg_value_hints) imports = '\n'.join(config.COMPILED_IMPORT_STATEMENTS) diff --git a/tensorflow/contrib/py2tf/api_test.py b/tensorflow/contrib/py2tf/api_test.py index 225b6d305f..2384447708 100644 --- a/tensorflow/contrib/py2tf/api_test.py +++ b/tensorflow/contrib/py2tf/api_test.py @@ -28,17 +28,146 @@ from tensorflow.python.platform import test class ApiTest(test.TestCase): + def setUp(self): + config.DEFAULT_UNCOMPILED_MODULES.add((math_ops.__name__,)) + config.COMPILED_IMPORT_STATEMENTS = ( + 'from tensorflow.python.ops ' + 'import control_flow_ops as tf',) + + def test_decorator_recurses(self): + + class TestClass(object): + + def called_member(self, a): + if a < 0: + a = -a + return a + + @api.convert(recursive=True) + def test_method(self, x, s, a): + while math_ops.reduce_sum(x) > s: + x //= self.called_member(a) + return x + + tc = TestClass() + with self.test_session() as sess: + x = tc.test_method( + constant_op.constant([2, 4]), constant_op.constant(1), + constant_op.constant(-2)) + self.assertListEqual([0, 1], sess.run(x).tolist()) + + def test_decorator_does_not_recurse(self): + + class TestClass(object): + + def called_member(self, a): + return math_ops.negative(a) + + @api.convert(recursive=False) + def test_method(self, x, s, a): + while math_ops.reduce_sum(x) > s: + x //= self.called_member(a) + return x + + tc = TestClass() + with self.test_session() as sess: + x = tc.test_method( + constant_op.constant([2, 4]), constant_op.constant(1), + constant_op.constant(-2)) + self.assertListEqual([0, 1], sess.run(x).tolist()) + + def test_decorator_calls_converted(self): + + class TestClass(object): + + @api.graph_ready + def called_member(self, a): + return math_ops.negative(a) + + @api.convert(recursive=True) + def test_method(self, x, s, a): + while math_ops.reduce_sum(x) > s: + x //= self.called_member(a) + return x + + tc = TestClass() + with self.test_session() as sess: + x = tc.test_method( + constant_op.constant([2, 4]), constant_op.constant(1), + constant_op.constant(-2)) + self.assertListEqual([0, 1], sess.run(x).tolist()) + + def test_decorator_calls_decorated(self): + + class TestClass(object): + + @api.convert() + def called_member(self, a): + if a < 0: + a = -a + return a + + @api.convert(recursive=True) + def test_method(self, x, s, a): + while math_ops.reduce_sum(x) > s: + x //= self.called_member(a) + return x + + tc = TestClass() + with self.test_session() as sess: + x = tc.test_method( + constant_op.constant([2, 4]), constant_op.constant(1), + constant_op.constant(-2)) + self.assertListEqual([0, 1], sess.run(x).tolist()) + + def test_convert_call_site_decorator(self): + + class TestClass(object): + + def called_member(self, a): + if a < 0: + a = -a + return a + + @api.convert(recursive=True) + def test_method(self, x, s, a): + while math_ops.reduce_sum(x) > s: + x //= api.convert_inline(self.called_member, a) + return x + + tc = TestClass() + with self.test_session() as sess: + x = tc.test_method( + constant_op.constant([2, 4]), constant_op.constant(1), + constant_op.constant(-2)) + self.assertListEqual([0, 1], sess.run(x).tolist()) + + def test_graph_ready_call_site_decorator(self): + + class TestClass(object): + + def called_member(self, a): + return math_ops.negative(a) + + @api.convert(recursive=True) + def test_method(self, x, s, a): + while math_ops.reduce_sum(x) > s: + x //= api.graph_ready(self.called_member(a)) + return x + + tc = TestClass() + with self.test_session() as sess: + x = tc.test_method( + constant_op.constant([2, 4]), constant_op.constant(1), + constant_op.constant(-2)) + self.assertListEqual([0, 1], sess.run(x).tolist()) + def test_to_graph_basic(self): def test_fn(x, s): while math_ops.reduce_sum(x) > s: x //= 2 return x - config.DEFAULT_UNCOMPILED_MODULES.add((math_ops.__name__,)) - config.COMPILED_IMPORT_STATEMENTS = ( - 'from tensorflow.python.ops ' - 'import control_flow_ops as tf', - ) compiled_fn = api.to_graph(test_fn) with self.test_session() as sess: @@ -51,7 +180,6 @@ class ApiTest(test.TestCase): x /= 2 return x - config.DEFAULT_UNCOMPILED_MODULES.add((math_ops.__name__,)) compiled_code = api.to_code(test_fn) # Just check for some key words and that it is parseable Python code. diff --git a/tensorflow/contrib/py2tf/conversion.py b/tensorflow/contrib/py2tf/conversion.py index 43bccae953..3bdbc66a99 100644 --- a/tensorflow/contrib/py2tf/conversion.py +++ b/tensorflow/contrib/py2tf/conversion.py @@ -28,6 +28,7 @@ from tensorflow.contrib.py2tf.convert import builtin_functions from tensorflow.contrib.py2tf.convert import call_trees from tensorflow.contrib.py2tf.convert import continue_canonicalization from tensorflow.contrib.py2tf.convert import control_flow +from tensorflow.contrib.py2tf.convert import decorators from tensorflow.contrib.py2tf.convert import for_canonicalization from tensorflow.contrib.py2tf.convert import logical_expressions from tensorflow.contrib.py2tf.convert import print_functions @@ -39,22 +40,35 @@ from tensorflow.contrib.py2tf.pyct.static_analysis import type_info from tensorflow.python.util import tf_inspect +# TODO(mdan): Might we not need any renaming at all? + + class ConversionMap(object): """ConversionMaps keep track of converting function hierarchies. Attributes: + recursive: Whether to recusrively convert any functions that the decorator + function may call. + nocompile_decorators: tuple of decorator functions that toggle compilation + off. dependency_cache: dict[object]: ast; maps original objects to their converted AST name_map: dict[string]: string; maps original objects to the name of their converted counterparts """ - def __init__(self): + # TODO(mdan): Rename to ConversionContext, and pull in additional flags. + + def __init__(self, recursive, nocompile_decorators, partial_types): + self.recursive = recursive + self.nocompile_decorators = nocompile_decorators + self.partial_types = partial_types if partial_types else () self.dependency_cache = {} self.name_map = {} def new_namer(self, global_symbols): - return naming.Namer(global_symbols, self.name_map) + return naming.Namer(global_symbols, self.recursive, self.name_map, + self.partial_types) def update_name_map(self, namer): for o, name in namer.renamed_calls.items(): @@ -102,19 +116,23 @@ def object_to_graph(o, conversion_map, value_hints): node, new_name = class_to_graph(o, conversion_map, value_hints) elif tf_inspect.isfunction(o): node, new_name = function_to_graph(o, conversion_map, value_hints) + elif tf_inspect.ismethod(o): + node, new_name = function_to_graph(o, conversion_map, value_hints) else: raise ValueError( - 'Unsupported object type %s. Only functions and classes are supported' - ' for now.') + 'Entity "%s" has unsupported type "%s". Only functions and classes are ' + 'supported for now.' % (o, type(o))) conversion_map.add_to_cache(o, node) - # Recursively convert remaining dependencies. - for obj in conversion_map.name_map.keys(): - if obj not in conversion_map.dependency_cache: - if hasattr(obj, 'im_class'): - # Class members are converted with their objects. - continue - object_to_graph(obj, conversion_map, None) + if conversion_map.recursive: + for obj in conversion_map.name_map.keys(): + if obj not in conversion_map.dependency_cache: + if (hasattr(obj, 'im_class') and + getattr(obj, 'im_class') not in conversion_map.partial_types): + # Class members are converted with their objects, unless they're + # only converted partially. + continue + object_to_graph(obj, conversion_map, None) return node, new_name @@ -163,7 +181,8 @@ def function_to_graph(f, conversion_map, param_value_hints, owner_type=None): node_globals[fn.__name__] = fn namer = conversion_map.new_namer(node_globals) - node = node_to_graph(node, namer, node_globals, param_value_hints) + node = node_to_graph(node, namer, node_globals, param_value_hints, + conversion_map.nocompile_decorators) # Simulate a rename to ensure the top level is in the name map. This is needed # for top level functions, and it also helps the consistency verification made @@ -184,7 +203,7 @@ def _static_analysis_pass(node, namespace, value_hints): return node -def node_to_graph(node, namer, namespace, value_hints): +def node_to_graph(node, namer, namespace, value_hints, nocompile_decorators): """Convert Python code to equivalent TF graph mode code. Args: @@ -193,6 +212,8 @@ def node_to_graph(node, namer, namespace, value_hints): namespace: Dict mapping symbol names to their corresponding live objects. value_hints: A dict containing value hints for symbols like function parameters. + nocompile_decorators: A tuple containing decorators to be stripped from + functions during conversion. Returns: A tuple (node, deps): @@ -200,6 +221,8 @@ def node_to_graph(node, namer, namespace, value_hints): * deps: A set of strings, the fully qualified names of object dependencies that this node has. """ + # TODO(mdan): Verify arguments for correctness. + # TODO(mdan): Factor out common elements. # These include: # * keeping track of symbols that have been created @@ -213,6 +236,7 @@ def node_to_graph(node, namer, namespace, value_hints): # to re-run the analysis. node = _static_analysis_pass(node, namespace, value_hints) + node = decorators.transform(node, nocompile_decorators) node = break_canonicalization.transform(node, namer) # Note: sequencing continue canonicalization before for loop one avoids @@ -230,7 +254,9 @@ def node_to_graph(node, namer, namespace, value_hints): node = _static_analysis_pass(node, namespace, value_hints) node = print_functions.transform(node) - node = call_trees.transform(node, namer, config.DEFAULT_UNCOMPILED_MODULES) + node = call_trees.transform(node, namer, namespace, + config.DEFAULT_UNCOMPILED_MODULES, + nocompile_decorators) node = control_flow.transform(node, namer) node = logical_expressions.transform(node) node = side_effect_guards.transform(node, namer) diff --git a/tensorflow/contrib/py2tf/conversion_test.py b/tensorflow/contrib/py2tf/conversion_test.py index d76f141809..e48bfe4464 100644 --- a/tensorflow/contrib/py2tf/conversion_test.py +++ b/tensorflow/contrib/py2tf/conversion_test.py @@ -28,13 +28,13 @@ class ConversionTest(test.TestCase): def test_object_to_graph_unsupported_types(self): with self.assertRaises(ValueError): - conversion.object_to_graph('dummy', {}, {}) + conversion.object_to_graph('dummy', None, {}) def test_object_to_graph_callable(self): def f(a): return a - conversion_map = conversion.ConversionMap() + conversion_map = conversion.ConversionMap(True, (), ()) ast, new_name = conversion.object_to_graph(f, conversion_map, {}) self.assertTrue(isinstance(ast, gast.FunctionDef), ast) self.assertEqual('tf__f', new_name) @@ -46,7 +46,7 @@ class ConversionTest(test.TestCase): def f(a): return g(a) - conversion_map = conversion.ConversionMap() + conversion_map = conversion.ConversionMap(True, (), ()) conversion.object_to_graph(f, conversion_map, {}) self.assertTrue(f in conversion_map.dependency_cache) diff --git a/tensorflow/contrib/py2tf/convert/BUILD b/tensorflow/contrib/py2tf/convert/BUILD index 0eb7998dc4..050e2ef108 100644 --- a/tensorflow/contrib/py2tf/convert/BUILD +++ b/tensorflow/contrib/py2tf/convert/BUILD @@ -22,6 +22,7 @@ py_library( "call_trees.py", "continue_canonicalization.py", "control_flow.py", + "decorators.py", "for_canonicalization.py", "logical_expressions.py", "print_functions.py", diff --git a/tensorflow/contrib/py2tf/convert/call_trees.py b/tensorflow/contrib/py2tf/convert/call_trees.py index 92c3439101..df071f596f 100644 --- a/tensorflow/contrib/py2tf/convert/call_trees.py +++ b/tensorflow/contrib/py2tf/convert/call_trees.py @@ -27,6 +27,7 @@ import types import gast from tensorflow.contrib.py2tf.pyct import anno +from tensorflow.contrib.py2tf.pyct import parser from tensorflow.contrib.py2tf.pyct import templates @@ -64,16 +65,75 @@ class FunctionNamer(object): class CallTreeTransformer(gast.NodeTransformer): """Transforms the call tree by renaming transformed symbols.""" - def __init__(self, namer, uncompiled_modules): + def __init__(self, namer, namespace, uncompiled_modules, + nocompile_decorators): self.namer = namer + self.namespace = namespace self.uncompiled_modules = uncompiled_modules + self.nocompile_decorators = nocompile_decorators # pylint:disable=invalid-name - def _should_compile(self, fqn): + def _resolve_name(self, node): + if isinstance(node, gast.Call): + return self._resolve_name(node.func) + if isinstance(node, gast.Name): + return self.namespace.get(node.id) + if isinstance(node, gast.Attribute): + parent = self._resolve_name(node.value) + if parent is not None: + return getattr(parent, node.attr) + return None + raise ValueError(node) + + def _try_resolve_target(self, node): + """Works for methods of objects of known type.""" + if anno.hasanno(node, 'live_val'): + return anno.getanno(node, 'live_val') + if isinstance(node, gast.Attribute) and anno.hasanno(node, 'type'): + member = getattr(anno.getanno(node, 'type'), node.attr) + return member + return None + + def _should_compile(self, node, fqn): for i in range(1, len(fqn)): if fqn[:i] in self.uncompiled_modules: return False + + # Check for local decorations + if anno.hasanno(node, 'graph_ready'): + return False + + # The decorators themselves are not to be converted. + # If present, the decorators should appear as static functions. + target_obj = self._try_resolve_target(node.func) + if target_obj is not None: + # This attribute is set by the decorator itself. + # TODO(mdan): This may not play nicely with other wrapping decorators. + if hasattr(target_obj, '__pyct_is_compile_decorator'): + return False + + if target_obj in self.nocompile_decorators: + return False + + # Inspect the target function decorators. If any include a @convert + # or @graph_ready annotation, then they must be called as they are. + # TODO(mdan): This may be quite heavy. + # To parse and re-analize each function for every call site could be quite + # wasteful. Maybe we could cache the parsed AST? + try: + target_node = parser.parse_object(target_obj).body[0] + except TypeError: + # Functions whose source we cannot access are compilable (e.g. wrapped + # to py_func). + return True + + for dec in target_node.decorator_list: + decorator_fn = self._resolve_name(dec) + if (decorator_fn is not None and + decorator_fn in self.nocompile_decorators): + return False + return True def _rename_compilable_function(self, node): @@ -82,15 +142,15 @@ class CallTreeTransformer(gast.NodeTransformer): target_obj = anno.getanno(node.func, 'live_val') target_fqn = anno.getanno(node.func, 'fqn') - if not self._should_compile(target_fqn): + if not self._should_compile(node, target_fqn): return node if anno.hasanno(node, 'is_constructor'): new_name = self.namer.compiled_class_name( - '.'.join(target_fqn), live_object=target_obj) + '__'.join(target_fqn), live_object=target_obj) else: new_name = self.namer.compiled_function_name( - '.'.join(target_fqn), live_object=target_obj) + '__'.join(target_fqn), live_object=target_obj) node.func = gast.Name(id=new_name, ctx=gast.Load(), annotation=None) return node @@ -101,15 +161,24 @@ class CallTreeTransformer(gast.NodeTransformer): assert anno.hasanno(node.func, 'type') target_type = anno.getanno(node.func, 'type') - if not self._should_compile(type_fqn): + if not self._should_compile(node, type_fqn): return node # TODO(mdan): We should not assume that the namer only needs the # member function name. + method_name = node.func.attr + method_object = getattr(target_type, method_name) new_name = self.namer.compiled_function_name( - node.func.attr, live_object=None, owner_type=target_type) - node.func.attr = new_name - + method_name, live_object=method_object, owner_type=target_type) + if new_name != node.func.attr: + # If a member function call is renamed, then the new function is no + # longer bound to the target object. We then refactor the call from: + # foo.bar(...) + # to: + # renamed_foo(bar, ...) + # TODO(mdan): This risks causing duplication, if target_type is renamed. + node.args = [node.func.value] + node.args + node.func = gast.Name(new_name, gast.Load(), None) return node def _wrap_to_py_func_no_return(self, node): @@ -136,6 +205,7 @@ class CallTreeTransformer(gast.NodeTransformer): wrapper=gast.Name(wrapper_name, gast.Load(), None), args=args) anno.setanno(call_expr.value, 'args_scope', args_scope) + # TODO(mdan): Rename this annotation to 'graph_ready' anno.setanno(wrapper_def, 'skip_processing', True) return (wrapper_def, call_expr) @@ -151,7 +221,7 @@ class CallTreeTransformer(gast.NodeTransformer): if not self._function_is_compilable(target_obj): if anno.hasanno(node.value.func, 'fqn'): target_fqn = anno.getanno(node.value.func, 'fqn') - if not self._should_compile(target_fqn): + if not self._should_compile(node.value, target_fqn): return node node = self._wrap_to_py_func_no_return(node.value) return node @@ -163,6 +233,17 @@ class CallTreeTransformer(gast.NodeTransformer): return node def visit_Call(self, node): + # If the function is wrapped by one of the marker decorators, + # consider it graph ready. + if anno.hasanno(node.func, 'live_val'): + target_obj = anno.getanno(node.func, 'live_val') + if target_obj in self.nocompile_decorators: + if len(node.args) < 1: + raise ValueError( + 'Found call to decorator function "%s", but it had no arguments. ' + 'A decorator needs at least an argument.') + anno.setanno(node.args[0], 'graph_ready', True) + self.generic_visit(node) if anno.hasanno(node.func, 'live_val'): target_obj = anno.getanno(node.func, 'live_val') @@ -180,20 +261,24 @@ class CallTreeTransformer(gast.NodeTransformer): # pylint:enable=invalid-name -def transform(node, namer, uncompiled_modules): +def transform(node, namer, namespace, uncompiled_modules, nocompile_decorators): """Transform function call to the compiled counterparts. Args: node: AST to transform. namer: FunctionNamer-like. + namespace: Dict mapping symbol names to their corresponding live objects. uncompiled_modules: set of string tuples, each tuple represents the fully qualified name of a package containing functions that will not be compiled. + nocompile_decorators: A tuple containing decorators to be stripped from + functions during conversion. Returns: A tuple (node, new_names): node: The transformed AST new_names: set(string), containing any newly-generated names """ - transformer = CallTreeTransformer(namer, uncompiled_modules) + transformer = CallTreeTransformer(namer, namespace, uncompiled_modules, + nocompile_decorators) node = transformer.visit(node) return node diff --git a/tensorflow/contrib/py2tf/convert/call_trees_test.py b/tensorflow/contrib/py2tf/convert/call_trees_test.py index 38c701eaad..3367d41db3 100644 --- a/tensorflow/contrib/py2tf/convert/call_trees_test.py +++ b/tensorflow/contrib/py2tf/convert/call_trees_test.py @@ -56,7 +56,7 @@ class CallTreesTest(test.TestCase): return test_fn_1(a) + 1 node = self._parse_and_analyze(test_fn_2, {'test_fn_1': test_fn_1}) - node = call_trees.transform(node, TestNamer(), set()) + node = call_trees.transform(node, TestNamer(), {}, (), ()) result = compiler.ast_to_object(node) # Only test_fn_2 is transformed, so we'll insert renamed_test_fn_1 manually. setattr(result, 'renamed_test_fn_1', renamed_test_fn_1) @@ -74,9 +74,9 @@ class CallTreesTest(test.TestCase): 'math_ops': math_ops, 'constant_op': constant_op }) - node = call_trees.transform(node, TestNamer(), + node = call_trees.transform(node, TestNamer(), {}, set(((math_ops.__name__,), - (constant_op.__name__,)))) + (constant_op.__name__,))), ()) result = compiler.ast_to_object(node) setattr(result, 'math_ops', math_ops) setattr(result, 'constant_op', constant_op) diff --git a/tensorflow/contrib/py2tf/convert/decorators.py b/tensorflow/contrib/py2tf/convert/decorators.py new file mode 100644 index 0000000000..a4313bfa51 --- /dev/null +++ b/tensorflow/contrib/py2tf/convert/decorators.py @@ -0,0 +1,56 @@ +# Copyright 2016 The TensorFlow Authors. 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. +# ============================================================================== +"""Handles decorators.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import gast + +from tensorflow.contrib.py2tf.pyct import anno +from tensorflow.contrib.py2tf.pyct import pretty_printer + + +class DecoratorsTransformer(gast.NodeTransformer): + """Converts or removes decorators.""" + + def __init__(self, remove_decorators): + self.remove_decorators = remove_decorators + + # pylint:disable=invalid-name + + def visit_FunctionDef(self, node): + self.generic_visit(node) + for dec in node.decorator_list: + if isinstance(dec, gast.Call): + dec = dec.func + if not anno.hasanno(dec, 'live_val'): + raise ValueError( + 'Could not resolve decorator: %s' % pretty_printer.fmt(dec)) + dec_value = anno.getanno(dec, 'live_val') + if dec_value in self.remove_decorators: + continue + raise ValueError('Dont know how to convert decorators for now.') + node.decorator_list = [] + return node + + # pylint:enable=invalid-name + + +def transform(node, remove_decorators): + transformer = DecoratorsTransformer(remove_decorators) + node = transformer.visit(node) + return node diff --git a/tensorflow/contrib/py2tf/naming.py b/tensorflow/contrib/py2tf/naming.py index 61772ec07b..a90758962b 100644 --- a/tensorflow/contrib/py2tf/naming.py +++ b/tensorflow/contrib/py2tf/naming.py @@ -34,8 +34,10 @@ class Namer(object): * side_effect_guards.SymbolNamer """ - def __init__(self, global_namespace, name_map=None): + def __init__(self, global_namespace, recursive, name_map, partial_types): self.global_namespace = global_namespace + self.recursive = recursive + self.partial_types = partial_types self.renamed_calls = {} if name_map is not None: @@ -54,6 +56,7 @@ class Namer(object): while new_name in self.global_namespace: n += 1 new_name = '%s_%d' % (new_name_root, n) + if live_object is not None: self.renamed_calls[live_object] = new_name self.generated_names.add(new_name) @@ -67,7 +70,9 @@ class Namer(object): if live_object is not None and live_object in self.renamed_calls: return self.renamed_calls[live_object] - if owner_type is None: + if not self.recursive: + new_name = original_name + elif owner_type is None or owner_type in self.partial_types: # Top level functions: rename new_name_root = 'tf__%s' % original_name new_name = new_name_root diff --git a/tensorflow/contrib/py2tf/naming_test.py b/tensorflow/contrib/py2tf/naming_test.py index 9403d9ae1f..7bfc9b8733 100644 --- a/tensorflow/contrib/py2tf/naming_test.py +++ b/tensorflow/contrib/py2tf/naming_test.py @@ -28,7 +28,7 @@ class NamerTest(test.TestCase): def bar(): pass - namer = naming.Namer(set()) + namer = naming.Namer({}, True, None, ()) self.assertEqual('tf__foo', namer.compiled_function_name('foo')) self.assertEqual('tf__bar', namer.compiled_function_name('bar', bar)) self.assertEqual({bar: 'tf__bar'}, namer.renamed_calls) @@ -38,7 +38,7 @@ class NamerTest(test.TestCase): def foo(): pass - namer = naming.Namer(set()) + namer = naming.Namer({}, True, None, ()) self.assertEqual('tf__foo', namer.compiled_function_name('foo', foo)) self.assertEqual('tf__foo', namer.compiled_function_name('foo', foo)) @@ -46,22 +46,22 @@ class NamerTest(test.TestCase): def foo(): pass - namer = naming.Namer(set(('tf__foo',))) + namer = naming.Namer({'tf__foo': 1}, True, None, ()) self.assertEqual('tf__foo_1', namer.compiled_function_name('foo', foo)) def test_new_symbol_tracks_names(self): - namer = naming.Namer(set()) + namer = naming.Namer({}, True, None, ()) self.assertEqual('temp', namer.new_symbol('temp', set())) self.assertItemsEqual(('temp',), namer.generated_names) def test_new_symbol_avoids_duplicates(self): - namer = naming.Namer(set()) + namer = naming.Namer({}, True, None, ()) self.assertEqual('temp', namer.new_symbol('temp', set())) self.assertEqual('temp_1', namer.new_symbol('temp', set())) self.assertItemsEqual(('temp', 'temp_1'), namer.generated_names) def test_new_symbol_avoids_conflicts(self): - namer = naming.Namer(set(('temp',))) + namer = naming.Namer({'temp': 1}, True, None, ()) # temp is reserved in the global namespace self.assertEqual('temp_1', namer.new_symbol('temp', set())) # temp_2 is reserved in the local namespace -- GitLab From 4b6abfd95254910d01e886123cd24c29f722e8d7 Mon Sep 17 00:00:00 2001 From: Julian Wolff Date: Mon, 22 Jan 2018 21:27:14 +0100 Subject: [PATCH 055/258] fix default parameters for TimeFreqLSTMCell, fixes #16100 (#16127) --- tensorflow/contrib/rnn/python/ops/rnn_cell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/rnn/python/ops/rnn_cell.py b/tensorflow/contrib/rnn/python/ops/rnn_cell.py index 6dccf1775e..d7ae6621db 100644 --- a/tensorflow/contrib/rnn/python/ops/rnn_cell.py +++ b/tensorflow/contrib/rnn/python/ops/rnn_cell.py @@ -329,7 +329,7 @@ class TimeFreqLSTMCell(rnn_cell_impl.RNNCell): def __init__(self, num_units, use_peepholes=False, cell_clip=None, initializer=None, num_unit_shards=1, forget_bias=1.0, - feature_size=None, frequency_skip=None, + feature_size=None, frequency_skip=1, reuse=None): """Initialize the parameters for an LSTM cell. -- GitLab From 6cd166382d0f29508be7dd274cb2edab2e94dbbe Mon Sep 17 00:00:00 2001 From: Clayne Robison Date: Mon, 22 Jan 2018 13:49:41 -0700 Subject: [PATCH 056/258] Fix convolutional_recurrent_test failure (#16297) --- tensorflow/core/kernels/mkl_input_conversion_op.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/kernels/mkl_input_conversion_op.cc b/tensorflow/core/kernels/mkl_input_conversion_op.cc index 001834b13b..4b5f7b8310 100644 --- a/tensorflow/core/kernels/mkl_input_conversion_op.cc +++ b/tensorflow/core/kernels/mkl_input_conversion_op.cc @@ -396,7 +396,7 @@ class MklInputConversionOp : public OpKernel { auto cpu_engine = engine(engine::cpu, 0); MklDnnData tf_input(&cpu_engine); auto input_tf_md = mkl_output_mkl_shape.GetTfLayout(); - tf_input.SetUsrMem(input_tf_md, &tf_tensor); + tf_input.SetUsrMem(input_tf_md, tf_tensor); // Create reorder between tensorflow layout and Mkl layout. std::vector net; -- GitLab From f20f28beea3b68e9a0179bf2b669f4827b4b6ac7 Mon Sep 17 00:00:00 2001 From: yordun Date: Mon, 22 Jan 2018 20:55:01 +0000 Subject: [PATCH 057/258] Removes redundant variable assignment (#16286) Addresses alert raised by lgtm.com: https://lgtm.com/projects/g/tensorflow/tensorflow/snapshot/e6183fbeecf069148371be83988e8e5db2b14185/files/tensorflow/python/framework/constant_op.py#xb77a2f6647d782be:1 --- tensorflow/python/framework/constant_op.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow/python/framework/constant_op.py b/tensorflow/python/framework/constant_op.py index ac915157f5..8c31e59b29 100644 --- a/tensorflow/python/framework/constant_op.py +++ b/tensorflow/python/framework/constant_op.py @@ -59,7 +59,6 @@ def _eager_reshape(tensor, shape, ctx): attr_t = tensor._datatype_enum() # pylint: disable=protected-access attr_tshape, (shape,) = execute.args_to_matching_eager( [shape], ctx, dtypes.int32) - attr_tshape = attr_tshape inputs_flat = [tensor, shape] attrs = ("T", attr_t, "Tshape", attr_tshape) result, = execute.execute( -- GitLab From 90c6308b56152569ee126ae87d717e0f1bb004b3 Mon Sep 17 00:00:00 2001 From: brett koonce Date: Mon, 22 Jan 2018 12:59:55 -0800 Subject: [PATCH 058/258] minor spelling tweaks for lite docs (#16275) --- tensorflow/contrib/lite/models/testdata/g3doc/README.md | 4 ++-- tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/contrib/lite/models/testdata/g3doc/README.md b/tensorflow/contrib/lite/models/testdata/g3doc/README.md index 667a588383..1c47e00aae 100644 --- a/tensorflow/contrib/lite/models/testdata/g3doc/README.md +++ b/tensorflow/contrib/lite/models/testdata/g3doc/README.md @@ -53,7 +53,7 @@ with the corresponding parameters as shown in the figure. ### Automatic Speech Recognizer (ASR) Acoustic Model (AM) The acoustic model for automatic speech recognition is the neural network model -for matching phonemes to the input autio features. It generates posterior +for matching phonemes to the input audio features. It generates posterior probabilities of phonemes from speech frontend features (log-mel filterbanks). It has an input size of 320 (float), an output size of 42 (float), five LSTM layers and one fully connected layers with a Softmax activation function, with @@ -68,7 +68,7 @@ for predicting the probability of a word given previous words in a sentence. It generates posterior probabilities of the next word based from a sequence of words. The words are encoded as indices in a fixed size dictionary. The model has two inputs both of size one (integer): the current word index and -next word index, an output size of one (float): the log probability. It consits +next word index, an output size of one (float): the log probability. It consists of three embedding layer, three LSTM layers, followed by a multiplication, a fully connected layers and an addition. The corresponding parameters as shown in the figure. diff --git a/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md b/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md index 4776741ab9..5e07795223 100644 --- a/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md +++ b/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md @@ -229,7 +229,7 @@ additional information about the multiple input arrays: well-formed quantized representation of these graphs. Such graphs should be fixed, but as a temporary work-around, setting this reorder_across_fake_quant flag allows the converter to perform necessary - graph transformaitons on them, at the cost of no longer faithfully matching + graph transformations on them, at the cost of no longer faithfully matching inference and training arithmetic. ### Logging flags -- GitLab From 9c94df8bf7247c642c345040affdd4e46c2cd65b Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Mon, 22 Jan 2018 13:00:54 -0800 Subject: [PATCH 059/258] Allowing custom creators for variable_scope.variable() PiperOrigin-RevId: 182822430 --- tensorflow/python/framework/ops.py | 17 ++ .../kernel_tests/variable_scope_test.py | 18 +++ tensorflow/python/ops/variable_scope.py | 146 ++++++++++++++---- 3 files changed, 151 insertions(+), 30 deletions(-) diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index e7f08a64a6..0eb06ae913 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -2695,6 +2695,7 @@ class Graph(object): self._scoped_c_graph = c_api_util.ScopedTFGraph() else: self._scoped_c_graph = None + self._variable_creator_stack = [] # TODO(apassos) remove once the C API is used by default. def _use_c_api_hack(self): @@ -2731,6 +2732,22 @@ class Graph(object): ret.append((filename, lineno, name, line)) return ret + # Note: this method is private because the API of tf.Graph() is public and + # frozen, and this functionality is still not ready for public visibility. + @tf_contextlib.contextmanager + def _variable_creator_scope(self, creator): + old = list(self._variable_creator_stack) + self._variable_creator_stack.append(creator) + try: + yield + finally: + self._variable_creator_stack = old + + # Note: this method is private because the API of tf.Graph() is public and + # frozen, and this functionality is still not ready for public visibility. + def _get_variable_creator_stack(self): + return list(self._variable_creator_stack) + def _extract_stack(self): """A lightweight, extensible re-implementation of traceback.extract_stack. diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index f1a86625e0..238d4b58d5 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -1253,6 +1253,24 @@ class VariableScopeWithCustomGetterTest(test.TestCase): (((np_vars[0] * np_vars[1]) + (np_vars[2] * np_vars[3])) + ((np_vars[4] * np_vars[5]) + (np_vars[6] * np_vars[7])))) + def testVariableCreator(self): + + variable_names = [] + + def creator_a(next_creator, **kwargs): + variable_names.append(kwargs.get("name", "")) + return next_creator(**kwargs) + + def creator_b(next_creator, **kwargs): + kwargs["name"] = "forced_name" + return next_creator(**kwargs) + + with variable_scope.variable_creator_scope(creator_a): + with variable_scope.variable_creator_scope(creator_b): + variable_scope.variable(1.0, name="one_name") + + self.assertAllEqual(variable_names, ["forced_name"]) + class PartitionInfoTest(test.TestCase): diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index 3a39af8e20..1facb8b1f2 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -785,26 +785,16 @@ class _VariableStore(object): if use_resource is None: # Set the default value if unspecified. use_resource = False - if use_resource: - v = resource_variable_ops.ResourceVariable( - initial_value=init_val, - name=name, - trainable=trainable, - collections=collections, - caching_device=caching_device, - dtype=variable_dtype, - validate_shape=validate_shape, - constraint=constraint) - else: - v = variables.Variable( - initial_value=init_val, - name=name, - trainable=trainable, - collections=collections, - caching_device=caching_device, - dtype=variable_dtype, - validate_shape=validate_shape, - constraint=constraint) + v = variable( + initial_value=init_val, + name=name, + trainable=trainable, + collections=collections, + caching_device=caching_device, + dtype=variable_dtype, + validate_shape=validate_shape, + constraint=constraint, + use_resource=use_resource) if context.in_graph_mode() or self._store_eager_variables: # In eager mode we do not want to keep default references to Variable # objects as this will prevent their memory from being released. @@ -2067,21 +2057,26 @@ def _compute_slice_dim_and_shape(full_shape, slicing): return slice_dim, slice_shape -def variable(initial_value=None, - trainable=True, - collections=None, - validate_shape=True, - caching_device=None, - name=None, - dtype=None, - use_resource=None): +def default_variable_creator(next_creator=None, **kwargs): + """Default variable creator.""" + assert next_creator is None + initial_value = kwargs.get("initial_value", None) + trainable = kwargs.get("trainable", True) + collections = kwargs.get("collections", None) + validate_shape = kwargs.get("validate_shape", True) + caching_device = kwargs.get("caching_device", None) + name = kwargs.get("name", None) + dtype = kwargs.get("dtype", None) + constraint = kwargs.get("constraint", None) + use_resource = kwargs.get("use_resource", None) if use_resource is None: use_resource = get_variable_scope().use_resource if use_resource or (use_resource is None and context.in_eager_mode()): return resource_variable_ops.ResourceVariable( initial_value=initial_value, trainable=trainable, collections=collections, validate_shape=validate_shape, - caching_device=caching_device, name=name, dtype=dtype) + caching_device=caching_device, name=name, dtype=dtype, + constraint=constraint) elif not use_resource and context.in_eager_mode(): raise RuntimeError( "VariableScope should use resource variable when eager execution is" @@ -2091,4 +2086,95 @@ def variable(initial_value=None, return variables.Variable( initial_value=initial_value, trainable=trainable, collections=collections, validate_shape=validate_shape, - caching_device=caching_device, name=name, dtype=dtype) + caching_device=caching_device, name=name, dtype=dtype, + constraint=constraint) + + +def _make_getter(captured_getter, captured_previous): + """Gets around capturing loop variables in python being broken.""" + return lambda **kwargs: captured_getter(captured_previous, **kwargs) + + +def variable(initial_value=None, + trainable=True, + collections=None, + validate_shape=True, + caching_device=None, + name=None, + dtype=None, + constraint=None, + use_resource=None): + previous_getter = lambda **kwargs: default_variable_creator(None, **kwargs) + for getter in ops.get_default_graph()._get_variable_creator_stack(): # pylint: disable=protected-access + previous_getter = _make_getter(getter, previous_getter) + return previous_getter(initial_value=initial_value, + trainable=trainable, + collections=collections, + validate_shape=validate_shape, + caching_device=caching_device, + name=name, dtype=dtype, + constraint=constraint, + use_resource=use_resource) + + +@tf_contextlib.contextmanager +def variable_creator_scope(variable_creator): + """Scope which defines a variable creation function to be used by variable(). + + variable_creator is expected to be a function with the following signature: + + ``` + def variable_creator(next_creator, **kwargs) + ``` + + The creator is supposed to eventually call the next_creator to create a + variable if it does want to create a variable and not call Variable or + ResourceVariable directly. This helps make creators composable. A creator may + choose to create multiple variables, return already existing variables, or + simply register that a variable was created and defer to the next creators in + line. Creators can also modify the keyword arguments seen by the next + creators. + + Custom getters in the variable scope will eventually resolve down to these + custom creators when they do create variables. + + The valid keyword arguments in kwds are: + initial_value: A `Tensor`, or Python object convertible to a `Tensor`, + which is the initial value for the Variable. The initial value must have + 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 + collection `GraphKeys.TRAINABLE_VARIABLES`. This collection is used as + the default list of variables to use by the `Optimizer` classes. + collections: List of graph collections keys. The new variable is added to + these collections. Defaults to `[GraphKeys.GLOBAL_VARIABLES]`. + validate_shape: If `False`, allows the variable to be initialized with a + value of unknown shape. If `True`, the default, the shape of + `initial_value` must be known. + caching_device: Optional device string describing where the Variable + should be cached for reading. Defaults to the Variable's device. + If not `None`, caches on another device. Typical use is to cache + on the device where the Ops using the Variable reside, to deduplicate + copying through `Switch` and other conditional statements. + name: Optional name for the variable. Defaults to `'Variable'` and gets + uniquified automatically. + dtype: If set, initial_value will be converted to the given type. + If `None`, either the datatype will be kept (if `initial_value` is + a Tensor), or `convert_to_tensor` will decide. + constraint: A constraint function to be applied to the variable after + updates by some algorithms. + use_resource: if True, a ResourceVariable is always created. + + This set may grow over time, so it's important the signature of creators is as + mentioned above. + + Args: + variable_creator: the passed creator + + Yields: + A scope in which the creator is active + """ + with ops.get_default_graph()._variable_creator_scope(variable_creator): # pylint: disable=protected-access + yield -- GitLab From 04be7c99da20338e246800aa3e087dba278577e9 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Mon, 22 Jan 2018 13:21:46 -0800 Subject: [PATCH 060/258] [TF:XLA] Bump open source llvm revision to r323081 PiperOrigin-RevId: 182825537 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index a1af85aa4e..25702087dc 100644 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -473,11 +473,11 @@ def tf_workspace(path_prefix="", tf_repo_name=""): tf_http_archive( name = "llvm", urls = [ - "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/4c73606e33bba4c18a77c28e5a853adfea421951.tar.gz", - "https://github.com/llvm-mirror/llvm/archive/4c73606e33bba4c18a77c28e5a853adfea421951.tar.gz", + "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/cecc5a23281018f9bbdd6f659462b8c99d8e8926.tar.gz", + "https://github.com/llvm-mirror/llvm/archive/cecc5a23281018f9bbdd6f659462b8c99d8e8926.tar.gz", ], - sha256 = "4e179ad9a7de252602b58e109ff00aad9662e1e83334791b56dafdb580a1e850", - strip_prefix = "llvm-4c73606e33bba4c18a77c28e5a853adfea421951", + sha256 = "b0960749fe2bf78d7c8350c18d584cf6dd5abeeae20da43d4829cdbc0166626c", + strip_prefix = "llvm-cecc5a23281018f9bbdd6f659462b8c99d8e8926", build_file = str(Label("//third_party/llvm:llvm.BUILD")), ) -- GitLab From 149ec37092de4a303f1bb94f99f8a069b434ec33 Mon Sep 17 00:00:00 2001 From: 4d55397500 <4d55397500@users.noreply.github.com> Date: Mon, 22 Jan 2018 13:30:33 -0800 Subject: [PATCH 061/258] 4d55397500 patch 1 (#16176) * Add pos_weights < 1, >1 meaning The current weighted_cross_entropy_with_logits docs don't explain practically the relationship of `pos_weights > 1`, `pos_weights < 1` to precision, recall, and class imbalance. * Update nn_impl.py The current weighted_cross_entropy_with_logits docs don't explain practically the relationship of `pos_weights > 1`, `pos_weights < 1` to precision, recall, and class imbalance. --- tensorflow/python/ops/nn_impl.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/ops/nn_impl.py b/tensorflow/python/ops/nn_impl.py index fd96f7b8fc..e56b46b91e 100644 --- a/tensorflow/python/ops/nn_impl.py +++ b/tensorflow/python/ops/nn_impl.py @@ -192,7 +192,10 @@ def weighted_cross_entropy_with_logits(targets, logits, pos_weight, name=None): targets * -log(sigmoid(logits)) + (1 - targets) * -log(1 - sigmoid(logits)) - The argument `pos_weight` is used as a multiplier for the positive targets: + A value `pos_weights > 1` decreases the false negative count, hence increasing the recall. + Conversely setting `pos_weights < 1` decreases the false positive count and increases the precision. + This can be seen from the fact that `pos_weight` is introduced as a multiplicative coefficient for the positive targets term + in the loss expression: targets * -log(sigmoid(logits)) * pos_weight + (1 - targets) * -log(1 - sigmoid(logits)) -- GitLab From a30e0710c8561c50059778f2ecd7bcbdae6467b0 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 22 Jan 2018 16:31:35 -0500 Subject: [PATCH 062/258] Move generated and real under discriminator namespace (#16158) --- tensorflow/contrib/gan/python/train.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tensorflow/contrib/gan/python/train.py b/tensorflow/contrib/gan/python/train.py index a32ddd7a06..5d0ac93aec 100644 --- a/tensorflow/contrib/gan/python/train.py +++ b/tensorflow/contrib/gan/python/train.py @@ -279,14 +279,16 @@ def acgan_model( generator_inputs = _convert_tensor_or_l_or_d(generator_inputs) generated_data = generator_fn(generator_inputs) with variable_scope.variable_scope(discriminator_scope) as dis_scope: - (discriminator_gen_outputs, discriminator_gen_classification_logits - ) = _validate_acgan_discriminator_outputs( - discriminator_fn(generated_data, generator_inputs)) + with ops.name_scope(dis_scope.name+'/generated/'): + (discriminator_gen_outputs, discriminator_gen_classification_logits + ) = _validate_acgan_discriminator_outputs( + discriminator_fn(generated_data, generator_inputs)) with variable_scope.variable_scope(dis_scope, reuse=True): - real_data = ops.convert_to_tensor(real_data) - (discriminator_real_outputs, discriminator_real_classification_logits - ) = _validate_acgan_discriminator_outputs( - discriminator_fn(real_data, generator_inputs)) + with ops.name_scope(dis_scope.name+'/real/'): + real_data = ops.convert_to_tensor(real_data) + (discriminator_real_outputs, discriminator_real_classification_logits + ) = _validate_acgan_discriminator_outputs( + discriminator_fn(real_data, generator_inputs)) if check_shapes: if not generated_data.shape.is_compatible_with(real_data.shape): raise ValueError( -- GitLab From c0d29859754257dec020e658629501efb756dd1d Mon Sep 17 00:00:00 2001 From: Robin Richtsfeld Date: Mon, 22 Jan 2018 22:37:09 +0100 Subject: [PATCH 063/258] De-Bazel pip_smoke_test sanity check (#15678) --- tensorflow/tools/ci_build/ci_sanity.sh | 16 +++++++--------- tensorflow/tools/pip_package/BUILD | 12 ------------ tensorflow/tools/pip_package/pip_smoke_test.py | 9 +++++++-- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/tensorflow/tools/ci_build/ci_sanity.sh b/tensorflow/tools/ci_build/ci_sanity.sh index b728c878da..b893632bb9 100755 --- a/tensorflow/tools/ci_build/ci_sanity.sh +++ b/tensorflow/tools/ci_build/ci_sanity.sh @@ -26,6 +26,8 @@ SCRIPT_DIR=$( cd ${0%/*} && pwd -P ) source "${SCRIPT_DIR}/builds/builds_common.sh" +ROOT_DIR=$( cd "$SCRIPT_DIR/../../.." && pwd -P ) + # Helper functions die() { echo $@ @@ -418,15 +420,8 @@ do_bazel_nobuild() { } do_pip_smoke_test() { - BUILD_CMD="bazel build ${BAZEL_FLAGS} //tensorflow/tools/pip_package:pip_smoke_test" - ${BUILD_CMD} - cmd_status \ - "Pip smoke test has failed. Please make sure any new TensorFlow are added to the tensorflow/tools/pip_package:build_pip_package dependencies." - - RUN_CMD="bazel-bin/tensorflow/tools/pip_package/pip_smoke_test" - ${RUN_CMD} - cmd_status \ - "The pip smoke test failed." + cd "$ROOT_DIR/tensorflow/tools/pip_package" + python pip_smoke_test.py } do_code_link_check() { @@ -548,7 +543,10 @@ while [[ ${COUNTER} -lt "${#SANITY_STEPS[@]}" ]]; do "${SANITY_STEPS[COUNTER]} (${SANITY_STEPS_DESC[COUNTER]}) ===" echo "" + # subshell: don't leak variables or changes of working directory + ( ${SANITY_STEPS[COUNTER]} ${INCREMENTAL_FLAG} + ) RESULT=$? if [[ ${RESULT} != "0" ]]; then diff --git a/tensorflow/tools/pip_package/BUILD b/tensorflow/tools/pip_package/BUILD index ff5dd6a0b0..c5f39ef7aa 100644 --- a/tensorflow/tools/pip_package/BUILD +++ b/tensorflow/tools/pip_package/BUILD @@ -47,18 +47,6 @@ py_binary( deps = ["//tensorflow:tensorflow_py"], ) -py_test( - name = "pip_smoke_test", - srcs = ["pip_smoke_test.py"], - data = [ - "//tensorflow:all_opensource_files", - ], - tags = [ - "manual", - "notap", - ], -) - py_binary( name = "check_load_py_test", srcs = ["check_load_py_test.py"], diff --git a/tensorflow/tools/pip_package/pip_smoke_test.py b/tensorflow/tools/pip_package/pip_smoke_test.py index cddf9c8f44..8eee489e2d 100644 --- a/tensorflow/tools/pip_package/pip_smoke_test.py +++ b/tensorflow/tools/pip_package/pip_smoke_test.py @@ -23,8 +23,13 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import os import subprocess + +os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))) + + PIP_PACKAGE_QUERY_EXPRESSION = \ 'deps(//tensorflow/tools/pip_package:build_pip_package)' @@ -134,8 +139,8 @@ def main(): raise RuntimeError("""One or more dependencies are not in the pip package. Please either blacklist the dependencies in -tensorflow/tensorflow/tensorflow/tools/pip_package/pip_smoke_test.py -or add them to tensorflow/tensorflow/tensorflow/tools/pip_package/BUILD.""") +//tensorflow/tools/pip_package/pip_smoke_test.py +or add them to //tensorflow/tools/pip_package/BUILD.""") else: print("TEST PASSED") -- GitLab From 510713ae69568b17d54f6d41cab6dffe796256c6 Mon Sep 17 00:00:00 2001 From: Robin Richtsfeld Date: Mon, 22 Jan 2018 22:38:57 +0100 Subject: [PATCH 064/258] [CMake] Add sanity tests for python file lists (#15670) * [CMake] Add sanity tests for python file lists * Add mpi_collectives to python_modules * Add documentation --- tensorflow/contrib/cmake/python_modules.txt | 4 + .../contrib/cmake/python_sanity_test.py | 124 ++++++++++++++++++ tensorflow/contrib/cmake/tf_python.cmake | 9 +- tensorflow/tools/ci_build/ci_sanity.sh | 9 +- 4 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 tensorflow/contrib/cmake/python_sanity_test.py diff --git a/tensorflow/contrib/cmake/python_modules.txt b/tensorflow/contrib/cmake/python_modules.txt index e37d059a84..09e9a68fd4 100644 --- a/tensorflow/contrib/cmake/python_modules.txt +++ b/tensorflow/contrib/cmake/python_modules.txt @@ -1,3 +1,5 @@ +# python_sanity_test.py will complain about invalid or missing entries +# problematic entries can be commented for temporary whitelisting tensorflow tensorflow/core tensorflow/core/example @@ -308,6 +310,8 @@ tensorflow/contrib/metrics tensorflow/contrib/metrics/python tensorflow/contrib/metrics/python/metrics tensorflow/contrib/metrics/python/ops +tensorflow/contrib/mpi_collectives/python +tensorflow/contrib/mpi_collectives/python/ops tensorflow/contrib/model_pruning tensorflow/contrib/model_pruning/examples tensorflow/contrib/model_pruning/examples/cifar10 diff --git a/tensorflow/contrib/cmake/python_sanity_test.py b/tensorflow/contrib/cmake/python_sanity_test.py new file mode 100644 index 0000000000..3be5bd1b23 --- /dev/null +++ b/tensorflow/contrib/cmake/python_sanity_test.py @@ -0,0 +1,124 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +""" +Complain about invalid or missing entries in python_*.txt files. +Problematic entries can be commented for temporary whitelisting. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import unittest + + +def abs_path(path): + root = os.path.dirname(__file__) + + for _ in range(3): + root = os.path.join(root, os.pardir) + + path = os.path.join(root, path) + path = os.path.abspath(path) + return path + +def read_entries(test): + with open(abs_path(test.entries_file), "r") as f: + lines = f.readlines() + + lines = [line.strip() for line in lines] + lines = [line for line in lines if line] + + test.entries = [] + test.whitelist = [] + + for line in lines: + # line is comment + if line.startswith('#'): + line = line[1:].strip() + # whitelist entry + if line.startswith('tensorflow/'): + test.whitelist.append(line) + # line has comment -> strip comment + elif line.find('#') != -1: + line = line[:line.find('#')].strip() + test.entries.append(line) + else: + test.entries.append(line) + +def test_invalid_directories(test): + for entry in test.entries: + if not os.path.isdir(abs_path(entry)): + problem = "'" + test.entries_file + "' contains invalid '" + entry + "'" + solution = "Please remove the invalid entry (or add the missing directory)." + raise AssertionError(problem + "\n" + solution) + +def test_missing_directory(test, path): + if path in test.whitelist: + return + + dir_exists = os.path.isdir(abs_path(path)) + entry_exists = path in test.entries + + if dir_exists and not entry_exists: + problem = "'" + test.entries_file + "' is missing '" + path + "'" + solution = "Please add the missing entry (comment to whitelist if needed)." + raise AssertionError(problem + "\n" + solution) + + +class PythonModuleTest(unittest.TestCase): + + def setUp(self): + self.entries_file = "tensorflow/contrib/cmake/python_modules.txt" + read_entries(self) + + def testInvalidEntries(self): + test_invalid_directories(self) + + def testMissingModules(self): + module_names = next(os.walk(abs_path("tensorflow/contrib")))[1] + + for module_name in module_names: + path = "tensorflow/contrib/" + module_name + + test_missing_directory(self, path + "/python") + test_missing_directory(self, path + "/python/ops") + test_missing_directory(self, path + "/python/kernels") + test_missing_directory(self, path + "/python/layers") + + +class PythonProtoTest(unittest.TestCase): + + def setUp(self): + self.entries_file = "tensorflow/contrib/cmake/python_protos.txt" + read_entries(self) + + def testInvalidEntries(self): + test_invalid_directories(self) + + +class PythonProtoCCTest(unittest.TestCase): + + def setUp(self): + self.entries_file = "tensorflow/contrib/cmake/python_protos_cc.txt" + read_entries(self) + + def testInvalidEntries(self): + test_invalid_directories(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tensorflow/contrib/cmake/tf_python.cmake b/tensorflow/contrib/cmake/tf_python.cmake index 17bbdb1a86..97f9ecc3ab 100755 --- a/tensorflow/contrib/cmake/tf_python.cmake +++ b/tensorflow/contrib/cmake/tf_python.cmake @@ -126,7 +126,8 @@ STRING(REGEX REPLACE ";" "\\\\;" python_protos "${python_protos}") STRING(REGEX REPLACE "\n" ";" python_protos "${python_protos}") foreach(python_proto ${python_protos}) - if(NOT python_proto MATCHES "\#") + if(NOT python_proto MATCHES "^\#") + STRING(REGEX REPLACE " *\#.*" "" python_proto "${python_proto}") if(NOT EXISTS "${tensorflow_source_dir}/${python_proto}") message(SEND_ERROR "Python proto directory not found: ${python_proto}") endif() @@ -147,7 +148,8 @@ STRING(REGEX REPLACE ";" "\\\\;" python_protos_cc "${python_protos_cc}") STRING(REGEX REPLACE "\n" ";" python_protos_cc "${python_protos_cc}") foreach(python_proto_cc ${python_protos_cc}) - if(NOT python_proto_cc MATCHES "\#") + if(NOT python_proto_cc MATCHES "^\#") + STRING(REGEX REPLACE " *\#.*" "" python_proto_cc "${python_proto_cc}") if(NOT EXISTS "${tensorflow_source_dir}/${python_proto_cc}") message(SEND_ERROR "Python proto CC directory not found: ${python_proto_cc}") endif() @@ -209,7 +211,8 @@ STRING(REGEX REPLACE ";" "\\\\;" python_modules "${python_modules}") STRING(REGEX REPLACE "\n" ";" python_modules "${python_modules}") foreach(python_module ${python_modules}) - if(NOT python_module MATCHES "\#") + if(NOT python_module MATCHES "^\#") + STRING(REGEX REPLACE " *\#.*" "" python_module "${python_module}") if(NOT EXISTS "${tensorflow_source_dir}/${python_module}") message(SEND_ERROR "Python module not found: ${python_module}") endif() diff --git a/tensorflow/tools/ci_build/ci_sanity.sh b/tensorflow/tools/ci_build/ci_sanity.sh index b893632bb9..06421c6bb5 100755 --- a/tensorflow/tools/ci_build/ci_sanity.sh +++ b/tensorflow/tools/ci_build/ci_sanity.sh @@ -506,9 +506,14 @@ do_check_load_py_test() { "check_load_py_test failed." } +do_cmake_python_sanity() { + cd "$ROOT_DIR/tensorflow/contrib/cmake" + python -m unittest -v python_sanity_test +} + # Supply all sanity step commands and descriptions -SANITY_STEPS=("do_pylint PYTHON2" "do_pylint PYTHON3" "do_buildifier" "do_bazel_nobuild" "do_pip_package_licenses_check" "do_lib_package_licenses_check" "do_java_package_licenses_check" "do_pip_smoke_test" "do_check_load_py_test" "do_code_link_check") -SANITY_STEPS_DESC=("Python 2 pylint" "Python 3 pylint" "buildifier check" "bazel nobuild" "pip: license check for external dependencies" "C library: license check for external dependencies" "Java Native Library: license check for external dependencies" "Pip Smoke Test: Checking py_test dependencies exist in pip package" "Check load py_test: Check that BUILD files with py_test target properly load py_test" "Code Link Check: Check there are no broken links") +SANITY_STEPS=("do_pylint PYTHON2" "do_pylint PYTHON3" "do_buildifier" "do_bazel_nobuild" "do_pip_package_licenses_check" "do_lib_package_licenses_check" "do_java_package_licenses_check" "do_pip_smoke_test" "do_check_load_py_test" "do_code_link_check" "do_cmake_python_sanity") +SANITY_STEPS_DESC=("Python 2 pylint" "Python 3 pylint" "buildifier check" "bazel nobuild" "pip: license check for external dependencies" "C library: license check for external dependencies" "Java Native Library: license check for external dependencies" "Pip Smoke Test: Checking py_test dependencies exist in pip package" "Check load py_test: Check that BUILD files with py_test target properly load py_test" "Code Link Check: Check there are no broken links" "Test entries in /tensorflow/contrib/cmake/python_{modules|protos|protos_cc}.txt for validity and consistency") INCREMENTAL_FLAG="" DEFAULT_BAZEL_CONFIGS="--config=hdfs --config=gcp" -- GitLab From a88e1aadfdc2520c75d625bcaa41791fe5c8c532 Mon Sep 17 00:00:00 2001 From: Yifei Feng Date: Mon, 22 Jan 2018 13:42:50 -0800 Subject: [PATCH 065/258] Buildifier cleanup. PiperOrigin-RevId: 182829120 --- tensorflow/contrib/lite/kernels/BUILD | 2 +- tensorflow/contrib/lite/kernels/internal/BUILD | 4 ++-- tensorflow/contrib/lite/toco/tflite/BUILD | 10 +++++----- tensorflow/core/BUILD | 6 +++--- tensorflow/core/kernels/BUILD | 10 +++++----- tensorflow/core/kernels/neon/BUILD | 2 +- tensorflow/core/platform/cloud/BUILD | 4 ++-- tensorflow/core/platform/default/build_config/BUILD | 4 ++-- tensorflow/core/platform/s3/BUILD | 12 ++++++------ tensorflow/core/profiler/BUILD | 2 +- third_party/aws.BUILD | 2 +- third_party/eigen3/BUILD | 2 +- third_party/jpeg/jpeg.BUILD | 2 +- third_party/swig.BUILD | 2 +- 14 files changed, 32 insertions(+), 32 deletions(-) diff --git a/tensorflow/contrib/lite/kernels/BUILD b/tensorflow/contrib/lite/kernels/BUILD index 7e9644f36c..bd390d664d 100644 --- a/tensorflow/contrib/lite/kernels/BUILD +++ b/tensorflow/contrib/lite/kernels/BUILD @@ -50,7 +50,7 @@ cc_library( deps = [ ":op_macros", "//tensorflow/contrib/lite:context", - "@gemmlowp//:gemmlowp", + "@gemmlowp", ], ) diff --git a/tensorflow/contrib/lite/kernels/internal/BUILD b/tensorflow/contrib/lite/kernels/internal/BUILD index a3ecb2ebf6..21118fc96d 100644 --- a/tensorflow/contrib/lite/kernels/internal/BUILD +++ b/tensorflow/contrib/lite/kernels/internal/BUILD @@ -145,7 +145,7 @@ cc_library( ":types", ":round", "//third_party/eigen3", - "@gemmlowp//:gemmlowp", + "@gemmlowp", "//tensorflow/contrib/lite:builtin_op_data", ] + select({ ":haswell": tflite_deps_intel, @@ -223,7 +223,7 @@ cc_library( ":round", ":types", "//third_party/eigen3", - "@gemmlowp//:gemmlowp", + "@gemmlowp", "//tensorflow/contrib/lite:builtin_op_data", ] + select({ ":haswell": tflite_deps_intel, diff --git a/tensorflow/contrib/lite/toco/tflite/BUILD b/tensorflow/contrib/lite/toco/tflite/BUILD index 332253a092..72c9266564 100644 --- a/tensorflow/contrib/lite/toco/tflite/BUILD +++ b/tensorflow/contrib/lite/toco/tflite/BUILD @@ -27,7 +27,7 @@ cc_library( "//tensorflow/contrib/lite/toco:model", "//tensorflow/core:protos_all_cc", "@com_google_absl//absl/memory", - "@flatbuffers//:flatbuffers", + "@flatbuffers", ], ) @@ -41,7 +41,7 @@ tf_cc_test( "//tensorflow/contrib/lite/toco:tooling_util", "//tensorflow/core:protos_all_cc", "@com_google_googletest//:gtest_main", - "@flatbuffers//:flatbuffers", + "@flatbuffers", ], ) @@ -87,7 +87,7 @@ cc_library( "//tensorflow/contrib/lite/toco:model", "//tensorflow/contrib/lite/toco:tooling_util", "@com_google_absl//absl/strings", - "@flatbuffers//:flatbuffers", + "@flatbuffers", ], ) @@ -117,7 +117,7 @@ cc_library( ":types", "//tensorflow/contrib/lite/schema:schema_fbs", "//tensorflow/contrib/lite/toco:model", - "@flatbuffers//:flatbuffers", + "@flatbuffers", ], ) @@ -131,7 +131,7 @@ tf_cc_test( "//tensorflow/contrib/lite:schema_fbs_version", "//tensorflow/contrib/lite/schema:schema_fbs", "@com_google_googletest//:gtest_main", - "@flatbuffers//:flatbuffers", + "@flatbuffers", ], ) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 9738a6bb95..232f7d9b3c 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -1068,8 +1068,8 @@ cc_library( ":protos_all_cc_impl", "//third_party/eigen3", "//third_party/fft2d:fft2d_headers", - "@fft2d//:fft2d", - "@gemmlowp//:gemmlowp", + "@fft2d", + "@gemmlowp", "@protobuf_archive//:protobuf", ], alwayslink = 1, @@ -2338,7 +2338,7 @@ cc_library( ":lib_internal", ":proto_text", "//third_party/eigen3", - "@local_config_sycl//sycl:sycl", + "@local_config_sycl//sycl", ], alwayslink = 0, ) diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD index 0794a6ac3d..c0d3867770 100644 --- a/tensorflow/core/kernels/BUILD +++ b/tensorflow/core/kernels/BUILD @@ -4268,7 +4268,7 @@ cc_library( "//tensorflow/core:framework", "//tensorflow/core:lib", "//third_party/fft2d:fft2d_headers", - "@fft2d//:fft2d", + "@fft2d", ], ) @@ -5007,8 +5007,8 @@ cc_library( "//tensorflow/core:protos_all_cc_impl", "//third_party/eigen3", "//third_party/fft2d:fft2d_headers", - "@fft2d//:fft2d", - "@gemmlowp//:gemmlowp", + "@fft2d", + "@gemmlowp", "@protobuf_archive//:protobuf", ], alwayslink = 1, @@ -5079,7 +5079,7 @@ tf_kernel_library( "//tensorflow/core:math_ops_op_lib", "//tensorflow/core:nn_ops_op_lib", "//third_party/eigen3", - "@gemmlowp//:gemmlowp", + "@gemmlowp", ], ) @@ -5992,6 +5992,6 @@ cc_library( "//tensorflow/core:framework", "//tensorflow/core:lib", "//third_party/eigen3", - "@gemmlowp//:gemmlowp", + "@gemmlowp", ], ) diff --git a/tensorflow/core/kernels/neon/BUILD b/tensorflow/core/kernels/neon/BUILD index 536b2bdc03..c3d24e50ef 100644 --- a/tensorflow/core/kernels/neon/BUILD +++ b/tensorflow/core/kernels/neon/BUILD @@ -39,6 +39,6 @@ tf_kernel_library( "//tensorflow/core:nn_ops_op_lib", "//tensorflow/core/kernels:bounds_check", "//tensorflow/core/kernels:ops_util", - "@gemmlowp//:gemmlowp", + "@gemmlowp", ], ) diff --git a/tensorflow/core/platform/cloud/BUILD b/tensorflow/core/platform/cloud/BUILD index 6b6be757f6..07aecf8483 100644 --- a/tensorflow/core/platform/cloud/BUILD +++ b/tensorflow/core/platform/cloud/BUILD @@ -102,7 +102,7 @@ cc_library( ":http_request", "//tensorflow/core:framework_headers_lib", "//tensorflow/core:lib_internal", - "@curl//:curl", + "@curl", ], ) @@ -119,7 +119,7 @@ cc_library( "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "//tensorflow/core:test", - "@curl//:curl", + "@curl", ], ) diff --git a/tensorflow/core/platform/default/build_config/BUILD b/tensorflow/core/platform/default/build_config/BUILD index f2fadb4558..2cd607edbe 100644 --- a/tensorflow/core/platform/default/build_config/BUILD +++ b/tensorflow/core/platform/default/build_config/BUILD @@ -122,7 +122,7 @@ cc_library( "//tensorflow/core:protos_cc", "@com_googlesource_code_re2//:re2", "@farmhash_archive//:farmhash", - "@fft2d//:fft2d", + "@fft2d", "@highwayhash//:sip_hash", "@png_archive//:png", ], @@ -140,7 +140,7 @@ cc_library( name = "jpeg", copts = tf_copts(), deps = [ - "@jpeg//:jpeg", + "@jpeg", ], ) diff --git a/tensorflow/core/platform/s3/BUILD b/tensorflow/core/platform/s3/BUILD index 2cd5f877c9..3a0ad2e9bd 100644 --- a/tensorflow/core/platform/s3/BUILD +++ b/tensorflow/core/platform/s3/BUILD @@ -45,8 +45,8 @@ tf_cc_binary( linkshared = 1, deps = [ "//tensorflow/core:framework_headers_lib", - "@aws//:aws", - "@curl//:curl", + "@aws", + "@curl", "@protobuf_archive//:protobuf_headers", ], ) @@ -62,7 +62,7 @@ cc_library( deps = [ "//tensorflow/core:lib", "//tensorflow/core:lib_internal", - "@aws//:aws", + "@aws", "@boringssl//:crypto", ], alwayslink = 1, @@ -79,7 +79,7 @@ cc_library( deps = [ "//tensorflow/core:lib", "//tensorflow/core:lib_internal", - "@aws//:aws", + "@aws", ], alwayslink = 1, ) @@ -97,7 +97,7 @@ cc_library( ":s3_crypto", "//tensorflow/core:lib", "//tensorflow/core:lib_internal", - "@aws//:aws", + "@aws", ], alwayslink = 1, ) @@ -117,6 +117,6 @@ tf_cc_test( "//tensorflow/core:lib_internal", "//tensorflow/core:test", "//tensorflow/core:test_main", - "@aws//:aws", + "@aws", ], ) diff --git a/tensorflow/core/profiler/BUILD b/tensorflow/core/profiler/BUILD index 5fbfc62e74..35d9993018 100644 --- a/tensorflow/core/profiler/BUILD +++ b/tensorflow/core/profiler/BUILD @@ -38,7 +38,7 @@ tf_cc_binary( "//tensorflow/core/profiler/internal:tfprof_stats", "//tensorflow/core/profiler/internal:tfprof_utils", "//tensorflow/core/profiler/internal/advisor:tfprof_advisor", - "@linenoise//:linenoise", + "@linenoise", ], ) diff --git a/third_party/aws.BUILD b/third_party/aws.BUILD index bf5310aa16..2dc921933c 100644 --- a/third_party/aws.BUILD +++ b/third_party/aws.BUILD @@ -75,7 +75,7 @@ cc_library( "aws-cpp-sdk-s3/include/", ], deps = [ - "@curl//:curl", + "@curl", ], ) diff --git a/third_party/eigen3/BUILD b/third_party/eigen3/BUILD index f5f3418527..f661093bc9 100644 --- a/third_party/eigen3/BUILD +++ b/third_party/eigen3/BUILD @@ -36,7 +36,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ "@eigen_archive//:eigen", - "@local_config_sycl//sycl:sycl", + "@local_config_sycl//sycl", ], ) diff --git a/third_party/jpeg/jpeg.BUILD b/third_party/jpeg/jpeg.BUILD index 527a08c4b3..37924125cf 100644 --- a/third_party/jpeg/jpeg.BUILD +++ b/third_party/jpeg/jpeg.BUILD @@ -219,7 +219,7 @@ genrule( " -o $$out" + " $$(dirname $(location simd/jdct.inc))/$$(basename $${out%.o}.asm)\n" + "done", - tools = ["@nasm//:nasm"], + tools = ["@nasm"], ) cc_library( diff --git a/third_party/swig.BUILD b/third_party/swig.BUILD index d698fa934b..f2f647401b 100644 --- a/third_party/swig.BUILD +++ b/third_party/swig.BUILD @@ -89,7 +89,7 @@ cc_binary( ], output_licenses = ["unencumbered"], visibility = ["//visibility:public"], - deps = ["@pcre//:pcre"], + deps = ["@pcre"], ) filegroup( -- GitLab From b36afe4ca4d7a4b289725b4a75156e97a83cca60 Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Mon, 22 Jan 2018 13:58:08 -0800 Subject: [PATCH 066/258] Track swapping candidates directly in memory instead of annotating them in the graph PiperOrigin-RevId: 182831471 --- .../grappler/optimizers/memory_optimizer.cc | 22 +++++++-------- .../optimizers/memory_optimizer_test.cc | 27 ++++++++++--------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/memory_optimizer.cc b/tensorflow/core/grappler/optimizers/memory_optimizer.cc index 8418abd80f..f537ecc41b 100644 --- a/tensorflow/core/grappler/optimizers/memory_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/memory_optimizer.cc @@ -829,7 +829,7 @@ static NodeDef* FindSwapOutTrigger( view.GetFanout(generator); NodeDef* trigger = nullptr; Costs::NanoSeconds earliest_fanout( - static_cast(std::numeric_limits::max())); + static_cast(std::numeric_limits::max() >> 2)); for (const auto& port : fanout) { if (port.node == node) { @@ -861,8 +861,9 @@ static bool IsSwappable(GraphView::InputPort input) { return !IsRefType(dtype); } -static bool IdentifySwappingCandidates(Cluster* cluster, GrapplerItem* item, - std::unordered_set* skip_list) { +static bool IdentifySwappingCandidates( + Cluster* cluster, GrapplerItem* item, std::unordered_set* skip_list, + std::unordered_map* nodes_to_swap) { GraphMemory memory(*item); const std::unordered_map& devices = cluster->GetDevices(); @@ -960,9 +961,8 @@ static bool IdentifySwappingCandidates(Cluster* cluster, GrapplerItem* item, } } if (!found) { - AttrValue& val = - (*fanout_to_swap.node->mutable_attr())["_swap_to_host"]; - val.mutable_list()->add_i(fanout_to_swap.port_id); + (*nodes_to_swap)[fanout_to_swap.node].inputs_to_swap.push_back( + fanout_to_swap.port_id); required_savings -= live_tensor.memory_used; updated_graph = true; if (required_savings < 0) { @@ -978,14 +978,13 @@ static bool IdentifySwappingCandidates(Cluster* cluster, GrapplerItem* item, bool SwappingPass(RewriterConfig::MemOptType optimization_level, Cluster* cluster, GrapplerItem* item, std::unordered_set* skip_list) { - bool updated_graph = false; + std::unordered_map nodes_to_swap; if (optimization_level == RewriterConfig::SWAPPING_HEURISTICS || optimization_level == RewriterConfig::HEURISTICS) { // Use heuristics to figure out what needs to be swapped; - updated_graph = IdentifySwappingCandidates(cluster, item, skip_list); + IdentifySwappingCandidates(cluster, item, skip_list, &nodes_to_swap); } // Look for manual annotatations in the graph. - std::unordered_map nodes_to_swap; for (auto& node : *item->graph.mutable_node()) { if (node.attr().count("_swap_to_host") != 0) { SwapInfo& swap_info = nodes_to_swap[&node]; @@ -1035,10 +1034,11 @@ bool SwappingPass(RewriterConfig::MemOptType optimization_level, } GraphView view(&item->graph); + bool updated_graph = false; + for (auto& swap : nodes_to_swap) { NodeDef* node = swap.first; const SwapInfo& swap_info = swap.second; - if (skip_list->find(node->name()) != skip_list->end()) { continue; } @@ -1064,7 +1064,7 @@ bool SwappingPass(RewriterConfig::MemOptType optimization_level, skip_list->insert(input_name); } - // Make sure the tensor isn't swapped out quickly look for node that + // Make sure the tensor is swapped out quickly: look for node that // will execute just after the tensor is generated and add a control // dependency from the swap out node to that node. NodeDef* out_trigger = diff --git a/tensorflow/core/grappler/optimizers/memory_optimizer_test.cc b/tensorflow/core/grappler/optimizers/memory_optimizer_test.cc index 185ac6040c..dd2d20d8d6 100644 --- a/tensorflow/core/grappler/optimizers/memory_optimizer_test.cc +++ b/tensorflow/core/grappler/optimizers/memory_optimizer_test.cc @@ -280,10 +280,14 @@ TEST_F(MemoryOptimizerTest, SwappingHeuristics) { Output axis = ops::Const(s.WithOpName("axis"), 0); Output e = ops::Concat(s.WithOpName("e").WithDevice("/gpu:0"), {a, b, c, d}, axis); + Output f = ops::Square(s.WithOpName("f").WithDevice("/gpu:0"), a); + Output g = ops::Sqrt(s.WithOpName("g").WithDevice("/gpu:0"), b); + Output h = ops::Exp(s.WithOpName("h").WithDevice("/gpu:0"), c); + Output i = ops::Log(s.WithOpName("i").WithDevice("/gpu:0"), d); GrapplerItem item; TF_CHECK_OK(s.ToGraphDef(&item.graph)); - item.fetch = {"e"}; + item.fetch = {"e", "f", "g", "h", "i"}; std::unique_ptr cluster(CreateVirtualCluster()); @@ -294,14 +298,12 @@ TEST_F(MemoryOptimizerTest, SwappingHeuristics) { for (const auto& node : output.node()) { if (node.name() == "e") { - EXPECT_TRUE(node.attr().count("_swap_to_host") > 0); - const AttrValue& val = node.attr().at("_swap_to_host"); - EXPECT_TRUE(val.has_list()); - std::set inputs_to_swap; - for (int64 input_id : val.list().i()) { - inputs_to_swap.insert(input_id); - } - EXPECT_EQ(std::set({1, 2, 3}), inputs_to_swap); + EXPECT_EQ(5, node.input_size()); + EXPECT_EQ("a", node.input(0)); + EXPECT_EQ("swap_in_e_1", node.input(1)); + EXPECT_EQ("swap_in_e_2", node.input(2)); + EXPECT_EQ("swap_in_e_3", node.input(3)); + EXPECT_EQ("axis", node.input(4)); } } } @@ -333,9 +335,10 @@ TEST_F(MemoryOptimizerTest, UnswappableInputs) { TF_EXPECT_OK(status); for (const auto& node : output.node()) { - if (node.name() == "d") { - EXPECT_EQ(1, node.attr().count("_swap_to_host")); - EXPECT_EQ(2, node.attr().at("_swap_to_host").list().i(0)); + if (node.name() == "e") { + // The d node isn't swappable. + EXPECT_EQ(4, node.input_size()); + EXPECT_EQ("d", node.input(2)); } } } -- GitLab From 9558c46b1b95b119d6304f623d1594c938e82a04 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Mon, 22 Jan 2018 14:21:16 -0800 Subject: [PATCH 067/258] Thread-safety for the TFE tape code. In multithreaded python any call to a python API function can release the GIL, so we should not assume our data structures haven't changed across calls to the python API. PiperOrigin-RevId: 182835555 --- tensorflow/python/eager/pywrap_tfe_src.cc | 25 ++++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/tensorflow/python/eager/pywrap_tfe_src.cc b/tensorflow/python/eager/pywrap_tfe_src.cc index a14b4aef5f..b3ce09ce90 100644 --- a/tensorflow/python/eager/pywrap_tfe_src.cc +++ b/tensorflow/python/eager/pywrap_tfe_src.cc @@ -22,6 +22,7 @@ limitations under the License. #include "tensorflow/c/eager/c_api_internal.h" #include "tensorflow/c/eager/tape.h" #include "tensorflow/core/lib/gtl/cleanup.h" +#include "tensorflow/core/lib/gtl/compactptrset.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/lib/strings/stringprintf.h" #include "tensorflow/core/platform/mutex.h" @@ -542,10 +543,10 @@ static PyTypeObject TFE_Py_Tape_Type = { // GIL, which is always held when any TFE_Py_* methods are called. We should // revisit this if/when decide to not hold the GIL while manipulating the tape // stack. -static std::unordered_set* tape_set = nullptr; -std::unordered_set* GetTapeSet() { +static tensorflow::gtl::CompactPointerSet* tape_set = nullptr; +tensorflow::gtl::CompactPointerSet* GetTapeSet() { if (tape_set == nullptr) { - tape_set = new std::unordered_set; + tape_set = new tensorflow::gtl::CompactPointerSet; } return tape_set; } @@ -636,8 +637,8 @@ PyObject* TFE_Py_TapeSetShouldRecord(PyObject* tensors) { if (*ThreadTapeIsStopped()) { Py_RETURN_FALSE; } - auto* tape_set = GetTapeSet(); - if (tape_set->empty()) { + auto* tape_set_ptr = GetTapeSet(); + if (tape_set_ptr->empty()) { Py_RETURN_FALSE; } PyObject* seq = PySequence_Fast(tensors, "expected a sequence"); @@ -654,7 +655,8 @@ PyObject* TFE_Py_TapeSetShouldRecord(PyObject* tensors) { tensor_ids.push_back(FastTensorId(item)); } Py_DECREF(seq); - for (TFE_Py_Tape* tape : *tape_set) { + auto tape_set = *tape_set_ptr; + for (TFE_Py_Tape* tape : tape_set) { if (tape->tape->ShouldRecord(tensor_ids)) { Py_RETURN_TRUE; } @@ -760,8 +762,7 @@ PyObject* TFE_Py_TapeWatchedVariables(PyObject* tape) { void TFE_Py_TapeSetRecordOperation(PyObject* op_type, PyObject* output_tensors, PyObject* input_tensors, PyObject* backward_function) { - auto* set = GetTapeSet(); - if (set->empty() || *ThreadTapeIsStopped()) { + if (GetTapeSet()->empty() || *ThreadTapeIsStopped()) { return; } std::vector input_ids = MakeTensorIDList(input_tensors); @@ -796,7 +797,8 @@ void TFE_Py_TapeSetRecordOperation(PyObject* op_type, PyObject* output_tensors, return; } - for (TFE_Py_Tape* tape : *set) { + auto set = *GetTapeSet(); + for (TFE_Py_Tape* tape : set) { Py_INCREF(backward_function); tape->tape->RecordOperation( op_type_str, output_info, input_ids, backward_function, @@ -805,7 +807,10 @@ void TFE_Py_TapeSetRecordOperation(PyObject* op_type, PyObject* output_tensors, } void TFE_Py_TapeSetDeleteTrace(tensorflow::int64 tensor_id) { - for (TFE_Py_Tape* tape : *GetTapeSet()) { + // Note: making a copy because deleting the trace can trigger a change to the + // set of tapes by allowing python's garbage collector to run. + auto tape_set = *GetTapeSet(); + for (TFE_Py_Tape* tape : tape_set) { tape->tape->DeleteTrace(tensor_id); } } -- GitLab From ca6e27c83d9abf322dbfeba47e1b227e03cbcf6a Mon Sep 17 00:00:00 2001 From: vchigrin Date: Tue, 23 Jan 2018 01:46:36 +0300 Subject: [PATCH 068/258] Fix periodic resample (#15617) * Fix documentation of periodic_resample operation. * Add check for desired shape sizes. * Add test for error reporting of periodic_resample operation. * Fix formatting in periodic_resample documentation. --- tensorflow/contrib/periodic_resample/BUILD | 12 ++++++ .../kernels/periodic_resample_op.h | 11 +++++ .../periodic_resample/ops/array_ops.cc | 42 ++++++++++++------- .../kernel_tests/periodic_resample_op_test.py | 14 +++++++ 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/tensorflow/contrib/periodic_resample/BUILD b/tensorflow/contrib/periodic_resample/BUILD index 71582f9c9a..7a2a51d265 100644 --- a/tensorflow/contrib/periodic_resample/BUILD +++ b/tensorflow/contrib/periodic_resample/BUILD @@ -6,6 +6,7 @@ exports_files(["LICENSE"]) load( "//tensorflow:tensorflow.bzl", + "py_test", "tf_gen_op_libs", "tf_custom_op_library", "tf_custom_op_py_library", @@ -69,6 +70,17 @@ py_library( ], ) +py_test( + name = "periodic_resample_op_test", + srcs = ["python/kernel_tests/periodic_resample_op_test.py"], + srcs_version = "PY2AND3", + deps = [ + ":init_py", + "//tensorflow/contrib/util:util_py", + "//tensorflow/python:framework_test_lib", + ], +) + # py_library( # name = "periodic_resample_op_py", # srcs = ["python/ops/periodic_resample_op.py"], diff --git a/tensorflow/contrib/periodic_resample/kernels/periodic_resample_op.h b/tensorflow/contrib/periodic_resample/kernels/periodic_resample_op.h index bef21f7a5c..ba410f025d 100644 --- a/tensorflow/contrib/periodic_resample/kernels/periodic_resample_op.h +++ b/tensorflow/contrib/periodic_resample/kernels/periodic_resample_op.h @@ -100,6 +100,8 @@ template = input_tensor_shape.dim_size(i), + tensorflow::errors::InvalidArgument( + "periodic_resample expects the size of non-adjustable " + "dimensions be at least as large as size of input tensor." + " Dimension ", i, " input tensor has size ", + input_tensor_shape.dim_size(i), ", desired shape has size ", + desired_shape[i], ".")); + // target_dimensions[i] = desired_shape(i); target_dimensions[i] = desired_shape[i]; new_sliced_size *= target_dimensions[i]; diff --git a/tensorflow/contrib/periodic_resample/ops/array_ops.cc b/tensorflow/contrib/periodic_resample/ops/array_ops.cc index c90fc06c7f..82bd796956 100644 --- a/tensorflow/contrib/periodic_resample/ops/array_ops.cc +++ b/tensorflow/contrib/periodic_resample/ops/array_ops.cc @@ -34,26 +34,40 @@ This function implements a slightly more generic version of the subpixel convolutions found in this [paper](https://arxiv.org/abs/1609.05158). The formula for computing the elements in the `output` tensor is as follows: + `T` = `values` tensor of rank `R` + `S` = desired `shape` of output tensor (vector of length `R`) + `P` = `output` tensor of rank `R` - \((T_1,\ldots,T_R)\) = shape(`T`) - \([S_1,\ldots,S_q,\ldots,S_R]\) = elements of vector `S` - A single element in `S` is left unspecified (denoted \(S_q=-1\)). - Let \(f_i\) denote the (possibly non-integer) factor that relates the original - dimension to the desired dimensions, \(S_i=f_i T_i\), for \(i\neq q\) where - \(f_i>0\). + \\((T_1,\\ldots,T_R)\\) = shape(`T`) + + \\([S_1,\\ldots,S_q,\\ldots,S_R]\\) = elements of vector `S` + + A single element in `S` is left unspecified (denoted \\(S_q=-1\\)). + + Let \\(f_i\\) denote the (possibly non-integer) factor that relates the original + dimension to the desired dimensions, \\(S_i=f_i T_i\\), for \\(i\\neq q\\) where + \\(f_i>0\\). + Define the following: - \(g_i=\lceil f_i\rceil\) - \(t=\prod_i T_i\) - \(s=\prod_{i\neq q} S_i\) - \(S_q\) can then be defined as by \(S_q=\lfloor t/s\rfloor\). + + \\(g_i=\\lceil f_i\\rceil\\) + + \\(t=\\prod_i T_i\\) + + \\(s=\\prod_{i\\neq q} S_i\\) + + \\(S_q\\) can then be defined by \\(S_q=\\lfloor t/s\\rfloor\\). The elements of the resulting tensor are defined as - \(P_{s_1,\ldots,s_R}=T_{h_1,\ldots,h_q,\ldots,h_R}\). - The \(h_i\) (\(i\neq q\)) are defined by \(h_i=\lfloor s_i/g_i\rfloor\). - \(h_q=S_q\sum_{j\neq q}^{q-1}G_j \mathrm{mod}(s_j,g_j) + s_q\), where - \(G_j=\prod_{i}^{j-1}g_i\) (\(G_0=1\)). + + \\(P_{s_1,\\ldots,s_R}=T_{h_1,\\ldots,h_q,\\ldots,h_R}\\). + + The \\(h_i\\) (\\(i\\neq q\\)) are defined by \\(h_i=\\lfloor s_i/g_i\\rfloor\\). + + \\(h_q=S_q\\sum_{j\\neq q}^{q-1}G_j \\mathrm{mod}(s_j,g_j) + s_q\\), where + \\(G_j=\\prod_{i}^{j-1}g_i\\) (\\(G_0=1\\)). One drawback of this method is that whenever the output dimensions are slightly less than integer multiples of the input dimensions, many of the tensor elements diff --git a/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py b/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py index 1d727870f6..a4665b4d5b 100644 --- a/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py +++ b/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy import tensorflow from tensorflow.contrib.periodic_resample import periodic_resample +from tensorflow.python.framework import errors_impl from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import googletest @@ -96,6 +97,19 @@ class PeriodicResampleTest(test_util.TensorFlowTestCase): result = periodic_resample(input_tensor, desired_shape).eval() self.assertAllEqual(result, output_tensor) + def testPeriodicResampleErrors(self): + input_tensor = numpy.zeros(shape=[1, 2, 2, 4]) + with self.test_session(): + variables.global_variables_initializer().run() + with self.assertRaisesWithPredicateMatch( + errors_impl.InvalidArgumentError, + 'Dimension 3 input tensor has size 4, desired shape has size 1'): + periodic_resample(input_tensor, [None, 4, 4, 1]).eval() + with self.assertRaisesWithPredicateMatch( + errors_impl.InvalidArgumentError, + '4, to be the same as the length of the desired shape, 3'): + periodic_resample(input_tensor, [None, 4, 4]).eval() + if __name__ == "__main__": googletest.main() -- GitLab From f02efd91973a596469333f562146b6b3c0e5c83a Mon Sep 17 00:00:00 2001 From: Anna R Date: Mon, 22 Jan 2018 14:59:19 -0800 Subject: [PATCH 069/258] Adding tf_export decorators/calls to TensorFlow functions and constants. PiperOrigin-RevId: 182841644 --- .../keras/_impl/keras/datasets/boston_housing.py | 2 ++ .../python/keras/_impl/keras/datasets/cifar10.py | 2 ++ .../python/keras/_impl/keras/datasets/cifar100.py | 2 ++ .../python/keras/_impl/keras/datasets/imdb.py | 3 +++ .../python/keras/_impl/keras/datasets/mnist.py | 2 ++ .../python/keras/_impl/keras/datasets/reuters.py | 3 +++ .../python/keras/_impl/keras/utils/data_utils.py | 6 +++++- .../keras/_impl/keras/utils/generic_utils.py | 7 +++++++ .../python/keras/_impl/keras/utils/io_utils.py | 2 ++ .../python/keras/_impl/keras/utils/layer_utils.py | 2 ++ .../python/keras/_impl/keras/utils/np_utils.py | 3 +++ .../keras/_impl/keras/utils/training_utils.py | 3 ++- .../python/keras/_impl/keras/utils/vis_utils.py | 2 ++ tensorflow/python/platform/benchmark.py | 2 ++ tensorflow/python/platform/gfile.py | 3 +++ tensorflow/python/platform/sysconfig.py | 5 +++++ tensorflow/python/platform/test.py | 5 +++++ tensorflow/tools/api/generator/BUILD | 15 +++++++++++++++ 18 files changed, 67 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/keras/_impl/keras/datasets/boston_housing.py b/tensorflow/python/keras/_impl/keras/datasets/boston_housing.py index 5d5d2c4f75..0570e9bc0c 100644 --- a/tensorflow/python/keras/_impl/keras/datasets/boston_housing.py +++ b/tensorflow/python/keras/_impl/keras/datasets/boston_housing.py @@ -21,8 +21,10 @@ from __future__ import print_function import numpy as np from tensorflow.python.keras._impl.keras.utils.data_utils import get_file +from tensorflow.python.util.tf_export import tf_export +@tf_export('keras.datasets.boston_housing.load_data') def load_data(path='boston_housing.npz', seed=113, test_split=0.2): """Loads the Boston Housing dataset. diff --git a/tensorflow/python/keras/_impl/keras/datasets/cifar10.py b/tensorflow/python/keras/_impl/keras/datasets/cifar10.py index 7905da66c1..1971f434b9 100644 --- a/tensorflow/python/keras/_impl/keras/datasets/cifar10.py +++ b/tensorflow/python/keras/_impl/keras/datasets/cifar10.py @@ -25,8 +25,10 @@ import numpy as np from tensorflow.python.keras._impl.keras import backend as K from tensorflow.python.keras._impl.keras.datasets.cifar import load_batch from tensorflow.python.keras._impl.keras.utils.data_utils import get_file +from tensorflow.python.util.tf_export import tf_export +@tf_export('keras.datasets.cifar10.load_data') def load_data(): """Loads CIFAR10 dataset. diff --git a/tensorflow/python/keras/_impl/keras/datasets/cifar100.py b/tensorflow/python/keras/_impl/keras/datasets/cifar100.py index b69c0724c5..f4039e9350 100644 --- a/tensorflow/python/keras/_impl/keras/datasets/cifar100.py +++ b/tensorflow/python/keras/_impl/keras/datasets/cifar100.py @@ -25,8 +25,10 @@ import numpy as np from tensorflow.python.keras._impl.keras import backend as K from tensorflow.python.keras._impl.keras.datasets.cifar import load_batch from tensorflow.python.keras._impl.keras.utils.data_utils import get_file +from tensorflow.python.util.tf_export import tf_export +@tf_export('keras.datasets.cifar100.load_data') def load_data(label_mode='fine'): """Loads CIFAR100 dataset. diff --git a/tensorflow/python/keras/_impl/keras/datasets/imdb.py b/tensorflow/python/keras/_impl/keras/datasets/imdb.py index 7d55ebc8e4..7946c46960 100644 --- a/tensorflow/python/keras/_impl/keras/datasets/imdb.py +++ b/tensorflow/python/keras/_impl/keras/datasets/imdb.py @@ -24,8 +24,10 @@ import numpy as np from six.moves import zip # pylint: disable=redefined-builtin from tensorflow.python.keras._impl.keras.utils.data_utils import get_file +from tensorflow.python.util.tf_export import tf_export +@tf_export('keras.datasets.imdb.load_data') def load_data(path='imdb.npz', num_words=None, skip_top=0, @@ -133,6 +135,7 @@ def load_data(path='imdb.npz', return (x_train, y_train), (x_test, y_test) +@tf_export('keras.datasets.imdb.get_word_index') def get_word_index(path='imdb_word_index.json'): """Retrieves the dictionary mapping word indices back to words. diff --git a/tensorflow/python/keras/_impl/keras/datasets/mnist.py b/tensorflow/python/keras/_impl/keras/datasets/mnist.py index e98f29537f..e9f5348015 100644 --- a/tensorflow/python/keras/_impl/keras/datasets/mnist.py +++ b/tensorflow/python/keras/_impl/keras/datasets/mnist.py @@ -21,8 +21,10 @@ from __future__ import print_function import numpy as np from tensorflow.python.keras._impl.keras.utils.data_utils import get_file +from tensorflow.python.util.tf_export import tf_export +@tf_export('keras.datasets.mnist.load_data') def load_data(path='mnist.npz'): """Loads the MNIST dataset. diff --git a/tensorflow/python/keras/_impl/keras/datasets/reuters.py b/tensorflow/python/keras/_impl/keras/datasets/reuters.py index 3fed12b59f..6da5aa4b5e 100644 --- a/tensorflow/python/keras/_impl/keras/datasets/reuters.py +++ b/tensorflow/python/keras/_impl/keras/datasets/reuters.py @@ -25,8 +25,10 @@ import numpy as np from six.moves import zip # pylint: disable=redefined-builtin from tensorflow.python.keras._impl.keras.utils.data_utils import get_file +from tensorflow.python.util.tf_export import tf_export +@tf_export('keras.datasets.reuters.load_data') def load_data(path='reuters.npz', num_words=None, skip_top=0, @@ -123,6 +125,7 @@ def load_data(path='reuters.npz', return (x_train, y_train), (x_test, y_test) +@tf_export('keras.datasets.reuters.get_word_index') def get_word_index(path='reuters_word_index.json'): """Retrieves the dictionary mapping word indices back to words. diff --git a/tensorflow/python/keras/_impl/keras/utils/data_utils.py b/tensorflow/python/keras/_impl/keras/utils/data_utils.py index d0be29f829..d9e8f37e36 100644 --- a/tensorflow/python/keras/_impl/keras/utils/data_utils.py +++ b/tensorflow/python/keras/_impl/keras/utils/data_utils.py @@ -38,6 +38,7 @@ from six.moves.urllib.error import URLError from six.moves.urllib.request import urlopen from tensorflow.python.keras._impl.keras.utils.generic_utils import Progbar +from tensorflow.python.util.tf_export import tf_export try: import queue # pylint:disable=g-import-not-at-top @@ -135,6 +136,7 @@ def _extract_archive(file_path, path='.', archive_format='auto'): return False +@tf_export('keras.utils.get_file') def get_file(fname, origin, untar=False, @@ -315,6 +317,7 @@ def validate_file(fpath, file_hash, algorithm='auto', chunk_size=65535): return False +@tf_export('keras.utils.Sequence') class Sequence(object): """Base object for fitting to a sequence of data, such as a dataset. @@ -402,6 +405,7 @@ def get_index(uid, i): return _SHARED_SEQUENCES[uid][i] +@tf_export('keras.utils.SequenceEnqueuer') class SequenceEnqueuer(object): """Base class to enqueue inputs. @@ -608,6 +612,7 @@ class OrderedEnqueuer(SequenceEnqueuer): self.executor.join() +@tf_export('keras.utils.GeneratorEnqueuer') class GeneratorEnqueuer(SequenceEnqueuer): """Builds a queue out of a data generator. @@ -752,4 +757,3 @@ class GeneratorEnqueuer(SequenceEnqueuer): success, value = self.queue.get() if not success: six.reraise(value.__class__, value, value.__traceback__) - diff --git a/tensorflow/python/keras/_impl/keras/utils/generic_utils.py b/tensorflow/python/keras/_impl/keras/utils/generic_utils.py index e9e54c2a2a..a805315c94 100644 --- a/tensorflow/python/keras/_impl/keras/utils/generic_utils.py +++ b/tensorflow/python/keras/_impl/keras/utils/generic_utils.py @@ -29,10 +29,12 @@ import six from tensorflow.python.util import tf_decorator from tensorflow.python.util import tf_inspect +from tensorflow.python.util.tf_export import tf_export _GLOBAL_CUSTOM_OBJECTS = {} +@tf_export('keras.utils.CustomObjectScope') class CustomObjectScope(object): """Provides a scope that changes to `_GLOBAL_CUSTOM_OBJECTS` cannot escape. @@ -68,6 +70,7 @@ class CustomObjectScope(object): _GLOBAL_CUSTOM_OBJECTS.update(self.backup) +@tf_export('keras.utils.custom_object_scope') def custom_object_scope(*args): """Provides a scope that changes to `_GLOBAL_CUSTOM_OBJECTS` cannot escape. @@ -98,6 +101,7 @@ def custom_object_scope(*args): return CustomObjectScope(*args) +@tf_export('keras.utils.get_custom_objects') def get_custom_objects(): """Retrieves a live reference to the global dictionary of custom objects. @@ -118,6 +122,7 @@ def get_custom_objects(): return _GLOBAL_CUSTOM_OBJECTS +@tf_export('keras.utils.serialize_keras_object') def serialize_keras_object(instance): _, instance = tf_decorator.unwrap(instance) if instance is None: @@ -133,6 +138,7 @@ def serialize_keras_object(instance): raise ValueError('Cannot serialize', instance) +@tf_export('keras.utils.deserialize_keras_object') def deserialize_keras_object(identifier, module_objects=None, custom_objects=None, @@ -275,6 +281,7 @@ def has_arg(fn, name, accept_all=False): return name in arg_spec.args +@tf_export('keras.utils.Progbar') class Progbar(object): """Displays a progress bar. diff --git a/tensorflow/python/keras/_impl/keras/utils/io_utils.py b/tensorflow/python/keras/_impl/keras/utils/io_utils.py index a8fc18c17a..e123339f5a 100644 --- a/tensorflow/python/keras/_impl/keras/utils/io_utils.py +++ b/tensorflow/python/keras/_impl/keras/utils/io_utils.py @@ -21,6 +21,7 @@ from collections import defaultdict import sys import numpy as np +from tensorflow.python.util.tf_export import tf_export try: @@ -29,6 +30,7 @@ except ImportError: h5py = None +@tf_export('keras.utils.HDF5Matrix') class HDF5Matrix(object): """Representation of HDF5 dataset to be used instead of a Numpy array. diff --git a/tensorflow/python/keras/_impl/keras/utils/layer_utils.py b/tensorflow/python/keras/_impl/keras/utils/layer_utils.py index 053c0600a3..30af285cbf 100644 --- a/tensorflow/python/keras/_impl/keras/utils/layer_utils.py +++ b/tensorflow/python/keras/_impl/keras/utils/layer_utils.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.keras._impl.keras import backend as K from tensorflow.python.keras._impl.keras.utils.conv_utils import convert_kernel +from tensorflow.python.util.tf_export import tf_export def count_params(weights): @@ -187,6 +188,7 @@ def print_summary(model, line_length=None, positions=None, print_fn=None): print_fn('_' * line_length) +@tf_export('keras.utils.convert_all_kernels_in_model') def convert_all_kernels_in_model(model): """Converts all convolution kernels in a model from Theano to TensorFlow. diff --git a/tensorflow/python/keras/_impl/keras/utils/np_utils.py b/tensorflow/python/keras/_impl/keras/utils/np_utils.py index 67d83bf42c..3dddb99191 100644 --- a/tensorflow/python/keras/_impl/keras/utils/np_utils.py +++ b/tensorflow/python/keras/_impl/keras/utils/np_utils.py @@ -18,8 +18,10 @@ from __future__ import division from __future__ import print_function import numpy as np +from tensorflow.python.util.tf_export import tf_export +@tf_export('keras.utils.to_categorical') def to_categorical(y, num_classes=None): """Converts a class vector (integers) to binary class matrix. @@ -48,6 +50,7 @@ def to_categorical(y, num_classes=None): return categorical +@tf_export('keras.utils.normalize') def normalize(x, axis=-1, order=2): """Normalizes a Numpy array. diff --git a/tensorflow/python/keras/_impl/keras/utils/training_utils.py b/tensorflow/python/keras/_impl/keras/utils/training_utils.py index 0bf4ac8a24..ce7402e9d2 100644 --- a/tensorflow/python/keras/_impl/keras/utils/training_utils.py +++ b/tensorflow/python/keras/_impl/keras/utils/training_utils.py @@ -21,6 +21,7 @@ from tensorflow.python.framework import ops from tensorflow.python.keras._impl.keras import backend as K from tensorflow.python.keras._impl.keras.engine.training import Model from tensorflow.python.ops import array_ops +from tensorflow.python.util.tf_export import tf_export def _get_available_devices(): @@ -32,6 +33,7 @@ def _normalize_device_name(name): return name +@tf_export('keras.utils.multi_gpu_model') def multi_gpu_model(model, gpus): """Replicates a model on different GPUs. @@ -203,4 +205,3 @@ def multi_gpu_model(model, gpus): for name, outputs in zip(model.output_names, all_outputs): merged.append(concatenate(outputs, axis=0, name=name)) return Model(model.inputs, merged) - diff --git a/tensorflow/python/keras/_impl/keras/utils/vis_utils.py b/tensorflow/python/keras/_impl/keras/utils/vis_utils.py index d56c4484ce..1ec8e3a2bf 100644 --- a/tensorflow/python/keras/_impl/keras/utils/vis_utils.py +++ b/tensorflow/python/keras/_impl/keras/utils/vis_utils.py @@ -19,6 +19,7 @@ from __future__ import print_function import os import sys +from tensorflow.python.util.tf_export import tf_export try: # pydot-ng is a fork of pydot that is better maintained. @@ -128,6 +129,7 @@ def model_to_dot(model, show_shapes=False, show_layer_names=True, rankdir='TB'): return dot +@tf_export('keras.utils.plot_model') def plot_model(model, to_file='model.png', show_shapes=False, diff --git a/tensorflow/python/platform/benchmark.py b/tensorflow/python/platform/benchmark.py index 837bca1dbd..12dae94a64 100644 --- a/tensorflow/python/platform/benchmark.py +++ b/tensorflow/python/platform/benchmark.py @@ -33,6 +33,7 @@ from tensorflow.python.platform import app from tensorflow.python.platform import gfile from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import tf_inspect +from tensorflow.python.util.tf_export import tf_export # When a subclass of the Benchmark class is created, it is added to @@ -181,6 +182,7 @@ class Benchmark(six.with_metaclass(_BenchmarkRegistrar, object)): throughput=throughput, extras=extras) +@tf_export("test.Benchmark") class TensorFlowBenchmark(Benchmark): """Abstract class that provides helpers for TensorFlow benchmarks.""" diff --git a/tensorflow/python/platform/gfile.py b/tensorflow/python/platform/gfile.py index 202475efdf..315889e9aa 100644 --- a/tensorflow/python/platform/gfile.py +++ b/tensorflow/python/platform/gfile.py @@ -34,8 +34,10 @@ from tensorflow.python.lib.io.file_io import stat as Stat from tensorflow.python.lib.io.file_io import walk as Walk # pylint: enable=unused-import from tensorflow.python.util.all_util import remove_undocumented +from tensorflow.python.util.tf_export import tf_export +@tf_export('gfile.GFile', 'gfile.Open') class GFile(_FileIO): """File I/O wrappers without thread locking.""" @@ -43,6 +45,7 @@ class GFile(_FileIO): super(GFile, self).__init__(name=name, mode=mode) +@tf_export('gfile.FastGFile') class FastGFile(_FileIO): """File I/O wrappers without thread locking.""" diff --git a/tensorflow/python/platform/sysconfig.py b/tensorflow/python/platform/sysconfig.py index f6c4f2227f..5c50fa023d 100644 --- a/tensorflow/python/platform/sysconfig.py +++ b/tensorflow/python/platform/sysconfig.py @@ -29,9 +29,11 @@ import os.path as _os_path from tensorflow.python.framework.versions import CXX11_ABI_FLAG as _CXX11_ABI_FLAG from tensorflow.python.framework.versions import MONOLITHIC_BUILD as _MONOLITHIC_BUILD from tensorflow.python.util.all_util import remove_undocumented +from tensorflow.python.util.tf_export import tf_export # pylint: disable=g-import-not-at-top +@tf_export('sysconfig.get_include') def get_include(): """Get the directory containing the TensorFlow C++ header files. @@ -46,6 +48,7 @@ def get_include(): return _os_path.join(_os_path.dirname(tf.__file__), 'include') +@tf_export('sysconfig.get_lib') def get_lib(): """Get the directory containing the TensorFlow framework library. @@ -56,6 +59,7 @@ def get_lib(): return _os_path.join(_os_path.dirname(tf.__file__)) +@tf_export('sysconfig.get_compile_flags') def get_compile_flags(): """Get the compilation flags for custom operators. @@ -69,6 +73,7 @@ def get_compile_flags(): return flags +@tf_export('sysconfig.get_link_flags') def get_link_flags(): """Get the link flags for custom operators. diff --git a/tensorflow/python/platform/test.py b/tensorflow/python/platform/test.py index ec280c6e1e..9b7655722a 100644 --- a/tensorflow/python/platform/test.py +++ b/tensorflow/python/platform/test.py @@ -56,6 +56,7 @@ from tensorflow.python.ops.gradient_checker import compute_gradient # pylint: enable=unused-import,g-bad-import-order import sys +from tensorflow.python.util.tf_export import tf_export if sys.version_info.major == 2: import mock # pylint: disable=g-import-not-at-top,unused-import else: @@ -68,12 +69,14 @@ Benchmark = _googletest.Benchmark # pylint: disable=invalid-name StubOutForTesting = _googletest.StubOutForTesting # pylint: disable=invalid-name +@tf_export('test.main') def main(argv=None): """Runs all unit tests.""" _test_util.InstallStackTraceHandler() return _googletest.main(argv) +@tf_export('test.get_temp_dir') def get_temp_dir(): """Returns a temporary directory for use during tests. @@ -85,6 +88,7 @@ def get_temp_dir(): return _googletest.GetTempDir() +@tf_export('test.test_src_dir_path') def test_src_dir_path(relative_path): """Creates an absolute test srcdir path given a relative path. @@ -98,6 +102,7 @@ def test_src_dir_path(relative_path): return _googletest.test_src_dir_path(relative_path) +@tf_export('test.is_built_with_cuda') def is_built_with_cuda(): """Returns whether TensorFlow was built with CUDA (GPU) support.""" return _test_util.IsGoogleCudaEnabled() diff --git a/tensorflow/tools/api/generator/BUILD b/tensorflow/tools/api/generator/BUILD index fa0f9b59aa..795b983821 100644 --- a/tensorflow/tools/api/generator/BUILD +++ b/tensorflow/tools/api/generator/BUILD @@ -51,6 +51,21 @@ genrule( "api/nn/__init__.py", "api/spectral/__init__.py", "api/train/__init__.py", + "api/app/__init__.py", + "api/gfile/__init__.py", + "api/keras/__init__.py", + "api/keras/datasets/__init__.py", + "api/keras/datasets/boston_housing/__init__.py", + "api/keras/datasets/cifar10/__init__.py", + "api/keras/datasets/cifar100/__init__.py", + "api/keras/datasets/imdb/__init__.py", + "api/keras/datasets/mnist/__init__.py", + "api/keras/datasets/reuters/__init__.py", + "api/keras/utils/__init__.py", + "api/logging/__init__.py", + "api/resource_loader/__init__.py", + "api/sysconfig/__init__.py", + "api/test/__init__.py", ], cmd = "$(location create_python_api) $(OUTS)", tools = ["create_python_api"], -- GitLab From 3127c1072bad02517484d5f91e90ece4a8ae06a8 Mon Sep 17 00:00:00 2001 From: Yunxing Dai Date: Mon, 22 Jan 2018 15:10:08 -0800 Subject: [PATCH 070/258] [XLA][BF16] Add tests to demonstrate the brokeness of BF16 RNG functions in LLVM backends. - Added prng tests to demonstrate the brokeness of BF16 RNG functions in LLVM backends. PiperOrigin-RevId: 182843680 --- tensorflow/compiler/tests/BUILD | 5 -- tensorflow/compiler/xla/tests/prng_test.cc | 76 +++++++++++++++++++--- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/tensorflow/compiler/tests/BUILD b/tensorflow/compiler/tests/BUILD index f7c6cd293a..314f5506b1 100644 --- a/tensorflow/compiler/tests/BUILD +++ b/tensorflow/compiler/tests/BUILD @@ -403,11 +403,6 @@ tf_xla_py_test( disabled_backends = [ "gpu", ], - tags = [ - "manual", - "no_oss", - "notap", - ], deps = [ ":xla_test", "//tensorflow/python:framework_for_generated_wrappers", diff --git a/tensorflow/compiler/xla/tests/prng_test.cc b/tensorflow/compiler/xla/tests/prng_test.cc index 6489eee9f3..d8d7272c3b 100644 --- a/tensorflow/compiler/xla/tests/prng_test.cc +++ b/tensorflow/compiler/xla/tests/prng_test.cc @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ +#include #include #include "tensorflow/compiler/xla/client/computation_builder.h" @@ -25,6 +26,7 @@ limitations under the License. #include "tensorflow/compiler/xla/tests/test_macros.h" #include "tensorflow/compiler/xla/util.h" #include "tensorflow/compiler/xla/xla_data.pb.h" +#include "tensorflow/core/lib/core/casts.h" #include "tensorflow/core/lib/gtl/array_slice.h" #include "tensorflow/core/platform/protobuf.h" #include "tensorflow/core/platform/test.h" @@ -36,36 +38,42 @@ namespace { class PrngTest : public ClientLibraryTestBase { protected: template - void UniformTest(T a, T b, tensorflow::gtl::ArraySlice dims); - - template - void BernoulliTest(float p, tensorflow::gtl::ArraySlice dims); + std::unique_ptr UniformTest(T a, T b, + tensorflow::gtl::ArraySlice dims, + int64 seed = 42); // Computes the χ² statistic of a sample of the discrete uniform distribution // of the given range size. `expected_count` is the number of times each // possible value is expected to be generated. Thus, the sample size is // `range_size * expected_count`. - double UniformChiSquared(int32 range_size, int32 expected_count); + double UniformChiSquared(int32 range_size, int32 expected_count, + int64 seed = 42); }; template -void PrngTest::UniformTest(T a, T b, tensorflow::gtl::ArraySlice dims) { +std::unique_ptr PrngTest::UniformTest( + T a, T b, tensorflow::gtl::ArraySlice dims, int64 seed) { ComputationBuilder builder(client_, TestName()); builder.RngUniform( builder.ConstantR0(a), builder.ConstantR0(b), ShapeUtil::MakeShape(primitive_util::NativeToPrimitiveType(), dims)); - SetSeed(42); + SetSeed(seed); auto actual = ExecuteAndTransferOrDie(&builder, /*arguments=*/{}); EXPECT_THAT(dims, ::testing::ElementsAreArray(actual->shape().dimensions())); actual->EachCell([=](tensorflow::gtl::ArraySlice, T value) { EXPECT_LE(a, value); EXPECT_LT(value, b); }); + return actual; } // Uniform random number generation tests XLA_TEST_F(PrngTest, ScalarU01) { UniformTest(0, 1, {}); } +XLA_TEST_F(PrngTest, ScalarU01limits) { + UniformTest(std::numeric_limits::min(), + std::numeric_limits::max(), {}); +} XLA_TEST_F(PrngTest, ZeroValuesU01) { UniformTest(0, 1, {0}); } XLA_TEST_F(PrngTest, TenValuesU01) { UniformTest(0, 1, {10}); } XLA_TEST_F(PrngTest, TenValuesU37) { UniformTest(3, 7, {10}); } @@ -73,6 +81,55 @@ XLA_TEST_F(PrngTest, ZeroValuesR2) { UniformTest(0, 1, {0, 20}); } XLA_TEST_F(PrngTest, LargeU01) { UniformTest(0, 1, {0x100, 0x100}); } XLA_TEST_F(PrngTest, TwelveValuesU524) { UniformTest(5, 24, {12}); } +// TODO(b/71543667): Fix Rng ops on LLVM backends. +XLA_TEST_F(PrngTest, DISABLED_ON_GPU(DISABLED_ON_CPU_PARALLEL( + DISABLED_ON_CPU(ScalarBF16Tests)))) { + for (int64 seed = 0; seed < 100; ++seed) { + // The largest negative number smaller than zero in bf16 that's not + // denormalized. + float low = bit_cast(0x80800000); + float high = 0.0f; + UniformTest(static_cast(low), + static_cast(high), {}, /*seed=*/seed); + + // Test odd and even values. + UniformTest(static_cast(32.75), + static_cast(33), {}, /*seed=*/seed); + UniformTest(static_cast(32.50), + static_cast(32.75), {}, /*seed=*/seed); + UniformTest(static_cast(-33.00), + static_cast(-32.75), {}, /*seed=*/seed); + UniformTest(static_cast(-32.75), + static_cast(-32.50), {}, /*seed=*/seed); + } +} + +// TODO(b/71543667): Fix Rng ops on LLVM backends. +XLA_TEST_F(PrngTest, DISABLED_ON_GPU(DISABLED_ON_CPU( + DISABLED_ON_CPU_PARALLEL(ScalarBF16CountTests)))) { + // There are 3 BF16 values in the range of [32.25, 33): 32.25, 32.5, 32.75, + // they should get similar counts. + bfloat16 low = static_cast(32.25); + bfloat16 high = static_cast(33); + bfloat16 interval = static_cast(0.25); + std::vector counts(static_cast((high - low) / interval), 0); + + constexpr int64 count = 100; + for (int64 seed = 0; seed < count; ++seed) { + auto result = UniformTest(low, high, {}, /*seed=*/seed); + result->Literal::EachCell( + [&](tensorflow::gtl::ArraySlice, bfloat16 value) { + int64 index = static_cast((value - low) / interval); + counts[index]++; + }); + } + // Each bucket should have similar amount of counts. That is, not more than + // 10% of total counts. This mostly tests that we don't fall into a 1:2:2 + // distribution, which yields 20% expected difference. + EXPECT_LT(std::abs(counts[0] - counts[1]), count * 0.1); + EXPECT_LT(std::abs(counts[1] - counts[2]), count * 0.1); +} + namespace { template T Square(T x) { @@ -80,7 +137,8 @@ T Square(T x) { } } // namespace -double PrngTest::UniformChiSquared(int32 range_size, int32 expected_count) { +double PrngTest::UniformChiSquared(int32 range_size, int32 expected_count, + int64 seed) { int32 sample_size = range_size * expected_count; ComputationBuilder builder(client_, TestName()); @@ -88,7 +146,7 @@ double PrngTest::UniformChiSquared(int32 range_size, int32 expected_count) { builder.ConstantR0(range_size), ShapeUtil::MakeShape(S32, {sample_size})); - SetSeed(42); + SetSeed(seed); auto actual = ExecuteAndTransferOrDie(&builder, /*arguments=*/{}); std::vector counts(range_size, 0); actual->EachCell([&counts](tensorflow::gtl::ArraySlice, -- GitLab From e2f379c73d9946b9932a88c94971043541ed263e Mon Sep 17 00:00:00 2001 From: Jeremy Lau Date: Mon, 22 Jan 2018 15:54:33 -0800 Subject: [PATCH 071/258] Add file name and line number to statuses generated by OP_REQUIRES macros. PiperOrigin-RevId: 182850486 --- tensorflow/compiler/tf2xla/xla_op_kernel.cc | 14 +++- tensorflow/compiler/tf2xla/xla_op_kernel.h | 6 +- tensorflow/core/framework/op_kernel.cc | 36 ++++++++-- tensorflow/core/framework/op_kernel.h | 68 ++++++++++--------- .../kernels/conditional_accumulator_base.h | 26 +++---- 5 files changed, 97 insertions(+), 53 deletions(-) diff --git a/tensorflow/compiler/tf2xla/xla_op_kernel.cc b/tensorflow/compiler/tf2xla/xla_op_kernel.cc index c0c4251eab..ee0aed672e 100644 --- a/tensorflow/compiler/tf2xla/xla_op_kernel.cc +++ b/tensorflow/compiler/tf2xla/xla_op_kernel.cc @@ -412,10 +412,20 @@ XlaCompiler* XlaOpKernelContext::compiler() const { return XlaContext::Get(context_).compiler(); } -void XlaOpKernelContext::CtxFailure(Status s) { context_->CtxFailure(s); } -void XlaOpKernelContext::CtxFailureWithWarning(Status s) { +void XlaOpKernelContext::CtxFailure(const Status& s) { + context_->CtxFailure(s); +} +void XlaOpKernelContext::CtxFailureWithWarning(const Status& s) { context_->CtxFailureWithWarning(s); } +void XlaOpKernelContext::CtxFailure(const char* file, int line, + const Status& s) { + context_->CtxFailure(file, line, s); +} +void XlaOpKernelContext::CtxFailureWithWarning(const char* file, int line, + const Status& s) { + context_->CtxFailureWithWarning(file, line, s); +} const xla::Computation* XlaOpKernelContext::GetOrCreateMax( const DataType type) { diff --git a/tensorflow/compiler/tf2xla/xla_op_kernel.h b/tensorflow/compiler/tf2xla/xla_op_kernel.h index f1ae81a5aa..6d3b6db228 100644 --- a/tensorflow/compiler/tf2xla/xla_op_kernel.h +++ b/tensorflow/compiler/tf2xla/xla_op_kernel.h @@ -173,8 +173,10 @@ class XlaOpKernelContext { const xla::ComputationDataHandle& handle); // Helper routines for the OP_REQUIRES macros - void CtxFailure(Status s); - void CtxFailureWithWarning(Status s); + void CtxFailure(const Status& s); + void CtxFailureWithWarning(const Status& s); + void CtxFailure(const char* file, int line, const Status& s); + void CtxFailureWithWarning(const char* file, int line, const Status& s); // If this kernel invocation is within a function execution, // call_frame() returns the call frame for the function call. diff --git a/tensorflow/core/framework/op_kernel.cc b/tensorflow/core/framework/op_kernel.cc index c879dc6f3f..aee3a0afbc 100644 --- a/tensorflow/core/framework/op_kernel.cc +++ b/tensorflow/core/framework/op_kernel.cc @@ -34,6 +34,7 @@ limitations under the License. #include "tensorflow/core/lib/core/notification.h" #include "tensorflow/core/lib/core/stringpiece.h" #include "tensorflow/core/lib/gtl/map_util.h" +#include "tensorflow/core/lib/io/path.h" #include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/logging.h" @@ -1162,24 +1163,51 @@ const Eigen::SyclDevice& OpKernelContext::eigen_device() const { } #endif -void OpKernelConstruction::CtxFailure(Status s) { +void OpKernelConstruction::CtxFailure(const Status& s) { VLOG(1) << s; SetStatus(s); } -void OpKernelConstruction::CtxFailureWithWarning(Status s) { +void OpKernelConstruction::CtxFailureWithWarning(const Status& s) { LOG(WARNING) << s; SetStatus(s); } -void OpKernelContext::CtxFailure(Status s) { +void OpKernelConstruction::CtxFailure(const char* file, int line, + const Status& s) { + VLOG(1) << "OP_REQUIRES failed at " << io::Basename(file) << ":" << line + << " : " << s; + SetStatus(s); +} + +void OpKernelConstruction::CtxFailureWithWarning(const char* file, int line, + const Status& s) { + LOG(WARNING) << "OP_REQUIRES failed at " << io::Basename(file) << ":" << line + << " : " << s; + SetStatus(s); +} + +void OpKernelContext::CtxFailure(const Status& s) { VLOG(1) << s; SetStatus(s); } -void OpKernelContext::CtxFailureWithWarning(Status s) { +void OpKernelContext::CtxFailureWithWarning(const Status& s) { LOG(WARNING) << s; SetStatus(s); } +void OpKernelContext::CtxFailure(const char* file, int line, const Status& s) { + VLOG(1) << "OP_REQUIRES failed at " << io::Basename(file) << ":" << line + << " : " << s; + SetStatus(s); +} + +void OpKernelContext::CtxFailureWithWarning(const char* file, int line, + const Status& s) { + LOG(WARNING) << "OP_REQUIRES failed at " << io::Basename(file) << ":" << line + << " : " << s; + SetStatus(s); +} + } // namespace tensorflow diff --git a/tensorflow/core/framework/op_kernel.h b/tensorflow/core/framework/op_kernel.h index 25150499ad..b72f1405cf 100644 --- a/tensorflow/core/framework/op_kernel.h +++ b/tensorflow/core/framework/op_kernel.h @@ -316,8 +316,10 @@ class OpKernelConstruction { int graph_def_version() const { return graph_def_version_; } // Helper routines for the OP_REQUIRES macros - void CtxFailure(Status s); - void CtxFailureWithWarning(Status s); + void CtxFailure(const Status& s); + void CtxFailureWithWarning(const Status& s); + void CtxFailure(const char* file, int line, const Status& s); + void CtxFailureWithWarning(const char* file, int line, const Status& s); // Unrecommended functions: these are functions that have some // current uses but are not recommended for use, and may go away at @@ -1014,8 +1016,10 @@ class OpKernelContext { } // Helper routines for the OP_REQUIRES macros - void CtxFailure(Status s); - void CtxFailureWithWarning(Status s); + void CtxFailure(const Status& s); + void CtxFailureWithWarning(const Status& s); + void CtxFailure(const char* file, int line, const Status& s); + void CtxFailureWithWarning(const char* file, int line, const Status& s); // Unrecommended functions: these are functions that have some // current uses but are not recommended for use, and may go away at @@ -1476,40 +1480,40 @@ inline void OpOutputList::set_ref(int i, mutex* mu, Tensor* tensor_for_ref) { // ... // } -#define OP_REQUIRES(CTX, EXP, STATUS) \ - do { \ - if (!TF_PREDICT_TRUE(EXP)) { \ - (CTX)->CtxFailure((STATUS)); \ - return; \ - } \ +#define OP_REQUIRES(CTX, EXP, STATUS) \ + do { \ + if (!TF_PREDICT_TRUE(EXP)) { \ + (CTX)->CtxFailure(__FILE__, __LINE__, (STATUS)); \ + return; \ + } \ } while (0) -#define OP_REQUIRES_OK(CTX, ...) \ - do { \ - ::tensorflow::Status _s(__VA_ARGS__); \ - if (!TF_PREDICT_TRUE(_s.ok())) { \ - (CTX)->CtxFailureWithWarning(_s); \ - return; \ - } \ +#define OP_REQUIRES_OK(CTX, ...) \ + do { \ + ::tensorflow::Status _s(__VA_ARGS__); \ + if (!TF_PREDICT_TRUE(_s.ok())) { \ + (CTX)->CtxFailureWithWarning(__FILE__, __LINE__, _s); \ + return; \ + } \ } while (0) -#define OP_REQUIRES_ASYNC(CTX, EXP, STATUS, CALLBACK) \ - do { \ - if (!TF_PREDICT_TRUE(EXP)) { \ - (CTX)->CtxFailure((STATUS)); \ - (CALLBACK)(); \ - return; \ - } \ +#define OP_REQUIRES_ASYNC(CTX, EXP, STATUS, CALLBACK) \ + do { \ + if (!TF_PREDICT_TRUE(EXP)) { \ + (CTX)->CtxFailure(__FILE__, __LINE__, (STATUS)); \ + (CALLBACK)(); \ + return; \ + } \ } while (0) -#define OP_REQUIRES_OK_ASYNC(CTX, STATUS, CALLBACK) \ - do { \ - ::tensorflow::Status _s(STATUS); \ - if (!TF_PREDICT_TRUE(_s.ok())) { \ - (CTX)->CtxFailureWithWarning(_s); \ - (CALLBACK)(); \ - return; \ - } \ +#define OP_REQUIRES_OK_ASYNC(CTX, STATUS, CALLBACK) \ + do { \ + ::tensorflow::Status _s(STATUS); \ + if (!TF_PREDICT_TRUE(_s.ok())) { \ + (CTX)->CtxFailureWithWarning(__FILE__, __LINE__, _s); \ + (CALLBACK)(); \ + return; \ + } \ } while (0) } // namespace tensorflow diff --git a/tensorflow/core/kernels/conditional_accumulator_base.h b/tensorflow/core/kernels/conditional_accumulator_base.h index 27db6ee785..794ac6fa6d 100644 --- a/tensorflow/core/kernels/conditional_accumulator_base.h +++ b/tensorflow/core/kernels/conditional_accumulator_base.h @@ -161,21 +161,21 @@ class ConditionalAccumulatorBase : public ResourceBase { * The below macros return a boolean if the test fails, so that the calling * function can get an indication that a failure has occurred. */ -#define OP_REQUIRES_BOOLEAN(CTX, EXP, STATUS) \ - do { \ - if (!TF_PREDICT_TRUE(EXP)) { \ - (CTX)->CtxFailure((STATUS)); \ - return false; \ - } \ +#define OP_REQUIRES_BOOLEAN(CTX, EXP, STATUS) \ + do { \ + if (!TF_PREDICT_TRUE(EXP)) { \ + (CTX)->CtxFailure(__FILE__, __LINE__, (STATUS)); \ + return false; \ + } \ } while (0) -#define OP_REQUIRES_OK_BOOLEAN(CTX, STATUS) \ - do { \ - ::tensorflow::Status _s(STATUS); \ - if (!TF_PREDICT_TRUE(_s.ok())) { \ - (CTX)->CtxFailureWithWarning(_s); \ - return false; \ - } \ +#define OP_REQUIRES_OK_BOOLEAN(CTX, STATUS) \ + do { \ + ::tensorflow::Status _s(STATUS); \ + if (!TF_PREDICT_TRUE(_s.ok())) { \ + (CTX)->CtxFailureWithWarning(__FILE__, __LINE__, _s); \ + return false; \ + } \ } while (0) /* -- GitLab From 9fc2c8ebc8adcbca10c9850a54f913f5e731429f Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Mon, 22 Jan 2018 16:28:47 -0800 Subject: [PATCH 072/258] Add functionality to include an optional additional header to be sent on every request when using the GCS file system. PiperOrigin-RevId: 182855525 --- .../core/platform/cloud/gcs_file_system.cc | 49 +- .../core/platform/cloud/gcs_file_system.h | 14 +- .../platform/cloud/gcs_file_system_test.cc | 424 +++++++++++------- 3 files changed, 329 insertions(+), 158 deletions(-) diff --git a/tensorflow/core/platform/cloud/gcs_file_system.cc b/tensorflow/core/platform/cloud/gcs_file_system.cc index 4b30291076..520720372d 100644 --- a/tensorflow/core/platform/cloud/gcs_file_system.cc +++ b/tensorflow/core/platform/cloud/gcs_file_system.cc @@ -117,6 +117,9 @@ constexpr char kReadRequestTimeout[] = "GCS_READ_REQUEST_TIMEOUT_SECS"; // The environment variable to configure the overall request timeout for // upload requests. constexpr char kWriteRequestTimeout[] = "GCS_WRITE_REQUEST_TIMEOUT_SECS"; +// The environment variable to configure an additional header to send with +// all requests to GCS (format HEADERNAME:HEADERCONTENT) +constexpr char kAdditionalRequestHeader[] = "GCS_ADDITIONAL_REQUEST_HEADER"; // TODO: DO NOT use a hardcoded path Status GetTmpFilename(string* filename) { @@ -607,6 +610,11 @@ bool GetEnvVar(const char* varname, bool (*convert)(StringPiece, T*), return convert(env_value, value); } +bool StringPieceIdentity(StringPiece str, StringPiece* value) { + *value = str; + return true; +} + } // namespace GcsFileSystem::GcsFileSystem() @@ -668,6 +676,36 @@ GcsFileSystem::GcsFileSystem() VLOG(1) << "GCS DNS cache is disabled, because " << kResolveCacheSecs << " = 0 (or is not set)"; } + + // Get the additional header + StringPiece add_header_contents; + if (GetEnvVar(kAdditionalRequestHeader, StringPieceIdentity, + &add_header_contents)) { + size_t split = add_header_contents.find(':', 0); + + if (split != StringPiece::npos) { + StringPiece header_name = add_header_contents.substr(0, split); + StringPiece header_value = add_header_contents.substr(split + 1); + + if (!header_name.empty() && !header_value.empty()) { + additional_header_.reset(new std::pair( + header_name.ToString(), header_value.ToString())); + + VLOG(1) << "GCS additional header ENABLED. " + << "Name: " << additional_header_->first << ", " + << "Value: " << additional_header_->second; + } else { + LOG(ERROR) << "GCS additional header DISABLED. Invalid contents: " + << add_header_contents; + } + } else { + LOG(ERROR) << "GCS additional header DISABLED. Invalid contents: " + << add_header_contents; + } + } else { + VLOG(1) << "GCS additional header DISABLED. No environment variable set."; + } + // Apply the overrides for request timeouts uint32 timeout_value; if (GetEnvVar(kRequestConnectionTimeout, strings::safe_strtou32, @@ -696,7 +734,8 @@ GcsFileSystem::GcsFileSystem( uint64 stat_cache_max_age, size_t stat_cache_max_entries, uint64 matching_paths_cache_max_age, size_t matching_paths_cache_max_entries, int64 initial_retry_delay_usec, - TimeoutConfig timeouts) + TimeoutConfig timeouts, + std::pair* additional_header) : auth_provider_(std::move(auth_provider)), http_request_factory_(std::move(http_request_factory)), file_block_cache_( @@ -705,7 +744,8 @@ GcsFileSystem::GcsFileSystem( matching_paths_cache_(new MatchingPathsCache( matching_paths_cache_max_age, matching_paths_cache_max_entries)), timeouts_(timeouts), - initial_retry_delay_usec_(initial_retry_delay_usec) {} + initial_retry_delay_usec_(initial_retry_delay_usec), + additional_header_(additional_header) {} Status GcsFileSystem::NewRandomAccessFile( const string& fname, std::unique_ptr* result) { @@ -1397,6 +1437,11 @@ Status GcsFileSystem::CreateHttpRequest(std::unique_ptr* request) { new_request->AddAuthBearerHeader(auth_token); + if (additional_header_) { + new_request->AddHeader(additional_header_->first, + additional_header_->second); + } + *request = std::move(new_request); return Status::OK(); } diff --git a/tensorflow/core/platform/cloud/gcs_file_system.h b/tensorflow/core/platform/cloud/gcs_file_system.h index adde161a93..2eae39608e 100644 --- a/tensorflow/core/platform/cloud/gcs_file_system.h +++ b/tensorflow/core/platform/cloud/gcs_file_system.h @@ -17,7 +17,9 @@ limitations under the License. #define TENSORFLOW_CORE_PLATFORM_GCS_FILE_SYSTEM_H_ #include +#include #include + #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/platform/cloud/auth_provider.h" #include "tensorflow/core/platform/cloud/expiring_lru_cache.h" @@ -44,7 +46,8 @@ class GcsFileSystem : public FileSystem { uint64 stat_cache_max_age, size_t stat_cache_max_entries, uint64 matching_paths_cache_max_age, size_t matching_paths_cache_max_entries, - int64 initial_retry_delay_usec, TimeoutConfig timeouts); + int64 initial_retry_delay_usec, TimeoutConfig timeouts, + std::pair* additional_header); Status NewRandomAccessFile( const string& filename, @@ -92,6 +95,12 @@ class GcsFileSystem : public FileSystem { size_t max_bytes() const { return file_block_cache_->max_bytes(); } uint64 max_staleness() const { return file_block_cache_->max_staleness(); } TimeoutConfig timeouts() const { return timeouts_; } + string additional_header_name() const { + return additional_header_ ? additional_header_->first : ""; + } + string additional_header_value() const { + return additional_header_ ? additional_header_->second : ""; + } uint64 stat_cache_max_age() const { return stat_cache_->max_age(); } size_t stat_cache_max_entries() const { return stat_cache_->max_entries(); } @@ -197,6 +206,9 @@ class GcsFileSystem : public FileSystem { /// The initial delay for exponential backoffs when retrying failed calls. const int64 initial_retry_delay_usec_ = 1000000L; + // Additional header material to be transmitted with all GCS requests + std::unique_ptr> additional_header_; + TF_DISALLOW_COPY_AND_ASSIGN(GcsFileSystem); }; diff --git a/tensorflow/core/platform/cloud/gcs_file_system_test.cc b/tensorflow/core/platform/cloud/gcs_file_system_test.cc index 772aec5273..d452074ce3 100644 --- a/tensorflow/core/platform/cloud/gcs_file_system_test.cc +++ b/tensorflow/core/platform/cloud/gcs_file_system_test.cc @@ -53,7 +53,8 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_NoBlockCache) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr file; TF_EXPECT_OK(fs.NewRandomAccessFile("gs://bucket/random_access.txt", &file)); @@ -93,7 +94,8 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_NoBlockCache_differentN) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr file; TF_EXPECT_OK(fs.NewRandomAccessFile("gs://bucket/random_access.txt", &file)); @@ -137,15 +139,15 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_WithBlockCache) { "Range: 18-26\n" "Timeouts: 5 1 20\n", "")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 9 /* block size */, 18 /* max bytes */, - 0 /* max staleness */, 0 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 9 /* block size */, 18 /* max bytes */, 0 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay */, + kTestTimeoutConfig, nullptr /* gcs additional header */); char scratch[100]; StringPiece result; @@ -211,15 +213,15 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_WithBlockCache_Flush) { "Range: 0-8\n" "Timeouts: 5 1 20\n", "012345678")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 9 /* block size */, 18 /* max bytes */, - 0 /* max staleness */, 0 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 9 /* block size */, 18 /* max bytes */, 0 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay */, + kTestTimeoutConfig, nullptr /* gcs additional header */); char scratch[100]; StringPiece result; @@ -252,15 +254,15 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_WithBlockCache_MaxStaleness) { "Range: 8-15\n" "Timeouts: 5 1 20\n", "89abcdef")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 8 /* block size */, 16 /* max bytes */, - 3600 /* max staleness */, 0 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 8 /* block size */, 16 /* max bytes */, 3600 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay */, + kTestTimeoutConfig, nullptr /* gcs additional header */); char scratch[100]; StringPiece result; // There should only be two HTTP requests issued to GCS even though we iterate @@ -294,15 +296,15 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_WithBlockCache_MaxStaleness) { TEST(GcsFileSystemTest, NewRandomAccessFile_NoObjectName) { std::vector requests; - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 0 /* read ahead bytes */, 0 /* max bytes */, - 0 /* max staleness */, 0 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 0 /* read ahead bytes */, 0 /* max bytes */, 0 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay */, + kTestTimeoutConfig, nullptr /* gcs additional header */); std::unique_ptr file; EXPECT_EQ(errors::Code::INVALID_ARGUMENT, @@ -344,7 +346,8 @@ TEST(GcsFileSystemTest, NewWritableFile) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); // Read from the file first, to fill the block cache. std::unique_ptr rfile; @@ -418,7 +421,8 @@ TEST(GcsFileSystemTest, NewWritableFile_ResumeUploadSucceeds) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr file; TF_EXPECT_OK(fs.NewWritableFile("gs://bucket/path/writeable.txt", &file)); @@ -465,15 +469,15 @@ TEST(GcsFileSystemTest, NewWritableFile_ResumeUploadSucceedsOnGetStatus) { "Range: 0-7\n" "Timeouts: 5 1 20\n", "01234567")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 8 /* block size */, 8 /* max bytes */, - 3600 /* max staleness */, 0 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 8 /* block size */, 8 /* max bytes */, 3600 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay */, + kTestTimeoutConfig, nullptr /* gcs additional header */); // Pull the file's first block into the cache. This will trigger the first // HTTP request to GCS. std::unique_ptr rfile; @@ -557,7 +561,8 @@ TEST(GcsFileSystemTest, NewWritableFile_ResumeUploadAllAttemptsFail) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 2 /* initial retry delay */, kTestTimeoutConfig); + 2 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr file; TF_EXPECT_OK(fs.NewWritableFile("gs://bucket/path/writeable.txt", &file)); @@ -612,7 +617,8 @@ TEST(GcsFileSystemTest, NewWritableFile_UploadReturns410) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr file; TF_EXPECT_OK(fs.NewWritableFile("gs://bucket/path/writeable.txt", &file)); @@ -641,7 +647,8 @@ TEST(GcsFileSystemTest, NewWritableFile_NoObjectName) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr file; EXPECT_EQ(errors::Code::INVALID_ARGUMENT, @@ -676,15 +683,15 @@ TEST(GcsFileSystemTest, NewAppendableFile) { "Range: 0-31\n" "Timeouts: 5 1 20\n", "01234567")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 32 /* block size */, 32 /* max bytes */, - 0 /* max staleness */, 0 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 32 /* block size */, 32 /* max bytes */, 0 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay */, + kTestTimeoutConfig, nullptr /* gcs additional header */); // Create an appendable file. This should read the file from GCS, and pull its // contents into the block cache. @@ -717,7 +724,8 @@ TEST(GcsFileSystemTest, NewAppendableFile_NoObjectName) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr file; EXPECT_EQ(errors::Code::INVALID_ARGUMENT, @@ -748,7 +756,8 @@ TEST(GcsFileSystemTest, NewReadOnlyMemoryRegionFromFile) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr region; TF_EXPECT_OK(fs.NewReadOnlyMemoryRegionFromFile( @@ -767,7 +776,8 @@ TEST(GcsFileSystemTest, NewReadOnlyMemoryRegionFromFile_NoObjectName) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr region; EXPECT_EQ(errors::Code::INVALID_ARGUMENT, @@ -789,7 +799,8 @@ TEST(GcsFileSystemTest, FileExists_YesAsObject) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.FileExists("gs://bucket/path/file1.txt")); } @@ -817,7 +828,8 @@ TEST(GcsFileSystemTest, FileExists_YesAsFolder) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.FileExists("gs://bucket/path/subfolder")); } @@ -841,7 +853,8 @@ TEST(GcsFileSystemTest, FileExists_YesAsBucket) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.FileExists("gs://bucket1")); TF_EXPECT_OK(fs.FileExists("gs://bucket1/")); @@ -869,7 +882,8 @@ TEST(GcsFileSystemTest, FileExists_NotAsObjectOrFolder) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); EXPECT_EQ(errors::Code::NOT_FOUND, fs.FileExists("gs://bucket/path/file1.txt").code()); @@ -894,7 +908,8 @@ TEST(GcsFileSystemTest, FileExists_NotAsBucket) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); EXPECT_EQ(errors::Code::INVALID_ARGUMENT, fs.FileExists("gs://bucket2/").code()); EXPECT_EQ(errors::Code::INVALID_ARGUMENT, @@ -924,15 +939,15 @@ TEST(GcsFileSystemTest, FileExists_StatCache) { "Timeouts: 5 1 10\n", "{\"items\": [ " " { \"name\": \"path/subfolder/\" }]}")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 0 /* block size */, 0 /* max bytes */, 0 /* max staleness */, - 3600 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 0 /* block size */, 0 /* max bytes */, 0 /* max staleness */, + 3600 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay */, + kTestTimeoutConfig, nullptr /* gcs additional header */); // The stat cache will ensure that repeated lookups don't trigger additional // HTTP requests. @@ -957,7 +972,8 @@ TEST(GcsFileSystemTest, GetChildren_NoItems) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector children; TF_EXPECT_OK(fs.GetChildren("gs://bucket/path/", &children)); @@ -983,7 +999,8 @@ TEST(GcsFileSystemTest, GetChildren_ThreeFiles) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector children; TF_EXPECT_OK(fs.GetChildren("gs://bucket/path/", &children)); @@ -1010,7 +1027,8 @@ TEST(GcsFileSystemTest, GetChildren_SelfDirectoryMarker) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector children; TF_EXPECT_OK(fs.GetChildren("gs://bucket/path/", &children)); @@ -1036,7 +1054,8 @@ TEST(GcsFileSystemTest, GetChildren_ThreeFiles_NoSlash) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector children; TF_EXPECT_OK(fs.GetChildren("gs://bucket/path", &children)); @@ -1059,7 +1078,8 @@ TEST(GcsFileSystemTest, GetChildren_Root) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector children; TF_EXPECT_OK(fs.GetChildren("gs://bucket-a-b-c", &children)); @@ -1082,7 +1102,8 @@ TEST(GcsFileSystemTest, GetChildren_Empty) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector children; TF_EXPECT_OK(fs.GetChildren("gs://bucket/path/", &children)); @@ -1121,7 +1142,8 @@ TEST(GcsFileSystemTest, GetChildren_Pagination) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector children; TF_EXPECT_OK(fs.GetChildren("gs://bucket/path", &children)); @@ -1146,7 +1168,8 @@ TEST(GcsFileSystemTest, GetMatchingPaths_NoWildcard) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector result; TF_EXPECT_OK( @@ -1172,7 +1195,8 @@ TEST(GcsFileSystemTest, GetMatchingPaths_BucketAndWildcard) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector result; TF_EXPECT_OK(fs.GetMatchingPaths("gs://bucket/*/*", &result)); @@ -1199,7 +1223,8 @@ TEST(GcsFileSystemTest, GetMatchingPaths_FolderAndWildcard_Matches) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector result; TF_EXPECT_OK(fs.GetMatchingPaths("gs://bucket/path/*/file2.txt", &result)); @@ -1223,7 +1248,8 @@ TEST(GcsFileSystemTest, GetMatchingPaths_SelfDirectoryMarker) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector result; TF_EXPECT_OK(fs.GetMatchingPaths("gs://bucket/path/*", &result)); @@ -1247,7 +1273,8 @@ TEST(GcsFileSystemTest, GetMatchingPaths_FolderAndWildcard_NoMatches) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector result; TF_EXPECT_OK(fs.GetMatchingPaths("gs://bucket/path/*/file3.txt", &result)); @@ -1263,7 +1290,8 @@ TEST(GcsFileSystemTest, GetMatchingPaths_OnlyWildcard) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::vector result; EXPECT_EQ(errors::Code::INVALID_ARGUMENT, @@ -1295,7 +1323,8 @@ TEST(GcsFileSystemTest, GetMatchingPaths_Cache) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 3600 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); // Repeated calls to fs.GetMatchingPaths on these patterns should not lead to // any additional HTTP requests to GCS. @@ -1336,7 +1365,8 @@ TEST(GcsFileSystemTest, GetMatchingPaths_Cache_Flush) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 3600 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); // This loop should trigger the first HTTP request to GCS. for (int i = 0; i < 10; i++) { @@ -1377,15 +1407,15 @@ TEST(GcsFileSystemTest, DeleteFile) { "Range: 0-15\n" "Timeouts: 5 1 20\n", "76543210")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 16 /* block size */, 16 /* max bytes */, - 0 /* max staleness */, 0 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 16 /* block size */, 16 /* max bytes */, 0 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay*/, + kTestTimeoutConfig, nullptr /* gcs additional header */); // Do an initial read of the file to load its contents into the block cache. char scratch[100]; @@ -1411,7 +1441,8 @@ TEST(GcsFileSystemTest, DeleteFile_NoObjectName) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); EXPECT_EQ(errors::Code::INVALID_ARGUMENT, fs.DeleteFile("gs://bucket/").code()); @@ -1431,7 +1462,8 @@ TEST(GcsFileSystemTest, DeleteDir_Empty) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.DeleteDir("gs://bucket/path/")); } @@ -1458,7 +1490,8 @@ TEST(GcsFileSystemTest, DeleteDir_OnlyDirMarkerLeft) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.DeleteDir("gs://bucket/path/")); } @@ -1476,7 +1509,8 @@ TEST(GcsFileSystemTest, DeleteDir_BucketOnly) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.DeleteDir("gs://bucket")); } @@ -1496,7 +1530,8 @@ TEST(GcsFileSystemTest, DeleteDir_NonEmpty) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); EXPECT_EQ(error::Code::FAILED_PRECONDITION, fs.DeleteDir("gs://bucket/path/").code()); @@ -1517,7 +1552,8 @@ TEST(GcsFileSystemTest, GetFileSize) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); uint64 size; TF_EXPECT_OK(fs.GetFileSize("gs://bucket/file.txt", &size)); @@ -1533,7 +1569,8 @@ TEST(GcsFileSystemTest, GetFileSize_NoObjectName) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); uint64 size; EXPECT_EQ(errors::Code::INVALID_ARGUMENT, @@ -1617,7 +1654,8 @@ TEST(GcsFileSystemTest, RenameFile_Folder) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.RenameFile("gs://bucket/path1", "gs://bucket/path2/")); } @@ -1680,15 +1718,15 @@ TEST(GcsFileSystemTest, RenameFile_Object) { "Range: 0-15\n" "Timeouts: 5 1 20\n", "fedcba98")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 16 /* block size */, 64 /* max bytes */, - 0 /* max staleness */, 0 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 16 /* block size */, 64 /* max bytes */, 0 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay*/, + kTestTimeoutConfig, nullptr /* gcs additional header */); // Do an initial read of the source and destination files to load their // contents into the block cache. char scratch[100]; @@ -1761,7 +1799,8 @@ TEST(GcsFileSystemTest, RenameFile_Object_DeletionRetried) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK( fs.RenameFile("gs://bucket/path/src.txt", "gs://bucket/path/dst.txt")); @@ -1801,7 +1840,8 @@ TEST(GcsFileSystemTest, RenameFile_Object_Incomplete) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); EXPECT_EQ( errors::Code::UNIMPLEMENTED, @@ -1824,7 +1864,8 @@ TEST(GcsFileSystemTest, Stat_Object) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); FileStatistics stat; TF_EXPECT_OK(fs.Stat("gs://bucket/file.txt", &stat)); @@ -1856,7 +1897,8 @@ TEST(GcsFileSystemTest, Stat_Folder) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); FileStatistics stat; TF_EXPECT_OK(fs.Stat("gs://bucket/subfolder", &stat)); @@ -1887,7 +1929,8 @@ TEST(GcsFileSystemTest, Stat_ObjectOrFolderNotFound) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); FileStatistics stat; EXPECT_EQ(error::Code::NOT_FOUND, fs.Stat("gs://bucket/path", &stat).code()); @@ -1906,7 +1949,8 @@ TEST(GcsFileSystemTest, Stat_Bucket) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); FileStatistics stat; TF_EXPECT_OK(fs.Stat("gs://bucket/", &stat)); @@ -1928,7 +1972,8 @@ TEST(GcsFileSystemTest, Stat_BucketNotFound) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); FileStatistics stat; EXPECT_EQ(error::Code::NOT_FOUND, fs.Stat("gs://bucket/", &stat).code()); @@ -1957,15 +2002,15 @@ TEST(GcsFileSystemTest, Stat_Cache) { "Timeouts: 5 1 10\n", "{\"items\": [ " " { \"name\": \"subfolder/\" }]}")}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 0 /* block size */, 0 /* max bytes */, 0 /* max staleness */, - 3600 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 0 /* block size */, 0 /* max bytes */, 0 /* max staleness */, + 3600 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay*/, + kTestTimeoutConfig, nullptr /* gcs additional header */); // Repeated calls to fs.Stat on these paths should not lead to any additional // HTTP requests to GCS. @@ -1998,15 +2043,15 @@ TEST(GcsFileSystemTest, Stat_Cache_Flush) { "Timeouts: 5 1 10\n", strings::StrCat("{\"size\": \"1010\"," "\"updated\": \"2016-04-29T23:15:24.896Z\"}"))}); - GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), - std::unique_ptr( - new FakeHttpRequestFactory(&requests)), - 0 /* block size */, 0 /* max bytes */, 0 /* max staleness */, - 3600 /* stat cache max age */, - 0 /* stat cache max entries */, - 0 /* matching paths cache max age */, - 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + GcsFileSystem fs( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 0 /* block size */, 0 /* max bytes */, 0 /* max staleness */, + 3600 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay*/, + kTestTimeoutConfig, nullptr /* gcs additional header */); // There should be a single HTTP request to GCS for fs.Stat in this loop. for (int i = 0; i < 10; i++) { FileStatistics stat; @@ -2048,7 +2093,8 @@ TEST(GcsFileSystemTest, IsDirectory_NotFound) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); EXPECT_EQ(error::Code::NOT_FOUND, fs.IsDirectory("gs://bucket/file.txt").code()); @@ -2077,7 +2123,8 @@ TEST(GcsFileSystemTest, IsDirectory_NotDirectoryButObject) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); EXPECT_EQ(error::Code::FAILED_PRECONDITION, fs.IsDirectory("gs://bucket/file.txt").code()); @@ -2106,7 +2153,8 @@ TEST(GcsFileSystemTest, IsDirectory_Yes) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.IsDirectory("gs://bucket/subfolder")); TF_EXPECT_OK(fs.IsDirectory("gs://bucket/subfolder/")); @@ -2131,7 +2179,8 @@ TEST(GcsFileSystemTest, IsDirectory_Bucket) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.IsDirectory("gs://bucket")); TF_EXPECT_OK(fs.IsDirectory("gs://bucket/")); @@ -2150,7 +2199,8 @@ TEST(GcsFileSystemTest, IsDirectory_BucketNotFound) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); EXPECT_EQ(error::Code::NOT_FOUND, fs.IsDirectory("gs://bucket/").code()); } @@ -2190,7 +2240,8 @@ TEST(GcsFileSystemTest, CreateDir_Folder) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.CreateDir("gs://bucket/subpath")); TF_EXPECT_OK(fs.CreateDir("gs://bucket/subpath/")); @@ -2215,7 +2266,8 @@ TEST(GcsFileSystemTest, CreateDir_Bucket) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); TF_EXPECT_OK(fs.CreateDir("gs://bucket/")); TF_EXPECT_OK(fs.CreateDir("gs://bucket")); @@ -2285,7 +2337,8 @@ TEST(GcsFileSystemTest, DeleteRecursively_Ok) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); int64 undeleted_files, undeleted_dirs; TF_EXPECT_OK(fs.DeleteRecursively("gs://bucket/path", &undeleted_files, @@ -2376,7 +2429,8 @@ TEST(GcsFileSystemTest, DeleteRecursively_DeletionErrors) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); int64 undeleted_files, undeleted_dirs; TF_EXPECT_OK(fs.DeleteRecursively("gs://bucket/path", &undeleted_files, @@ -2409,7 +2463,8 @@ TEST(GcsFileSystemTest, DeleteRecursively_NotAFolder) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay*/, kTestTimeoutConfig); + 0 /* initial retry delay*/, kTestTimeoutConfig, + nullptr /* gcs additional header */); int64 undeleted_files, undeleted_dirs; EXPECT_EQ(error::Code::NOT_FOUND, @@ -2420,6 +2475,64 @@ TEST(GcsFileSystemTest, DeleteRecursively_NotAFolder) { EXPECT_EQ(1, undeleted_dirs); } +TEST(GcsFileSystemTest, AdditionalRequestHeaderTest) { + GcsFileSystem fs1; + EXPECT_EQ("", fs1.additional_header_name()); + EXPECT_EQ("", fs1.additional_header_value()); + + setenv("GCS_ADDITIONAL_REQUEST_HEADER", + "X-Add-Header:My Additional Header Value", 1); + GcsFileSystem fs2; + EXPECT_EQ("X-Add-Header", fs2.additional_header_name()); + EXPECT_EQ("My Additional Header Value", fs2.additional_header_value()); + + setenv("GCS_ADDITIONAL_REQUEST_HEADER", "Someinvalidheadervalue", 1); + GcsFileSystem fs3; + EXPECT_EQ("", fs3.additional_header_name()); + EXPECT_EQ("", fs3.additional_header_value()); + + setenv("GCS_ADDITIONAL_REQUEST_HEADER", ":thisisinvalid", 1); + GcsFileSystem fs4; + EXPECT_EQ("", fs4.additional_header_name()); + EXPECT_EQ("", fs4.additional_header_value()); + + setenv("GCS_ADDITIONAL_REQUEST_HEADER", "soisthis:", 1); + GcsFileSystem fs5; + EXPECT_EQ("", fs5.additional_header_name()); + EXPECT_EQ("", fs5.additional_header_value()); + + setenv("GCS_ADDITIONAL_REQUEST_HEADER", "a:b", 1); + GcsFileSystem fs6; + EXPECT_EQ("a", fs6.additional_header_name()); + EXPECT_EQ("b", fs6.additional_header_value()); + + auto* add_header = new std::pair( + "mynewheader", "newheadercontents"); + + std::vector requests( + {// IsDirectory is checking whether there are children objects. + new FakeHttpRequest("Uri: https://www.googleapis.com/fake\n" + "Auth Token: fake_token\n" + "Header mynewheader: newheadercontents\n" + "Header Hello: world\n", + "{}")}); + GcsFileSystem fs7( + std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 0 /* block size */, 0 /* max bytes */, 0 /* max staleness */, + 0 /* stat cache max age */, 0 /* stat cache max entries */, + 0 /* matching paths cache max age */, + 0 /* matching paths cache max entries */, 0 /* initial retry delay */, + kTestTimeoutConfig, add_header /* gcs additional header */); + + std::unique_ptr request; + TF_EXPECT_OK(fs7.CreateHttpRequest(&request)); + request->SetUri("https://www.googleapis.com/fake"); + request->AddHeader("Hello", "world"); + TF_EXPECT_OK(request->Send()); +} + TEST(GcsFileSystemTest, OverrideCacheParameters) { // Verify defaults are propagated correctly. GcsFileSystem fs1; @@ -2485,7 +2598,8 @@ TEST(GcsFileSystemTest, CreateHttpRequest) { 0 /* stat cache max age */, 0 /* stat cache max entries */, 0 /* matching paths cache max age */, 0 /* matching paths cache max entries */, - 0 /* initial retry delay */, kTestTimeoutConfig); + 0 /* initial retry delay */, kTestTimeoutConfig, + nullptr /* gcs additional header */); std::unique_ptr request; TF_EXPECT_OK(fs.CreateHttpRequest(&request)); -- GitLab From 2e1dfe4a288fe1258f2f497ae6a5874eff127f82 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 16:41:37 -0800 Subject: [PATCH 073/258] Adds unit tests for squeeze, to test the case when all dims are 1. PiperOrigin-RevId: 182857374 --- tensorflow/contrib/lite/kernels/squeeze_test.cc | 11 +++++++++++ tensorflow/contrib/lite/testing/generate_examples.py | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/tensorflow/contrib/lite/kernels/squeeze_test.cc b/tensorflow/contrib/lite/kernels/squeeze_test.cc index 409227b626..a8aab88357 100644 --- a/tensorflow/contrib/lite/kernels/squeeze_test.cc +++ b/tensorflow/contrib/lite/kernels/squeeze_test.cc @@ -22,6 +22,7 @@ namespace tflite { namespace { using ::testing::ElementsAreArray; +using ::testing::IsEmpty; class BaseSqueezeOpModel : public SingleOpModel { public: @@ -103,6 +104,16 @@ TEST(FloatSqueezeOpTest, SqueezeNegativeAxis) { 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0})); } +TEST(FloatSqueezeOpTest, SqueezeAllDims) { + std::initializer_list data = {3.85}; + FloatSqueezeOpModel m({TensorType_FLOAT32, {1, 1, 1, 1, 1, 1, 1}}, + {TensorType_FLOAT32, {1}}, {}); + m.SetInput(data); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), IsEmpty()); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({3.85})); +} + } // namespace } // namespace tflite diff --git a/tensorflow/contrib/lite/testing/generate_examples.py b/tensorflow/contrib/lite/testing/generate_examples.py index 29bf2cd7fc..9713532326 100644 --- a/tensorflow/contrib/lite/testing/generate_examples.py +++ b/tensorflow/contrib/lite/testing/generate_examples.py @@ -1361,6 +1361,10 @@ def make_squeeze_tests(zip_path): "dtype": [tf.int32, tf.float32, tf.int64], "input_shape": [[1]], "axis": [None, [], [0], [-1]], + }, { + "dtype": [tf.int32, tf.float32, tf.int64], + "input_shape": [[1, 1, 1, 1, 1]], + "axis": [None, [], [0], [3, 0], [-2, 0, 3, 2]], }] def build_graph(parameters): -- GitLab From 59ca0dfb87f822d25e434a8d5520b09f49d30535 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 16:44:22 -0800 Subject: [PATCH 074/258] Replaced LOGs with NSLogs. Also inserted exit(-1) after LOG(FATAL)s. Removed unused definition of CHECK macro. PiperOrigin-RevId: 182857784 --- .../ios/simple/RunModelViewController.mm | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/tensorflow/contrib/lite/examples/ios/simple/RunModelViewController.mm b/tensorflow/contrib/lite/examples/ios/simple/RunModelViewController.mm index a885a57b65..0ab7aa25d0 100644 --- a/tensorflow/contrib/lite/examples/ios/simple/RunModelViewController.mm +++ b/tensorflow/contrib/lite/examples/ios/simple/RunModelViewController.mm @@ -29,13 +29,6 @@ #include "ios_image_load.h" -#define LOG(x) std::cerr -#define CHECK(x) \ - if (!(x)) { \ - LOG(ERROR) << #x << "failed"; \ - exit(1); \ - } - NSString* RunInferenceOnImage(); @interface RunModelViewController () @@ -89,8 +82,8 @@ static void GetTopN(const float* prediction, const int prediction_size, const in NSString* FilePathForResourceName(NSString* name, NSString* extension) { NSString* file_path = [[NSBundle mainBundle] pathForResource:name ofType:extension]; if (file_path == NULL) { - LOG(FATAL) << "Couldn't find '" << [name UTF8String] << "." << [extension UTF8String] - << "' in bundle."; + NSLog(@"Couldn't find '%@.%@' in bundle.", name, extension); + exit(-1); } return file_path; } @@ -106,11 +99,12 @@ NSString* RunInferenceOnImage() { std::unique_ptr model( tflite::FlatBufferModel::BuildFromFile([graph_path UTF8String])); if (!model) { - LOG(FATAL) << "Failed to mmap model " << [graph UTF8String]; + NSLog(@"Failed to mmap model %@.", graph); + exit(-1); } - LOG(INFO) << "Loaded model " << [graph UTF8String]; + NSLog(@"Loaded model %@.", graph); model->error_reporter(); - LOG(INFO) << "resolved reporter"; + NSLog(@"Resolved reporter."); #ifdef TFLITE_CUSTOM_OPS_HEADER tflite::MutableOpResolver resolver; @@ -122,7 +116,8 @@ NSString* RunInferenceOnImage() { std::unique_ptr interpreter; tflite::InterpreterBuilder(*model, resolver)(&interpreter); if (!interpreter) { - LOG(FATAL) << "Failed to construct interpreter"; + NSLog(@"Failed to construct interpreter."); + exit(-1); } if (num_threads != -1) { @@ -136,7 +131,8 @@ NSString* RunInferenceOnImage() { } if (interpreter->AllocateTensors() != kTfLiteOk) { - LOG(FATAL) << "Failed to allocate tensors!"; + NSLog(@"Failed to allocate tensors."); + exit(-1); } // Read the label list @@ -181,7 +177,8 @@ NSString* RunInferenceOnImage() { } if (interpreter->Invoke() != kTfLiteOk) { - LOG(FATAL) << "Failed to invoke!"; + NSLog(@"Failed to invoke!"); + exit(-1); } float* output = interpreter->typed_output_tensor(0); @@ -211,11 +208,9 @@ NSString* RunInferenceOnImage() { ss << "\n"; } - LOG(INFO) << "Predictions: " << ss.str(); - std::string predictions = ss.str(); NSString* result = @""; result = [NSString stringWithFormat:@"%@ - %s", result, predictions.c_str()]; - + NSLog(@"Predictions: %@", result); return result; } -- GitLab From 4222bd9dd19fb147998c55c7562733f56d76ddac Mon Sep 17 00:00:00 2001 From: Andrew Harp Date: Mon, 22 Jan 2018 19:53:09 -0500 Subject: [PATCH 075/258] Replace inception5h references with inception_v1 --- WORKSPACE | 8 ++++---- tensorflow/examples/android/BUILD | 2 +- tensorflow/examples/android/download-models.gradle | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 7ae39374f1..1e38a9a8cd 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -41,12 +41,12 @@ load("//tensorflow:workspace.bzl", "tf_workspace") tf_workspace() new_http_archive( - name = "inception5h", + name = "inception_v1", build_file = "models.BUILD", - sha256 = "d13569f6a98159de37e92e9c8ec4dae8f674fbf475f69fe6199b514f756d4364", + sha256 = "7efe12a8363f09bc24d7b7a450304a15655a57a7751929b2c1593a71183bb105", urls = [ - "http://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip", - "http://download.tensorflow.org/models/inception5h.zip", + "http://storage.googleapis.com/download.tensorflow.org/models/inception_v1.zip", + "http://download.tensorflow.org/models/inception_v1.zip", ], ) diff --git a/tensorflow/examples/android/BUILD b/tensorflow/examples/android/BUILD index 46df5973e8..1214647797 100644 --- a/tensorflow/examples/android/BUILD +++ b/tensorflow/examples/android/BUILD @@ -92,7 +92,7 @@ android_binary( filegroup( name = "external_assets", srcs = [ - "@inception5h//:model_files", + "@inception_v1//:model_files", "@mobile_ssd//:model_files", "@speech_commands//:model_files", "@stylize//:model_files", diff --git a/tensorflow/examples/android/download-models.gradle b/tensorflow/examples/android/download-models.gradle index 0e2cf65f53..d3b67eab52 100644 --- a/tensorflow/examples/android/download-models.gradle +++ b/tensorflow/examples/android/download-models.gradle @@ -9,7 +9,7 @@ */ // hard coded model files // LINT.IfChange -def models = ['inception5h.zip', +def models = ['inception_v1.zip', 'object_detection/ssd_mobilenet_v1_android_export.zip', 'stylize_v1.zip', 'speech_commands_conv_actions.zip'] -- GitLab From 02e141bf2d672dc858c2067c0245c23b10602f52 Mon Sep 17 00:00:00 2001 From: Francois Chollet Date: Mon, 22 Jan 2018 17:10:35 -0800 Subject: [PATCH 076/258] Add SeparableConv1D layer and refactor SeparableConv2D to maximize code reuse and maintenability. PiperOrigin-RevId: 182861372 --- tensorflow/python/layers/convolutional.py | 443 ++++++++++++++++-- .../python/layers/convolutional_test.py | 162 +++++++ tensorflow/python/layers/layers.py | 4 + ...flow.keras.layers.-separable-conv2-d.pbtxt | 2 +- ...ras.layers.-separable-convolution2-d.pbtxt | 2 +- ...tensorflow.layers.-separable-conv1-d.pbtxt | 144 ++++++ ...tensorflow.layers.-separable-conv2-d.pbtxt | 2 +- .../tools/api/golden/tensorflow.layers.pbtxt | 8 + 8 files changed, 718 insertions(+), 49 deletions(-) create mode 100644 tensorflow/tools/api/golden/tensorflow.layers.-separable-conv1-d.pbtxt diff --git a/tensorflow/python/layers/convolutional.py b/tensorflow/python/layers/convolutional.py index ab1fa551e1..79c421f4c9 100644 --- a/tensorflow/python/layers/convolutional.py +++ b/tensorflow/python/layers/convolutional.py @@ -819,8 +819,8 @@ def conv3d(inputs, return layer.apply(inputs) -class SeparableConv2D(Conv2D): - """Depthwise separable 2D convolution. +class _SeparableConv(_Conv): + """Abstract base layer for separable nD convolution. This layer performs a depthwise convolution that acts separately on channels, followed by a pointwise convolution that mixes channels. @@ -829,12 +829,13 @@ class SeparableConv2D(Conv2D): It then optionally applies an activation function to produce the final output. Arguments: + rank: An integer, the rank of the convolution, e.g. "2" for 2D convolution. filters: Integer, the dimensionality of the output space (i.e. the number of filters in the convolution). - kernel_size: A tuple or list of 2 integers specifying the spatial + kernel_size: A tuple or list of integers specifying the spatial dimensions of the filters. Can be a single integer to specify the same value for all spatial dimensions. - strides: A tuple or list of 2 positive integers specifying the strides + strides: A tuple or list of integers specifying the strides of the convolution. Can be a single integer to specify the same value for all spatial dimensions. Specifying any `stride` value != 1 is incompatible with specifying @@ -843,9 +844,8 @@ class SeparableConv2D(Conv2D): data_format: A string, one of `channels_last` (default) or `channels_first`. The ordering of the dimensions in the inputs. `channels_last` corresponds to inputs with shape - `(batch, height, width, channels)` while `channels_first` corresponds to - inputs with shape `(batch, channels, height, width)`. - + `(batch, ..., channels)` while `channels_first` corresponds to + inputs with shape `(batch, channels, ...)`. dilation_rate: An integer or tuple/list of 2 integers, specifying the dilation rate to use for dilated convolution. Can be a single integer to specify the same value for @@ -883,12 +883,14 @@ class SeparableConv2D(Conv2D): name: A string, the name of the layer. """ - def __init__(self, filters, + def __init__(self, + rank, + filters, kernel_size, - strides=(1, 1), + strides=1, padding='valid', data_format='channels_last', - dilation_rate=(1, 1), + dilation_rate=1, depth_multiplier=1, activation=None, use_bias=True, @@ -905,7 +907,8 @@ class SeparableConv2D(Conv2D): trainable=True, name=None, **kwargs): - super(SeparableConv2D, self).__init__( + super(_SeparableConv, self).__init__( + rank=rank, filters=filters, kernel_size=kernel_size, strides=strides, @@ -920,7 +923,6 @@ class SeparableConv2D(Conv2D): trainable=trainable, name=name, **kwargs) - self.data_format = data_format self.depth_multiplier = depth_multiplier self.depthwise_initializer = depthwise_initializer self.pointwise_initializer = pointwise_initializer @@ -930,26 +932,21 @@ class SeparableConv2D(Conv2D): self.pointwise_constraint = pointwise_constraint def build(self, input_shape): - if len(input_shape) < 4: - raise ValueError('Inputs to `SeparableConv2D` should have rank 4. ' - 'Received input shape:', str(input_shape)) + input_shape = tensor_shape.TensorShape(input_shape) if self.data_format == 'channels_first': channel_axis = 1 else: - channel_axis = 3 - if input_shape[channel_axis] is None: - raise ValueError('The channel dimension of the inputs to ' - '`SeparableConv2D` ' + channel_axis = -1 + if input_shape[channel_axis].value is None: + raise ValueError('The channel dimension of the inputs ' 'should be defined. Found `None`.') - input_dim = int(input_shape[channel_axis]) - self.input_spec = base.InputSpec(ndim=4, axes={channel_axis: input_dim}) - depthwise_kernel_shape = (self.kernel_size[0], - self.kernel_size[1], - input_dim, - self.depth_multiplier) - pointwise_kernel_shape = (1, 1, - self.depth_multiplier * input_dim, - self.filters) + input_dim = input_shape[channel_axis].value + self.input_spec = base.InputSpec(ndim=self.rank + 2, + axes={channel_axis: input_dim}) + depthwise_kernel_shape = self.kernel_size + (input_dim, + self.depth_multiplier) + pointwise_kernel_shape = ( + 1,) * self.rank + (self.depth_multiplier * input_dim, self.filters) self.depthwise_kernel = self.add_variable( name='depthwise_kernel', @@ -979,6 +976,264 @@ class SeparableConv2D(Conv2D): self.bias = None self.built = True + def call(self, inputs): + raise NotImplementedError + + +class SeparableConv1D(_SeparableConv): + """Depthwise separable 1D convolution. + + This layer performs a depthwise convolution that acts separately on + channels, followed by a pointwise convolution that mixes channels. + If `use_bias` is True and a bias initializer is provided, + it adds a bias vector to the output. + It then optionally applies an activation function to produce the final output. + + Arguments: + filters: Integer, the dimensionality of the output space (i.e. the number + of filters in the convolution). + kernel_size: A single integer specifying the spatial + dimensions of the filters. + strides: A single integer specifying the strides + of the convolution. + Specifying any `stride` value != 1 is incompatible with specifying + any `dilation_rate` value != 1. + padding: One of `"valid"` or `"same"` (case-insensitive). + data_format: A string, one of `channels_last` (default) or `channels_first`. + The ordering of the dimensions in the inputs. + `channels_last` corresponds to inputs with shape + `(batch, length, channels)` while `channels_first` corresponds to + inputs with shape `(batch, channels, length)`. + dilation_rate: A single integer, specifying + the dilation rate to use for dilated convolution. + Currently, specifying any `dilation_rate` value != 1 is + incompatible with specifying any stride value != 1. + depth_multiplier: The number of depthwise convolution output channels for + each input channel. The total number of depthwise convolution output + channels will be equal to `num_filters_in * depth_multiplier`. + activation: Activation function. Set it to None to maintain a + linear activation. + use_bias: Boolean, whether the layer uses a bias. + depthwise_initializer: An initializer for the depthwise convolution kernel. + pointwise_initializer: An initializer for the pointwise convolution kernel. + bias_initializer: An initializer for the bias vector. If None, the default + initializer will be used. + depthwise_regularizer: Optional regularizer for the depthwise + convolution kernel. + pointwise_regularizer: Optional regularizer for the pointwise + convolution kernel. + bias_regularizer: Optional regularizer for the bias vector. + activity_regularizer: Optional regularizer function for the output. + depthwise_constraint: Optional projection function to be applied to the + depthwise kernel after being updated by an `Optimizer` (e.g. used for + norm constraints or value constraints for layer weights). The function + must take as input the unprojected variable and must return the + projected variable (which must have the same shape). Constraints are + not safe to use when doing asynchronous distributed training. + pointwise_constraint: Optional projection function to be applied to the + pointwise kernel after being updated by an `Optimizer`. + bias_constraint: Optional projection function to be applied to the + bias after being updated by an `Optimizer`. + trainable: Boolean, if `True` also add variables to the graph collection + `GraphKeys.TRAINABLE_VARIABLES` (see `tf.Variable`). + name: A string, the name of the layer. + """ + + def __init__(self, filters, + kernel_size, + strides=1, + padding='valid', + data_format='channels_last', + dilation_rate=1, + depth_multiplier=1, + activation=None, + use_bias=True, + depthwise_initializer=None, + pointwise_initializer=None, + bias_initializer=init_ops.zeros_initializer(), + depthwise_regularizer=None, + pointwise_regularizer=None, + bias_regularizer=None, + activity_regularizer=None, + depthwise_constraint=None, + pointwise_constraint=None, + bias_constraint=None, + trainable=True, + name=None, + **kwargs): + super(SeparableConv1D, self).__init__( + rank=1, + filters=filters, + kernel_size=kernel_size, + strides=strides, + padding=padding, + data_format=data_format, + dilation_rate=dilation_rate, + depth_multiplier=depth_multiplier, + activation=activation, + use_bias=use_bias, + depthwise_initializer=depthwise_initializer, + pointwise_initializer=pointwise_initializer, + bias_initializer=bias_initializer, + depthwise_regularizer=depthwise_regularizer, + pointwise_regularizer=pointwise_regularizer, + bias_regularizer=bias_regularizer, + activity_regularizer=activity_regularizer, + depthwise_constraint=depthwise_constraint, + pointwise_constraint=pointwise_constraint, + bias_constraint=bias_constraint, + trainable=trainable, + name=name, + **kwargs) + + def call(self, inputs): + if self.data_format == 'channels_last': + strides = (1, 1) + self.strides + (1,) + spatial_start_dim = 1 + else: + strides = (1, 1, 1) + self.strides + spatial_start_dim = 2 + + # Explictly broadcast inputs and kernels to 4D. + # TODO(fchollet): refactor when a native separable_conv1d op is available. + inputs = array_ops.expand_dims(inputs, spatial_start_dim) + depthwise_kernel = array_ops.expand_dims(self.depthwise_kernel, 0) + pointwise_kernel = array_ops.expand_dims(self.pointwise_kernel, 0) + dilation_rate = (1,) + self.dilation_rate + + outputs = nn.separable_conv2d( + inputs, + depthwise_kernel, + pointwise_kernel, + strides=strides, + padding=self.padding.upper(), + rate=dilation_rate, + data_format=utils.convert_data_format(self.data_format, ndim=4)) + + if self.use_bias: + outputs = nn.bias_add( + outputs, + self.bias, + data_format=utils.convert_data_format(self.data_format, ndim=4)) + + outputs = array_ops.squeeze(outputs, [spatial_start_dim]) + + if self.activation is not None: + return self.activation(outputs) + return outputs + + +class SeparableConv2D(_SeparableConv): + """Depthwise separable 2D convolution. + + This layer performs a depthwise convolution that acts separately on + channels, followed by a pointwise convolution that mixes channels. + If `use_bias` is True and a bias initializer is provided, + it adds a bias vector to the output. + It then optionally applies an activation function to produce the final output. + + Arguments: + filters: Integer, the dimensionality of the output space (i.e. the number + of filters in the convolution). + kernel_size: A tuple or list of 2 integers specifying the spatial + dimensions of the filters. Can be a single integer to specify the same + value for all spatial dimensions. + strides: A tuple or list of 2 positive integers specifying the strides + of the convolution. Can be a single integer to specify the same value for + all spatial dimensions. + Specifying any `stride` value != 1 is incompatible with specifying + any `dilation_rate` value != 1. + padding: One of `"valid"` or `"same"` (case-insensitive). + data_format: A string, one of `channels_last` (default) or `channels_first`. + The ordering of the dimensions in the inputs. + `channels_last` corresponds to inputs with shape + `(batch, height, width, channels)` while `channels_first` corresponds to + inputs with shape `(batch, channels, height, width)`. + + dilation_rate: An integer or tuple/list of 2 integers, specifying + the dilation rate to use for dilated convolution. + Can be a single integer to specify the same value for + all spatial dimensions. + Currently, specifying any `dilation_rate` value != 1 is + incompatible with specifying any stride value != 1. + depth_multiplier: The number of depthwise convolution output channels for + each input channel. The total number of depthwise convolution output + channels will be equal to `num_filters_in * depth_multiplier`. + activation: Activation function. Set it to None to maintain a + linear activation. + use_bias: Boolean, whether the layer uses a bias. + depthwise_initializer: An initializer for the depthwise convolution kernel. + pointwise_initializer: An initializer for the pointwise convolution kernel. + bias_initializer: An initializer for the bias vector. If None, the default + initializer will be used. + depthwise_regularizer: Optional regularizer for the depthwise + convolution kernel. + pointwise_regularizer: Optional regularizer for the pointwise + convolution kernel. + bias_regularizer: Optional regularizer for the bias vector. + activity_regularizer: Optional regularizer function for the output. + depthwise_constraint: Optional projection function to be applied to the + depthwise kernel after being updated by an `Optimizer` (e.g. used for + norm constraints or value constraints for layer weights). The function + must take as input the unprojected variable and must return the + projected variable (which must have the same shape). Constraints are + not safe to use when doing asynchronous distributed training. + pointwise_constraint: Optional projection function to be applied to the + pointwise kernel after being updated by an `Optimizer`. + bias_constraint: Optional projection function to be applied to the + bias after being updated by an `Optimizer`. + trainable: Boolean, if `True` also add variables to the graph collection + `GraphKeys.TRAINABLE_VARIABLES` (see `tf.Variable`). + name: A string, the name of the layer. + """ + + def __init__(self, filters, + kernel_size, + strides=(1, 1), + padding='valid', + data_format='channels_last', + dilation_rate=(1, 1), + depth_multiplier=1, + activation=None, + use_bias=True, + depthwise_initializer=None, + pointwise_initializer=None, + bias_initializer=init_ops.zeros_initializer(), + depthwise_regularizer=None, + pointwise_regularizer=None, + bias_regularizer=None, + activity_regularizer=None, + depthwise_constraint=None, + pointwise_constraint=None, + bias_constraint=None, + trainable=True, + name=None, + **kwargs): + super(SeparableConv2D, self).__init__( + rank=2, + filters=filters, + kernel_size=kernel_size, + strides=strides, + padding=padding, + data_format=data_format, + dilation_rate=dilation_rate, + depth_multiplier=depth_multiplier, + activation=activation, + use_bias=use_bias, + depthwise_initializer=depthwise_initializer, + pointwise_initializer=pointwise_initializer, + bias_initializer=bias_initializer, + depthwise_regularizer=depthwise_regularizer, + pointwise_regularizer=pointwise_regularizer, + bias_regularizer=bias_regularizer, + activity_regularizer=activity_regularizer, + depthwise_constraint=depthwise_constraint, + pointwise_constraint=pointwise_constraint, + bias_constraint=bias_constraint, + trainable=trainable, + name=name, + **kwargs) + def call(self, inputs): # Apply the actual ops. if self.data_format == 'channels_last': @@ -1004,25 +1259,121 @@ class SeparableConv2D(Conv2D): return self.activation(outputs) return outputs - def compute_output_shape(self, input_shape): - input_shape = tensor_shape.TensorShape(input_shape).as_list() - if self.data_format == 'channels_first': - rows = input_shape[2] - cols = input_shape[3] - else: - rows = input_shape[1] - cols = input_shape[2] - rows = utils.conv_output_length(rows, self.kernel_size[0], - self.padding, self.strides[0]) - cols = utils.conv_output_length(cols, self.kernel_size[1], - self.padding, self.strides[1]) - if self.data_format == 'channels_first': - return tensor_shape.TensorShape( - [input_shape[0], self.filters, rows, cols]) - else: - return tensor_shape.TensorShape( - [input_shape[0], rows, cols, self.filters]) +def separable_conv1d(inputs, + filters, + kernel_size, + strides=1, + padding='valid', + data_format='channels_last', + dilation_rate=1, + depth_multiplier=1, + activation=None, + use_bias=True, + depthwise_initializer=None, + pointwise_initializer=None, + bias_initializer=init_ops.zeros_initializer(), + depthwise_regularizer=None, + pointwise_regularizer=None, + bias_regularizer=None, + activity_regularizer=None, + depthwise_constraint=None, + pointwise_constraint=None, + bias_constraint=None, + trainable=True, + name=None, + reuse=None): + """Functional interface for the depthwise separable 1D convolution layer. + + This layer performs a depthwise convolution that acts separately on + channels, followed by a pointwise convolution that mixes channels. + If `use_bias` is True and a bias initializer is provided, + it adds a bias vector to the output. + It then optionally applies an activation function to produce the final output. + + Arguments: + inputs: Input tensor. + filters: Integer, the dimensionality of the output space (i.e. the number + of filters in the convolution). + kernel_size: A single integer specifying the spatial + dimensions of the filters. + strides: A single integer specifying the strides + of the convolution. + Specifying any `stride` value != 1 is incompatible with specifying + any `dilation_rate` value != 1. + padding: One of `"valid"` or `"same"` (case-insensitive). + data_format: A string, one of `channels_last` (default) or `channels_first`. + The ordering of the dimensions in the inputs. + `channels_last` corresponds to inputs with shape + `(batch, length, channels)` while `channels_first` corresponds to + inputs with shape `(batch, channels, length)`. + dilation_rate: A single integer, specifying + the dilation rate to use for dilated convolution. + Currently, specifying any `dilation_rate` value != 1 is + incompatible with specifying any stride value != 1. + depth_multiplier: The number of depthwise convolution output channels for + each input channel. The total number of depthwise convolution output + channels will be equal to `num_filters_in * depth_multiplier`. + activation: Activation function. Set it to None to maintain a + linear activation. + use_bias: Boolean, whether the layer uses a bias. + depthwise_initializer: An initializer for the depthwise convolution kernel. + pointwise_initializer: An initializer for the pointwise convolution kernel. + bias_initializer: An initializer for the bias vector. If None, the default + initializer will be used. + depthwise_regularizer: Optional regularizer for the depthwise + convolution kernel. + pointwise_regularizer: Optional regularizer for the pointwise + convolution kernel. + bias_regularizer: Optional regularizer for the bias vector. + activity_regularizer: Optional regularizer function for the output. + depthwise_constraint: Optional projection function to be applied to the + depthwise kernel after being updated by an `Optimizer` (e.g. used for + norm constraints or value constraints for layer weights). The function + must take as input the unprojected variable and must return the + projected variable (which must have the same shape). Constraints are + not safe to use when doing asynchronous distributed training. + pointwise_constraint: Optional projection function to be applied to the + pointwise kernel after being updated by an `Optimizer`. + bias_constraint: Optional projection function to be applied to the + bias after being updated by an `Optimizer`. + trainable: Boolean, if `True` also add variables to the graph collection + `GraphKeys.TRAINABLE_VARIABLES` (see `tf.Variable`). + name: A string, the name of the layer. + reuse: Boolean, whether to reuse the weights of a previous layer + by the same name. + + Returns: + Output tensor. + + Raises: + ValueError: if eager execution is enabled. + """ + layer = SeparableConv1D( + filters=filters, + kernel_size=kernel_size, + strides=strides, + padding=padding, + data_format=data_format, + dilation_rate=dilation_rate, + depth_multiplier=depth_multiplier, + activation=activation, + use_bias=use_bias, + depthwise_initializer=depthwise_initializer, + pointwise_initializer=pointwise_initializer, + bias_initializer=bias_initializer, + depthwise_regularizer=depthwise_regularizer, + pointwise_regularizer=pointwise_regularizer, + bias_regularizer=bias_regularizer, + activity_regularizer=activity_regularizer, + depthwise_constraint=depthwise_constraint, + pointwise_constraint=pointwise_constraint, + bias_constraint=bias_constraint, + trainable=trainable, + name=name, + _reuse=reuse, + _scope=name) + return layer.apply(inputs) def separable_conv2d(inputs, diff --git a/tensorflow/python/layers/convolutional_test.py b/tensorflow/python/layers/convolutional_test.py index e41eb5c32f..160e732b67 100644 --- a/tensorflow/python/layers/convolutional_test.py +++ b/tensorflow/python/layers/convolutional_test.py @@ -326,6 +326,168 @@ class ConvTest(test.TestCase): self.assertEqual(conv3d.bias_constraint, b_constraint) +@test_util.with_c_api +class SeparableConv1DTest(test.TestCase): + + def testInvalidDataFormat(self): + length = 9 + data = random_ops.random_uniform((5, length, 3), seed=1) + with self.assertRaisesRegexp(ValueError, 'data_format'): + conv_layers.separable_conv1d(data, 32, 3, data_format='invalid') + + def testInvalidStrides(self): + length = 9 + data = random_ops.random_uniform((5, length, 3), seed=1) + with self.assertRaisesRegexp(ValueError, 'strides'): + conv_layers.separable_conv1d(data, 32, 3, strides=(1, 2)) + + with self.assertRaisesRegexp(ValueError, 'strides'): + conv_layers.separable_conv1d(data, 32, 3, strides=None) + + def testInvalidKernelSize(self): + length = 9 + data = random_ops.random_uniform((5, length, 3), seed=1) + with self.assertRaisesRegexp(ValueError, 'kernel_size'): + conv_layers.separable_conv1d(data, 32, (1, 2)) + + with self.assertRaisesRegexp(ValueError, 'kernel_size'): + conv_layers.separable_conv1d(data, 32, None) + + def testCreateSeparableConv1D(self): + length = 9 + data = random_ops.random_uniform((5, length, 4)) + layer = conv_layers.SeparableConv1D(32, 3, activation=nn_ops.relu) + output = layer.apply(data) + self.assertEqual(output.op.name, 'separable_conv1d/Relu') + self.assertEqual(output.get_shape().as_list(), [5, length - 2, 32]) + self.assertEqual(layer.depthwise_kernel.get_shape().as_list(), [3, 4, 1]) + self.assertEqual(layer.pointwise_kernel.get_shape().as_list(), [1, 4, 32]) + self.assertEqual(layer.bias.get_shape().as_list(), [32]) + + def testCreateSeparableConv1DDepthMultiplier(self): + length = 9 + data = random_ops.random_uniform((5, length, 4)) + layer = conv_layers.SeparableConv1D(32, 3, depth_multiplier=2) + output = layer.apply(data) + self.assertEqual(output.get_shape().as_list(), [5, length - 2, 32]) + self.assertEqual(layer.depthwise_kernel.get_shape().as_list(), [3, 4, 2]) + self.assertEqual(layer.pointwise_kernel.get_shape().as_list(), [1, 8, 32]) + self.assertEqual(layer.bias.get_shape().as_list(), [32]) + + def testCreateSeparableConv1DChannelsFirst(self): + length = 9 + data = random_ops.random_uniform((5, 4, length)) + layer = conv_layers.SeparableConv1D(32, 3, data_format='channels_first') + output = layer.apply(data) + self.assertEqual(output.get_shape().as_list(), [5, 32, length - 2]) + self.assertEqual(layer.depthwise_kernel.get_shape().as_list(), [3, 4, 1]) + self.assertEqual(layer.pointwise_kernel.get_shape().as_list(), [1, 4, 32]) + self.assertEqual(layer.bias.get_shape().as_list(), [32]) + + def testSeparableConv1DPaddingSame(self): + length = 9 + data = random_ops.random_uniform((5, length, 32), seed=1) + layer = conv_layers.SeparableConv1D( + 64, length, padding='same') + output = layer.apply(data) + self.assertEqual(output.get_shape().as_list(), [5, length, 64]) + + def testCreateSeparableConv1DWithStrides(self): + length = 10 + data = random_ops.random_uniform((5, length, 3), seed=1) + layer = conv_layers.SeparableConv1D(32, 3, strides=2, padding='same') + output = layer.apply(data) + self.assertEqual(output.get_shape().as_list(), [5, length // 2, 32]) + + def testCreateSeparableConv1DWithStridesChannelsFirst(self): + data_format = 'channels_first' + length = 10 + data = random_ops.random_uniform((5, 3, length), seed=1) + layer = conv_layers.SeparableConv1D( + 32, 3, strides=2, padding='same', data_format=data_format) + output = layer.apply(data) + self.assertEqual(output.get_shape().as_list(), [5, 32, length // 2]) + + def testFunctionalConv1DReuse(self): + length = 10 + data = random_ops.random_uniform((5, length, 3), seed=1) + conv_layers.separable_conv1d(data, 32, 3, name='sepconv1') + self.assertEqual(len(variables.trainable_variables()), 3) + conv_layers.separable_conv1d(data, 32, 3, name='sepconv1', reuse=True) + self.assertEqual(len(variables.trainable_variables()), 3) + + def testFunctionalConv1DReuseFromScope(self): + with variable_scope.variable_scope('scope'): + length = 10 + data = random_ops.random_uniform((5, length, 3), seed=1) + conv_layers.separable_conv1d(data, 32, 3, name='sepconv1') + self.assertEqual(len(variables.trainable_variables()), 3) + with variable_scope.variable_scope('scope', reuse=True): + conv_layers.separable_conv1d(data, 32, 3, name='sepconv1') + self.assertEqual(len(variables.trainable_variables()), 3) + + def testFunctionalConv1DNoReuse(self): + length = 10 + data = random_ops.random_uniform((5, length, 3), seed=1) + conv_layers.separable_conv1d(data, 32, 3) + self.assertEqual(len(variables.trainable_variables()), 3) + conv_layers.separable_conv1d(data, 32, 3) + self.assertEqual(len(variables.trainable_variables()), 6) + + def testSeparableConv1DDepthwiseRegularizer(self): + length = 9 + data = random_ops.random_uniform((5, length, 4)) + reg = lambda x: 0.1 * math_ops.reduce_sum(x) + layer = conv_layers.SeparableConv1D(32, 3, depthwise_regularizer=reg) + layer.apply(data) + loss_keys = ops.get_collection(ops.GraphKeys.REGULARIZATION_LOSSES) + self.assertEqual(len(loss_keys), 1) + self.assertEqual(layer.losses, loss_keys) + + def testSeparableConv1DPointwiseRegularizer(self): + length = 9 + data = random_ops.random_uniform((5, length, 4)) + reg = lambda x: 0.1 * math_ops.reduce_sum(x) + layer = conv_layers.SeparableConv1D(32, 3, pointwise_regularizer=reg) + layer.apply(data) + loss_keys = ops.get_collection(ops.GraphKeys.REGULARIZATION_LOSSES) + self.assertEqual(len(loss_keys), 1) + self.assertEqual(layer.losses, loss_keys) + + def testSeparableConv1DBiasRegularizer(self): + length = 9 + data = random_ops.random_uniform((5, length, 4)) + reg = lambda x: 0.1 * math_ops.reduce_sum(x) + layer = conv_layers.SeparableConv1D(32, 3, bias_regularizer=reg) + layer.apply(data) + loss_keys = ops.get_collection(ops.GraphKeys.REGULARIZATION_LOSSES) + self.assertEqual(len(loss_keys), 1) + self.assertEqual(layer.losses, loss_keys) + + def testSeparableConv1DNoBias(self): + length = 9 + data = random_ops.random_uniform((5, length, 4)) + layer = conv_layers.SeparableConv1D( + 32, 3, activation=nn_ops.relu, use_bias=False) + output = layer.apply(data) + self.assertEqual(output.op.name, 'separable_conv1d/Relu') + self.assertEqual(layer.bias, None) + + def testConstraints(self): + d_constraint = lambda x: x / math_ops.reduce_sum(x) + p_constraint = lambda x: x / math_ops.reduce_sum(x) + b_constraint = lambda x: x / math_ops.reduce_max(x) + layer = conv_layers.SeparableConv1D(2, 3, + depthwise_constraint=d_constraint, + pointwise_constraint=p_constraint, + bias_constraint=b_constraint) + inputs = random_ops.random_uniform((5, 3, 5), seed=1) + layer(inputs) + self.assertEqual(layer.depthwise_constraint, d_constraint) + self.assertEqual(layer.pointwise_constraint, p_constraint) + self.assertEqual(layer.bias_constraint, b_constraint) + + @test_util.with_c_api class SeparableConv2DTest(test.TestCase): diff --git a/tensorflow/python/layers/layers.py b/tensorflow/python/layers/layers.py index 0a52b1e8d9..1555846efd 100644 --- a/tensorflow/python/layers/layers.py +++ b/tensorflow/python/layers/layers.py @@ -22,6 +22,7 @@ @@Conv1D @@Conv2D @@Conv3D +@@SeparableConv1D @@SeparableConv2D @@Conv2DTranspose @@Conv3DTranspose @@ -43,6 +44,7 @@ @@conv1d @@conv2d @@conv3d +@@separable_conv1d @@separable_conv2d @@conv2d_transpose @@conv3d_transpose @@ -78,6 +80,7 @@ from tensorflow.python.layers.core import dropout from tensorflow.python.layers.core import flatten # Convolutional layers. +from tensorflow.python.layers.convolutional import SeparableConv1D from tensorflow.python.layers.convolutional import SeparableConv2D from tensorflow.python.layers.convolutional import SeparableConvolution2D from tensorflow.python.layers.convolutional import Conv2DTranspose @@ -91,6 +94,7 @@ from tensorflow.python.layers.convolutional import Convolution2D from tensorflow.python.layers.convolutional import Conv3D from tensorflow.python.layers.convolutional import Convolution3D +from tensorflow.python.layers.convolutional import separable_conv1d from tensorflow.python.layers.convolutional import separable_conv2d from tensorflow.python.layers.convolutional import conv2d_transpose from tensorflow.python.layers.convolutional import conv3d_transpose diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-conv2-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-conv2-d.pbtxt index a6d9b57c88..5d898fb2bd 100644 --- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-conv2-d.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-conv2-d.pbtxt @@ -2,7 +2,7 @@ path: "tensorflow.keras.layers.SeparableConv2D" tf_class { is_instance: "" is_instance: "" - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-convolution2-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-convolution2-d.pbtxt index 551d695379..c758d87993 100644 --- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-convolution2-d.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-convolution2-d.pbtxt @@ -2,7 +2,7 @@ path: "tensorflow.keras.layers.SeparableConvolution2D" tf_class { is_instance: "" is_instance: "" - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/tensorflow.layers.-separable-conv1-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.layers.-separable-conv1-d.pbtxt new file mode 100644 index 0000000000..05799ecfc9 --- /dev/null +++ b/tensorflow/tools/api/golden/tensorflow.layers.-separable-conv1-d.pbtxt @@ -0,0 +1,144 @@ +path: "tensorflow.layers.SeparableConv1D" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "graph" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "scope_name" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'filters\', \'kernel_size\', \'strides\', \'padding\', \'data_format\', \'dilation_rate\', \'depth_multiplier\', \'activation\', \'use_bias\', \'depthwise_initializer\', \'pointwise_initializer\', \'bias_initializer\', \'depthwise_regularizer\', \'pointwise_regularizer\', \'bias_regularizer\', \'activity_regularizer\', \'depthwise_constraint\', \'pointwise_constraint\', \'bias_constraint\', \'trainable\', \'name\'], varargs=None, keywords=kwargs, defaults=[\'1\', \'valid\', \'channels_last\', \'1\', \'1\', \'None\', \'True\', \'None\', \'None\', \'\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'True\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\', \'name\', \'shape\', \'dtype\', \'initializer\', \'regularizer\', \'trainable\', \'constraint\', \'partitioner\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'True\', \'None\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/tensorflow.layers.-separable-conv2-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.layers.-separable-conv2-d.pbtxt index 4d91ab1d8c..c2aeb35c46 100644 --- a/tensorflow/tools/api/golden/tensorflow.layers.-separable-conv2-d.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.layers.-separable-conv2-d.pbtxt @@ -1,7 +1,7 @@ path: "tensorflow.layers.SeparableConv2D" tf_class { is_instance: "" - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/tensorflow.layers.pbtxt b/tensorflow/tools/api/golden/tensorflow.layers.pbtxt index c45d6e6c05..59134f8489 100644 --- a/tensorflow/tools/api/golden/tensorflow.layers.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.layers.pbtxt @@ -68,6 +68,10 @@ tf_module { name: "MaxPooling3D" mtype: "" } + member { + name: "SeparableConv1D" + mtype: "" + } member { name: "SeparableConv2D" mtype: "" @@ -136,6 +140,10 @@ tf_module { name: "max_pooling3d" argspec: "args=[\'inputs\', \'pool_size\', \'strides\', \'padding\', \'data_format\', \'name\'], varargs=None, keywords=None, defaults=[\'valid\', \'channels_last\', \'None\'], " } + member_method { + name: "separable_conv1d" + argspec: "args=[\'inputs\', \'filters\', \'kernel_size\', \'strides\', \'padding\', \'data_format\', \'dilation_rate\', \'depth_multiplier\', \'activation\', \'use_bias\', \'depthwise_initializer\', \'pointwise_initializer\', \'bias_initializer\', \'depthwise_regularizer\', \'pointwise_regularizer\', \'bias_regularizer\', \'activity_regularizer\', \'depthwise_constraint\', \'pointwise_constraint\', \'bias_constraint\', \'trainable\', \'name\', \'reuse\'], varargs=None, keywords=None, defaults=[\'1\', \'valid\', \'channels_last\', \'1\', \'1\', \'None\', \'True\', \'None\', \'None\', \'\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'True\', \'None\', \'None\'], " + } member_method { name: "separable_conv2d" argspec: "args=[\'inputs\', \'filters\', \'kernel_size\', \'strides\', \'padding\', \'data_format\', \'dilation_rate\', \'depth_multiplier\', \'activation\', \'use_bias\', \'depthwise_initializer\', \'pointwise_initializer\', \'bias_initializer\', \'depthwise_regularizer\', \'pointwise_regularizer\', \'bias_regularizer\', \'activity_regularizer\', \'depthwise_constraint\', \'pointwise_constraint\', \'bias_constraint\', \'trainable\', \'name\', \'reuse\'], varargs=None, keywords=None, defaults=[\'(1, 1)\', \'valid\', \'channels_last\', \'(1, 1)\', \'1\', \'None\', \'True\', \'None\', \'None\', \'\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'True\', \'None\', \'None\'], " -- GitLab From f5356644fd3467afa275ec2155281825b7e927a0 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Mon, 22 Jan 2018 17:12:18 -0800 Subject: [PATCH 077/258] Ops to get and set individual elements of TensorLists, and their gradients. PiperOrigin-RevId: 182861559 --- .../base_api/api_def_TensorGetItem.pbtxt | 11 ++ .../api_def_TensorListElementShape.pbtxt | 8 + .../base_api/api_def_TensorListReserve.pbtxt | 10 + .../base_api/api_def_TensorSetItem.pbtxt | 11 ++ tensorflow/core/framework/tensor.cc | 4 +- tensorflow/core/framework/tensor.h | 6 +- tensorflow/core/kernels/list_kernels.cc | 175 ++++++++++++++++++ tensorflow/core/kernels/list_kernels.h | 30 ++- tensorflow/core/ops/list_ops.cc | 76 ++++++++ tensorflow/python/BUILD | 1 + tensorflow/python/kernel_tests/BUILD | 2 + .../python/kernel_tests/list_ops_test.py | 37 ++++ tensorflow/python/ops/list_ops.py | 43 ++++- 13 files changed, 397 insertions(+), 17 deletions(-) create mode 100644 tensorflow/core/api_def/base_api/api_def_TensorGetItem.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_TensorListElementShape.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_TensorListReserve.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_TensorSetItem.pbtxt diff --git a/tensorflow/core/api_def/base_api/api_def_TensorGetItem.pbtxt b/tensorflow/core/api_def/base_api/api_def_TensorGetItem.pbtxt new file mode 100644 index 0000000000..2869967d83 --- /dev/null +++ b/tensorflow/core/api_def/base_api/api_def_TensorGetItem.pbtxt @@ -0,0 +1,11 @@ +op { + graph_op_name: "TensorListGetItem" + summary: "Returns the item in the list with the given index." + description: < typename TTypes::Tensor Tensor::shaped( gtl::ArraySlice new_sizes) { - CheckTypeAndIsAligned(DataTypeToEnum::v()); + CheckType(DataTypeToEnum::v()); + CHECK(IsAligned()); Eigen::array dims; FillDimsAndValidateCompatibleShape(new_sizes, &dims); return typename TTypes::Tensor(base(), dims); @@ -687,7 +688,8 @@ typename TTypes::UnalignedTensor Tensor::unaligned_shaped( template typename TTypes::ConstTensor Tensor::shaped( gtl::ArraySlice new_sizes) const { - CheckTypeAndIsAligned(DataTypeToEnum::v()); + CheckType(DataTypeToEnum::v()); + CHECK(IsAligned()); Eigen::array dims; FillDimsAndValidateCompatibleShape(new_sizes, &dims); return typename TTypes::ConstTensor(base(), dims); diff --git a/tensorflow/core/kernels/list_kernels.cc b/tensorflow/core/kernels/list_kernels.cc index 5e405f16a4..baf0a4abe4 100644 --- a/tensorflow/core/kernels/list_kernels.cc +++ b/tensorflow/core/kernels/list_kernels.cc @@ -87,6 +87,14 @@ REGISTER_LIST_COPY(VariantDeviceCopyDirection::DEVICE_TO_DEVICE); REGISTER_UNARY_VARIANT_DECODE_FUNCTION(TensorList, TensorList::kTypeName); +Status TensorListShape(const TensorList& t, TensorShape* s) { + *s = TensorShape({}); + return Status::OK(); +} + +REGISTER_UNARY_VARIANT_SHAPE_FUNCTION(TensorList, TensorList::kTypeName, + TensorListShape); + bool TensorList::Decode(const VariantTensorData& data) { tensors = data.tensors(); string metadata; @@ -251,6 +259,45 @@ REGISTER_KERNEL_BUILDER( #endif // GOOGLE_CUDA +class TensorListElementShape : public OpKernel { + public: + explicit TensorListElementShape(OpKernelConstruction* c) : OpKernel(c) {} + + void Compute(OpKernelContext* c) override { + OP_REQUIRES( + c, c->input(0).shape().num_elements() == 1, + errors::InvalidArgument("List tensors are supposed to be scalars.")); + const TensorList* l = c->input(0).scalar()().get(); + OP_REQUIRES(c, l != nullptr, + errors::InvalidArgument( + "TensorListElementShape received a variant which is not a " + "list. Saw: '", + c->input(0).scalar()().DebugString(), "'")); + Tensor* result; + OP_REQUIRES_OK(c, c->allocate_output( + 0, TensorShape{l->element_shape.dims()}, &result)); + for (int i = 0; i < l->element_shape.dims(); ++i) { + if (result->dtype() == DT_INT32) { + result->flat()(i) = l->element_shape.dim_size(i); + } else { + result->flat()(i) = l->element_shape.dim_size(i); + } + } + } +}; + +REGISTER_KERNEL_BUILDER(Name("TensorListElementShape").Device(DEVICE_CPU), + TensorListElementShape); + +#if GOOGLE_CUDA + +REGISTER_KERNEL_BUILDER(Name("TensorListElementShape") + .Device(DEVICE_GPU) + .HostMemory("element_shape"), + TensorListElementShape); + +#endif // GOOGLE_CUDA + class TensorListPopBack : public OpKernel { public: explicit TensorListPopBack(OpKernelConstruction* c) : OpKernel(c) { @@ -299,6 +346,134 @@ REGISTER_KERNEL_BUILDER(Name("TensorListPopBack").Device(DEVICE_GPU), #endif // GOOGLE_CUDA +class TensorListReserve : public OpKernel { + public: + explicit TensorListReserve(OpKernelConstruction* c) : OpKernel(c) { + OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_)); + } + + void Compute(OpKernelContext* c) override { + PartialTensorShape element_shape; + OP_REQUIRES_OK(c, TensorShapeFromTensor(c->input(0), &element_shape)); + int32 num_elements = c->input(1).scalar()(); + TensorList output; + output.element_shape = element_shape; + output.element_dtype = element_dtype_; + output.tensors.resize(num_elements, Tensor(DT_INVALID)); + Tensor* result; + AllocatorAttributes attr; + attr.set_on_host(true); + OP_REQUIRES_OK(c, c->allocate_output(0, TensorShape{}, &result, attr)); + result->scalar()() = std::move(output); + } + + private: + DataType element_dtype_; +}; + +REGISTER_KERNEL_BUILDER(Name("TensorListReserve").Device(DEVICE_CPU), + TensorListReserve); + +#if GOOGLE_CUDA + +REGISTER_KERNEL_BUILDER(Name("TensorListReserve") + .Device(DEVICE_GPU) + .HostMemory("element_shape") + .HostMemory("num_elements"), + TensorListReserve); + +#endif // GOOGLE_CUDA + +class TensorListGetItem : public OpKernel { + public: + explicit TensorListGetItem(OpKernelConstruction* c) : OpKernel(c) { + OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_)); + } + + void Compute(OpKernelContext* c) override { + OP_REQUIRES( + c, c->input(0).shape().num_elements() == 1, + errors::InvalidArgument("List tensors are supposed to be scalars.")); + const TensorList* l = c->input(0).scalar()().get(); + OP_REQUIRES(c, l != nullptr, + errors::InvalidArgument( + "Input handle is not a list. Saw: '", + c->input(0).scalar()().DebugString(), "'")); + OP_REQUIRES(c, element_dtype_ == l->element_dtype, + errors::InvalidArgument("Invalid data types; op elements ", + DataTypeString(element_dtype_), + " but list elements ", + DataTypeString(l->element_dtype))); + int32 index = c->input(1).scalar()(); + OP_REQUIRES(c, index < l->tensors.size(), + errors::InvalidArgument("Trying to access element ", index, + " in a list with ", l->tensors.size(), + " elements.")); + c->set_output(0, l->tensors[index]); + } + + private: + DataType element_dtype_; +}; + +REGISTER_KERNEL_BUILDER(Name("TensorListGetItem").Device(DEVICE_CPU), + TensorListGetItem); + +#if GOOGLE_CUDA + +REGISTER_KERNEL_BUILDER( + Name("TensorListGetItem").Device(DEVICE_GPU).HostMemory("index"), + TensorListGetItem); + +#endif // GOOGLE_CUDA + +class TensorListSetItem : public OpKernel { + public: + explicit TensorListSetItem(OpKernelConstruction* c) : OpKernel(c) { + OP_REQUIRES_OK(c, c->GetAttr("element_dtype", &element_dtype_)); + } + + void Compute(OpKernelContext* c) override { + const TensorList* l = c->input(0).scalar()().get(); + OP_REQUIRES(c, l != nullptr, + errors::InvalidArgument( + "Input handle is not a list. Saw: '", + c->input(0).scalar()().DebugString(), "'")); + OP_REQUIRES(c, element_dtype_ == l->element_dtype, + errors::InvalidArgument("Invalid data types; op elements ", + DataTypeString(element_dtype_), + " but list elements ", + DataTypeString(l->element_dtype))); + int32 index = c->input(1).scalar()(); + OP_REQUIRES(c, index < l->tensors.size(), + errors::InvalidArgument("Trying to modify element ", index, + " in a list with ", l->tensors.size(), + " elements.")); + TensorList output; + output = *l; + output.tensors[index] = c->input(2); + Tensor* result; + AllocatorAttributes attr; + attr.set_on_host(true); + OP_REQUIRES_OK(c, c->allocate_output(0, TensorShape{}, &result, attr)); + result->scalar()() = std::move(output); + } + + private: + DataType element_dtype_; +}; + +REGISTER_KERNEL_BUILDER(Name("TensorListSetItem").Device(DEVICE_CPU), + TensorListSetItem); + +#if GOOGLE_CUDA + +REGISTER_KERNEL_BUILDER( + Name("TensorListSetItem").Device(DEVICE_GPU).HostMemory("index"), + TensorListSetItem); + +#endif // GOOGLE_CUDA + #define REGISTER_TENSOR_LIST_STACK_CPU(T) \ REGISTER_KERNEL_BUILDER(Name("TensorListStack") \ .TypeConstraint("element_dtype") \ diff --git a/tensorflow/core/kernels/list_kernels.h b/tensorflow/core/kernels/list_kernels.h index 6a2a572b6d..1e6cbfebbe 100644 --- a/tensorflow/core/kernels/list_kernels.h +++ b/tensorflow/core/kernels/list_kernels.h @@ -76,14 +76,14 @@ class TensorListStack : public OpKernel { errors::InvalidArgument( "Input handle is not a list. Saw: '", c->input(0).scalar()().DebugString(), "'")); - OP_REQUIRES(c, l->element_shape.IsFullyDefined(), - errors::InvalidArgument("Tried to stack elements from a list " - "with non-fully-defined shape.")); OP_REQUIRES(c, element_dtype_ == l->element_dtype, errors::InvalidArgument("Invalid data types; op elements ", DataTypeString(element_dtype_), " but list elements ", DataTypeString(l->element_dtype))); + OP_REQUIRES(c, l->element_shape.IsFullyDefined(), + errors::InvalidArgument("Tried to stack elements from a list " + "with non-fully-defined shape.")); if (num_elements_ != -1) { OP_REQUIRES(c, l->tensors.size() == num_elements_, errors::InvalidArgument("Operation expected a list with ", @@ -98,16 +98,23 @@ class TensorListStack : public OpKernel { } Tensor* output; OP_REQUIRES_OK(c, c->allocate_output(0, resulting_shape, &output)); + if (output->NumElements() == 0) { + return; + } ConstMatrixVector inputs_flat; inputs_flat.reserve(l->tensors.size()); for (const auto& t : l->tensors) { + OP_REQUIRES( + c, l->element_shape.IsCompatibleWith(t.shape()), + errors::InvalidArgument( + "Tensor with invalid shape in list. List element shape shape: ", + l->element_shape.DebugString(), + " and tensor shape: ", t.shape().DebugString())); inputs_flat.emplace_back(new typename TTypes::ConstMatrix( t.shaped({1, t.NumElements()}))); } - auto output_flat = - output->shaped({1, static_cast(l->tensors.size()) * - l->element_shape.num_elements()}); + auto output_flat = output->shaped({1, output->NumElements()}); #if GOOGLE_CUDA if (std::is_same::value) { @@ -195,17 +202,26 @@ Status TensorListBinaryAdd(OpKernelContext* c, const TensorList& a, for (int i = 0; i < a.tensors.size(); ++i) { const Tensor& a_tensor = a.tensors[i]; const Tensor& b_tensor = b.tensors[i]; + if (a_tensor.dtype() == DT_INVALID) { + out->tensors.push_back(b_tensor); + continue; + } + if (b_tensor.dtype() == DT_INVALID) { + out->tensors.push_back(a_tensor); + continue; + } if (a_tensor.shape() != b_tensor.shape()) { // TODO(apassos) support broadcasting additions here? return errors::InvalidArgument( "Trying to add two tensors with incompatible element shapes. " "One is ", a_tensor.shape().DebugString(), " and the other is ", - b_tensor.shape().DebugString()); + b_tensor.shape().DebugString(), " in position ", i); } Tensor out_tensor; TF_RETURN_IF_ERROR( c->allocate_temp(a_tensor.dtype(), a_tensor.shape(), &out_tensor)); + out->tensors.push_back(out_tensor); switch (out_tensor.dtype()) { #define DTYPE_CASE(dtype) \ case DataTypeToEnum::value: \ diff --git a/tensorflow/core/ops/list_ops.cc b/tensorflow/core/ops/list_ops.cc index db53485772..fa40f41bb9 100644 --- a/tensorflow/core/ops/list_ops.cc +++ b/tensorflow/core/ops/list_ops.cc @@ -176,5 +176,81 @@ REGISTER_OP("TensorListFromTensor") return Status::OK(); }); +REGISTER_OP("TensorListElementShape") + .Input("input_handle: variant") + .Output("element_shape: shape_type") + .Attr("shape_type: {int32, int64}") + .SetShapeFn([](shape_inference::InferenceContext* c) { + auto* handle_data = c->input_handle_shapes_and_types(0); + if (handle_data == nullptr) { + c->set_output(0, c->Vector(c->UnknownDim())); + return Status::OK(); + } + c->set_output(0, c->Vector(c->Rank((*handle_data)[0].shape))); + return Status::OK(); + }); + +REGISTER_OP("TensorListReserve") + .Input("element_shape: shape_type") + .Input("num_elements: int32") + .Output("handle: variant") + .Attr("element_dtype: type") + .Attr("shape_type: {int32, int64}") + .SetShapeFn([](shape_inference::InferenceContext* c) { + shape_inference::ShapeHandle s; + TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(0, &s)); + DataType t; + TF_RETURN_IF_ERROR(c->GetAttr("element_dtype", &t)); + c->set_output_handle_shapes_and_types( + 0, std::vector{{s, t}}); + return Status::OK(); + }); + +REGISTER_OP("TensorListGetItem") + .Input("input_handle: variant") + .Input("index: int32") + .Output("item: element_dtype") + .Attr("element_dtype: type") + .SetShapeFn([](shape_inference::InferenceContext* c) { + DataType t; + TF_RETURN_IF_ERROR(c->GetAttr("element_dtype", &t)); + auto* handle_data = c->input_handle_shapes_and_types(0); + shape_inference::ShapeHandle element_shape = c->UnknownShape(); + if (handle_data != nullptr) { + const shape_inference::ShapeAndType& list_shape_type = + (*handle_data)[0]; + element_shape = list_shape_type.shape; + if (list_shape_type.dtype != t) { + return errors::InvalidArgument("Expected list with element dtype ", + DataTypeString(t), + " but got list with element dtype ", + DataTypeString(list_shape_type.dtype)); + } + } + c->set_output(0, element_shape); + return Status::OK(); + }); + +REGISTER_OP("TensorListSetItem") + .Input("input_handle: variant") + .Input("index: int32") + .Input("item: element_dtype") + .Output("output_handle: variant") + .Attr("element_dtype: type") + .SetShapeFn([](shape_inference::InferenceContext* c) { + DataType t; + TF_RETURN_IF_ERROR(c->GetAttr("element_dtype", &t)); + auto* handle_data = c->input_handle_shapes_and_types(0); + if (handle_data == nullptr) { + c->set_output_handle_shapes_and_types(0, {{c->UnknownShape(), t}}); + return Status::OK(); + } + const shape_inference::ShapeAndType& list_shape_type = (*handle_data)[0]; + shape_inference::ShapeHandle s = c->input(2); + TF_RETURN_IF_ERROR(c->Merge(s, list_shape_type.shape, &s)); + c->set_output_handle_shapes_and_types(0, *handle_data); + return Status::OK(); + }); + } // namespace } // namespace tensorflow diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index dbb29d9878..a0193ca6ca 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -1951,6 +1951,7 @@ py_library( srcs = ["ops/list_ops.py"], srcs_version = "PY2AND3", deps = [ + ":array_ops", ":list_ops_gen", ], ) diff --git a/tensorflow/python/kernel_tests/BUILD b/tensorflow/python/kernel_tests/BUILD index de6aba4477..c6a4510e8f 100644 --- a/tensorflow/python/kernel_tests/BUILD +++ b/tensorflow/python/kernel_tests/BUILD @@ -87,6 +87,8 @@ cuda_py_test( srcs = ["list_ops_test.py"], additional_deps = [ "//third_party/py/numpy", + "//tensorflow/python:array_ops", + "//tensorflow/python:math_ops", "//tensorflow/python:list_ops", "//tensorflow/python/eager:context", "//tensorflow/python:framework_for_generated_wrappers", diff --git a/tensorflow/python/kernel_tests/list_ops_test.py b/tensorflow/python/kernel_tests/list_ops_test.py index 8fae044e2e..1577b7bc80 100644 --- a/tensorflow/python/kernel_tests/list_ops_test.py +++ b/tensorflow/python/kernel_tests/list_ops_test.py @@ -26,6 +26,7 @@ from tensorflow.python.eager import backprop from tensorflow.python.eager import context from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops @@ -82,6 +83,21 @@ class ListOpsTest(test_util.TensorFlowTestCase): with context.device("gpu:0"): self.testTensorListFromTensor() + def testGetSetItem(self): + t = constant_op.constant([1.0, 2.0]) + l = list_ops.tensor_list_from_tensor(t, element_shape=scalar_shape()) + e0 = list_ops.tensor_list_get_item(l, 0, element_dtype=dtypes.float32) + self.assertAllEqual(e0, 1.0) + l = list_ops.tensor_list_set_item(l, 0, 3.0) + t = list_ops.tensor_list_stack(l, element_dtype=dtypes.float32) + self.assertAllEqual(t, [3.0, 2.0]) + + def testGetSetGPU(self): + if not context.num_gpus(): + return + with context.device("gpu:0"): + self.testGetSetItem() + def testUnknownShape(self): l = list_ops.empty_tensor_list(element_dtype=dtypes.float32, element_shape=-1) @@ -159,6 +175,27 @@ class ListOpsTest(test_util.TensorFlowTestCase): result = c2 * 2.0 self.assertAllEqual(tape.gradient(result, [c])[0], [2.0, 2.0]) + def testGetSetGradients(self): + with backprop.GradientTape() as tape: + c = constant_op.constant([1.0, 2.0]) + tape.watch(c) + l = list_ops.tensor_list_from_tensor(c, element_shape=scalar_shape()) + c2 = constant_op.constant(3.0) + tape.watch(c2) + l = list_ops.tensor_list_set_item(l, 0, c2) + e = list_ops.tensor_list_get_item(l, 0, element_dtype=dtypes.float32) + ee = list_ops.tensor_list_get_item(l, 1, element_dtype=dtypes.float32) + y = e * e + ee * ee + grad_c, grad_c2 = tape.gradient(y, [c, c2]) + self.assertAllEqual(grad_c, [0.0, 4.0]) + self.assertAllEqual(grad_c2, 6.0) + + def testSetOutOfBounds(self): + c = constant_op.constant([1.0, 2.0]) + l = list_ops.tensor_list_from_tensor(c, element_shape=scalar_shape()) + with self.assertRaises(errors.InvalidArgumentError): + list_ops.tensor_list_set_item(l, 20, 3.0) + if __name__ == "__main__": ops.enable_eager_execution() diff --git a/tensorflow/python/ops/list_ops.py b/tensorflow/python/ops/list_ops.py index 6b31c00639..bba59ebcef 100644 --- a/tensorflow/python/ops/list_ops.py +++ b/tensorflow/python/ops/list_ops.py @@ -19,7 +19,9 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_list_ops # go/tf-wildcard-import # pylint: disable=wildcard-import @@ -28,28 +30,30 @@ from tensorflow.python.ops.gen_list_ops import * @ops.RegisterGradient("TensorListPushBack") -def _PushBackGradient(op, dresult): +def _PushBackGrad(op, dresult): return gen_list_ops.tensor_list_pop_back( dresult, element_dtype=op.get_attr("element_dtype")) @ops.RegisterGradient("TensorListPopBack") -def _PopBackGradient(unused_op, dlist, delement): +def _PopBackGrad(op, dlist, delement): if dlist is None: dlist = gen_list_ops.empty_tensor_list( element_dtype=delement.dtype, - element_shape=-1) + element_shape=gen_list_ops.tensor_list_element_shape( + op.outputs[0], shape_type=dtypes.int32)) return gen_list_ops.tensor_list_push_back(dlist, delement) @ops.RegisterGradient("TensorListStack") -def _TensorListStack(unused_op, dtensor): +def _TensorListStackGrad(unused_op, dtensor): return gen_list_ops.tensor_list_from_tensor(dtensor, element_shape=dtensor.shape[1:]) @ops.RegisterGradient("TensorListFromTensor") -def _TensorListFromTensor(op, dlist): +def _TensorListFromTensorGrad(op, dlist): + """Gradient for TensorListFromTensor.""" if op.inputs[0].shape[0] is not None: num_elements = op.inputs[0].shape[0] else: @@ -57,7 +61,34 @@ def _TensorListFromTensor(op, dlist): if dlist is None: dlist = gen_list_ops.empty_tensor_list( element_dtype=op.inputs[0].dtype, - element_shape=-1) + element_shape=gen_list_ops.tensor_list_element_shape( + op.outputs[0], shape_type=dtypes.int32)) return gen_list_ops.tensor_list_stack( dlist, element_dtype=op.inputs[0].dtype, num_elements=num_elements) + + +@ops.RegisterGradient("TensorListGetItem") +def _TensorListGetItemGrad(op, ditem): + """Gradient for TensorListGetItem.""" + list_size = gen_list_ops.tensor_list_length(op.inputs[0]) + list_grad = gen_list_ops.tensor_list_set_item( + gen_list_ops.tensor_list_reserve( + gen_list_ops.tensor_list_element_shape(op.inputs[0], + shape_type=dtypes.int32), + list_size, element_dtype=ditem.dtype), + index=op.inputs[1], + item=ditem) + index_grad = None + return list_grad, index_grad + + +@ops.RegisterGradient("TensorListSetItem") +def _TensorListSetItemGrad(op, dlist): + _, index, item = op.inputs + list_grad = gen_list_ops.tensor_list_set_item( + dlist, index=index, item=array_ops.zeros_like(item)) + index_grad = None + element_grad = gen_list_ops.tensor_list_get_item( + dlist, index, element_dtype=item.dtype) + return list_grad, index_grad, element_grad -- GitLab From 2968447d32bdfd0dd6fafabfcd1aafd6dc261803 Mon Sep 17 00:00:00 2001 From: Anna R Date: Mon, 22 Jan 2018 17:16:44 -0800 Subject: [PATCH 078/258] Adding tf_export decorators/calls to TensorFlow functions and constants. PiperOrigin-RevId: 182862075 --- tensorflow/python/ops/array_ops.py | 46 ++++++++++++++++ .../python/ops/candidate_sampling_ops.py | 7 +++ tensorflow/python/ops/check_ops.py | 23 ++++++++ tensorflow/python/ops/clip_ops.py | 8 +++ tensorflow/python/ops/confusion_matrix.py | 2 + tensorflow/python/ops/control_flow_ops.py | 7 +++ tensorflow/python/ops/ctc_ops.py | 4 ++ tensorflow/python/ops/data_flow_ops.py | 9 +++ tensorflow/python/ops/embedding_ops.py | 3 + tensorflow/python/ops/functional_ops.py | 5 ++ tensorflow/python/ops/gradient_checker.py | 3 + tensorflow/python/ops/gradients_impl.py | 4 ++ tensorflow/python/ops/histogram_ops.py | 2 + tensorflow/python/ops/image_ops_impl.py | 33 ++++++++++- tensorflow/python/ops/init_ops.py | 22 ++++++++ tensorflow/python/ops/io_ops.py | 8 +++ tensorflow/python/ops/linalg_ops.py | 8 +++ tensorflow/python/ops/logging_ops.py | 2 + tensorflow/python/ops/lookup_ops.py | 3 + tensorflow/python/ops/math_ops.py | 55 +++++++++++++++++++ tensorflow/python/ops/metrics_impl.py | 34 ++++++++++++ tensorflow/python/ops/nn_impl.py | 19 +++++++ tensorflow/python/ops/nn_ops.py | 25 +++++++++ tensorflow/python/ops/numerics.py | 3 + tensorflow/python/ops/parsing_ops.py | 9 +++ .../python/ops/partitioned_variables.py | 5 ++ tensorflow/python/ops/random_ops.py | 9 +++ tensorflow/python/ops/rnn.py | 7 +++ tensorflow/python/ops/rnn_cell_impl.py | 11 ++++ tensorflow/python/ops/script_ops.py | 2 + tensorflow/python/ops/session_ops.py | 4 ++ tensorflow/python/ops/sets_impl.py | 5 ++ tensorflow/python/ops/sparse_ops.py | 27 +++++++++ tensorflow/python/ops/special_math_ops.py | 3 + tensorflow/python/ops/spectral_ops.py | 8 +++ tensorflow/python/ops/state_ops.py | 7 +++ tensorflow/python/ops/string_ops.py | 3 + tensorflow/python/ops/summary_ops.py | 2 + tensorflow/python/ops/template.py | 2 + tensorflow/python/ops/tensor_array_ops.py | 2 + tensorflow/python/ops/variable_scope.py | 11 +++- tensorflow/python/ops/variables.py | 17 ++++++ tensorflow/tools/api/generator/BUILD | 6 ++ 43 files changed, 473 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index 78b4a7101c..6210204d80 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -103,16 +103,19 @@ from tensorflow.python.ops import gen_math_ops # pylint: disable=wildcard-import from tensorflow.python.ops.gen_array_ops import * from tensorflow.python.util import deprecation +from tensorflow.python.util.tf_export import tf_export # pylint: enable=wildcard-import # Used for slicing to specify a new 1 size dimension newaxis = None +tf_export("newaxis").export_constant(__name__, "newaxis") # We override the 'slice' for the "slice" op, so we keep python's # existing 'slice' for later use in this module. _BaseSlice = slice +@tf_export("identity") def identity(input, name=None): # pylint: disable=redefined-builtin r"""Return a tensor with the same shape and contents as input. @@ -135,6 +138,7 @@ def identity(input, name=None): # pylint: disable=redefined-builtin # pylint: disable=redefined-builtin,protected-access +@tf_export("expand_dims") def expand_dims(input, axis=None, name=None, dim=None): """Inserts a dimension of 1 into a tensor's shape. @@ -211,6 +215,7 @@ listdiff.__doc__ = gen_array_ops._list_diff.__doc__ + "\n" + listdiff.__doc__ # pylint: disable=undefined-variable,protected-access +@tf_export("setdiff1d") def setdiff1d(x, y, index_dtype=dtypes.int32, name=None): return gen_array_ops._list_diff(x, y, index_dtype, name) @@ -220,6 +225,7 @@ setdiff1d.__doc__ = gen_array_ops._list_diff.__doc__ # pylint: enable=protected-access +@tf_export("broadcast_dynamic_shape") def broadcast_dynamic_shape(shape_x, shape_y): # pylint: disable=protected-access """Returns the broadcasted dynamic shape between `shape_x` and `shape_y`. @@ -235,6 +241,7 @@ def broadcast_dynamic_shape(shape_x, shape_y): # pylint: enable=protected-access +@tf_export("broadcast_static_shape") def broadcast_static_shape(shape_x, shape_y): """Returns the broadcasted static shape between `shape_x` and `shape_y`. @@ -251,6 +258,7 @@ def broadcast_static_shape(shape_x, shape_y): return common_shapes.broadcast_shape(shape_x, shape_y) +@tf_export("shape") def shape(input, name=None, out_type=dtypes.int32): # pylint: disable=redefined-builtin """Returns the shape of a tensor. @@ -304,6 +312,7 @@ def shape_internal(input, name=None, optimize=True, out_type=dtypes.int32): return gen_array_ops.shape(input, name=name, out_type=out_type) +@tf_export("shape_n") def shape_n(input, out_type=dtypes.int32, name=None): # pylint: disable=redefined-builtin """Returns shape of tensors. @@ -330,6 +339,7 @@ def shape_n(input, out_type=dtypes.int32, name=None): return output +@tf_export("size") def size(input, name=None, out_type=dtypes.int32): # pylint: disable=redefined-builtin """Returns the size of a tensor. @@ -387,6 +397,7 @@ def size_internal(input, name=None, optimize=True, out_type=dtypes.int32): return gen_array_ops.size(input, name=name, out_type=out_type) +@tf_export("rank") def rank(input, name=None): # pylint: disable=redefined-builtin """Returns the rank of a tensor. @@ -577,6 +588,7 @@ def _slice_helper(tensor, slice_spec, var=None): # pylint: disable=undefined-variable,protected-access,redefined-outer-name +@tf_export("slice") def slice(input_, begin, size, name=None): # pylint: disable=redefined-builtin """Extracts a slice from a tensor. @@ -629,6 +641,7 @@ def slice(input_, begin, size, name=None): # pylint: disable=invalid-name +@tf_export("strided_slice") def strided_slice(input_, begin, end, @@ -817,6 +830,7 @@ def _SliceHelperVar(var, slice_spec): ops.Tensor._override_operator("__getitem__", _slice_helper) +@tf_export("parallel_stack") def parallel_stack(values, name="parallel_stack"): """Stacks a list of rank-`R` tensors into one rank-`(R+1)` tensor in parallel. @@ -867,6 +881,7 @@ def parallel_stack(values, name="parallel_stack"): [expand_dims(value, 0) for value in values], shape=output_shape) +@tf_export("stack") def stack(values, axis=0, name="stack"): """Stacks a list of rank-`R` tensors into one rank-`(R+1)` tensor. @@ -1012,6 +1027,7 @@ ops.register_tensor_conversion_function((list, tuple), _autopacking_conversion_function, 99) +@tf_export("unstack") def unstack(value, num=None, axis=0, name="unstack"): """Unpacks the given dimension of a rank-`R` tensor into rank-`(R-1)` tensors. @@ -1061,6 +1077,7 @@ def unstack(value, num=None, axis=0, name="unstack"): return gen_array_ops._unpack(value, num=num, axis=axis, name=name) +@tf_export("concat") def concat(values, axis, name="concat"): """Concatenates tensors along one dimension. @@ -1157,6 +1174,7 @@ def concat(values, axis, name="concat"): return gen_array_ops._concat_v2(values=values, axis=axis, name=name) +@tf_export("boolean_mask") def boolean_mask(tensor, mask, name="boolean_mask", axis=None): """Apply boolean mask to tensor. Numpy equivalent is `tensor[mask]`. @@ -1237,6 +1255,7 @@ def boolean_mask(tensor, mask, name="boolean_mask", axis=None): return _apply_mask_1d(tensor, mask, axis) +@tf_export("sparse_mask") def sparse_mask(a, mask_indices, name=None): """Masks elements of `IndexedSlices`. @@ -1279,6 +1298,7 @@ def sparse_mask(a, mask_indices, name=None): return ops.IndexedSlices(out_values, out_indices, a.dense_shape) +@tf_export("unique") def unique(x, out_idx=dtypes.int32, name=None): # TODO(yongtang): switch to v2 once API deprecation # period (3 weeks) pass. @@ -1290,6 +1310,7 @@ def unique(x, out_idx=dtypes.int32, name=None): unique.__doc__ = gen_array_ops._unique.__doc__ +@tf_export("split") def split(value, num_or_size_splits, axis=0, num=None, name="split"): """Splits a tensor into sub tensors. @@ -1356,6 +1377,7 @@ def split(value, num_or_size_splits, axis=0, num=None, name="split"): name=name) +@tf_export("transpose") def transpose(a, perm=None, name="transpose", conjugate=False): """Transposes `a`. Permutes the dimensions according to `perm`. @@ -1432,6 +1454,7 @@ def transpose(a, perm=None, name="transpose", conjugate=False): # pylint: disable=invalid-name +@tf_export("matrix_transpose", "linalg.transpose") def matrix_transpose(a, name="matrix_transpose", conjugate=False): """Transposes last two dimensions of tensor `a`. @@ -1503,6 +1526,7 @@ def matrix_transpose(a, name="matrix_transpose", conjugate=False): # pylint: enable=invalid-name +@tf_export("zeros") def zeros(shape, dtype=dtypes.float32, name=None): """Creates a tensor with all elements set to zero. @@ -1547,6 +1571,7 @@ def zeros(shape, dtype=dtypes.float32, name=None): return output +@tf_export("zeros_like") def zeros_like(tensor, dtype=None, name=None, optimize=True): """Creates a tensor with all elements set to zero. @@ -1599,6 +1624,7 @@ def zeros_like(tensor, dtype=None, name=None, optimize=True): return gen_array_ops._zeros_like(tensor, name=name) +@tf_export("ones_like") def ones_like(tensor, dtype=None, name=None, optimize=True): """Creates a tensor with all elements set to 1. @@ -1636,6 +1662,7 @@ def ones_like(tensor, dtype=None, name=None, optimize=True): return ret +@tf_export("ones") def ones(shape, dtype=dtypes.float32, name=None): """Creates a tensor with all elements set to 1. @@ -1675,6 +1702,7 @@ def ones(shape, dtype=dtypes.float32, name=None): return output +@tf_export("placeholder") def placeholder(dtype, shape=None, name=None): """Inserts a placeholder for a tensor that will be always fed. @@ -1728,6 +1756,7 @@ def _normalize_sparse_shape(shape, name): return (ops.convert_to_tensor(shape, dtype=dtypes.int64, name=name), rank) +@tf_export("sparse_placeholder") def sparse_placeholder(dtype, shape=None, name=None): """Inserts a placeholder for a sparse tensor that will be always fed. @@ -1794,6 +1823,7 @@ def sparse_placeholder(dtype, shape=None, name=None): # pylint: enable=redefined-outer-name +@tf_export("pad") def pad(tensor, paddings, mode="CONSTANT", name=None, constant_values=0): # pylint: disable=invalid-name """Pads a tensor. @@ -1887,6 +1917,7 @@ def pad(tensor, paddings, mode="CONSTANT", name=None, constant_values=0): # pyl return result +@tf_export("meshgrid") def meshgrid(*args, **kwargs): """Broadcasts parameters for evaluation on an N-D grid. @@ -2026,6 +2057,7 @@ def _TileGradShape(op): return [tensor_shape.TensorShape(output_dims)] +@tf_export("edit_distance") def edit_distance(hypothesis, truth, normalize=True, name="edit_distance"): """Computes the Levenshtein distance between sequences. @@ -2139,6 +2171,7 @@ def _FakeQuantWithMinMaxVarsPerChannelGradient(op, grad): narrow_range=op.get_attr("narrow_range")) +@tf_export("required_space_to_batch_paddings") def required_space_to_batch_paddings(input_shape, block_shape, base_paddings=None, @@ -2217,6 +2250,7 @@ def required_space_to_batch_paddings(input_shape, return result_paddings, result_crops +@tf_export("space_to_batch") def space_to_batch(input, paddings, block_size, name=None): # pylint: disable=redefined-builtin result = space_to_batch_nd( input, @@ -2230,6 +2264,7 @@ def space_to_batch(input, paddings, block_size, name=None): # pylint: disable=r space_to_batch.__doc__ = gen_array_ops._space_to_batch.__doc__ +@tf_export("space_to_depth") def space_to_depth(input, block_size, name=None, data_format="NHWC"): # pylint: disable=redefined-builtin return gen_array_ops.space_to_depth(input, block_size, data_format, name=name) @@ -2237,6 +2272,7 @@ def space_to_depth(input, block_size, name=None, data_format="NHWC"): # pylint: space_to_depth.__doc__ = gen_array_ops.space_to_depth.__doc__ +@tf_export("depth_to_space") def depth_to_space(input, block_size, name=None, data_format="NHWC"): # pylint: disable=redefined-builtin return gen_array_ops.depth_to_space(input, block_size, data_format, name=name) @@ -2244,6 +2280,7 @@ def depth_to_space(input, block_size, name=None, data_format="NHWC"): # pylint: depth_to_space.__doc__ = gen_array_ops.depth_to_space.__doc__ +@tf_export("batch_to_space") def batch_to_space(input, crops, block_size, name=None): # pylint: disable=redefined-builtin result = batch_to_space_nd( input, @@ -2257,6 +2294,7 @@ def batch_to_space(input, crops, block_size, name=None): # pylint: disable=rede batch_to_space.__doc__ = gen_array_ops._batch_to_space.__doc__ +@tf_export("one_hot") def one_hot(indices, depth, on_value=None, @@ -2416,6 +2454,7 @@ def _all_dimensions(x): return range(0, rank(x)) +@tf_export("sequence_mask") def sequence_mask(lengths, maxlen=None, dtype=dtypes.bool, name=None): """Returns a mask tensor representing the first N positions of each cell. @@ -2478,6 +2517,7 @@ def sequence_mask(lengths, maxlen=None, dtype=dtypes.bool, name=None): return gen_math_ops.cast(result, dtype) +@tf_export("squeeze") def squeeze(input, axis=None, name=None, squeeze_dims=None): # pylint: disable=redefined-builtin """Removes dimensions of size 1 from the shape of a tensor. @@ -2527,6 +2567,7 @@ def squeeze(input, axis=None, name=None, squeeze_dims=None): return gen_array_ops._squeeze(input, axis, name) +@tf_export("where") def where(condition, x=None, y=None, name=None): """Return the elements, either from `x` or `y`, depending on the `condition`. @@ -2579,6 +2620,7 @@ def where(condition, x=None, y=None, name=None): raise ValueError("x and y must both be non-None or both be None.") +@tf_export("reverse") def reverse(tensor, axis, name=None): return gen_array_ops.reverse_v2(tensor, axis, name) @@ -2587,6 +2629,7 @@ reverse.__doc__ = gen_array_ops.reverse_v2.__doc__ # pylint: disable=redefined-builtin +@tf_export("reverse_sequence") def reverse_sequence(input, seq_lengths, seq_axis=None, @@ -2614,6 +2657,7 @@ reverse_sequence.__doc__ = deprecation.rewrite_argument_docstring( "seq_dim", "seq_axis") +@tf_export("gather") def gather(params, indices, validate_indices=None, name=None, axis=0): # TODO(rjryan): Remove "Gather" creation in favor of GatherV2 once the forward # compatibility 3 week period has passed. @@ -2629,6 +2673,7 @@ gather.__doc__ = gen_array_ops.gather_v2.__doc__ # Define quantize_v2 here in order to make name the second-to-last attribute, # because round_mode was added later. +@tf_export("quantize_v2") @deprecation.deprecated( "2017-10-25", "`tf.quantize_v2` is deprecated, please use `tf.quantize` instead.") @@ -2653,6 +2698,7 @@ quantize_v2.__doc__ = """Please use `tf.quantize` instead.""" # We want to expose tf.quantize instead of tf.quantize_v2; we can deprecate # tf.quantize_v2 in next version of TensorFlow. +@tf_export("quantize") def quantize(input, # pylint: disable=redefined-builtin min_range, max_range, diff --git a/tensorflow/python/ops/candidate_sampling_ops.py b/tensorflow/python/ops/candidate_sampling_ops.py index d6294c24f5..20445c78a2 100644 --- a/tensorflow/python/ops/candidate_sampling_ops.py +++ b/tensorflow/python/ops/candidate_sampling_ops.py @@ -23,8 +23,10 @@ from tensorflow.python.framework import random_seed from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_candidate_sampling_ops from tensorflow.python.ops import math_ops +from tensorflow.python.util.tf_export import tf_export +@tf_export('nn.uniform_candidate_sampler') def uniform_candidate_sampler(true_classes, num_true, num_sampled, unique, range_max, seed=None, name=None): """Samples a set of classes using a uniform base distribution. @@ -80,6 +82,7 @@ def uniform_candidate_sampler(true_classes, num_true, num_sampled, unique, seed2=seed2, name=name) +@tf_export('nn.log_uniform_candidate_sampler') def log_uniform_candidate_sampler(true_classes, num_true, num_sampled, unique, range_max, seed=None, name=None): """Samples a set of classes using a log-uniform (Zipfian) base distribution. @@ -138,6 +141,7 @@ def log_uniform_candidate_sampler(true_classes, num_true, num_sampled, unique, seed2=seed2, name=name) +@tf_export('nn.learned_unigram_candidate_sampler') def learned_unigram_candidate_sampler(true_classes, num_true, num_sampled, unique, range_max, seed=None, name=None): """Samples a set of classes from a distribution learned during training. @@ -194,6 +198,7 @@ def learned_unigram_candidate_sampler(true_classes, num_true, num_sampled, seed2=seed2, name=name) +@tf_export('nn.fixed_unigram_candidate_sampler') def fixed_unigram_candidate_sampler(true_classes, num_true, num_sampled, @@ -285,6 +290,7 @@ def fixed_unigram_candidate_sampler(true_classes, unigrams=unigrams, seed=seed1, seed2=seed2, name=name) +@tf_export('nn.all_candidate_sampler') def all_candidate_sampler(true_classes, num_true, num_sampled, unique, seed=None, name=None): """Generate the set of all classes. @@ -320,6 +326,7 @@ def all_candidate_sampler(true_classes, num_true, num_sampled, unique, name=name) +@tf_export('nn.compute_accidental_hits') def compute_accidental_hits(true_classes, sampled_candidates, num_true, seed=None, name=None): """Compute the position ids in `sampled_candidates` matching `true_classes`. diff --git a/tensorflow/python/ops/check_ops.py b/tensorflow/python/ops/check_ops.py index eb7806ed0b..0fd6e29a49 100644 --- a/tensorflow/python/ops/check_ops.py +++ b/tensorflow/python/ops/check_ops.py @@ -57,6 +57,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.util import compat +from tensorflow.python.util.tf_export import tf_export NUMERIC_TYPES = frozenset( [dtypes.float32, dtypes.float64, dtypes.int8, dtypes.int16, dtypes.int32, @@ -111,6 +112,7 @@ def _shape_and_dtype_str(tensor): return 'shape=%s dtype=%s' % (tensor.shape, tensor.dtype.name) +@tf_export('assert_proper_iterable') def assert_proper_iterable(values): """Static assert that values is a "proper" iterable. @@ -138,6 +140,7 @@ def assert_proper_iterable(values): 'Expected argument "values" to be iterable. Found: %s' % type(values)) +@tf_export('assert_negative') def assert_negative(x, data=None, summarize=None, message=None, name=None): """Assert the condition `x < 0` holds element-wise. @@ -178,6 +181,7 @@ def assert_negative(x, data=None, summarize=None, message=None, name=None): return assert_less(x, zero, data=data, summarize=summarize) +@tf_export('assert_positive') def assert_positive(x, data=None, summarize=None, message=None, name=None): """Assert the condition `x > 0` holds element-wise. @@ -217,6 +221,7 @@ def assert_positive(x, data=None, summarize=None, message=None, name=None): return assert_less(zero, x, data=data, summarize=summarize) +@tf_export('assert_non_negative') def assert_non_negative(x, data=None, summarize=None, message=None, name=None): """Assert the condition `x >= 0` holds element-wise. @@ -258,6 +263,7 @@ def assert_non_negative(x, data=None, summarize=None, message=None, name=None): return assert_less_equal(zero, x, data=data, summarize=summarize) +@tf_export('assert_non_positive') def assert_non_positive(x, data=None, summarize=None, message=None, name=None): """Assert the condition `x <= 0` holds element-wise. @@ -299,6 +305,7 @@ def assert_non_positive(x, data=None, summarize=None, message=None, name=None): return assert_less_equal(x, zero, data=data, summarize=summarize) +@tf_export('assert_equal') def assert_equal(x, y, data=None, summarize=None, message=None, name=None): """Assert the condition `x == y` holds element-wise. @@ -395,6 +402,7 @@ def assert_equal(x, y, data=None, summarize=None, message=None, name=None): return control_flow_ops.Assert(condition, data, summarize=summarize) +@tf_export('assert_none_equal') def assert_none_equal( x, y, data=None, summarize=None, message=None, name=None): """Assert the condition `x != y` holds for all elements. @@ -445,6 +453,7 @@ def assert_none_equal( return control_flow_ops.Assert(condition, data, summarize=summarize) +@tf_export('assert_near') def assert_near( x, y, rtol=None, atol=None, data=None, summarize=None, message=None, name=None): @@ -522,6 +531,7 @@ def assert_near( return control_flow_ops.Assert(condition, data, summarize=summarize) +@tf_export('assert_less') def assert_less(x, y, data=None, summarize=None, message=None, name=None): """Assert the condition `x < y` holds element-wise. @@ -569,6 +579,7 @@ def assert_less(x, y, data=None, summarize=None, message=None, name=None): return control_flow_ops.Assert(condition, data, summarize=summarize) +@tf_export('assert_less_equal') def assert_less_equal(x, y, data=None, summarize=None, message=None, name=None): """Assert the condition `x <= y` holds element-wise. @@ -616,6 +627,7 @@ def assert_less_equal(x, y, data=None, summarize=None, message=None, name=None): return control_flow_ops.Assert(condition, data, summarize=summarize) +@tf_export('assert_greater') def assert_greater(x, y, data=None, summarize=None, message=None, name=None): """Assert the condition `x > y` holds element-wise. @@ -663,6 +675,7 @@ def assert_greater(x, y, data=None, summarize=None, message=None, name=None): return control_flow_ops.Assert(condition, data, summarize=summarize) +@tf_export('assert_greater_equal') def assert_greater_equal(x, y, data=None, summarize=None, message=None, name=None): """Assert the condition `x >= y` holds element-wise. @@ -760,6 +773,7 @@ def _assert_rank_condition( return control_flow_ops.Assert(condition, data, summarize=summarize) +@tf_export('assert_rank') def assert_rank(x, rank, data=None, summarize=None, message=None, name=None): """Assert `x` has rank equal to `rank`. @@ -821,6 +835,7 @@ def assert_rank(x, rank, data=None, summarize=None, message=None, name=None): return assert_op +@tf_export('assert_rank_at_least') def assert_rank_at_least( x, rank, data=None, summarize=None, message=None, name=None): """Assert `x` has rank equal to `rank` or higher. @@ -951,6 +966,7 @@ def _assert_ranks_condition( return control_flow_ops.Assert(condition, data, summarize=summarize) +@tf_export('assert_rank_in') def assert_rank_in( x, ranks, data=None, summarize=None, message=None, name=None): """Assert `x` has rank in `ranks`. @@ -1012,6 +1028,7 @@ def assert_rank_in( return assert_op +@tf_export('assert_integer') def assert_integer(x, message=None, name=None): """Assert that `x` is of integer dtype. @@ -1049,6 +1066,7 @@ def assert_integer(x, message=None, name=None): return control_flow_ops.no_op('statically_determined_was_integer') +@tf_export('assert_type') def assert_type(tensor, tf_type, message=None, name=None): """Statically asserts that the given `Tensor` is of the specified type. @@ -1096,10 +1114,12 @@ def _get_diff_for_monotonic_comparison(x): return control_flow_ops.cond(is_shorter_than_two, short_result, diff) +@tf_export('is_numeric_tensor') def is_numeric_tensor(tensor): return isinstance(tensor, ops.Tensor) and tensor.dtype in NUMERIC_TYPES +@tf_export('is_non_decreasing') def is_non_decreasing(x, name=None): """Returns `True` if `x` is non-decreasing. @@ -1126,6 +1146,7 @@ def is_non_decreasing(x, name=None): return math_ops.reduce_all(math_ops.less_equal(zero, diff)) +@tf_export('is_strictly_increasing') def is_strictly_increasing(x, name=None): """Returns `True` if `x` is strictly increasing. @@ -1184,6 +1205,7 @@ def _assert_same_base_type(items, expected_type=None): return expected_type +@tf_export('assert_same_float_dtype') def assert_same_float_dtype(tensors=None, dtype=None): """Validate and return float type based on `tensors` and `dtype`. @@ -1212,6 +1234,7 @@ def assert_same_float_dtype(tensors=None, dtype=None): return dtype +@tf_export('assert_scalar') def assert_scalar(tensor, name=None): with ops.name_scope(name, 'assert_scalar', [tensor]) as name_scope: tensor = ops.convert_to_tensor(tensor, name=name_scope) diff --git a/tensorflow/python/ops/clip_ops.py b/tensorflow/python/ops/clip_ops.py index 80803530c1..dd8c33247c 100644 --- a/tensorflow/python/ops/clip_ops.py +++ b/tensorflow/python/ops/clip_ops.py @@ -28,8 +28,10 @@ from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_nn_ops from tensorflow.python.ops import math_ops +from tensorflow.python.util.tf_export import tf_export +@tf_export("clip_by_value") def clip_by_value(t, clip_value_min, clip_value_max, name=None): """Clips tensor values to a specified min and max. @@ -70,6 +72,7 @@ def clip_by_value(t, clip_value_min, clip_value_max, return t_max +@tf_export("clip_by_norm") def clip_by_norm(t, clip_norm, axes=None, name=None): """Clips tensor values to a maximum L2-norm. @@ -117,6 +120,8 @@ def clip_by_norm(t, clip_norm, axes=None, name=None): return tclip + +@tf_export("global_norm") def global_norm(t_list, name=None): """Computes the global norm of multiple tensors. @@ -164,6 +169,8 @@ def global_norm(t_list, name=None): return norm + +@tf_export("clip_by_global_norm") def clip_by_global_norm(t_list, clip_norm, use_norm=None, name=None): """Clips values of multiple tensors by the ratio of the sum of their norms. @@ -246,6 +253,7 @@ def clip_by_global_norm(t_list, clip_norm, use_norm=None, name=None): return list_clipped, use_norm +@tf_export("clip_by_average_norm") def clip_by_average_norm(t, clip_norm, name=None): """Clips tensor values to a maximum average L2-norm. diff --git a/tensorflow/python/ops/confusion_matrix.py b/tensorflow/python/ops/confusion_matrix.py index 32e071db17..50690cd891 100644 --- a/tensorflow/python/ops/confusion_matrix.py +++ b/tensorflow/python/ops/confusion_matrix.py @@ -31,6 +31,7 @@ from tensorflow.python.ops import check_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import sparse_ops +from tensorflow.python.util.tf_export import tf_export def remove_squeezable_dimensions( @@ -93,6 +94,7 @@ def remove_squeezable_dimensions( return labels, predictions +@tf_export('confusion_matrix') def confusion_matrix(labels, predictions, num_classes=None, dtype=dtypes.int32, name=None, weights=None): """Computes the confusion matrix from predictions and labels. diff --git a/tensorflow/python/ops/control_flow_ops.py b/tensorflow/python/ops/control_flow_ops.py index 86941a7f2a..d379eccc20 100644 --- a/tensorflow/python/ops/control_flow_ops.py +++ b/tensorflow/python/ops/control_flow_ops.py @@ -82,6 +82,7 @@ from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import deprecation from tensorflow.python.util import nest from tensorflow.python.util import tf_should_use +from tensorflow.python.util.tf_export import tf_export # We override the 'tuple' for a control flow op, so we keep python's @@ -117,6 +118,7 @@ def _summarize_eager(tensor, summarize=None): # Assert and Print are special symbols in python, so we must # use an upper-case version of them. +@tf_export("Assert") @tf_should_use.should_use_result def Assert(condition, data, summarize=None, name=None): """Asserts that the given condition is true. @@ -1867,6 +1869,7 @@ def _UnpackIfSingleton(res): # pylint: disable=redefined-outer-name # pylint: disable=g-doc-args +@tf_export("cond") @deprecation.deprecated_args( None, "fn1/fn2 are deprecated in favor of the true_fn/false_fn arguments.", @@ -2843,6 +2846,7 @@ class WhileContext(ControlFlowContext): # pylint: disable=redefined-outer-name +@tf_export("while_loop") def while_loop(cond, body, loop_vars, shape_invariants=None, parallel_iterations=10, back_prop=True, swap_memory=False, name=None, maximum_iterations=None): @@ -3110,6 +3114,7 @@ def _GroupControlDeps(dev, deps, name=None): # TODO(touts): Accept "inputs" as a list. +@tf_export("group") def group(*inputs, **kwargs): """Create an op that groups multiple operations. @@ -3175,6 +3180,7 @@ def group(*inputs, **kwargs): return no_op(name=name) +@tf_export("tuple") def tuple(tensors, name=None, control_inputs=None): """Group tensors together. @@ -3328,6 +3334,7 @@ def _case_verify_and_canonicalize_args(pred_fn_pairs, exclusive, name): return predicates, actions +@tf_export("case") def case(pred_fn_pairs, default=None, exclusive=False, diff --git a/tensorflow/python/ops/ctc_ops.py b/tensorflow/python/ops/ctc_ops.py index f037767cf4..83da6739db 100644 --- a/tensorflow/python/ops/ctc_ops.py +++ b/tensorflow/python/ops/ctc_ops.py @@ -25,9 +25,11 @@ from tensorflow.python.framework import sparse_tensor from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_ctc_ops from tensorflow.python.ops.nn_grad import _BroadcastMul +from tensorflow.python.util.tf_export import tf_export # pylint: disable=protected-access, invalid-name +@tf_export("nn.ctc_loss") def ctc_loss(labels, inputs, sequence_length, preprocess_collapse_repeated=False, ctc_merge_repeated=True, @@ -185,6 +187,7 @@ def _CTCLossGrad(op, grad_loss, _): return [_BroadcastMul(grad_loss, grad_without_gradient), None, None, None] +@tf_export("nn.ctc_greedy_decoder") def ctc_greedy_decoder(inputs, sequence_length, merge_repeated=True): """Performs greedy decoding on the logits given in input (best path). @@ -228,6 +231,7 @@ def ctc_greedy_decoder(inputs, sequence_length, merge_repeated=True): log_probabilities) +@tf_export("nn.ctc_beam_search_decoder") def ctc_beam_search_decoder(inputs, sequence_length, beam_width=100, top_paths=1, merge_repeated=True): """Performs beam search decoding on the logits given in input. diff --git a/tensorflow/python/ops/data_flow_ops.py b/tensorflow/python/ops/data_flow_ops.py index f441f6d4bf..34f0bf7b78 100644 --- a/tensorflow/python/ops/data_flow_ops.py +++ b/tensorflow/python/ops/data_flow_ops.py @@ -39,6 +39,7 @@ from tensorflow.python.ops import math_ops # go/tf-wildcard-import # pylint: disable=wildcard-import from tensorflow.python.ops.gen_data_flow_ops import * +from tensorflow.python.util.tf_export import tf_export # pylint: enable=wildcard-import @@ -107,6 +108,7 @@ def _shape_common(s1, s2): # pylint: disable=protected-access +@tf_export("QueueBase") class QueueBase(object): """Base class for queue implementations. @@ -596,6 +598,7 @@ class QueueBase(object): return gen_data_flow_ops._queue_size(self._queue_ref, name=name) +@tf_export("RandomShuffleQueue") class RandomShuffleQueue(QueueBase): """A queue implementation that dequeues elements in a random order. @@ -674,6 +677,7 @@ class RandomShuffleQueue(QueueBase): super(RandomShuffleQueue, self).__init__(dtypes, shapes, names, queue_ref) +@tf_export("FIFOQueue") class FIFOQueue(QueueBase): """A queue implementation that dequeues elements in first-in first-out order. @@ -727,6 +731,7 @@ class FIFOQueue(QueueBase): super(FIFOQueue, self).__init__(dtypes, shapes, names, queue_ref) +@tf_export("PaddingFIFOQueue") class PaddingFIFOQueue(QueueBase): """A FIFOQueue that supports batching variable-sized tensors by padding. @@ -797,6 +802,7 @@ class PaddingFIFOQueue(QueueBase): super(PaddingFIFOQueue, self).__init__(dtypes, shapes, names, queue_ref) +@tf_export("PriorityQueue") class PriorityQueue(QueueBase): """A queue implementation that dequeues elements in prioritized order. @@ -1106,6 +1112,7 @@ class Barrier(object): self._barrier_ref, name=name) +@tf_export("ConditionalAccumulatorBase") class ConditionalAccumulatorBase(object): """A conditional accumulator for aggregating gradients. @@ -1184,6 +1191,7 @@ class ConditionalAccumulatorBase(object): name=name) +@tf_export("ConditionalAccumulator") class ConditionalAccumulator(ConditionalAccumulatorBase): """A conditional accumulator for aggregating gradients. @@ -1263,6 +1271,7 @@ class ConditionalAccumulator(ConditionalAccumulatorBase): return out +@tf_export("SparseConditionalAccumulator") class SparseConditionalAccumulator(ConditionalAccumulatorBase): """A conditional accumulator for aggregating sparse gradients. diff --git a/tensorflow/python/ops/embedding_ops.py b/tensorflow/python/ops/embedding_ops.py index f4561d1a83..3826585f59 100644 --- a/tensorflow/python/ops/embedding_ops.py +++ b/tensorflow/python/ops/embedding_ops.py @@ -32,6 +32,7 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import variables from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.util.tf_export import tf_export def _gather(params, ids, name=None): @@ -257,6 +258,7 @@ def _embedding_lookup_and_transform(params, return ret +@tf_export("nn.embedding_lookup") def embedding_lookup( params, ids, @@ -325,6 +327,7 @@ def embedding_lookup( transform_fn=None) +@tf_export("nn.embedding_lookup_sparse") def embedding_lookup_sparse(params, sp_ids, sp_weights, diff --git a/tensorflow/python/ops/functional_ops.py b/tensorflow/python/ops/functional_ops.py index 688512bea6..7dbccf1caf 100644 --- a/tensorflow/python/ops/functional_ops.py +++ b/tensorflow/python/ops/functional_ops.py @@ -44,9 +44,11 @@ from tensorflow.python.ops.gen_functional_ops import * from tensorflow.python.ops.gen_functional_ops import _symbolic_gradient # pylint: enable=unused-import from tensorflow.python.util import nest +from tensorflow.python.util.tf_export import tf_export # TODO(yuanbyu, mrry): Handle stride to support sliding windows. +@tf_export("foldl") def foldl(fn, elems, initializer=None, parallel_iterations=10, back_prop=True, swap_memory=False, name=None): """foldl on the list of tensors unpacked from `elems` on dimension 0. @@ -134,6 +136,7 @@ def foldl(fn, elems, initializer=None, parallel_iterations=10, back_prop=True, return r_a +@tf_export("foldr") def foldr(fn, elems, initializer=None, parallel_iterations=10, back_prop=True, swap_memory=False, name=None): """foldr on the list of tensors unpacked from `elems` on dimension 0. @@ -221,6 +224,7 @@ def foldr(fn, elems, initializer=None, parallel_iterations=10, back_prop=True, return r_a +@tf_export("map_fn") def map_fn(fn, elems, dtype=None, parallel_iterations=10, back_prop=True, swap_memory=False, infer_shape=True, name=None): """map on the list of tensors unpacked from `elems` on dimension 0. @@ -424,6 +428,7 @@ def map_fn(fn, elems, dtype=None, parallel_iterations=10, back_prop=True, return output_pack(results_flat) +@tf_export("scan") def scan(fn, elems, initializer=None, parallel_iterations=10, back_prop=True, swap_memory=False, infer_shape=True, name=None): """scan on the list of tensors unpacked from `elems` on dimension 0. diff --git a/tensorflow/python/ops/gradient_checker.py b/tensorflow/python/ops/gradient_checker.py index 193046ba70..12afcd0b51 100644 --- a/tensorflow/python/ops/gradient_checker.py +++ b/tensorflow/python/ops/gradient_checker.py @@ -31,6 +31,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients from tensorflow.python.ops import math_ops from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.util.tf_export import tf_export def _product(t): @@ -264,6 +265,7 @@ def _compute_gradient_list(x, return ret +@tf_export("test.compute_gradient") def compute_gradient(x, x_shape, y, @@ -325,6 +327,7 @@ def compute_gradient(x, return ret +@tf_export("test.compute_gradient_error") def compute_gradient_error(x, x_shape, y, diff --git a/tensorflow/python/ops/gradients_impl.py b/tensorflow/python/ops/gradients_impl.py index 20c7a9fd66..5d4b9ecd8b 100644 --- a/tensorflow/python/ops/gradients_impl.py +++ b/tensorflow/python/ops/gradients_impl.py @@ -50,6 +50,7 @@ from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import spectral_grad # pylint: disable=unused-import from tensorflow.python.ops import tensor_array_ops from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.util.tf_export import tf_export # Warn the user if we convert a sparse representation to dense with at @@ -394,6 +395,7 @@ def _MaybeCompile(scope, op, func, grad_fn): return grad_fn() +@tf_export("gradients") def gradients(ys, xs, grad_ys=None, @@ -799,6 +801,7 @@ def _MultiDeviceAddN(tensor_list): return math_ops.add_n(summands) +@tf_export("AggregationMethod") class AggregationMethod(object): """A class listing aggregation methods used to combine gradients. @@ -971,6 +974,7 @@ def _hessian_vector_product(ys, xs, v): return gradients(elemwise_products, xs) +@tf_export("hessians") def hessians(ys, xs, name="hessians", colocate_gradients_with_ops=False, gate_gradients=False, aggregation_method=None): """Constructs the Hessian of sum of `ys` with respect to `x` in `xs`. diff --git a/tensorflow/python/ops/histogram_ops.py b/tensorflow/python/ops/histogram_ops.py index 51e4be9343..d46084a41f 100644 --- a/tensorflow/python/ops/histogram_ops.py +++ b/tensorflow/python/ops/histogram_ops.py @@ -30,8 +30,10 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import clip_ops from tensorflow.python.ops import gen_math_ops from tensorflow.python.ops import math_ops +from tensorflow.python.util.tf_export import tf_export +@tf_export('histogram_fixed_width') def histogram_fixed_width(values, value_range, nbins=100, diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 9f09d0a4d1..d860a3b618 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -36,6 +36,7 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import string_ops from tensorflow.python.ops import variables +from tensorflow.python.util.tf_export import tf_export ops.NotDifferentiable('RandomCrop') @@ -201,6 +202,7 @@ def fix_image_flip_shape(image, result): return result +@tf_export('image.random_flip_up_down') def random_flip_up_down(image, seed=None): """Randomly flips an image vertically (upside down). @@ -232,6 +234,7 @@ def random_flip_up_down(image, seed=None): return fix_image_flip_shape(image, result) +@tf_export('image.random_flip_left_right') def random_flip_left_right(image, seed=None): """Randomly flip an image horizontally (left to right). @@ -263,6 +266,7 @@ def random_flip_left_right(image, seed=None): return fix_image_flip_shape(image, result) +@tf_export('image.flip_left_right') def flip_left_right(image): """Flip an image horizontally (left to right). @@ -288,6 +292,7 @@ def flip_left_right(image): array_ops.reverse(image, [1], name=scope)) +@tf_export('image.flip_up_down') def flip_up_down(image): """Flip an image vertically (upside down). @@ -313,6 +318,7 @@ def flip_up_down(image): array_ops.reverse(image, [0], name=scope)) +@tf_export('image.rot90') def rot90(image, k=1, name=None): """Rotate an image counter-clockwise by 90 degrees. @@ -350,6 +356,7 @@ def rot90(image, k=1, name=None): return ret +@tf_export('image.transpose_image') def transpose_image(image): """Transpose an image by swapping the first and second dimension. @@ -371,6 +378,7 @@ def transpose_image(image): return array_ops.transpose(image, [1, 0, 2], name=scope) +@tf_export('image.central_crop') def central_crop(image, central_fraction): """Crop the central region of the image. @@ -424,6 +432,7 @@ def central_crop(image, central_fraction): return image +@tf_export('image.pad_to_bounding_box') def pad_to_bounding_box(image, offset_height, offset_width, target_height, target_width): """Pad `image` with zeros to the specified `height` and `width`. @@ -504,6 +513,7 @@ def pad_to_bounding_box(image, offset_height, offset_width, target_height, return padded +@tf_export('image.crop_to_bounding_box') def crop_to_bounding_box(image, offset_height, offset_width, target_height, target_width): """Crops an image to a specified bounding box. @@ -582,6 +592,7 @@ def crop_to_bounding_box(image, offset_height, offset_width, target_height, return cropped +@tf_export('image.resize_image_with_crop_or_pad') def resize_image_with_crop_or_pad(image, target_height, target_width): """Crops and/or pads an image to a target width and height. @@ -696,6 +707,7 @@ def resize_image_with_crop_or_pad(image, target_height, target_width): return resized +@tf_export('image.ResizeMethod') class ResizeMethod(object): BILINEAR = 0 NEAREST_NEIGHBOR = 1 @@ -703,6 +715,7 @@ class ResizeMethod(object): AREA = 3 +@tf_export('image.resize_images') def resize_images(images, size, method=ResizeMethod.BILINEAR, @@ -813,6 +826,7 @@ def resize_images(images, return images +@tf_export('image.per_image_standardization') def per_image_standardization(image): """Linearly scales `image` to have zero mean and unit norm. @@ -856,6 +870,7 @@ def per_image_standardization(image): return image +@tf_export('image.random_brightness') def random_brightness(image, max_delta, seed=None): """Adjust the brightness of images by a random factor. @@ -882,6 +897,7 @@ def random_brightness(image, max_delta, seed=None): return adjust_brightness(image, delta) +@tf_export('image.random_contrast') def random_contrast(image, lower, upper, seed=None): """Adjust the contrast of an image by a random factor. @@ -913,6 +929,7 @@ def random_contrast(image, lower, upper, seed=None): return adjust_contrast(image, contrast_factor) +@tf_export('image.adjust_brightness') def adjust_brightness(image, delta): """Adjust the brightness of RGB or Grayscale images. @@ -947,6 +964,7 @@ def adjust_brightness(image, delta): return convert_image_dtype(adjusted, orig_dtype, saturate=True) +@tf_export('image.adjust_contrast') def adjust_contrast(images, contrast_factor): """Adjust contrast of RGB or grayscale images. @@ -988,6 +1006,7 @@ def adjust_contrast(images, contrast_factor): return convert_image_dtype(adjusted, orig_dtype, saturate=True) +@tf_export('image.adjust_gamma') def adjust_gamma(image, gamma=1, gain=1): """Performs Gamma Correction on the input image. @@ -1026,7 +1045,7 @@ def adjust_gamma(image, gamma=1, gain=1): 'Gamma should be a non-negative real number.') if assert_op: gamma = control_flow_ops.with_dependencies(assert_op, gamma) - + # scale = max(dtype) - min(dtype). scale = constant_op.constant(image.dtype.limits[1] - image.dtype.limits[0], dtype=dtypes.float32) @@ -1036,6 +1055,7 @@ def adjust_gamma(image, gamma=1, gain=1): return adjusted_img +@tf_export('image.convert_image_dtype') def convert_image_dtype(image, dtype, saturate=False, name=None): """Convert `image` to `dtype`, scaling its values if needed. @@ -1114,6 +1134,7 @@ def convert_image_dtype(image, dtype, saturate=False, name=None): return math_ops.cast(scaled, dtype, name=name) +@tf_export('image.rgb_to_grayscale') def rgb_to_grayscale(images, name=None): """Converts one or more images from RGB to Grayscale. @@ -1143,6 +1164,7 @@ def rgb_to_grayscale(images, name=None): return convert_image_dtype(gray_float, orig_dtype, name=name) +@tf_export('image.grayscale_to_rgb') def grayscale_to_rgb(images, name=None): """Converts one or more images from Grayscale to RGB. @@ -1169,6 +1191,7 @@ def grayscale_to_rgb(images, name=None): # pylint: disable=invalid-name +@tf_export('image.random_hue') def random_hue(image, max_delta, seed=None): """Adjust the hue of an RGB image by a random factor. @@ -1201,6 +1224,7 @@ def random_hue(image, max_delta, seed=None): return adjust_hue(image, delta) +@tf_export('image.adjust_hue') def adjust_hue(image, delta, name=None): """Adjust hue of an RGB image. @@ -1234,6 +1258,7 @@ def adjust_hue(image, delta, name=None): return convert_image_dtype(rgb_altered, orig_dtype) +@tf_export('image.random_saturation') def random_saturation(image, lower, upper, seed=None): """Adjust the saturation of an RGB image by a random factor. @@ -1266,6 +1291,7 @@ def random_saturation(image, lower, upper, seed=None): return adjust_saturation(image, saturation_factor) +@tf_export('image.adjust_saturation') def adjust_saturation(image, saturation_factor, name=None): """Adjust saturation of an RGB image. @@ -1297,6 +1323,8 @@ def adjust_saturation(image, saturation_factor, name=None): gen_image_ops.adjust_saturation(flt_image, saturation_factor), orig_dtype) + +@tf_export('image.decode_image') def decode_image(contents, channels=None, name=None): """Convenience function for `decode_bmp`, `decode_gif`, `decode_jpeg`, and `decode_png`. @@ -1389,6 +1417,7 @@ def decode_image(contents, channels=None, name=None): return control_flow_ops.cond(is_jpeg, _jpeg, check_png, name='cond_jpeg') +@tf_export('image.total_variation') def total_variation(images, name=None): """Calculate and return the total variation for one or more images. @@ -1459,6 +1488,7 @@ def total_variation(images, name=None): return tot_var +@tf_export('image.sample_distorted_bounding_box') def sample_distorted_bounding_box(image_size, bounding_boxes, seed=None, seed2=None, min_object_covered=None, aspect_ratio_range=None, area_range=None, @@ -1560,6 +1590,7 @@ def sample_distorted_bounding_box(image_size, bounding_boxes, seed=None, name=name) +@tf_export('image.non_max_suppression') def non_max_suppression(boxes, scores, max_output_size, diff --git a/tensorflow/python/ops/init_ops.py b/tensorflow/python/ops/init_ops.py index 5dc43d65b9..c7502d0fda 100644 --- a/tensorflow/python/ops/init_ops.py +++ b/tensorflow/python/ops/init_ops.py @@ -44,8 +44,10 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import random_ops from tensorflow.python.util.deprecation import deprecated +from tensorflow.python.util.tf_export import tf_export +@tf_export("keras.initializers.Initializer") class Initializer(object): """Initializer base class: all initializers inherit from this class. """ @@ -83,6 +85,8 @@ class Initializer(object): return cls(**config) +@tf_export("keras.initializers.Zeros", "initializers.zeros", + "zeros_initializer") class Zeros(Initializer): """Initializer that generates tensors initialized to 0.""" @@ -98,6 +102,7 @@ class Zeros(Initializer): return {"dtype": self.dtype.name} +@tf_export("keras.initializers.Ones", "initializers.ones", "ones_initializer") class Ones(Initializer): """Initializer that generates tensors initialized to 1.""" @@ -113,6 +118,8 @@ class Ones(Initializer): return {"dtype": self.dtype.name} +@tf_export("keras.initializers.Constant", "initializers.constant", + "constant_initializer") class Constant(Initializer): """Initializer that generates tensors with constant values. @@ -217,6 +224,8 @@ class Constant(Initializer): return {"value": self.value, "dtype": self.dtype.name} +@tf_export("keras.initializers.RandomUniform", "initializers.random_uniform", + "random_uniform_initializer") class RandomUniform(Initializer): """Initializer that generates tensors with a uniform distribution. @@ -252,6 +261,8 @@ class RandomUniform(Initializer): } +@tf_export("keras.initializers.RandomNormal", "initializers.random_normal", + "random_normal_initializer") class RandomNormal(Initializer): """Initializer that generates tensors with a normal distribution. @@ -287,6 +298,8 @@ class RandomNormal(Initializer): } +@tf_export("keras.initializers.TruncatedNormal", + "initializers.truncated_normal", "truncated_normal_initializer") class TruncatedNormal(Initializer): """Initializer that generates a truncated normal distribution. @@ -327,6 +340,8 @@ class TruncatedNormal(Initializer): } +@tf_export("initializers.uniform_unit_scaling", + "uniform_unit_scaling_initializer") class UniformUnitScaling(Initializer): """Initializer that generates tensors without scaling variance. @@ -385,6 +400,8 @@ class UniformUnitScaling(Initializer): return {"factor": self.factor, "seed": self.seed, "dtype": self.dtype.name} +@tf_export("keras.initializers.VarianceScaling", + "initializers.variance_scaling", "variance_scaling_initializer") class VarianceScaling(Initializer): """Initializer capable of adapting its scale to the shape of weights tensors. @@ -464,6 +481,8 @@ class VarianceScaling(Initializer): } +@tf_export("keras.initializers.Orthogonal", "initializers.orthogonal", + "orthogonal_initializer") class Orthogonal(Initializer): """Initializer that generates an orthogonal matrix. @@ -523,6 +542,7 @@ class Orthogonal(Initializer): return {"gain": self.gain, "seed": self.seed, "dtype": self.dtype.name} +@tf_export("keras.initializers.Identity", "initializers.identity") class Identity(Initializer): """Initializer that generates the identity matrix. @@ -570,6 +590,7 @@ identity_initializer = Identity # pylint: enable=invalid-name +@tf_export("glorot_uniform_initializer") def glorot_uniform_initializer(seed=None, dtype=dtypes.float32): """The Glorot uniform initializer, also called Xavier uniform initializer. @@ -593,6 +614,7 @@ def glorot_uniform_initializer(seed=None, dtype=dtypes.float32): scale=1.0, mode="fan_avg", distribution="uniform", seed=seed, dtype=dtype) +@tf_export("glorot_normal_initializer") def glorot_normal_initializer(seed=None, dtype=dtypes.float32): """The Glorot normal initializer, also called Xavier normal initializer. diff --git a/tensorflow/python/ops/io_ops.py b/tensorflow/python/ops/io_ops.py index 670bb9a9c2..5e70b3186f 100644 --- a/tensorflow/python/ops/io_ops.py +++ b/tensorflow/python/ops/io_ops.py @@ -79,6 +79,7 @@ from tensorflow.python.ops import gen_io_ops # go/tf-wildcard-import # pylint: disable=wildcard-import from tensorflow.python.ops.gen_io_ops import * +from tensorflow.python.util.tf_export import tf_export # pylint: enable=wildcard-import @@ -140,6 +141,7 @@ def _restore_slice(file_pattern, tensor_name, shape_and_slice, tensor_type, preferred_shard, name=name) +@tf_export("ReaderBase") class ReaderBase(object): """Base class for different Reader types, that produce a record every step. @@ -354,6 +356,7 @@ ops.NotDifferentiable("ReaderRestoreState") ops.NotDifferentiable("ReaderReset") +@tf_export("WholeFileReader") class WholeFileReader(ReaderBase): """A Reader that outputs the entire contents of a file as a value. @@ -381,6 +384,7 @@ class WholeFileReader(ReaderBase): ops.NotDifferentiable("WholeFileReader") +@tf_export("TextLineReader") class TextLineReader(ReaderBase): """A Reader that outputs the lines of a file delimited by newlines. @@ -410,6 +414,7 @@ class TextLineReader(ReaderBase): ops.NotDifferentiable("TextLineReader") +@tf_export("FixedLengthRecordReader") class FixedLengthRecordReader(ReaderBase): """A Reader that outputs fixed-length records from a file. @@ -452,6 +457,7 @@ class FixedLengthRecordReader(ReaderBase): ops.NotDifferentiable("FixedLengthRecordReader") +@tf_export("TFRecordReader") class TFRecordReader(ReaderBase): """A Reader that outputs the records from a TFRecords file. @@ -482,6 +488,7 @@ class TFRecordReader(ReaderBase): ops.NotDifferentiable("TFRecordReader") +@tf_export("LMDBReader") class LMDBReader(ReaderBase): """A Reader that outputs the records from a LMDB file. @@ -506,6 +513,7 @@ class LMDBReader(ReaderBase): ops.NotDifferentiable("LMDBReader") +@tf_export("IdentityReader") class IdentityReader(ReaderBase): """A Reader that outputs the queued work as both the key and value. diff --git a/tensorflow/python/ops/linalg_ops.py b/tensorflow/python/ops/linalg_ops.py index be9beee633..9803eed6ae 100644 --- a/tensorflow/python/ops/linalg_ops.py +++ b/tensorflow/python/ops/linalg_ops.py @@ -31,6 +31,7 @@ from tensorflow.python.ops.gen_linalg_ops import * # pylint: enable=wildcard-import from tensorflow.python.util import compat from tensorflow.python.util import deprecation +from tensorflow.python.util.tf_export import tf_export # Names below are lower_case. # pylint: disable=invalid-name @@ -77,6 +78,7 @@ def _RegularizedGramianCholesky(matrix, l2_regularizer, first_kind): return gen_linalg_ops.cholesky(gramian) +@tf_export('cholesky_solve', 'linalg.cholesky_solve') def cholesky_solve(chol, rhs, name=None): """Solves systems of linear eqns `A X = RHS`, given Cholesky factorizations. @@ -119,6 +121,7 @@ def cholesky_solve(chol, rhs, name=None): return x +@tf_export('eye', 'linalg.eye') def eye(num_rows, num_columns=None, batch_shape=None, @@ -188,6 +191,7 @@ def eye(num_rows, return array_ops.matrix_set_diag(zero_matrix, diag_ones) +@tf_export('matrix_solve_ls', 'linalg.lstsq') def matrix_solve_ls(matrix, rhs, l2_regularizer=0.0, fast=True, name=None): r"""Solves one or more linear least-squares problems. @@ -324,6 +328,7 @@ def matrix_solve_ls(matrix, rhs, l2_regularizer=0.0, fast=True, name=None): # pylint: enable=protected-access +@tf_export('self_adjoint_eig', 'linalg.eigh') def self_adjoint_eig(tensor, name=None): """Computes the eigen decomposition of a batch of self-adjoint matrices. @@ -346,6 +351,7 @@ def self_adjoint_eig(tensor, name=None): return e, v +@tf_export('self_adjoint_eigvals', 'linalg.eigvalsh') def self_adjoint_eigvals(tensor, name=None): """Computes the eigenvalues of one or more self-adjoint matrices. @@ -368,6 +374,7 @@ def self_adjoint_eigvals(tensor, name=None): return e +@tf_export('svd', 'linalg.svd') def svd(tensor, full_matrices=False, compute_uv=True, name=None): r"""Computes the singular value decompositions of one or more matrices. @@ -439,6 +446,7 @@ def svd(tensor, full_matrices=False, compute_uv=True, name=None): # pylint: disable=redefined-builtin +@tf_export('norm', 'linalg.norm') @deprecation.deprecated_args( None, 'keep_dims is deprecated, use keepdims instead', 'keep_dims') def norm(tensor, diff --git a/tensorflow/python/ops/logging_ops.py b/tensorflow/python/ops/logging_ops.py index 51ab2aec22..eadbc1b7c3 100644 --- a/tensorflow/python/ops/logging_ops.py +++ b/tensorflow/python/ops/logging_ops.py @@ -27,6 +27,7 @@ from tensorflow.python.ops import gen_logging_ops from tensorflow.python.ops.gen_logging_ops import * # pylint: enable=wildcard-import from tensorflow.python.util.deprecation import deprecated +from tensorflow.python.util.tf_export import tf_export # The python wrapper for Assert is in control_flow_ops, as the Assert # call relies on certain conditionals for its dependencies. Use @@ -35,6 +36,7 @@ from tensorflow.python.util.deprecation import deprecated # Assert and Print are special symbols in python, so we must # use an upper-case version of them. +@tf_export("Print") def Print(input_, data, message=None, first_n=None, summarize=None, name=None): """Prints a list of tensors. diff --git a/tensorflow/python/ops/lookup_ops.py b/tensorflow/python/ops/lookup_ops.py index 333e36873a..f539a7bb68 100644 --- a/tensorflow/python/ops/lookup_ops.py +++ b/tensorflow/python/ops/lookup_ops.py @@ -40,8 +40,10 @@ from tensorflow.python.ops.gen_lookup_ops import * # pylint: enable=wildcard-import from tensorflow.python.util import compat from tensorflow.python.util.deprecation import deprecated +from tensorflow.python.util.tf_export import tf_export +@tf_export("initialize_all_tables") @deprecated(None, "Use `tf.tables_initializer` instead.") def initialize_all_tables(name="init_all_tables"): """Returns an Op that initializes all tables of the default graph. @@ -56,6 +58,7 @@ def initialize_all_tables(name="init_all_tables"): return tables_initializer(name) +@tf_export("tables_initializer") def tables_initializer(name="init_all_tables"): """Returns an Op that initializes all tables of the default graph. diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index cfdfa09757..9ad1031354 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -172,6 +172,7 @@ from tensorflow.python.ops.gen_math_ops import * # pylint: enable=wildcard-import from tensorflow.python.util import compat from tensorflow.python.util import deprecation +from tensorflow.python.util.tf_export import tf_export # Aliases for some automatically-generated names. linspace = gen_math_ops.lin_space @@ -190,6 +191,7 @@ def _set_doc(doc): # pylint: disable=redefined-builtin +@tf_export("argmax") @deprecation.deprecated_args(None, "Use the `axis` argument instead", "dimension") @_set_doc( @@ -209,6 +211,7 @@ def argmax(input, return gen_math_ops.arg_max(input, axis, name=name, output_type=output_type) +@tf_export("argmin") @deprecation.deprecated_args(None, "Use the `axis` argument instead", "dimension") @_set_doc( @@ -233,6 +236,7 @@ def argmin(input, # pylint: disable=anomalous-backslash-in-string,protected-access # pylint: disable=g-docstring-has-escape +@tf_export("abs") def abs(x, name=None): r"""Computes the absolute value of a tensor. @@ -307,6 +311,7 @@ class DivideDelegateWithName(object): return _div_python2(self.x, y, self.name) +@tf_export("divide") def divide(x, y, name=None): """Computes Python style division of `x` by `y`.""" @@ -318,6 +323,7 @@ def divide(x, y, name=None): return x / y +@tf_export("multiply") def multiply(x, y, name=None): return gen_math_ops._mul(x, y, name) @@ -337,6 +343,7 @@ _mul.__doc__ = ( gen_math_ops._mul.__doc__ + ("" if _mul.__doc__ is None else _mul.__doc__)) +@tf_export("subtract") def subtract(x, y, name=None): return gen_math_ops._sub(x, y, name) @@ -357,6 +364,7 @@ _sub.__doc__ = ( # pylint: disable=g-docstring-has-escape +@tf_export("negative") def negative(x, name=None): """Computes numerical negative value element-wise. @@ -405,6 +413,7 @@ def _neg(x, name=None): # pylint: enable=g-docstring-has-escape +@tf_export("sign") def sign(x, name=None): """Returns an element-wise indication of the sign of a number. @@ -435,6 +444,7 @@ def sign(x, name=None): return gen_math_ops.sign(x, name=name) +@tf_export("square") def square(x, name=None): r"""Computes square of x element-wise. @@ -457,6 +467,7 @@ def square(x, name=None): return gen_math_ops.square(x, name=name) +@tf_export("sqrt") def sqrt(x, name=None): r"""Computes square root of x element-wise. @@ -479,6 +490,7 @@ def sqrt(x, name=None): return gen_math_ops.sqrt(x, name=name) +@tf_export("erf") def erf(x, name=None): """Computes the Gauss error function of `x` element-wise. @@ -499,6 +511,7 @@ def erf(x, name=None): return gen_math_ops.erf(x, name=name) +@tf_export("scalar_mul") def scalar_mul(scalar, x): """Multiplies a scalar times a `Tensor` or `IndexedSlices` object. @@ -528,6 +541,7 @@ def scalar_mul(scalar, x): raise ValueError("Only scalar multiply works, got shape %s" % shape) +@tf_export("pow") def pow(x, y, name=None): r"""Computes the power of one value to another. @@ -555,6 +569,7 @@ def pow(x, y, name=None): # pylint: disable=redefined-builtin,redefined-outer-name +@tf_export("complex") def complex(real, imag, name=None): r"""Converts two real numbers to a complex number. @@ -596,6 +611,7 @@ def complex(real, imag, name=None): return gen_math_ops._complex(real, imag, Tout=Tout, name=name) +@tf_export("real") def real(input, name=None): r"""Returns the real part of a complex (or real) tensor. @@ -626,6 +642,7 @@ def real(input, name=None): return input +@tf_export("imag") def imag(input, name=None): r"""Returns the imaginary part of a complex (or real) tensor. @@ -655,6 +672,7 @@ def imag(input, name=None): return array_ops.zeros_like(input) +@tf_export("angle") def angle(input, name=None): r"""Returns the element-wise argument of a complex (or real) tensor. @@ -693,6 +711,7 @@ def angle(input, name=None): # pylint: enable=redefined-outer-name,redefined-builtin +@tf_export("round") def round(x, name=None): """Rounds the values of a tensor to the nearest integer, element-wise. @@ -719,6 +738,7 @@ def round(x, name=None): return gen_math_ops.round(x, name=name) +@tf_export("cast") def cast(x, dtype, name=None): """Casts a tensor to a new type. @@ -759,6 +779,7 @@ def cast(x, dtype, name=None): return gen_math_ops.cast(x, base_type, name=name) +@tf_export("saturate_cast") def saturate_cast(value, dtype, name=None): """Performs a safe saturating cast of `value` to `dtype`. @@ -792,6 +813,7 @@ def saturate_cast(value, dtype, name=None): return cast(value, dtype, name=name) +@tf_export("to_float") def to_float(x, name="ToFloat"): """Casts a tensor to type `float32`. @@ -808,6 +830,7 @@ def to_float(x, name="ToFloat"): return cast(x, dtypes.float32, name=name) +@tf_export("to_double") def to_double(x, name="ToDouble"): """Casts a tensor to type `float64`. @@ -824,6 +847,7 @@ def to_double(x, name="ToDouble"): return cast(x, dtypes.float64, name=name) +@tf_export("to_int32") def to_int32(x, name="ToInt32"): """Casts a tensor to type `int32`. @@ -840,6 +864,7 @@ def to_int32(x, name="ToInt32"): return cast(x, dtypes.int32, name=name) +@tf_export("to_int64") def to_int64(x, name="ToInt64"): """Casts a tensor to type `int64`. @@ -856,6 +881,7 @@ def to_int64(x, name="ToInt64"): return cast(x, dtypes.int64, name=name) +@tf_export("to_bfloat16") def to_bfloat16(x, name="ToBFloat16"): """Casts a tensor to type `bfloat16`. @@ -1029,6 +1055,7 @@ def _div_python2(x, y, name=None): return gen_math_ops._floor_div(x, y, name=name) +@tf_export("truediv") def truediv(x, y, name=None): """Divides x / y elementwise (using Python 3 division operator semantics). @@ -1060,6 +1087,7 @@ def truediv(x, y, name=None): return _truediv_python3(x, y, name) +@tf_export("div") def div(x, y, name=None): """Divides x / y elementwise (using Python 2 division operator semantics). @@ -1087,6 +1115,7 @@ mod = gen_math_ops._floor_mod # TODO(aselle): Deprecate this once all internal functionality uses # tf.truncatediv +@tf_export("floordiv") def floordiv(x, y, name=None): """Divides `x / y` elementwise, rounding toward the most negative integer. @@ -1157,6 +1186,7 @@ _OverrideBinaryOperatorHelper(gen_math_ops._floor_mod, "mod") _OverrideBinaryOperatorHelper(pow, "pow") +@tf_export("logical_xor") def logical_xor(x, y, name="LogicalXor"): """x ^ y = (x | y) & ~(x & y).""" # TODO(alemi) Make this a cwise op if people end up relying on it. @@ -1176,6 +1206,7 @@ ops.Tensor._override_operator("__gt__", gen_math_ops.greater) ops.Tensor._override_operator("__ge__", gen_math_ops.greater_equal) +@tf_export("range") def range(start, limit=None, delta=1, dtype=None, name="range"): """Creates a sequence of numbers. @@ -1281,6 +1312,7 @@ def _may_reduce_to_scalar(keepdims, axis, reduction_indices, output): return output +@tf_export("reduce_sum") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def reduce_sum(input_tensor, @@ -1341,6 +1373,7 @@ def reduce_sum(input_tensor, name=name)) +@tf_export("count_nonzero") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def count_nonzero(input_tensor, @@ -1407,6 +1440,7 @@ def count_nonzero(input_tensor, dtype=dtype) +@tf_export("reduce_mean") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def reduce_mean(input_tensor, @@ -1478,6 +1512,7 @@ def reduce_mean(input_tensor, name=name)) +@tf_export("reduce_prod") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def reduce_prod(input_tensor, @@ -1527,6 +1562,7 @@ def reduce_prod(input_tensor, name=name)) +@tf_export("reduce_min") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def reduce_min(input_tensor, @@ -1575,6 +1611,7 @@ def reduce_min(input_tensor, name=name)) +@tf_export("reduce_max") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def reduce_max(input_tensor, @@ -1623,6 +1660,7 @@ def reduce_max(input_tensor, name=name)) +@tf_export("reduce_all") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def reduce_all(input_tensor, @@ -1680,6 +1718,7 @@ def reduce_all(input_tensor, name=name)) +@tf_export("reduce_any") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def reduce_any(input_tensor, @@ -1737,6 +1776,7 @@ def reduce_any(input_tensor, name=name)) +@tf_export("reduce_logsumexp") @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") def reduce_logsumexp(input_tensor, @@ -1810,6 +1850,7 @@ def reduce_logsumexp(input_tensor, return _may_reduce_to_scalar(keepdims, axis, reduction_indices, result) +@tf_export("trace", "linalg.trace") def trace(x, name=None): """Compute the trace of a tensor `x`. @@ -1851,6 +1892,7 @@ def trace(x, name=None): return reduce_sum(array_ops.matrix_diag_part(x), [-1], name=name) +@tf_export("matmul") def matmul(a, b, transpose_a=False, @@ -2103,6 +2145,7 @@ def _as_indexed_slices_list(inputs, optimize=True): return casted_outputs +@tf_export("add_n") def add_n(inputs, name=None): """Adds all input tensors element-wise. @@ -2132,6 +2175,7 @@ def add_n(inputs, name=None): return gen_math_ops._add_n(inputs, name=name) +@tf_export("accumulate_n") def accumulate_n(inputs, shape=None, tensor_dtype=None, name=None): """Returns the element-wise sum of a list of tensors. @@ -2216,6 +2260,7 @@ def accumulate_n(inputs, shape=None, tensor_dtype=None, name=None): ref, var_name=var.op.name, name=name) +@tf_export("nn.sigmoid", "sigmoid") def sigmoid(x, name=None): """Computes sigmoid of `x` element-wise. @@ -2238,6 +2283,7 @@ def sigmoid(x, name=None): return gen_math_ops._sigmoid(x, name=name) +@tf_export("log_sigmoid") def log_sigmoid(x, name=None): """Computes log sigmoid of `x` element-wise. @@ -2256,6 +2302,7 @@ def log_sigmoid(x, name=None): return gen_math_ops._neg(gen_nn_ops.softplus(-x), name=name) +@tf_export("nn.tanh", "tanh") def tanh(x, name=None): """Computes hyperbolic tangent of `x` element-wise. @@ -2276,6 +2323,7 @@ def tanh(x, name=None): return gen_math_ops._tanh(x, name=name) +@tf_export("bincount") def bincount(arr, weights=None, minlength=None, @@ -2322,6 +2370,7 @@ def bincount(arr, return gen_math_ops.bincount(arr, output_size, weights) +@tf_export("cumsum") def cumsum(x, axis=0, exclusive=False, reverse=False, name=None): """Compute the cumulative sum of the tensor `x` along `axis`. @@ -2373,6 +2422,7 @@ def cumsum(x, axis=0, exclusive=False, reverse=False, name=None): x, axis, exclusive=exclusive, reverse=reverse, name=name) +@tf_export("cumprod") def cumprod(x, axis=0, exclusive=False, reverse=False, name=None): """Compute the cumulative product of the tensor `x` along `axis`. @@ -2424,6 +2474,7 @@ def cumprod(x, axis=0, exclusive=False, reverse=False, name=None): x, axis, exclusive=exclusive, reverse=reverse, name=name) +@tf_export("conj") def conj(x, name=None): r"""Returns the complex conjugate of a complex number. @@ -2502,6 +2553,7 @@ def reduced_shape(input_shape, axes): ]) # [1, 1] +@tf_export("sparse_segment_sum") def sparse_segment_sum(data, indices, segment_ids, name=None, num_segments=None): r"""Computes the sum along sparse segments of a tensor. @@ -2576,6 +2628,7 @@ def sparse_segment_sum(data, indices, segment_ids, name=None, name=name) +@tf_export("sparse_segment_mean") def sparse_segment_mean(data, indices, segment_ids, name=None, num_segments=None): r"""Computes the mean along sparse segments of a tensor. @@ -2619,6 +2672,7 @@ def sparse_segment_mean(data, indices, segment_ids, name=None, name=name) +@tf_export("sparse_segment_sqrt_n") def sparse_segment_sqrt_n(data, indices, segment_ids, name=None, num_segments=None): r"""Computes the sum along sparse segments of a tensor divided by the sqrt(N). @@ -2655,6 +2709,7 @@ def sparse_segment_sqrt_n(data, indices, segment_ids, name=None, name=name) +@tf_export("tensordot", "linalg.tensordot") def tensordot(a, b, axes, name=None): r"""Tensor contraction of a and b along specified axes. diff --git a/tensorflow/python/ops/metrics_impl.py b/tensorflow/python/ops/metrics_impl.py index 25e1613a65..92b3ff2250 100644 --- a/tensorflow/python/ops/metrics_impl.py +++ b/tensorflow/python/ops/metrics_impl.py @@ -34,6 +34,7 @@ from tensorflow.python.ops import state_ops from tensorflow.python.ops import variable_scope from tensorflow.python.ops import weights_broadcast_ops from tensorflow.python.util.deprecation import deprecated +from tensorflow.python.util.tf_export import tf_export def metric_variable(shape, dtype, validate_shape=True, name=None): @@ -262,6 +263,7 @@ def _streaming_confusion_matrix(labels, predictions, num_classes, weights=None): return total_cm, update_op +@tf_export('metrics.mean') def mean(values, weights=None, metrics_collections=None, updates_collections=None, name=None): """Computes the (weighted) mean of the given values. @@ -337,6 +339,7 @@ def mean(values, weights=None, metrics_collections=None, return mean_t, update_op +@tf_export('metrics.accuracy') def accuracy(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, name=None): """Calculates how often `predictions` matches `labels`. @@ -552,6 +555,7 @@ def _confusion_matrix_at_thresholds( return values, update_ops +@tf_export('metrics.auc') def auc(labels, predictions, weights=None, num_thresholds=200, metrics_collections=None, updates_collections=None, curve='ROC', name=None, summation_method='trapezoidal'): @@ -682,6 +686,7 @@ def auc(labels, predictions, weights=None, num_thresholds=200, return auc_value, update_op +@tf_export('metrics.mean_absolute_error') def mean_absolute_error(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, @@ -740,6 +745,7 @@ def mean_absolute_error(labels, predictions, weights=None, updates_collections, name or 'mean_absolute_error') +@tf_export('metrics.mean_cosine_distance') def mean_cosine_distance(labels, predictions, dim, weights=None, metrics_collections=None, updates_collections=None, @@ -812,6 +818,7 @@ def mean_cosine_distance(labels, predictions, dim, weights=None, return mean_distance, update_op +@tf_export('metrics.mean_per_class_accuracy') def mean_per_class_accuracy(labels, predictions, num_classes, @@ -896,6 +903,7 @@ def mean_per_class_accuracy(labels, return mean_accuracy_v, update_op +@tf_export('metrics.mean_iou') def mean_iou(labels, predictions, num_classes, @@ -997,6 +1005,7 @@ def mean_iou(labels, return mean_iou_v, update_op +@tf_export('metrics.mean_relative_error') def mean_relative_error(labels, predictions, normalizer, weights=None, metrics_collections=None, updates_collections=None, @@ -1063,6 +1072,7 @@ def mean_relative_error(labels, predictions, normalizer, weights=None, updates_collections, name or 'mean_relative_error') +@tf_export('metrics.mean_squared_error') def mean_squared_error(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, @@ -1121,6 +1131,7 @@ def mean_squared_error(labels, predictions, weights=None, updates_collections, name or 'mean_squared_error') +@tf_export('metrics.mean_tensor') def mean_tensor(values, weights=None, metrics_collections=None, updates_collections=None, name=None): """Computes the element-wise (weighted) mean of the given tensors. @@ -1206,6 +1217,7 @@ def mean_tensor(values, weights=None, metrics_collections=None, return mean_t, update_op +@tf_export('metrics.percentage_below') def percentage_below(values, threshold, weights=None, metrics_collections=None, updates_collections=None, @@ -1307,6 +1319,7 @@ def _count_condition(values, weights=None, metrics_collections=None, return value_tensor, update_op +@tf_export('metrics.false_negatives') def false_negatives(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, @@ -1356,6 +1369,7 @@ def false_negatives(labels, predictions, weights=None, updates_collections) +@tf_export('metrics.false_negatives_at_thresholds') def false_negatives_at_thresholds(labels, predictions, thresholds, weights=None, metrics_collections=None, updates_collections=None, @@ -1409,6 +1423,7 @@ def false_negatives_at_thresholds(labels, predictions, thresholds, weights=None, return values['fn'], update_ops['fn'] +@tf_export('metrics.false_positives') def false_positives(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, @@ -1459,6 +1474,7 @@ def false_positives(labels, predictions, weights=None, updates_collections) +@tf_export('metrics.false_positives_at_thresholds') def false_positives_at_thresholds(labels, predictions, thresholds, weights=None, metrics_collections=None, updates_collections=None, @@ -1512,6 +1528,7 @@ def false_positives_at_thresholds(labels, predictions, thresholds, weights=None, return values['fp'], update_ops['fp'] +@tf_export('metrics.true_negatives') def true_negatives(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, @@ -1562,6 +1579,7 @@ def true_negatives(labels, predictions, weights=None, updates_collections) +@tf_export('metrics.true_negatives_at_thresholds') def true_negatives_at_thresholds(labels, predictions, thresholds, weights=None, metrics_collections=None, updates_collections=None, @@ -1615,6 +1633,7 @@ def true_negatives_at_thresholds(labels, predictions, thresholds, weights=None, return values['tn'], update_ops['tn'] +@tf_export('metrics.true_positives') def true_positives(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, @@ -1665,6 +1684,7 @@ def true_positives(labels, predictions, weights=None, updates_collections) +@tf_export('metrics.true_positives_at_thresholds') def true_positives_at_thresholds(labels, predictions, thresholds, weights=None, metrics_collections=None, updates_collections=None, @@ -1718,6 +1738,7 @@ def true_positives_at_thresholds(labels, predictions, thresholds, weights=None, return values['tp'], update_ops['tp'] +@tf_export('metrics.precision') def precision(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1803,6 +1824,7 @@ def precision(labels, predictions, weights=None, return p, update_op +@tf_export('metrics.precision_at_thresholds') def precision_at_thresholds(labels, predictions, thresholds, weights=None, metrics_collections=None, @@ -1878,6 +1900,7 @@ def precision_at_thresholds(labels, predictions, thresholds, return prec, update_op +@tf_export('metrics.recall') def recall(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -2217,6 +2240,7 @@ def _streaming_sparse_false_negative_at_k(labels, return var, state_ops.assign_add(var, batch_total_fn, name='update') +@tf_export('metrics.recall_at_k') def recall_at_k(labels, predictions, k, @@ -2310,6 +2334,7 @@ def recall_at_k(labels, name=scope) +@tf_export('metrics.recall_at_top_k') def recall_at_top_k(labels, predictions_idx, k=None, @@ -2385,6 +2410,7 @@ def recall_at_top_k(labels, return metric, update +@tf_export('metrics.recall_at_thresholds') def recall_at_thresholds(labels, predictions, thresholds, weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -2456,6 +2482,7 @@ def recall_at_thresholds(labels, predictions, thresholds, return rec, update_op +@tf_export('metrics.root_mean_squared_error') def root_mean_squared_error(labels, predictions, weights=None, metrics_collections=None, updates_collections=None, @@ -2525,6 +2552,7 @@ def root_mean_squared_error(labels, predictions, weights=None, return rmse, update_rmse_op +@tf_export('metrics.sensitivity_at_specificity') def sensitivity_at_specificity( labels, predictions, specificity, weights=None, num_thresholds=200, metrics_collections=None, updates_collections=None, name=None): @@ -2887,6 +2915,7 @@ def _streaming_sparse_average_precision_at_top_k(labels, return mean_average_precision, update +@tf_export('metrics.sparse_average_precision_at_k') @deprecated(None, 'Use average_precision_at_k instead') def sparse_average_precision_at_k(labels, predictions, @@ -2906,6 +2935,7 @@ def sparse_average_precision_at_k(labels, name=name) +@tf_export('metrics.average_precision_at_k') def average_precision_at_k(labels, predictions, k, @@ -3080,6 +3110,7 @@ def _streaming_sparse_false_positive_at_k(labels, return var, state_ops.assign_add(var, batch_total_fp, name='update') +@tf_export('metrics.precision_at_top_k') def precision_at_top_k(labels, predictions_idx, k=None, @@ -3159,6 +3190,7 @@ def precision_at_top_k(labels, return metric, update +@tf_export('metrics.sparse_precision_at_k') @deprecated(None, 'Use precision_at_k instead') def sparse_precision_at_k(labels, predictions, @@ -3180,6 +3212,7 @@ def sparse_precision_at_k(labels, name=name) +@tf_export('metrics.precision_at_k') def precision_at_k(labels, predictions, k, @@ -3273,6 +3306,7 @@ def precision_at_k(labels, name=scope) +@tf_export('metrics.specificity_at_sensitivity') def specificity_at_sensitivity( labels, predictions, sensitivity, weights=None, num_thresholds=200, metrics_collections=None, updates_collections=None, name=None): diff --git a/tensorflow/python/ops/nn_impl.py b/tensorflow/python/ops/nn_impl.py index fd96f7b8fc..67eee1c29e 100644 --- a/tensorflow/python/ops/nn_impl.py +++ b/tensorflow/python/ops/nn_impl.py @@ -35,8 +35,10 @@ from tensorflow.python.ops import sparse_ops from tensorflow.python.ops import variables from tensorflow.python.util.deprecation import deprecated_args from tensorflow.python.util.deprecation import deprecated_argument_lookup +from tensorflow.python.util.tf_export import tf_export +@tf_export("nn.log_poisson_loss") def log_poisson_loss(targets, log_input, compute_full_loss=False, name=None): """Computes log Poisson loss given `log_input`. @@ -101,6 +103,7 @@ def log_poisson_loss(targets, log_input, compute_full_loss=False, name=None): return result +@tf_export("nn.sigmoid_cross_entropy_with_logits") def sigmoid_cross_entropy_with_logits( # pylint: disable=invalid-name _sentinel=None, labels=None, @@ -180,6 +183,7 @@ def sigmoid_cross_entropy_with_logits( # pylint: disable=invalid-name name=name) +@tf_export("nn.weighted_cross_entropy_with_logits") def weighted_cross_entropy_with_logits(targets, logits, pos_weight, name=None): """Computes a weighted cross entropy. @@ -251,6 +255,7 @@ def weighted_cross_entropy_with_logits(targets, logits, pos_weight, name=None): name=name) +@tf_export("nn.relu_layer") def relu_layer(x, weights, biases, name=None): """Computes Relu(x * weight + biases). @@ -297,6 +302,7 @@ def _swish_grad(features, grad): shape_func=_swish_shape, func_name="swish", noinline=True) +@tf_export("nn.swish") def swish(features): # pylint: disable=g-doc-args """Computes the Swish activation function: `x * sigmoid(x)`. @@ -316,6 +322,7 @@ def swish(features): return features * math_ops.sigmoid(features) +@tf_export("nn.l2_normalize") @deprecated_args(None, "dim is deprecated, use axis instead", "dim") def l2_normalize(x, axis=None, epsilon=1e-12, name=None, dim=None): """Normalizes along dimension `axis` using an L2 norm. @@ -347,6 +354,7 @@ def l2_normalize(x, axis=None, epsilon=1e-12, name=None, dim=None): return math_ops.multiply(x, x_inv_norm, name=name) +@tf_export("nn.zero_fraction") def zero_fraction(value, name=None): """Returns the fraction of zeros in `value`. @@ -374,6 +382,7 @@ def zero_fraction(value, name=None): # pylint: disable=redefined-builtin +@tf_export("nn.depthwise_conv2d") def depthwise_conv2d(input, filter, strides, @@ -450,6 +459,7 @@ def depthwise_conv2d(input, # pylint: disable=redefined-builtin,line-too-long +@tf_export("nn.separable_conv2d") def separable_conv2d(input, depthwise_filter, pointwise_filter, @@ -550,6 +560,7 @@ def separable_conv2d(input, # pylint: enable=redefined-builtin,line-too-long +@tf_export("nn.sufficient_statistics") def sufficient_statistics(x, axes, shift=None, keep_dims=False, name=None): """Calculate the sufficient statistics for the mean and variance of `x`. @@ -599,6 +610,7 @@ def sufficient_statistics(x, axes, shift=None, keep_dims=False, name=None): return counts, m_ss, v_ss, shift +@tf_export("nn.normalize_moments") def normalize_moments(counts, mean_ss, variance_ss, shift, name=None): """Calculate the mean and variance of based on the sufficient statistics. @@ -630,6 +642,7 @@ def normalize_moments(counts, mean_ss, variance_ss, shift, name=None): return (mean, variance) +@tf_export("nn.moments") def moments(x, axes, shift=None, # pylint: disable=unused-argument name=None, keep_dims=False): @@ -682,6 +695,7 @@ def moments(x, axes, return (mean, variance) +@tf_export("nn.weighted_moments") def weighted_moments(x, axes, frequency_weights, name=None, keep_dims=False): """Returns the frequency-weighted mean and variance of `x`. @@ -753,6 +767,7 @@ def weighted_moments(x, axes, frequency_weights, name=None, keep_dims=False): return weighted_mean, weighted_variance +@tf_export("nn.batch_normalization") def batch_normalization(x, mean, variance, @@ -810,6 +825,7 @@ def batch_normalization(x, if offset is not None else -mean * inv) +@tf_export("nn.fused_batch_norm") def fused_batch_norm( x, scale, @@ -882,6 +898,7 @@ def fused_batch_norm( return y, batch_mean, batch_var +@tf_export("nn.batch_norm_with_global_normalization") def batch_norm_with_global_normalization(t, m, v, @@ -1109,6 +1126,7 @@ def _compute_sampled_logits(weights, return out_logits, out_labels +@tf_export("nn.nce_loss") def nce_loss(weights, biases, labels, @@ -1217,6 +1235,7 @@ def nce_loss(weights, return _sum_rows(sampled_losses) +@tf_export("nn.sampled_softmax_loss") def sampled_softmax_loss(weights, biases, labels, diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 865e459e90..09aa45dae1 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -39,6 +39,7 @@ from tensorflow.python.ops.gen_nn_ops import * # pylint: enable=wildcard-import from tensorflow.python.util import deprecation +from tensorflow.python.util.tf_export import tf_export # Aliases for some automatically-generated names. @@ -190,6 +191,7 @@ class _NonAtrousConvolution(object): name=self.name) +@tf_export("nn.with_space_to_batch") def with_space_to_batch( input, # pylint: disable=redefined-builtin dilation_rate, @@ -633,6 +635,7 @@ def _get_strides_and_dilation_rate(num_spatial_dims, strides, dilation_rate): return strides, dilation_rate +@tf_export("nn.convolution") def convolution(input, filter, # pylint: disable=redefined-builtin padding, strides=None, dilation_rate=None, name=None, data_format=None): @@ -848,6 +851,7 @@ class Convolution(object): return self.conv_op(inp, filter) +@tf_export("nn.pool") def pool(input, # pylint: disable=redefined-builtin window_shape, pooling_type, @@ -1015,6 +1019,7 @@ def pool(input, # pylint: disable=redefined-builtin filter_shape=window_shape) +@tf_export("nn.atrous_conv2d") def atrous_conv2d(value, filters, rate, padding, name=None): """Atrous convolution (a.k.a. convolution with holes or dilated convolution). @@ -1150,6 +1155,7 @@ def atrous_conv2d(value, filters, rate, padding, name=None): name=name) +@tf_export("nn.conv2d_transpose") def conv2d_transpose(value, filter, # pylint: disable=redefined-builtin output_shape, @@ -1225,6 +1231,7 @@ def conv2d_transpose(value, name=name) +@tf_export("nn.atrous_conv2d_transpose") def atrous_conv2d_transpose(value, filters, output_shape, @@ -1371,6 +1378,7 @@ def atrous_conv2d_transpose(value, block_size=rate) +@tf_export("nn.conv3d_transpose") def conv3d_transpose(value, filter, # pylint: disable=redefined-builtin output_shape, @@ -1444,6 +1452,7 @@ def conv3d_transpose(value, # pylint: disable=protected-access +@tf_export("nn.bias_add") def bias_add(value, bias, data_format=None, name=None): """Adds `bias` to `value`. @@ -1498,6 +1507,7 @@ def bias_add_v1(value, bias, name=None): return gen_nn_ops._bias_add_v1(value, bias, name=name) +@tf_export("nn.crelu") def crelu(features, name=None, axis=-1): """Computes Concatenated ReLU. @@ -1521,6 +1531,7 @@ def crelu(features, name=None, axis=-1): return gen_nn_ops.relu(c) +@tf_export("nn.relu6") def relu6(features, name=None): """Computes Rectified Linear 6: `min(max(features, 0), 6)`. Source: [Convolutional Deep Belief Networks on CIFAR-10. A. Krizhevsky](http://www.cs.utoronto.ca/~kriz/conv-cifar10-aug2010.pdf) @@ -1538,6 +1549,7 @@ def relu6(features, name=None): return gen_nn_ops._relu6(features, name=name) +@tf_export("nn.leaky_relu") def leaky_relu(features, alpha=0.2, name=None): """Compute the Leaky ReLU activation function. @@ -1661,6 +1673,7 @@ def _softmax(logits, compute_op, dim=-1, name=None): return output +@tf_export("nn.softmax") @deprecation.deprecated_args(None, "dim is deprecated, use axis instead", "dim") def softmax(logits, axis=None, name=None, dim=None): """Computes softmax activations. @@ -1690,6 +1703,7 @@ def softmax(logits, axis=None, name=None, dim=None): return _softmax(logits, gen_nn_ops._softmax, axis, name) +@tf_export("nn.log_softmax") @deprecation.deprecated_args(None, "dim is deprecated, use axis instead", "dim") def log_softmax(logits, axis=None, name=None, dim=None): """Computes log softmax activations. @@ -1728,6 +1742,7 @@ def _ensure_xent_args(name, sentinel, labels, logits): raise ValueError("Both labels and logits must be provided.") +@tf_export("nn.softmax_cross_entropy_with_logits_v2") def softmax_cross_entropy_with_logits_v2(_sentinel=None, # pylint: disable=invalid-name labels=None, logits=None, dim=-1, name=None): @@ -1842,6 +1857,7 @@ See tf.nn.softmax_cross_entropy_with_logits_v2. """ +@tf_export("nn.softmax_cross_entropy_with_logits") @deprecation.deprecated(date=None, instructions=_XENT_DEPRECATION) def softmax_cross_entropy_with_logits(_sentinel=None, # pylint: disable=invalid-name labels=None, logits=None, @@ -1898,6 +1914,7 @@ def softmax_cross_entropy_with_logits(_sentinel=None, # pylint: disable=invalid labels=labels, logits=logits, dim=dim, name=name) +@tf_export("nn.sparse_softmax_cross_entropy_with_logits") def sparse_softmax_cross_entropy_with_logits(_sentinel=None, # pylint: disable=invalid-name labels=None, logits=None, name=None): @@ -1996,6 +2013,7 @@ def sparse_softmax_cross_entropy_with_logits(_sentinel=None, # pylint: disable= return cost +@tf_export("nn.avg_pool") def avg_pool(value, ksize, strides, padding, data_format="NHWC", name=None): """Performs the average pooling on the input. @@ -2028,6 +2046,7 @@ def avg_pool(value, ksize, strides, padding, data_format="NHWC", name=None): name=name) +@tf_export("nn.max_pool") def max_pool(value, ksize, strides, padding, data_format="NHWC", name=None): """Performs the max pooling on the input. @@ -2099,6 +2118,7 @@ def _calc_bias_add_flops(graph, node): return ops.OpStats("flops", input_count) +@tf_export("nn.xw_plus_b") def xw_plus_b(x, weights, biases, name=None): # pylint: disable=invalid-name """Computes matmul(x, weights) + biases. @@ -2145,6 +2165,7 @@ def xw_plus_b_v1(x, weights, biases, name=None): # pylint: disable=invalid-name return bias_add_v1(mm, biases, name=name) +@tf_export("nn.dropout") def dropout(x, keep_prob, noise_shape=None, seed=None, name=None): # pylint: disable=invalid-name """Computes dropout. @@ -2209,6 +2230,7 @@ def dropout(x, keep_prob, noise_shape=None, seed=None, name=None): # pylint: di return ret +@tf_export("nn.top_k") def top_k(input, k=1, sorted=True, name=None): """Finds values and indices of the `k` largest entries for the last dimension. @@ -2266,6 +2288,7 @@ def nth_element(input, n, reverse=False, name=None): return gen_nn_ops.nth_element(input, n, reverse=reverse, name=name) +@tf_export("nn.conv1d") @deprecation.deprecated_arg_values( None, "`NCHW` for data_format is deprecated, use `NCW` instead", warn_once=True, data_format="NCHW") @@ -2451,6 +2474,7 @@ def _calc_dilation2d_flops(graph, node): return ops.OpStats("flops", (output_count * filter_height * filter_width * 2)) +@tf_export("nn.erosion2d") def erosion2d(value, kernel, strides, rates, padding, name=None): """Computes the grayscale erosion of 4-D `value` and 3-D `kernel` tensors. @@ -2508,6 +2532,7 @@ def erosion2d(value, kernel, strides, rates, padding, name=None): name=name)) +@tf_export("nn.in_top_k") def in_top_k(predictions, targets, k, name=None): r"""Says whether the targets are in the top `K` predictions. diff --git a/tensorflow/python/ops/numerics.py b/tensorflow/python/ops/numerics.py index f3558fda9c..b4ce1cbf25 100644 --- a/tensorflow/python/ops/numerics.py +++ b/tensorflow/python/ops/numerics.py @@ -24,8 +24,10 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops +from tensorflow.python.util.tf_export import tf_export +@tf_export("verify_tensor_all_finite") def verify_tensor_all_finite(t, msg, name=None): """Assert that the tensor does not contain any NaN's or Inf's. @@ -45,6 +47,7 @@ def verify_tensor_all_finite(t, msg, name=None): return out +@tf_export("add_check_numerics_ops") def add_check_numerics_ops(): """Connect a `check_numerics` to every floating point tensor. diff --git a/tensorflow/python/ops/parsing_ops.py b/tensorflow/python/ops/parsing_ops.py index 7b6f08f68c..b0315ceee2 100644 --- a/tensorflow/python/ops/parsing_ops.py +++ b/tensorflow/python/ops/parsing_ops.py @@ -36,6 +36,7 @@ from tensorflow.python.ops import sparse_ops from tensorflow.python.ops.gen_parsing_ops import * # pylint: enable=wildcard-import,undefined-variable from tensorflow.python.platform import tf_logging +from tensorflow.python.util.tf_export import tf_export ops.NotDifferentiable("DecodeRaw") @@ -44,6 +45,7 @@ ops.NotDifferentiable("SerializeTensor") ops.NotDifferentiable("StringToNumber") +@tf_export("VarLenFeature") class VarLenFeature(collections.namedtuple("VarLenFeature", ["dtype"])): """Configuration for parsing a variable-length input feature. @@ -53,6 +55,7 @@ class VarLenFeature(collections.namedtuple("VarLenFeature", ["dtype"])): pass +@tf_export("SparseFeature") class SparseFeature( collections.namedtuple( "SparseFeature", @@ -127,6 +130,7 @@ class SparseFeature( cls, index_key, value_key, dtype, size, already_sorted) +@tf_export("FixedLenFeature") class FixedLenFeature(collections.namedtuple( "FixedLenFeature", ["shape", "dtype", "default_value"])): """Configuration for parsing a fixed-length input feature. @@ -146,6 +150,7 @@ class FixedLenFeature(collections.namedtuple( cls, shape, dtype, default_value) +@tf_export("FixedLenSequenceFeature") class FixedLenSequenceFeature(collections.namedtuple( "FixedLenSequenceFeature", ["shape", "dtype", "allow_missing", "default_value"])): @@ -355,6 +360,7 @@ def _prepend_none_dimension(features): return features +@tf_export("parse_example") def parse_example(serialized, features, name=None, example_names=None): # pylint: disable=line-too-long """Parses `Example` protos into a `dict` of tensors. @@ -715,6 +721,7 @@ def _parse_example_raw(serialized, return dict(zip(sparse_keys + dense_keys, sparse_tensors + dense_values)) +@tf_export("parse_single_example") def parse_single_example(serialized, features, name=None, example_names=None): """Parses a single `Example` proto. @@ -850,6 +857,7 @@ def _parse_single_example_raw(serialized, return outputs +@tf_export("parse_single_sequence_example") def parse_single_sequence_example( serialized, context_features=None, sequence_features=None, example_name=None, name=None): @@ -1171,6 +1179,7 @@ def _parse_single_sequence_example_raw(serialized, # Swap `name` and `na_value` for backward compatibility. +@tf_export("decode_csv") def decode_csv(records, record_defaults, field_delim=",", use_quote_delim=True, name=None, na_value=""): # pylint: disable=protected-access diff --git a/tensorflow/python/ops/partitioned_variables.py b/tensorflow/python/ops/partitioned_variables.py index edcc0e1d7c..174cabdf80 100644 --- a/tensorflow/python/ops/partitioned_variables.py +++ b/tensorflow/python/ops/partitioned_variables.py @@ -58,6 +58,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import tensor_shape from tensorflow.python.ops import variable_scope from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.util.tf_export import tf_export __all__ = [ "create_partitioned_variables", @@ -67,6 +68,7 @@ __all__ = [ ] +@tf_export("variable_axis_size_partitioner") def variable_axis_size_partitioner( max_shard_bytes, axis=0, bytes_per_string_element=16, max_shards=None): """Get a partitioner for VariableScope to keep shards below `max_shard_bytes`. @@ -151,6 +153,7 @@ def variable_axis_size_partitioner( return _partitioner +@tf_export("min_max_variable_partitioner") def min_max_variable_partitioner(max_partitions=1, axis=0, min_slice_size=256 << 10, bytes_per_string_element=16): @@ -214,6 +217,7 @@ def min_max_variable_partitioner(max_partitions=1, axis=0, return _partitioner +@tf_export("fixed_size_partitioner") def fixed_size_partitioner(num_shards, axis=0): """Partitioner to specify a fixed number of shards along given axis. @@ -232,6 +236,7 @@ def fixed_size_partitioner(num_shards, axis=0): return _partitioner +@tf_export("create_partitioned_variables") def create_partitioned_variables( shape, slicing, initializer, dtype=dtypes.float32, trainable=True, collections=None, name=None, reuse=None): diff --git a/tensorflow/python/ops/random_ops.py b/tensorflow/python/ops/random_ops.py index a2264a7bdf..2c86358d21 100644 --- a/tensorflow/python/ops/random_ops.py +++ b/tensorflow/python/ops/random_ops.py @@ -29,6 +29,7 @@ from tensorflow.python.ops import math_ops # go/tf-wildcard-import # pylint: disable=wildcard-import from tensorflow.python.ops.gen_random_ops import * +from tensorflow.python.util.tf_export import tf_export # pylint: enable=wildcard-import @@ -43,6 +44,7 @@ def _ShapeTensor(shape): # pylint: disable=protected-access +@tf_export("random_normal") def random_normal(shape, mean=0.0, stddev=1.0, @@ -135,6 +137,7 @@ def parameterized_truncated_normal(shape, return rnd +@tf_export("truncated_normal") def truncated_normal(shape, mean=0.0, stddev=1.0, @@ -179,6 +182,7 @@ ops.NotDifferentiable("ParameterizedTruncatedNormal") ops.NotDifferentiable("TruncatedNormal") +@tf_export("random_uniform") def random_uniform(shape, minval=0, maxval=None, @@ -244,6 +248,7 @@ def random_uniform(shape, ops.NotDifferentiable("RandomUniform") +@tf_export("random_shuffle") def random_shuffle(value, seed=None, name=None): """Randomly shuffles a tensor along its first dimension. @@ -274,6 +279,7 @@ def random_shuffle(value, seed=None, name=None): value, seed=seed1, seed2=seed2, name=name) +@tf_export("random_crop") def random_crop(value, size, seed=None, name=None): """Randomly crops a tensor to a given size. @@ -316,6 +322,7 @@ def random_crop(value, size, seed=None, name=None): return array_ops.slice(value, offset, size, name=name) +@tf_export("multinomial") def multinomial(logits, num_samples, seed=None, name=None, output_dtype=None): """Draws samples from a multinomial distribution. @@ -351,6 +358,7 @@ def multinomial(logits, num_samples, seed=None, name=None, output_dtype=None): ops.NotDifferentiable("Multinomial") +@tf_export("random_gamma") def random_gamma(shape, alpha, beta=None, @@ -418,6 +426,7 @@ def random_gamma(shape, ops.NotDifferentiable("RandomGamma") +@tf_export("random_poisson") def random_poisson(lam, shape, dtype=dtypes.float32, seed=None, name=None): """Draws `shape` samples from each of the given Poisson distribution(s). diff --git a/tensorflow/python/ops/rnn.py b/tensorflow/python/ops/rnn.py index fd14740a00..a079b4485f 100644 --- a/tensorflow/python/ops/rnn.py +++ b/tensorflow/python/ops/rnn.py @@ -41,6 +41,7 @@ from tensorflow.python.ops import rnn_cell_impl from tensorflow.python.ops import tensor_array_ops from tensorflow.python.ops import variable_scope as vs from tensorflow.python.util import nest +from tensorflow.python.util.tf_export import tf_export # pylint: disable=protected-access @@ -321,6 +322,7 @@ def _reverse_seq(input_seq, lengths): return results +@tf_export("nn.bidirectional_dynamic_rnn") def bidirectional_dynamic_rnn(cell_fw, cell_bw, inputs, sequence_length=None, initial_state_fw=None, initial_state_bw=None, dtype=None, parallel_iterations=None, @@ -450,6 +452,7 @@ def bidirectional_dynamic_rnn(cell_fw, cell_bw, inputs, sequence_length=None, return (outputs, output_states) +@tf_export("nn.dynamic_rnn") def dynamic_rnn(cell, inputs, sequence_length=None, initial_state=None, dtype=None, parallel_iterations=None, swap_memory=False, time_major=False, scope=None): @@ -850,6 +853,7 @@ def _dynamic_rnn_loop(cell, return (final_outputs, final_state) +@tf_export("nn.raw_rnn") def raw_rnn(cell, loop_fn, parallel_iterations=None, swap_memory=False, scope=None): """Creates an `RNN` specified by RNNCell `cell` and loop function `loop_fn`. @@ -1157,6 +1161,7 @@ def raw_rnn(cell, loop_fn, return (emit_ta, final_state, final_loop_state) +@tf_export("nn.static_rnn") def static_rnn(cell, inputs, initial_state=None, @@ -1326,6 +1331,7 @@ def static_rnn(cell, return (outputs, state) +@tf_export("nn.static_state_saving_rnn") def static_state_saving_rnn(cell, inputs, state_saver, @@ -1410,6 +1416,7 @@ def static_state_saving_rnn(cell, return (outputs, state) +@tf_export("nn.static_bidirectional_rnn") def static_bidirectional_rnn(cell_fw, cell_bw, inputs, diff --git a/tensorflow/python/ops/rnn_cell_impl.py b/tensorflow/python/ops/rnn_cell_impl.py index b41aff76d4..1bf5551aff 100644 --- a/tensorflow/python/ops/rnn_cell_impl.py +++ b/tensorflow/python/ops/rnn_cell_impl.py @@ -47,6 +47,7 @@ from tensorflow.python.ops import variable_scope as vs from tensorflow.python.ops import variables as tf_variables from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import nest +from tensorflow.python.util.tf_export import tf_export _BIAS_VARIABLE_NAME = "bias" @@ -133,6 +134,7 @@ def _zero_state_tensors(state_size, batch_size, dtype): return nest.map_structure(get_state_shape, state_size) +@tf_export("nn.rnn_cell.RNNCell") class RNNCell(base_layer.Layer): """Abstract object representing an RNN cell. @@ -294,6 +296,7 @@ class _LayerRNNCell(RNNCell): *args, **kwargs) +@tf_export("nn.rnn_cell.BasicRNNCell") class BasicRNNCell(_LayerRNNCell): """The most basic RNN cell. @@ -351,6 +354,7 @@ class BasicRNNCell(_LayerRNNCell): return output, output +@tf_export("nn.rnn_cell.GRUCell") class GRUCell(_LayerRNNCell): """Gated Recurrent Unit cell (cf. http://arxiv.org/abs/1406.1078). @@ -448,6 +452,7 @@ class GRUCell(_LayerRNNCell): _LSTMStateTuple = collections.namedtuple("LSTMStateTuple", ("c", "h")) +@tf_export("nn.rnn_cell.LSTMStateTuple") class LSTMStateTuple(_LSTMStateTuple): """Tuple used by LSTM Cells for `state_size`, `zero_state`, and output state. @@ -467,6 +472,7 @@ class LSTMStateTuple(_LSTMStateTuple): return c.dtype +@tf_export("nn.rnn_cell.BasicLSTMCell") class BasicLSTMCell(_LayerRNNCell): """Basic LSTM recurrent network cell. @@ -591,6 +597,7 @@ class BasicLSTMCell(_LayerRNNCell): return new_h, new_state +@tf_export("nn.rnn_cell.LSTMCell") class LSTMCell(_LayerRNNCell): """Long short-term memory unit (LSTM) recurrent network cell. @@ -834,6 +841,7 @@ def _default_dropout_state_filter_visitor(substate): return True +@tf_export("nn.rnn_cell.DropoutWrapper") class DropoutWrapper(RNNCell): """Operator adding dropout to inputs and outputs of the given cell.""" @@ -1058,6 +1066,7 @@ class DropoutWrapper(RNNCell): return output, new_state +@tf_export("nn.rnn_cell.ResidualWrapper") class ResidualWrapper(RNNCell): """RNNCell wrapper that ensures cell inputs are added to the outputs.""" @@ -1113,6 +1122,7 @@ class ResidualWrapper(RNNCell): return (res_outputs, new_state) +@tf_export("nn.rnn_cell.DeviceWrapper") class DeviceWrapper(RNNCell): """Operator that ensures an RNNCell runs on a particular device.""" @@ -1147,6 +1157,7 @@ class DeviceWrapper(RNNCell): return self._cell(inputs, state, scope=scope) +@tf_export("nn.rnn_cell.MultiRNNCell") class MultiRNNCell(RNNCell): """RNN cell composed sequentially of multiple simple cells.""" diff --git a/tensorflow/python/ops/script_ops.py b/tensorflow/python/ops/script_ops.py index c0c1ade495..4b5072fd67 100644 --- a/tensorflow/python/ops/script_ops.py +++ b/tensorflow/python/ops/script_ops.py @@ -33,6 +33,7 @@ from tensorflow.python.eager import context from tensorflow.python.framework import function from tensorflow.python.framework import ops from tensorflow.python.ops import gen_script_ops +from tensorflow.python.util.tf_export import tf_export class EagerFunc(object): @@ -243,6 +244,7 @@ def eager_py_func(func, inp, Tout, name=None): return _internal_py_func(func=func, inp=inp, Tout=Tout, eager=True, name=name) +@tf_export("py_func") def py_func(func, inp, Tout, stateful=True, name=None): """Wraps a python function and uses it as a TensorFlow op. diff --git a/tensorflow/python/ops/session_ops.py b/tensorflow/python/ops/session_ops.py index dc4d913c93..cedd36c1de 100644 --- a/tensorflow/python/ops/session_ops.py +++ b/tensorflow/python/ops/session_ops.py @@ -36,6 +36,7 @@ from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_data_flow_ops from tensorflow.python.util import compat +from tensorflow.python.util.tf_export import tf_export def encode_resource_handle(resource_handle): @@ -141,6 +142,7 @@ class TensorHandle(object): return feeder.op.name + ";" + TensorHandle._get_reader_key(handle) +@tf_export("get_session_handle") def get_session_handle(data, name=None): """Return the handle of `data`. @@ -183,6 +185,7 @@ def get_session_handle(data, name=None): return gen_data_flow_ops._get_session_handle(data, name=name) # pylint: disable=protected-access +@tf_export("get_session_tensor") def get_session_tensor(handle, dtype, name=None): """Get the tensor of type `dtype` by feeding a tensor handle. @@ -223,6 +226,7 @@ def get_session_tensor(handle, dtype, name=None): return (holder, tensor) +@tf_export("delete_session_tensor") def delete_session_tensor(handle, name=None): """Delete the tensor for the given tensor handle. diff --git a/tensorflow/python/ops/sets_impl.py b/tensorflow/python/ops/sets_impl.py index 6aa9e3419e..b0eecd8a1e 100644 --- a/tensorflow/python/ops/sets_impl.py +++ b/tensorflow/python/ops/sets_impl.py @@ -23,6 +23,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.ops import gen_set_ops +from tensorflow.python.util.tf_export import tf_export _VALID_DTYPES = set([ @@ -30,6 +31,7 @@ _VALID_DTYPES = set([ dtypes.uint8, dtypes.uint16, dtypes.string]) +@tf_export("sets.set_size") def set_size(a, validate_indices=True): """Compute number of unique elements along last dimension of `a`. @@ -131,6 +133,7 @@ def _set_operation(a, b, set_operation, validate_indices=True): return sparse_tensor.SparseTensor(indices, values, shape) +@tf_export("sets.set_intersection") def set_intersection(a, b, validate_indices=True): """Compute set intersection of elements in last dimension of `a` and `b`. @@ -197,6 +200,7 @@ def set_intersection(a, b, validate_indices=True): return _set_operation(a, b, "intersection", validate_indices) +@tf_export("sets.set_difference") def set_difference(a, b, aminusb=True, validate_indices=True): """Compute set difference of elements in last dimension of `a` and `b`. @@ -267,6 +271,7 @@ def set_difference(a, b, aminusb=True, validate_indices=True): return _set_operation(a, b, "a-b" if aminusb else "b-a", validate_indices) +@tf_export("sets.set_union") def set_union(a, b, validate_indices=True): """Compute set union of elements in last dimension of `a` and `b`. diff --git a/tensorflow/python/ops/sparse_ops.py b/tensorflow/python/ops/sparse_ops.py index c368d166f5..3224856d7b 100644 --- a/tensorflow/python/ops/sparse_ops.py +++ b/tensorflow/python/ops/sparse_ops.py @@ -65,6 +65,7 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops.gen_sparse_ops import * # pylint: enable=wildcard-import from tensorflow.python.util import deprecation +from tensorflow.python.util.tf_export import tf_export def _convert_to_sparse_tensor(sp_input): @@ -108,6 +109,7 @@ def _convert_to_sparse_tensors(sp_inputs): # pylint: disable=protected-access +@tf_export("sparse_concat") def sparse_concat(axis, sp_inputs, name=None, @@ -236,6 +238,7 @@ def sparse_concat(axis, return sparse_tensor.SparseTensor(output_ind, output_val, output_shape) +@tf_export("sparse_add") def sparse_add(a, b, thresh=0): """Adds two tensors, at least one of each is a `SparseTensor`. @@ -463,6 +466,7 @@ def sparse_dense_cwise_add(sp_t, dense_t): return sparse_tensor.SparseTensor(sp_t.indices, result, sp_t.dense_shape) +@tf_export("sparse_reorder") def sparse_reorder(sp_input, name=None): """Reorders a `SparseTensor` into the canonical, row-major ordering. @@ -511,6 +515,7 @@ def sparse_reorder(sp_input, name=None): return sparse_tensor.SparseTensor(reordered_ind, reordered_val, dense_shape) +@tf_export("sparse_reshape") def sparse_reshape(sp_input, shape, name=None): """Reshapes a `SparseTensor` to represent values in a new dense shape. @@ -603,6 +608,7 @@ class KeywordRequired(object): return "KeywordRequired()" +@tf_export("sparse_split") def sparse_split(keyword_required=KeywordRequired(), sp_input=None, num_split=None, axis=None, name=None, split_dim=None): @@ -669,6 +675,7 @@ def sparse_split(keyword_required=KeywordRequired(), return sparse_tensors +@tf_export("sparse_slice") def sparse_slice(sp_input, start, size, name=None): """Slice a `SparseTensor` based on the `start` and `size. @@ -713,6 +720,8 @@ def sparse_slice(sp_input, start, size, name=None): output_values, output_shape) + +@tf_export("sparse_to_dense") def sparse_to_dense(sparse_indices, output_shape, sparse_values, @@ -768,6 +777,7 @@ def sparse_to_dense(sparse_indices, name=name) +@tf_export("sparse_reduce_max") def sparse_reduce_max(sp_input, axis=None, keep_dims=False, reduction_axes=None): """Computes the max of elements across dimensions of a SparseTensor. @@ -815,6 +825,7 @@ def sparse_reduce_max(sp_input, axis=None, keep_dims=False, keep_dims) +@tf_export("sparse_reduce_max_sparse") def sparse_reduce_max_sparse(sp_input, axis=None, keep_dims=False, reduction_axes=None): """Computes the max of elements across dimensions of a SparseTensor. @@ -852,6 +863,7 @@ def sparse_reduce_max_sparse(sp_input, axis=None, keep_dims=False, return sparse_tensor.SparseTensor(output_ind, output_val, output_shape) +@tf_export("sparse_reduce_sum") def sparse_reduce_sum(sp_input, axis=None, keep_dims=False, reduction_axes=None): """Computes the sum of elements across dimensions of a SparseTensor. @@ -899,6 +911,7 @@ def sparse_reduce_sum(sp_input, axis=None, keep_dims=False, keep_dims) +@tf_export("sparse_reduce_sum_sparse") def sparse_reduce_sum_sparse(sp_input, axis=None, keep_dims=False, reduction_axes=None): """Computes the sum of elements across dimensions of a SparseTensor. @@ -936,6 +949,7 @@ def sparse_reduce_sum_sparse(sp_input, axis=None, keep_dims=False, return sparse_tensor.SparseTensor(output_ind, output_val, output_shape) +@tf_export("sparse_tensor_to_dense") def sparse_tensor_to_dense(sp_input, default_value=0, validate_indices=True, @@ -987,6 +1001,7 @@ def sparse_tensor_to_dense(sp_input, name=name) +@tf_export("sparse_to_indicator") def sparse_to_indicator(sp_input, vocab_size, name=None): """Converts a `SparseTensor` of ids into a dense bool indicator tensor. @@ -1049,6 +1064,7 @@ def sparse_to_indicator(sp_input, vocab_size, name=None): sp_new, default_value=False, validate_indices=False, name=name) +@tf_export("sparse_merge") def sparse_merge(sp_ids, sp_values, vocab_size, name=None, already_sorted=False): """Combines a batch of feature ids and values into a single `SparseTensor`. @@ -1189,6 +1205,7 @@ def sparse_merge(sp_ids, sp_values, vocab_size, name=None, return result if already_sorted else sparse_reorder(result) +@tf_export("sparse_retain") def sparse_retain(sp_input, to_retain): """Retains specified non-empty values within a `SparseTensor`. @@ -1232,6 +1249,7 @@ def sparse_retain(sp_input, to_retain): array_ops.identity(sp_input.dense_shape)) +@tf_export("sparse_reset_shape") def sparse_reset_shape(sp_input, new_shape=None): """Resets the shape of a `SparseTensor` with indices and values unchanged. @@ -1333,6 +1351,7 @@ def sparse_reset_shape(sp_input, new_shape=None): return sparse_tensor.SparseTensor(in_indices, in_values, output_shape_tensor) +@tf_export("sparse_fill_empty_rows") def sparse_fill_empty_rows(sp_input, default_value, name=None): """Fills empty rows in the input 2-D `SparseTensor` with a default value. @@ -1396,6 +1415,7 @@ def sparse_fill_empty_rows(sp_input, default_value, name=None): empty_row_indicator) +@tf_export("serialize_sparse") def serialize_sparse(sp_input, name=None, out_type=dtypes.string): """Serialize a `SparseTensor` into a 3-vector (1-D `Tensor`) object. @@ -1421,6 +1441,7 @@ def serialize_sparse(sp_input, name=None, out_type=dtypes.string): out_type=out_type) +@tf_export("serialize_many_sparse") def serialize_many_sparse(sp_input, name=None, out_type=dtypes.string): """Serialize `N`-minibatch `SparseTensor` into an `[N, 3]` `Tensor`. @@ -1521,6 +1542,7 @@ def deserialize_sparse(serialized_sparse, dtype, rank=None, name=None): return sparse_tensor.SparseTensor(output_indices, output_values, output_shape) +@tf_export("deserialize_many_sparse") def deserialize_many_sparse(serialized_sparse, dtype, rank=None, name=None): """Deserialize and concatenate `SparseTensors` from a serialized minibatch. @@ -1590,6 +1612,7 @@ def deserialize_many_sparse(serialized_sparse, dtype, rank=None, name=None): return sparse_tensor.SparseTensor(output_indices, output_values, output_shape) +@tf_export("sparse_tensor_dense_matmul") def sparse_tensor_dense_matmul(sp_a, b, adjoint_a=False, @@ -1806,6 +1829,7 @@ def sparse_tensor_dense_matmul(sp_a, adjoint_b=adjoint_b) +@tf_export("sparse_softmax") def sparse_softmax(sp_input, name=None): """Applies softmax to a batched N-D `SparseTensor`. @@ -1860,6 +1884,7 @@ def sparse_softmax(sp_input, name=None): sp_input.indices, out_vals, sp_input.dense_shape) +@tf_export("sparse_maximum") def sparse_maximum(sp_a, sp_b, name=None): """Returns the element-wise max of two SparseTensors. @@ -1896,6 +1921,7 @@ def sparse_maximum(sp_a, sp_b, name=None): return sparse_tensor.SparseTensor(out_indices, out_values, sp_a.dense_shape) +@tf_export("sparse_minimum") def sparse_minimum(sp_a, sp_b, name=None): """Returns the element-wise min of two SparseTensors. @@ -1932,6 +1958,7 @@ def sparse_minimum(sp_a, sp_b, name=None): return sparse_tensor.SparseTensor(out_indices, out_values, sp_a.dense_shape) +@tf_export("sparse_transpose") def sparse_transpose(sp_input, perm=None, name=None): """Transposes a `SparseTensor` diff --git a/tensorflow/python/ops/special_math_ops.py b/tensorflow/python/ops/special_math_ops.py index fe3f734322..1990087072 100644 --- a/tensorflow/python/ops/special_math_ops.py +++ b/tensorflow/python/ops/special_math_ops.py @@ -31,9 +31,11 @@ from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.util.tf_export import tf_export # TODO(b/27419586) Change docstring for required dtype of x once int allowed +@tf_export('lbeta') def lbeta(x, name='lbeta'): r"""Computes \\(ln(|Beta(x)|)\\), reducing along the last dimension. @@ -82,6 +84,7 @@ def lbeta(x, name='lbeta'): return result +@tf_export('einsum', 'linalg.einsum') def einsum(equation, *inputs, **kwargs): """A generalized contraction between tensors of arbitrary dimension. diff --git a/tensorflow/python/ops/spectral_ops.py b/tensorflow/python/ops/spectral_ops.py index 69f868c67a..a579688276 100644 --- a/tensorflow/python/ops/spectral_ops.py +++ b/tensorflow/python/ops/spectral_ops.py @@ -41,6 +41,7 @@ from tensorflow.python.ops import array_ops as _array_ops from tensorflow.python.ops import gen_spectral_ops from tensorflow.python.ops import math_ops as _math_ops from tensorflow.python.util.all_util import remove_undocumented +from tensorflow.python.util.tf_export import tf_export def _infer_fft_length_for_rfft(input_tensor, fft_rank): @@ -164,11 +165,17 @@ ifft2d = gen_spectral_ops.ifft2d fft3d = gen_spectral_ops.fft3d ifft3d = gen_spectral_ops.ifft3d rfft = _rfft_wrapper(gen_spectral_ops.rfft, 1, "rfft") +tf_export("spectral.rfft")(rfft) irfft = _irfft_wrapper(gen_spectral_ops.irfft, 1, "irfft") +tf_export("spectral.irfft")(irfft) rfft2d = _rfft_wrapper(gen_spectral_ops.rfft2d, 2, "rfft2d") +tf_export("spectral.rfft2d")(rfft2d) irfft2d = _irfft_wrapper(gen_spectral_ops.irfft2d, 2, "irfft2d") +tf_export("spectral.irfft2d")(irfft2d) rfft3d = _rfft_wrapper(gen_spectral_ops.rfft3d, 3, "rfft3d") +tf_export("spectral.rfft3d")(rfft3d) irfft3d = _irfft_wrapper(gen_spectral_ops.irfft3d, 3, "irfft3d") +tf_export("spectral.irfft3d")(irfft3d) def _validate_dct_arguments(dct_type, n, axis, norm): @@ -184,6 +191,7 @@ def _validate_dct_arguments(dct_type, n, axis, norm): # TODO(rjryan): Implement `type`, `n` and `axis` parameters. +@tf_export("spectral.dct") def dct(input, type=2, n=None, axis=-1, norm=None, name=None): # pylint: disable=redefined-builtin """Computes the 1D [Discrete Cosine Transform (DCT)][dct] of `input`. diff --git a/tensorflow/python/ops/state_ops.py b/tensorflow/python/ops/state_ops.py index dee495f78f..3cc76fdbf3 100644 --- a/tensorflow/python/ops/state_ops.py +++ b/tensorflow/python/ops/state_ops.py @@ -89,6 +89,7 @@ from tensorflow.python.ops import gen_state_ops # go/tf-wildcard-import # pylint: disable=wildcard-import from tensorflow.python.ops.gen_state_ops import * +from tensorflow.python.util.tf_export import tf_export # pylint: enable=wildcard-import @@ -189,6 +190,7 @@ def is_variable_initialized(ref, name=None): name=name) +@tf_export("assign_sub") def assign_sub(ref, value, use_locking=None, name=None): """Update 'ref' by subtracting 'value' from it. @@ -217,6 +219,7 @@ def assign_sub(ref, value, use_locking=None, name=None): return ref.assign_sub(value) +@tf_export("assign_add") def assign_add(ref, value, use_locking=None, name=None): """Update 'ref' by adding 'value' to it. @@ -245,6 +248,7 @@ def assign_add(ref, value, use_locking=None, name=None): return ref.assign_add(value) +@tf_export("assign") def assign(ref, value, validate_shape=None, use_locking=None, name=None): """Update 'ref' by assigning 'value' to it. @@ -277,6 +281,7 @@ def assign(ref, value, validate_shape=None, use_locking=None, name=None): return ref.assign(value) +@tf_export("count_up_to") def count_up_to(ref, limit, name=None): r"""Increments 'ref' until it reaches 'limit'. @@ -299,6 +304,7 @@ def count_up_to(ref, limit, name=None): ref.handle, limit, T=ref.dtype, name=name) +@tf_export("scatter_update") def scatter_update(ref, indices, updates, use_locking=True, name=None): # pylint: disable=line-too-long r"""Applies sparse updates to a variable reference. @@ -354,6 +360,7 @@ def scatter_update(ref, indices, updates, use_locking=True, name=None): return ref.read_value() +@tf_export("scatter_nd_update") def scatter_nd_update(ref, indices, updates, use_locking=True, name=None): r"""Applies sparse `updates` to individual values or slices in a Variable. diff --git a/tensorflow/python/ops/string_ops.py b/tensorflow/python/ops/string_ops.py index f30e79a108..b8c39d91b4 100644 --- a/tensorflow/python/ops/string_ops.py +++ b/tensorflow/python/ops/string_ops.py @@ -47,9 +47,11 @@ from tensorflow.python.ops import math_ops # pylint: disable=wildcard-import from tensorflow.python.ops.gen_string_ops import * from tensorflow.python.util import deprecation +from tensorflow.python.util.tf_export import tf_export # pylint: enable=wildcard-import +@tf_export("string_split") def string_split(source, delimiter=" ", skip_empty=True): # pylint: disable=invalid-name """Split elements of `source` based on `delimiter` into a `SparseTensor`. @@ -120,6 +122,7 @@ def _reduce_join_reduction_dims(x, axis, reduction_indices): return math_ops.range(array_ops.rank(x) - 1, -1, -1) +@tf_export("reduce_join") def reduce_join(inputs, axis=None, keep_dims=False, separator="", diff --git a/tensorflow/python/ops/summary_ops.py b/tensorflow/python/ops/summary_ops.py index 2cf2eda16e..7f4f4ce5ab 100644 --- a/tensorflow/python/ops/summary_ops.py +++ b/tensorflow/python/ops/summary_ops.py @@ -25,9 +25,11 @@ from tensorflow.python.ops import summary_op_util # go/tf-wildcard-import # pylint: disable=wildcard-import from tensorflow.python.ops.gen_logging_ops import * +from tensorflow.python.util.tf_export import tf_export # pylint: enable=wildcard-import +@tf_export("summary.tensor_summary") def tensor_summary(name, tensor, summary_description=None, diff --git a/tensorflow/python/ops/template.py b/tensorflow/python/ops/template.py index 99a71cbe79..84449e00be 100644 --- a/tensorflow/python/ops/template.py +++ b/tensorflow/python/ops/template.py @@ -29,11 +29,13 @@ from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import tf_contextlib from tensorflow.python.util import tf_decorator from tensorflow.python.util.deprecation import deprecated +from tensorflow.python.util.tf_export import tf_export __all__ = ["make_template"] +@tf_export("make_template") def make_template(name_, func_, create_scope_now_=False, unique_name_=None, custom_getter_=None, **kwargs): """Given an arbitrary function, wrap it so that it does variable sharing. diff --git a/tensorflow/python/ops/tensor_array_ops.py b/tensorflow/python/ops/tensor_array_ops.py index 398521c9b5..5cdf03509e 100644 --- a/tensorflow/python/ops/tensor_array_ops.py +++ b/tensorflow/python/ops/tensor_array_ops.py @@ -35,6 +35,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_data_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.util import tf_should_use +from tensorflow.python.util.tf_export import tf_export # _GraphTensorArray accesses many of the hidden generated ops, but is in @@ -711,6 +712,7 @@ class _EagerTensorArray(object): # TensorArray is designed to hide an underlying implementation object # and as such accesses many of that object's hidden fields. # pylint: disable=protected-access +@tf_export("TensorArray") class TensorArray(object): """Class wrapping dynamic-sized, per-time-step, write-once Tensor arrays. diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index 1facb8b1f2..c52d5fff5d 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -40,6 +40,7 @@ from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import variables from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import tf_contextlib +from tensorflow.python.util.tf_export import tf_export __all__ = ["AUTO_REUSE", "VariableScope", "get_variable_scope", "get_variable", "get_local_variable", "variable_scope", @@ -186,6 +187,7 @@ class _ReuseMode(enum.Enum): # REUSE_TRUE = 3 AUTO_REUSE = _ReuseMode.AUTO_REUSE +tf_export("AUTO_REUSE").export_constant(__name__, "AUTO_REUSE") AUTO_REUSE.__doc__ = """ When passed in as the value for the `reuse` flag, AUTO_REUSE indicates that get_variable() should create the requested variable if it doesn't exist or, if @@ -853,12 +855,14 @@ class _VariableStore(object): # To stop regularization, use this regularizer +@tf_export("no_regularizer") def no_regularizer(_): """Use this function to prevent regularization of variables.""" return None # TODO(alive): support caching devices and partitioned variables in Eager mode. +@tf_export("VariableScope") class VariableScope(object): """Variable scope object to carry defaults to provide to `get_variable`. @@ -1158,6 +1162,7 @@ _VARSTORE_KEY = ("__variable_store",) _VARSCOPE_KEY = ("__varscope",) +@tf_export("get_variable_scope") def get_variable_scope(): """Returns the current variable scope.""" scope = ops.get_collection(_VARSCOPE_KEY) @@ -1238,6 +1243,7 @@ class EagerVariableStore(object): # pylint: enable=protected-access +@tf_export("get_variable") def get_variable(name, shape=None, dtype=None, @@ -1349,6 +1355,7 @@ get_variable.__doc__ = get_variable_or_local_docstring % ( @functools.wraps(get_variable) +@tf_export("get_local_variable") def get_local_variable(*args, **kwargs): kwargs["trainable"] = False if "collections" in kwargs: @@ -1663,7 +1670,8 @@ def _get_unique_variable_scope(prefix): # Named like a function for backwards compatibility with the # @tf_contextlib.contextmanager version, which was switched to a class to avoid # some object creation overhead. -class variable_scope(object): # pylint: disable=invalid-name +@tf_export("variable_scope") # pylint: disable=invalid-name +class variable_scope(object): """A context manager for defining ops that creates variables (layers). This context manager validates that the (optional) `values` are from the same @@ -1996,6 +2004,7 @@ class variable_scope(object): # pylint: disable=invalid-name # pylint: disable=g-doc-return-or-yield +@tf_export("variable_op_scope") @tf_contextlib.contextmanager def variable_op_scope(values, name_or_scope, diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index b25855633e..7d7fa646c0 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -31,8 +31,10 @@ from tensorflow.python.ops import state_ops from tensorflow.python.util import compat from tensorflow.python.util import tf_should_use from tensorflow.python.util.deprecation import deprecated +from tensorflow.python.util.tf_export import tf_export +@tf_export("Variable") class Variable(object): """See the @{$variables$Variables How To} for a high level overview. @@ -1308,6 +1310,7 @@ class PartitionedVariable(object): "assign() has not been implemented for PartitionedVariable.") +@tf_export("global_variables") def global_variables(scope=None): """Returns global variables. @@ -1333,6 +1336,7 @@ def global_variables(scope=None): return ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES, scope) +@tf_export("all_variables") @deprecated("2017-03-02", "Please use tf.global_variables instead.") def all_variables(): """See `tf.global_variables`.""" @@ -1357,6 +1361,7 @@ def _all_saveable_objects(scope=None): ops.get_collection(ops.GraphKeys.SAVEABLE_OBJECTS, scope)) +@tf_export("local_variables") def local_variables(scope=None): """Returns local variables. @@ -1384,6 +1389,7 @@ def local_variables(scope=None): return ops.get_collection(ops.GraphKeys.LOCAL_VARIABLES, scope) +@tf_export("model_variables") def model_variables(scope=None): """Returns all variables in the MODEL_VARIABLES collection. @@ -1400,6 +1406,7 @@ def model_variables(scope=None): return ops.get_collection(ops.GraphKeys.MODEL_VARIABLES, scope) +@tf_export("trainable_variables") def trainable_variables(scope=None): """Returns all variables created with `trainable=True`. @@ -1421,6 +1428,7 @@ def trainable_variables(scope=None): return ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES, scope) +@tf_export("moving_average_variables") def moving_average_variables(scope=None): """Returns all variables that maintain their moving averages. @@ -1442,6 +1450,7 @@ def moving_average_variables(scope=None): return ops.get_collection(ops.GraphKeys.MOVING_AVERAGE_VARIABLES, scope) +@tf_export("initializers.variables", "variables_initializer") def variables_initializer(var_list, name="init"): """Returns an Op that initializes a list of variables. @@ -1467,6 +1476,7 @@ def variables_initializer(var_list, name="init"): return control_flow_ops.no_op(name=name) +@tf_export("initialize_variables") @tf_should_use.should_use_result @deprecated("2017-03-02", "Use `tf.variables_initializer` instead.") def initialize_variables(var_list, name="init"): @@ -1474,6 +1484,7 @@ def initialize_variables(var_list, name="init"): return variables_initializer(var_list, name=name) +@tf_export("initializers.global_variables", "global_variables_initializer") def global_variables_initializer(): """Returns an Op that initializes global variables. @@ -1487,6 +1498,7 @@ def global_variables_initializer(): return variables_initializer(global_variables()) +@tf_export("initialize_all_variables") @tf_should_use.should_use_result @deprecated("2017-03-02", "Use `tf.global_variables_initializer` instead.") def initialize_all_variables(): @@ -1494,6 +1506,7 @@ def initialize_all_variables(): return global_variables_initializer() +@tf_export("initializers.local_variables", "local_variables_initializer") def local_variables_initializer(): """Returns an Op that initializes all local variables. @@ -1507,6 +1520,7 @@ def local_variables_initializer(): return variables_initializer(local_variables()) +@tf_export("initialize_local_variables") @tf_should_use.should_use_result @deprecated("2017-03-02", "Use `tf.local_variables_initializer` instead.") def initialize_local_variables(): @@ -1514,6 +1528,7 @@ def initialize_local_variables(): return local_variables_initializer() +@tf_export("is_variable_initialized") @tf_should_use.should_use_result def is_variable_initialized(variable): """Tests if a variable has been initialized. @@ -1528,6 +1543,7 @@ def is_variable_initialized(variable): return state_ops.is_variable_initialized(variable) +@tf_export("assert_variables_initialized") @tf_should_use.should_use_result def assert_variables_initialized(var_list=None): """Returns an Op to check if variables are initialized. @@ -1570,6 +1586,7 @@ def assert_variables_initialized(var_list=None): return array_ops.stack(ranks) +@tf_export("report_uninitialized_variables") @tf_should_use.should_use_result def report_uninitialized_variables(var_list=None, name="report_uninitialized_variables"): diff --git a/tensorflow/tools/api/generator/BUILD b/tensorflow/tools/api/generator/BUILD index 795b983821..26f5223334 100644 --- a/tensorflow/tools/api/generator/BUILD +++ b/tensorflow/tools/api/generator/BUILD @@ -66,6 +66,12 @@ genrule( "api/resource_loader/__init__.py", "api/sysconfig/__init__.py", "api/test/__init__.py", + "api/initializers/__init__.py", + "api/keras/initializers/__init__.py", + "api/metrics/__init__.py", + "api/nn/rnn_cell/__init__.py", + "api/sets/__init__.py", + "api/summary/__init__.py", ], cmd = "$(location create_python_api) $(OUTS)", tools = ["create_python_api"], -- GitLab From 6042b5d267f42d004087b44c29525951700579f9 Mon Sep 17 00:00:00 2001 From: Jeremy Lau Date: Mon, 22 Jan 2018 17:26:43 -0800 Subject: [PATCH 079/258] Reject retried RecvTensor requests. Retried RecvTensorRequests are problematic because a RecvTensor with no corresponding sender will wait forever, and the tensor may have been delivered to a previous retry. This change adds a unique request_id to each RecvTensor request, and we check these request_ids against a set of recent request_ids. If a request_id is in the recent set, we reject the RecvTensor request. PiperOrigin-RevId: 182863245 --- tensorflow/contrib/gdr/BUILD | 2 + tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc | 2 + tensorflow/contrib/gdr/gdr_worker.cc | 13 ++- tensorflow/contrib/gdr/gdr_worker.h | 2 + tensorflow/contrib/mpi/BUILD | 2 + tensorflow/contrib/mpi/mpi_rendezvous_mgr.cc | 8 +- tensorflow/contrib/mpi/mpi_rendezvous_mgr.h | 6 +- tensorflow/core/distributed_runtime/BUILD | 44 +++++++++ .../distributed_runtime/recent_request_ids.cc | 57 +++++++++++ .../distributed_runtime/recent_request_ids.h | 72 ++++++++++++++ .../recent_request_ids_test.cc | 96 +++++++++++++++++++ .../core/distributed_runtime/request_id.cc | 30 ++++++ .../core/distributed_runtime/request_id.h | 31 ++++++ .../distributed_runtime/request_id_test.cc | 29 ++++++ tensorflow/core/distributed_runtime/rpc/BUILD | 2 + .../rpc/grpc_worker_service.cc | 12 ++- .../rpc/grpc_worker_service.h | 4 + .../rpc/rpc_rendezvous_mgr.cc | 2 + tensorflow/core/protobuf/worker.proto | 15 ++- 19 files changed, 421 insertions(+), 8 deletions(-) create mode 100644 tensorflow/core/distributed_runtime/recent_request_ids.cc create mode 100644 tensorflow/core/distributed_runtime/recent_request_ids.h create mode 100644 tensorflow/core/distributed_runtime/recent_request_ids_test.cc create mode 100644 tensorflow/core/distributed_runtime/request_id.cc create mode 100644 tensorflow/core/distributed_runtime/request_id.h create mode 100644 tensorflow/core/distributed_runtime/request_id_test.cc diff --git a/tensorflow/contrib/gdr/BUILD b/tensorflow/contrib/gdr/BUILD index bdbe6f0a72..707ae25d48 100644 --- a/tensorflow/contrib/gdr/BUILD +++ b/tensorflow/contrib/gdr/BUILD @@ -82,6 +82,7 @@ tf_cuda_library( "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "//tensorflow/core/distributed_runtime:graph_mgr", + "//tensorflow/core/distributed_runtime:recent_request_ids", "//tensorflow/core/distributed_runtime:rendezvous_mgr_interface", "//tensorflow/core/distributed_runtime:worker", "//tensorflow/core/distributed_runtime:worker_cache", @@ -103,6 +104,7 @@ cc_library( "//tensorflow/core:framework", "//tensorflow/core:lib", "//tensorflow/core/distributed_runtime:base_rendezvous_mgr", + "//tensorflow/core/distributed_runtime:request_id", "//tensorflow/core/distributed_runtime:tensor_coding", "//tensorflow/core/distributed_runtime:worker_cache", "//tensorflow/core/distributed_runtime:worker_env", diff --git a/tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc b/tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc index adef2aac33..28f68cec8c 100644 --- a/tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc +++ b/tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc @@ -20,6 +20,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/common_runtime/process_util.h" +#include "tensorflow/core/distributed_runtime/request_id.h" #include "tensorflow/core/distributed_runtime/tensor_coding.h" #include "tensorflow/core/distributed_runtime/worker_cache.h" #include "tensorflow/core/distributed_runtime/worker_interface.h" @@ -47,6 +48,7 @@ class GdrRecvTensorCall : public BaseRecvTensorCall { recv_args_(recv_args) { req_.set_step_id(step_id); req_.set_rendezvous_key(key.data(), key.size()); + req_.set_request_id(GetUniqueRequestId()); } ~GdrRecvTensorCall() override {} diff --git a/tensorflow/contrib/gdr/gdr_worker.cc b/tensorflow/contrib/gdr/gdr_worker.cc index 5686412347..ce1d8d2d73 100644 --- a/tensorflow/contrib/gdr/gdr_worker.cc +++ b/tensorflow/contrib/gdr/gdr_worker.cc @@ -41,17 +41,26 @@ namespace tensorflow { GdrWorker::GdrWorker(WorkerEnv* worker_env, RemoteMemoryManager* remote_memory_manager) - : GrpcWorker(worker_env), remote_memory_manager_(remote_memory_manager) {} + : GrpcWorker(worker_env), + remote_memory_manager_(remote_memory_manager), + recv_tensor_recent_request_ids_(100000) {} void GdrWorker::GrpcRecvTensorAsync(CallOptions* opts, const RecvTensorRequest* request, ::grpc::ByteBuffer* response, StatusCallback done) { + Status s = recv_tensor_recent_request_ids_.TrackUnique( + request->request_id(), "RecvTensor (GdrWorker)", *request); + if (!s.ok()) { + done(s); + return; + } + const int64 step_id = request->step_id(); const string& key = request->rendezvous_key(); TRACEPRINTF("RecvTensor: %lld %s", step_id, key.c_str()); Rendezvous::ParsedKey parsed; - Status s = Rendezvous::ParseKey(key, &parsed); + s = Rendezvous::ParseKey(key, &parsed); Device* src_dev = nullptr; if (s.ok()) { s = PrepareRecvTensor(parsed, &src_dev); diff --git a/tensorflow/contrib/gdr/gdr_worker.h b/tensorflow/contrib/gdr/gdr_worker.h index a30b7baaed..54081f655e 100644 --- a/tensorflow/contrib/gdr/gdr_worker.h +++ b/tensorflow/contrib/gdr/gdr_worker.h @@ -18,6 +18,7 @@ limitations under the License. #include "tensorflow/contrib/gdr/gdr_memory_manager.h" +#include "tensorflow/core/distributed_runtime/recent_request_ids.h" #include "tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h" namespace tensorflow { @@ -38,6 +39,7 @@ class GdrWorker : public GrpcWorker { private: RemoteMemoryManager* remote_memory_manager_; // Not owned + RecentRequestIds recv_tensor_recent_request_ids_; }; } // namespace tensorflow diff --git a/tensorflow/contrib/mpi/BUILD b/tensorflow/contrib/mpi/BUILD index d9d55faf50..23f90cf77e 100644 --- a/tensorflow/contrib/mpi/BUILD +++ b/tensorflow/contrib/mpi/BUILD @@ -71,6 +71,8 @@ cc_library( "//tensorflow/core:protos_cc", "//tensorflow/core:worker_proto_cc", "//tensorflow/core/distributed_runtime:base_rendezvous_mgr", + "//tensorflow/core/distributed_runtime:recent_request_ids", + "//tensorflow/core/distributed_runtime:request_id", "//tensorflow/core/distributed_runtime:session_mgr", "//tensorflow/core/distributed_runtime:tensor_coding", "//tensorflow/core/distributed_runtime:worker_env", diff --git a/tensorflow/contrib/mpi/mpi_rendezvous_mgr.cc b/tensorflow/contrib/mpi/mpi_rendezvous_mgr.cc index 1a2563d20f..8d14a3ef04 100644 --- a/tensorflow/contrib/mpi/mpi_rendezvous_mgr.cc +++ b/tensorflow/contrib/mpi/mpi_rendezvous_mgr.cc @@ -33,8 +33,10 @@ limitations under the License. namespace tensorflow { MPIRendezvousMgr::MPIRendezvousMgr(const WorkerEnv* env) - : BaseRendezvousMgr(env), worker_env_2(env), use_optimal_transfer_(false) { - + : BaseRendezvousMgr(env), + worker_env_2(env), + use_optimal_transfer_(false), + recv_tensor_recent_request_ids_(100000) { const char* mpienv = getenv("MPI_OPTIMAL_PATH"); if (mpienv && mpienv[0] == '1') { LOG(INFO) << "MPI Optimal copy path enabled (Requires CUDA-Aware MPI when " @@ -149,6 +151,8 @@ MPIRemoteRendezvous::~MPIRemoteRendezvous() {} */ void MPIRendezvousMgr::AddRequest(RecvTensorRequest request, const int mpi_dst) { + TF_CHECK_OK(recv_tensor_recent_request_ids_.TrackUnique( + req.request_id(), "RecvTensor (MPIRendezvousMgr)", req)); const int64 step_id = request.step_id(); const std::string& key = request.rendezvous_key(); Rendezvous::ParsedKey parsed; diff --git a/tensorflow/contrib/mpi/mpi_rendezvous_mgr.h b/tensorflow/contrib/mpi/mpi_rendezvous_mgr.h index b15748d63c..ca42ee2f6d 100644 --- a/tensorflow/contrib/mpi/mpi_rendezvous_mgr.h +++ b/tensorflow/contrib/mpi/mpi_rendezvous_mgr.h @@ -30,10 +30,11 @@ limitations under the License. #include +#include "tensorflow/contrib/mpi/mpi_msg.pb.h" #include "tensorflow/contrib/mpi/mpi_utils.h" #include "tensorflow/core/distributed_runtime/base_rendezvous_mgr.h" +#include "tensorflow/core/distributed_runtime/request_id.h" #include "tensorflow/core/distributed_runtime/worker_env.h" -#include "tensorflow/contrib/mpi/mpi_msg.pb.h" #include "tensorflow/core/protobuf/worker.pb.h" #define TAG_REQTENSOR 1010 @@ -104,6 +105,7 @@ class MPIRequestTensorCall { void Init(const Rendezvous::ParsedKey& parsed, const int64 step_id) { req_.set_step_id(step_id); req_.set_rendezvous_key(parsed.FullKey().data(), parsed.FullKey().size()); + req_.set_request_id(GetUniqueRequestId()); request_buffer_size_ = req_.ByteSize(); // request_buffer_ = new char[request_buffer_size_]; // req_.SerializeToArray(request_buffer_, request_buffer_size_); @@ -177,6 +179,8 @@ class MPIRendezvousMgr : public BaseRendezvousMgr { std::map> recv_tensor_map_ GUARDED_BY(mrq_); + RecentRequestIds recv_tensor_recent_request_ids_; + void AddRequest(RecvTensorRequest, const int); void MPIBackgroundThread(); diff --git a/tensorflow/core/distributed_runtime/BUILD b/tensorflow/core/distributed_runtime/BUILD index 2db7ebd795..f4ee841032 100644 --- a/tensorflow/core/distributed_runtime/BUILD +++ b/tensorflow/core/distributed_runtime/BUILD @@ -556,3 +556,47 @@ tf_cuda_cc_test( "//tensorflow/core/kernels:array", ], ) + +cc_library( + name = "request_id", + srcs = ["request_id.cc"], + hdrs = ["request_id.h"], + deps = [ + "//tensorflow/core:lib", + "//tensorflow/core:lib_internal", + ], +) + +tf_cc_test( + name = "request_id_test", + size = "small", + srcs = ["request_id_test.cc"], + deps = [ + ":request_id", + "//tensorflow/core:test", + "//tensorflow/core:test_main", + ], +) + +cc_library( + name = "recent_request_ids", + srcs = ["recent_request_ids.cc"], + hdrs = ["recent_request_ids.h"], + deps = [ + "//tensorflow/core:lib", + "//tensorflow/core:worker_proto_cc", + ], +) + +tf_cc_test( + name = "recent_request_ids_test", + size = "small", + srcs = ["recent_request_ids_test.cc"], + deps = [ + ":recent_request_ids", + "//tensorflow/core:lib", + "//tensorflow/core:test", + "//tensorflow/core:test_main", + "//tensorflow/core:worker_proto_cc", + ], +) diff --git a/tensorflow/core/distributed_runtime/recent_request_ids.cc b/tensorflow/core/distributed_runtime/recent_request_ids.cc new file mode 100644 index 0000000000..c30879406c --- /dev/null +++ b/tensorflow/core/distributed_runtime/recent_request_ids.cc @@ -0,0 +1,57 @@ +/* Copyright 2017 The TensorFlow Authors. 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/distributed_runtime/recent_request_ids.h" + +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/lib/strings/strcat.h" +#include "tensorflow/core/platform/logging.h" + +namespace tensorflow { + +RecentRequestIds::RecentRequestIds(int num_tracked_request_ids) + : circular_buffer_(num_tracked_request_ids) { + set_.reserve(num_tracked_request_ids); +} + +Status RecentRequestIds::TrackUnique(int64 request_id, + const string& method_name, + const protobuf::Message& request) { + mutex_lock l(mu_); + if (request_id == 0) { + // For backwards compatibility, allow all requests with request_id 0. + return Status::OK(); + } + if (set_.count(request_id) > 0) { + // Note: RecentRequestIds is not strict LRU because we don't update + // request_id's age in the circular_buffer_ if it's tracked again. Strict + // LRU is not useful here because returning this error will close the + // current Session. + return errors::Aborted("The same ", method_name, + " request was received twice. ", + request.ShortDebugString()); + } + + // Remove the oldest request_id from the set_. circular_buffer_ is + // zero-initialized, and zero is never tracked, so it's safe to do this even + // when the buffer is not yet full. + set_.erase(circular_buffer_[next_index_]); + circular_buffer_[next_index_] = request_id; + set_.insert(request_id); + next_index_ = (next_index_ + 1) % circular_buffer_.size(); + return Status::OK(); +} + +} // namespace tensorflow diff --git a/tensorflow/core/distributed_runtime/recent_request_ids.h b/tensorflow/core/distributed_runtime/recent_request_ids.h new file mode 100644 index 0000000000..396235dcc6 --- /dev/null +++ b/tensorflow/core/distributed_runtime/recent_request_ids.h @@ -0,0 +1,72 @@ +/* Copyright 2017 The TensorFlow Authors. 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 THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ +#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ + +#include + +#include "tensorflow/core/lib/core/status.h" +#include "tensorflow/core/lib/gtl/flatset.h" +#include "tensorflow/core/platform/mutex.h" +#include "tensorflow/core/platform/thread_annotations.h" +#include "tensorflow/core/platform/types.h" +#include "tensorflow/core/protobuf/worker.pb.h" + +namespace tensorflow { + +// RecentRequestIds tracks recent 64-bit request_ids. When maximum capacity is +// reached, the oldest request_id is evicted. Thread safe. +// +// Some RPCs like RecvTensor are unsafe to retry. For example, RecvTensor pairs +// one sender and one receiver, and the receiver waits for the sender's tensor. +// Retried RecvTensor requests are problematic, because the original RecvTensor +// request may have consumed the sender's tensor, so a retried request might +// block forever. RecentRequestIds identifies retried requests, so we can fail +// them instead of blocking forever. +// +// Internally, recent request_ids are stored in two data structures: a set and a +// circular buffer. The set is used for efficient lookups, and the circular +// buffer tracks the oldest request_id. When the buffer is full, the new +// request_id replaces the oldest request_id in the circular buffer, and the +// oldest request_id is removed from the set. +class RecentRequestIds { + public: + // num_tracked_request_ids should be much larger than the number of RPCs that + // can be received in a small time window. For example, we observed a peak RPC + // rate of ~700 RecvTensor RPC/s when training inception v3 on TPUs, so we + // currently set num_tracked_request_ids to 100,000 for RecvTensor. + RecentRequestIds(int num_tracked_request_ids); + + // Returns OK iff request_id has not been seen in the last + // num_tracked_request_ids insertions. For backwards compatibility, this + // always returns OK for request_id 0. The method_name and the request's + // ShortDebugString are added to returned errors. + Status TrackUnique(int64 request_id, const string& method_name, + const protobuf::Message& request); + + private: + mutex mu_; + // next_index_ indexes into circular_buffer_, and points to the next storage + // space to use. When the buffer is full, next_index_ points at the oldest + // request_id. + int next_index_ GUARDED_BY(mu_) = 0; + std::vector circular_buffer_ GUARDED_BY(mu_); + gtl::FlatSet set_ GUARDED_BY(mu_); +}; + +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ diff --git a/tensorflow/core/distributed_runtime/recent_request_ids_test.cc b/tensorflow/core/distributed_runtime/recent_request_ids_test.cc new file mode 100644 index 0000000000..9a0facf540 --- /dev/null +++ b/tensorflow/core/distributed_runtime/recent_request_ids_test.cc @@ -0,0 +1,96 @@ +/* Copyright 2017 The TensorFlow Authors. 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/distributed_runtime/recent_request_ids.h" + +#include + +#include "tensorflow/core/lib/core/status_test_util.h" +#include "tensorflow/core/platform/test.h" +#include "tensorflow/core/platform/types.h" +#include "tensorflow/core/protobuf/worker.pb.h" + +namespace tensorflow { + +Status TrackUnique(int64 request_id, RecentRequestIds* recent_request_ids) { + RecvTensorRequest request; + request.set_request_id(request_id); + return recent_request_ids->TrackUnique(request_id, "recent_request_ids_test", + request); +} + +// request_id 0 is always valid. +TEST(RecentRequestIds, Zero) { + RecentRequestIds recent_request_ids(1); + EXPECT_TRUE(TrackUnique(0, &recent_request_ids).ok()); + EXPECT_TRUE(TrackUnique(0, &recent_request_ids).ok()); + EXPECT_TRUE(TrackUnique(0, &recent_request_ids).ok()); +} + +TEST(RecentRequestIds, Unordered) { + // Capacity for 6 numbers. + RecentRequestIds recent_request_ids(6); + + // Some unordered numbers to insert into request_id_set. + std::vector numbers = {53754, 23351, 164101, 7476, + 162432, 130761, 164102}; + + // Insert numbers[0..6) and check that all previously inserted numbers remain + // in the set. + for (int i = 0; i < 6; ++i) { + TF_EXPECT_OK(TrackUnique(numbers[i], &recent_request_ids)); + + for (int j = 0; j <= i; ++j) { + EXPECT_FALSE(TrackUnique(numbers[j], &recent_request_ids).ok()) + << "i=" << i << " j=" << j; + } + } + + // Insert numbers[6]. Inserting this 7th number should evict the first number + // from the set. The set should only contain numbers[1..7). + TF_EXPECT_OK(TrackUnique(numbers[6], &recent_request_ids)); + for (int i = 1; i < 7; ++i) { + EXPECT_FALSE(TrackUnique(numbers[i], &recent_request_ids).ok()) + << "i=" << i; + } + + // Insert numbers[0] again. This should succeed because we just evicted it + // from the set. + TF_EXPECT_OK(TrackUnique(numbers[0], &recent_request_ids)); +} + +// Check that the oldest request_id is evicted. +void TestOrdered(int num_request_ids) { + RecentRequestIds recent_request_ids(num_request_ids); + + // Insert [1..101). The current number and the (num_request_ids - 1) preceding + // numbers should still be in the set. + for (int i = 1; i < 101; ++i) { + TF_EXPECT_OK(TrackUnique(i, &recent_request_ids)); + + for (int j = std::max(1, i - num_request_ids + 1); j <= i; ++j) { + EXPECT_FALSE(TrackUnique(j, &recent_request_ids).ok()) + << "i=" << i << " j=" << j; + } + } +} + +// Test eviction with various numbers of buckets. +TEST(RecentRequestIds, Ordered2) { TestOrdered(2); } +TEST(RecentRequestIds, Ordered3) { TestOrdered(3); } +TEST(RecentRequestIds, Ordered4) { TestOrdered(4); } +TEST(RecentRequestIds, Ordered5) { TestOrdered(5); } + +} // namespace tensorflow diff --git a/tensorflow/core/distributed_runtime/request_id.cc b/tensorflow/core/distributed_runtime/request_id.cc new file mode 100644 index 0000000000..230c6f9601 --- /dev/null +++ b/tensorflow/core/distributed_runtime/request_id.cc @@ -0,0 +1,30 @@ +/* Copyright 2017 The TensorFlow Authors. 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/distributed_runtime/request_id.h" + +#include "tensorflow/core/platform/types.h" + +namespace tensorflow { + +int64 GetUniqueRequestId() { + int64 request_id = 0; + while (request_id == 0) { + request_id = random::New64(); + } + return request_id; +} + +} // namespace tensorflow diff --git a/tensorflow/core/distributed_runtime/request_id.h b/tensorflow/core/distributed_runtime/request_id.h new file mode 100644 index 0000000000..288c49153d --- /dev/null +++ b/tensorflow/core/distributed_runtime/request_id.h @@ -0,0 +1,31 @@ +/* Copyright 2017 The TensorFlow Authors. 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 THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ +#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ + +#include "tensorflow/core/lib/random/random.h" +#include "tensorflow/core/platform/types.h" + +namespace tensorflow { + +// Returns a request_id for use with RecentRequestIds. This number will not be +// zero, and must be unique over RecentRequestIds' window of +// num_tracked_request_ids. See recent_request_ids.h for more details. +int64 GetUniqueRequestId(); + +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ diff --git a/tensorflow/core/distributed_runtime/request_id_test.cc b/tensorflow/core/distributed_runtime/request_id_test.cc new file mode 100644 index 0000000000..e0dc9d9347 --- /dev/null +++ b/tensorflow/core/distributed_runtime/request_id_test.cc @@ -0,0 +1,29 @@ +/* Copyright 2017 The TensorFlow Authors. 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/distributed_runtime/request_id.h" + +#include "tensorflow/core/platform/test.h" + +namespace tensorflow { + +// Try requesting some request_ids and verify that none are zero. +TEST(GetUniqueRequestId, Basic) { + for (int i = 0; i < 1000000; ++i) { + EXPECT_NE(GetUniqueRequestId(), 0); + } +} + +} // namespace tensorflow diff --git a/tensorflow/core/distributed_runtime/rpc/BUILD b/tensorflow/core/distributed_runtime/rpc/BUILD index 80640c806d..dade26abc6 100644 --- a/tensorflow/core/distributed_runtime/rpc/BUILD +++ b/tensorflow/core/distributed_runtime/rpc/BUILD @@ -186,6 +186,7 @@ tf_cuda_library( "//tensorflow/core:lib_internal", "//tensorflow/core:worker_proto_cc", "//tensorflow/core/distributed_runtime:graph_mgr", + "//tensorflow/core/distributed_runtime:recent_request_ids", "//tensorflow/core/distributed_runtime:rendezvous_mgr_interface", "//tensorflow/core/distributed_runtime:worker", "//tensorflow/core/distributed_runtime:worker_cache", @@ -270,6 +271,7 @@ cc_library( "//tensorflow/core:framework", "//tensorflow/core:lib", "//tensorflow/core/distributed_runtime:base_rendezvous_mgr", + "//tensorflow/core/distributed_runtime:request_id", "//tensorflow/core/distributed_runtime:tensor_coding", "//tensorflow/core/distributed_runtime:worker_cache", "//tensorflow/core/distributed_runtime:worker_env", diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.cc b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.cc index 15faf21daf..95811476f7 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.cc @@ -354,7 +354,8 @@ class GrpcWorkerService : public AsyncServiceInterface { } // namespace -GrpcWorker::GrpcWorker(WorkerEnv* worker_env) : Worker(worker_env) {} +GrpcWorker::GrpcWorker(WorkerEnv* worker_env) + : Worker(worker_env), recv_tensor_recent_request_ids_(100000) {} // GrpcRecvTensorAsync: unlike the other Worker methods, which use protocol // buffers for a response object, to avoid extra protocol buffer serialization @@ -363,11 +364,18 @@ void GrpcWorker::GrpcRecvTensorAsync(CallOptions* opts, const RecvTensorRequest* request, ::grpc::ByteBuffer* response, StatusCallback done) { + Status s = recv_tensor_recent_request_ids_.TrackUnique( + request->request_id(), "RecvTensor (GrpcWorker)", *request); + if (!s.ok()) { + done(s); + return; + } + const int64 step_id = request->step_id(); const string& key = request->rendezvous_key(); TRACEPRINTF("RecvTensor: %lld %s", step_id, key.c_str()); Rendezvous::ParsedKey parsed; - Status s = Rendezvous::ParseKey(key, &parsed); + s = Rendezvous::ParseKey(key, &parsed); Device* src_dev = nullptr; if (s.ok()) { s = PrepareRecvTensor(parsed, &src_dev); diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h index 64d7c986da..28b389b25f 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h @@ -16,6 +16,7 @@ limitations under the License. #ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_H_ #define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_H_ +#include "tensorflow/core/distributed_runtime/recent_request_ids.h" #include "tensorflow/core/distributed_runtime/worker.h" namespace grpc { @@ -40,6 +41,9 @@ class GrpcWorker : public Worker { StatusCallback done); WorkerEnv* env(); + + private: + RecentRequestIds recv_tensor_recent_request_ids_; }; std::unique_ptr NewGrpcWorker(WorkerEnv* worker_env); diff --git a/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc b/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc index 72dfe5c062..067dc5dff5 100644 --- a/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc +++ b/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc @@ -21,6 +21,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/common_runtime/dma_helper.h" #include "tensorflow/core/common_runtime/process_util.h" +#include "tensorflow/core/distributed_runtime/request_id.h" #include "tensorflow/core/distributed_runtime/tensor_coding.h" #include "tensorflow/core/distributed_runtime/worker_cache.h" #include "tensorflow/core/distributed_runtime/worker_interface.h" @@ -67,6 +68,7 @@ class RpcRecvTensorCall : public BaseRecvTensorCall { done_ = std::move(done); req_.set_step_id(step_id); req_.set_rendezvous_key(key.data(), key.size()); + req_.set_request_id(GetUniqueRequestId()); } void Reset(WorkerCacheInterface* wc) { diff --git a/tensorflow/core/protobuf/worker.proto b/tensorflow/core/protobuf/worker.proto index 9b51db1362..3e7289bd91 100644 --- a/tensorflow/core/protobuf/worker.proto +++ b/tensorflow/core/protobuf/worker.proto @@ -292,7 +292,10 @@ message RecvTensorRequest { // into a RunGraph call on the same WorkerService. int64 step_id = 1; - // A key that identifies the tensor to be received. + // A key identifying the channel to receive tensors from. A RecvTensor request + // retrieves one tensor from the channel, but multiple tensors can be sent and + // received over the same channel with multiple RecvTensor requests. See + // rendezvous.h for details. string rendezvous_key = 2; // If true, use an out-of-band DMA mechanism to transfer the @@ -307,6 +310,16 @@ message RecvTensorRequest { // Optional information needed by the RPC subsystem. google.protobuf.Any transport_options = 6; + + // Unique identifier for this request. Every RecvTensorRequest must have a + // unique request_id, and retried RecvTensorRequests must have the same + // request_id. If request_id is zero, retry detection is disabled. + // + // Retried RecvTensorRequests are problematic because a RecvTensor with no + // corresponding sender will wait forever, and the tensor may have been + // delivered to a previous retry. Workers use request_ids to reject retried + // RecvTensor requests instead of waiting forever. + int64 request_id = 7; } message RecvTensorResponse { -- GitLab From c2c9e3beef18c5f1ed443d372dec18c8acc5d991 Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Mon, 22 Jan 2018 17:43:06 -0800 Subject: [PATCH 080/258] _DefinedFunction.name should be a string. With the C API enabled and python2, it was being set to a unicode object. PiperOrigin-RevId: 182865087 --- tensorflow/python/framework/function.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/framework/function.py b/tensorflow/python/framework/function.py index 416bbf4f48..cba225e749 100644 --- a/tensorflow/python/framework/function.py +++ b/tensorflow/python/framework/function.py @@ -417,7 +417,7 @@ class _DefinedFunction(object): if self._func_name: assert self._func_name == self._op_def.name else: - self._func_name = self._op_def.name + self._func_name = compat.as_str(self._op_def.name) def _set_c_attrs(self, attrs): """Sets `attrs` as attributes of self._c_func. -- GitLab From e9831da422ff294c68cb0e13e667e0d760a094d0 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Mon, 22 Jan 2018 17:49:30 -0800 Subject: [PATCH 081/258] Add test for float16 support with conv1d and update docstring (#16273) * Add test for float16 support with conv1d and update docs The float16 support for conv1d has already been in place. However there was no test for float16 with conv1d. This fix adds test case to cover float16 support with conv1d. In addition, float64 support with conv1d is not possible because conv1d calls conv2d, which in turn does not support float64 yet (See 12941, 13097, and 12943) The docstring incorrectly claims float64 support with conv1d. This fix updates related docstring to remove float64 part. Signed-off-by: Yong Tang * Update docstring of conv1d to remove float64 and add float16. Signed-off-by: Yong Tang * Update docstring with TODO. Signed-off-by: Yong Tang --- tensorflow/python/kernel_tests/conv1d_test.py | 44 ++++++++++--------- tensorflow/python/ops/nn_ops.py | 2 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/tensorflow/python/kernel_tests/conv1d_test.py b/tensorflow/python/kernel_tests/conv1d_test.py index d92797a7d3..e2e6205911 100644 --- a/tensorflow/python/kernel_tests/conv1d_test.py +++ b/tensorflow/python/kernel_tests/conv1d_test.py @@ -30,27 +30,29 @@ from tensorflow.python.platform import test class Conv1DTest(test.TestCase): def testBasic(self): - """Test that argument passing to conv2d is handled properly.""" - - x = constant_op.constant([1, 2, 3, 4], dtype=dtypes.float32) - x = array_ops.expand_dims(x, 0) # Add batch dimension - x = array_ops.expand_dims(x, 2) # And depth dimension - filters = constant_op.constant([2, 1], dtype=dtypes.float32) - filters = array_ops.expand_dims(filters, 1) # in_channels - filters = array_ops.expand_dims(filters, 2) # out_channels - # Filters is 2x1x1 - for stride in [1, 2]: - with self.test_session(use_gpu=test.is_gpu_available()): - c = nn_ops.conv1d(x, filters, stride, padding="VALID") - reduced = array_ops.squeeze(c) - output = reduced.eval() - if stride == 1: - self.assertEqual(len(output), 3) - self.assertAllClose(output, - [2 * 1 + 1 * 2, 2 * 2 + 1 * 3, 2 * 3 + 1 * 4]) - else: - self.assertEqual(len(output), 2) - self.assertAllClose(output, [2 * 1 + 1 * 2, 2 * 3 + 1 * 4]) + """Test that argument passing to conv1d is handled properly.""" + # TODO(yongtang): dtypes.float64 can only be enabled once conv2d support + # dtypes.float64, as conv1d implicitly calls conv2d after expand_dims. + for dtype in [dtypes.float16, dtypes.float32]: + x = constant_op.constant([1, 2, 3, 4], dtype=dtype) + x = array_ops.expand_dims(x, 0) # Add batch dimension + x = array_ops.expand_dims(x, 2) # And depth dimension + filters = constant_op.constant([2, 1], dtype=dtype) + filters = array_ops.expand_dims(filters, 1) # in_channels + filters = array_ops.expand_dims(filters, 2) # out_channels + # Filters is 2x1x1 + for stride in [1, 2]: + with self.test_session(use_gpu=test.is_gpu_available()): + c = nn_ops.conv1d(x, filters, stride, padding="VALID") + reduced = array_ops.squeeze(c) + output = reduced.eval() + if stride == 1: + self.assertEqual(len(output), 3) + self.assertAllClose(output, + [2 * 1 + 1 * 2, 2 * 2 + 1 * 3, 2 * 3 + 1 * 4]) + else: + self.assertEqual(len(output), 2) + self.assertAllClose(output, [2 * 1 + 1 * 2, 2 * 3 + 1 * 4]) def testConv1DTranspose(self): with self.test_session(): diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index bd8d02fec1..5fa78a5862 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -2303,7 +2303,7 @@ def conv1d(value, filters, stride, padding, returned to the caller. Args: - value: A 3D `Tensor`. Must be of type `float32` or `float64`. + value: A 3D `Tensor`. Must be of type `float16` or `float32`. filters: A 3D `Tensor`. Must have the same type as `input`. stride: An `integer`. The number of entries by which the filter is moved right at each step. -- GitLab From 55161ebccec68ac4a8b581404a1bae10f4302842 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 18:18:46 -0800 Subject: [PATCH 082/258] Update ops-related pbtxt files. PiperOrigin-RevId: 182868865 --- .../core/ops/compat/ops_history.v1.pbtxt | 92 +++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 92 +++++++++++++++++++ 2 files changed, 184 insertions(+) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index 08b685319e..438882dc9e 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -63085,6 +63085,27 @@ op { } is_stateful: true } +op { + name: "TensorListElementShape" + input_arg { + name: "input_handle" + type: DT_VARIANT + } + output_arg { + name: "element_shape" + type_attr: "shape_type" + } + attr { + name: "shape_type" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} op { name: "TensorListFromTensor" input_arg { @@ -63114,6 +63135,25 @@ op { } } } +op { + name: "TensorListGetItem" + input_arg { + name: "input_handle" + type: DT_VARIANT + } + input_arg { + name: "index" + type: DT_INT32 + } + output_arg { + name: "item" + type_attr: "element_dtype" + } + attr { + name: "element_dtype" + type: "type" + } +} op { name: "TensorListLength" input_arg { @@ -63163,6 +63203,58 @@ op { type: "type" } } +op { + name: "TensorListReserve" + input_arg { + name: "element_shape" + type_attr: "shape_type" + } + input_arg { + name: "num_elements" + type: DT_INT32 + } + output_arg { + name: "handle" + type: DT_VARIANT + } + attr { + name: "element_dtype" + type: "type" + } + attr { + name: "shape_type" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} +op { + name: "TensorListSetItem" + input_arg { + name: "input_handle" + type: DT_VARIANT + } + input_arg { + name: "index" + type: DT_INT32 + } + input_arg { + name: "item" + type_attr: "element_dtype" + } + output_arg { + name: "output_handle" + type: DT_VARIANT + } + attr { + name: "element_dtype" + type: "type" + } +} op { name: "TensorListStack" input_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index 82a895a98b..45eb1a9cac 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -29675,6 +29675,27 @@ op { } is_stateful: true } +op { + name: "TensorListElementShape" + input_arg { + name: "input_handle" + type: DT_VARIANT + } + output_arg { + name: "element_shape" + type_attr: "shape_type" + } + attr { + name: "shape_type" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} op { name: "TensorListFromTensor" input_arg { @@ -29704,6 +29725,25 @@ op { } } } +op { + name: "TensorListGetItem" + input_arg { + name: "input_handle" + type: DT_VARIANT + } + input_arg { + name: "index" + type: DT_INT32 + } + output_arg { + name: "item" + type_attr: "element_dtype" + } + attr { + name: "element_dtype" + type: "type" + } +} op { name: "TensorListLength" input_arg { @@ -29753,6 +29793,58 @@ op { type: "type" } } +op { + name: "TensorListReserve" + input_arg { + name: "element_shape" + type_attr: "shape_type" + } + input_arg { + name: "num_elements" + type: DT_INT32 + } + output_arg { + name: "handle" + type: DT_VARIANT + } + attr { + name: "element_dtype" + type: "type" + } + attr { + name: "shape_type" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} +op { + name: "TensorListSetItem" + input_arg { + name: "input_handle" + type: DT_VARIANT + } + input_arg { + name: "index" + type: DT_INT32 + } + input_arg { + name: "item" + type_attr: "element_dtype" + } + output_arg { + name: "output_handle" + type: DT_VARIANT + } + attr { + name: "element_dtype" + type: "type" + } +} op { name: "TensorListStack" input_arg { -- GitLab From 2325517293569552a4be8fedba687ace25302d55 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 22 Jan 2018 18:45:56 -0800 Subject: [PATCH 083/258] Go: Update generated wrapper functions for TensorFlow ops. PiperOrigin-RevId: 182871435 --- tensorflow/go/op/wrappers.go | 220 +++++++++++++++++------------------ 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/tensorflow/go/op/wrappers.go b/tensorflow/go/op/wrappers.go index 7bcc55959c..8df4e98adc 100644 --- a/tensorflow/go/op/wrappers.go +++ b/tensorflow/go/op/wrappers.go @@ -116,6 +116,53 @@ func WriteImageSummary(scope *Scope, writer tf.Output, step tf.Output, tag tf.Ou return scope.AddOperation(opspec) } +// Outputs a `tf.Event` protocol buffer. +// +// When CreateSummaryDbWriter is being used, this op can be useful for +// importing data from event logs. +// +// Arguments: +// writer: A handle to a summary writer. +// event: A string containing a binary-encoded tf.Event proto. +// +// Returns the created operation. +func ImportEvent(scope *Scope, writer tf.Output, event tf.Output) (o *tf.Operation) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "ImportEvent", + Input: []tf.Input{ + writer, event, + }, + } + return scope.AddOperation(opspec) +} + +// Outputs a `Summary` protocol buffer with a tensor. +// +// Arguments: +// writer: A handle to a summary writer. +// step: The step to write the summary for. +// tensor: A tensor to serialize. +// tag: The summary's tag. +// summary_metadata: Serialized SummaryMetadata protocol buffer containing +// plugin-related metadata for this summary. +// +// Returns the created operation. +func WriteSummary(scope *Scope, writer tf.Output, step tf.Output, tensor tf.Output, tag tf.Output, summary_metadata tf.Output) (o *tf.Operation) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "WriteSummary", + Input: []tf.Input{ + writer, step, tensor, tag, summary_metadata, + }, + } + return scope.AddOperation(opspec) +} + // Partitions `data` into `num_partitions` tensors using indices from `partitions`. // // For each index tuple `js` of size `partitions.ndim`, the slice `data[js, ...]` @@ -22381,6 +22428,69 @@ func Abs(scope *Scope, x tf.Output) (y tf.Output) { return op.Output(0) } +// Flushes and closes the summary writer. +// +// Also removes it from the resource manager. To reopen, use another +// CreateSummaryFileWriter op. +// +// Arguments: +// writer: A handle to the summary writer resource. +// +// Returns the created operation. +func CloseSummaryWriter(scope *Scope, writer tf.Output) (o *tf.Operation) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "CloseSummaryWriter", + Input: []tf.Input{ + writer, + }, + } + return scope.AddOperation(opspec) +} + +// StackV2Attr is an optional argument to StackV2. +type StackV2Attr func(optionalAttr) + +// StackV2StackName sets the optional stack_name attribute to value. +// +// value: Overrides the name used for the temporary stack resource. Default +// value is the name of the 'Stack' op (which is guaranteed unique). +// If not specified, defaults to "" +func StackV2StackName(value string) StackV2Attr { + return func(m optionalAttr) { + m["stack_name"] = value + } +} + +// A stack that produces elements in first-in last-out order. +// +// Arguments: +// max_size: The maximum size of the stack if non-negative. If negative, the stack +// size is unlimited. +// elem_type: The type of the elements on the stack. +// +// Returns The handle to the stack. +func StackV2(scope *Scope, max_size tf.Output, elem_type tf.DataType, optional ...StackV2Attr) (handle tf.Output) { + if scope.Err() != nil { + return + } + attrs := map[string]interface{}{"elem_type": elem_type} + for _, a := range optional { + a(attrs) + } + opspec := tf.OpSpec{ + Type: "StackV2", + Input: []tf.Input{ + max_size, + }, + Attrs: attrs, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + // OrderedMapStageAttr is an optional argument to OrderedMapStage. type OrderedMapStageAttr func(optionalAttr) @@ -28227,113 +28337,3 @@ func FlushSummaryWriter(scope *Scope, writer tf.Output) (o *tf.Operation) { } return scope.AddOperation(opspec) } - -// StackV2Attr is an optional argument to StackV2. -type StackV2Attr func(optionalAttr) - -// StackV2StackName sets the optional stack_name attribute to value. -// -// value: Overrides the name used for the temporary stack resource. Default -// value is the name of the 'Stack' op (which is guaranteed unique). -// If not specified, defaults to "" -func StackV2StackName(value string) StackV2Attr { - return func(m optionalAttr) { - m["stack_name"] = value - } -} - -// A stack that produces elements in first-in last-out order. -// -// Arguments: -// max_size: The maximum size of the stack if non-negative. If negative, the stack -// size is unlimited. -// elem_type: The type of the elements on the stack. -// -// Returns The handle to the stack. -func StackV2(scope *Scope, max_size tf.Output, elem_type tf.DataType, optional ...StackV2Attr) (handle tf.Output) { - if scope.Err() != nil { - return - } - attrs := map[string]interface{}{"elem_type": elem_type} - for _, a := range optional { - a(attrs) - } - opspec := tf.OpSpec{ - Type: "StackV2", - Input: []tf.Input{ - max_size, - }, - Attrs: attrs, - } - op := scope.AddOperation(opspec) - return op.Output(0) -} - -// Flushes and closes the summary writer. -// -// Also removes it from the resource manager. To reopen, use another -// CreateSummaryFileWriter op. -// -// Arguments: -// writer: A handle to the summary writer resource. -// -// Returns the created operation. -func CloseSummaryWriter(scope *Scope, writer tf.Output) (o *tf.Operation) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "CloseSummaryWriter", - Input: []tf.Input{ - writer, - }, - } - return scope.AddOperation(opspec) -} - -// Outputs a `Summary` protocol buffer with a tensor. -// -// Arguments: -// writer: A handle to a summary writer. -// step: The step to write the summary for. -// tensor: A tensor to serialize. -// tag: The summary's tag. -// summary_metadata: Serialized SummaryMetadata protocol buffer containing -// plugin-related metadata for this summary. -// -// Returns the created operation. -func WriteSummary(scope *Scope, writer tf.Output, step tf.Output, tensor tf.Output, tag tf.Output, summary_metadata tf.Output) (o *tf.Operation) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "WriteSummary", - Input: []tf.Input{ - writer, step, tensor, tag, summary_metadata, - }, - } - return scope.AddOperation(opspec) -} - -// Outputs a `tf.Event` protocol buffer. -// -// When CreateSummaryDbWriter is being used, this op can be useful for -// importing data from event logs. -// -// Arguments: -// writer: A handle to a summary writer. -// event: A string containing a binary-encoded tf.Event proto. -// -// Returns the created operation. -func ImportEvent(scope *Scope, writer tf.Output, event tf.Output) (o *tf.Operation) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "ImportEvent", - Input: []tf.Input{ - writer, event, - }, - } - return scope.AddOperation(opspec) -} -- GitLab From 7c4a128ac2d569d0b614cca8d8626ca382b90d40 Mon Sep 17 00:00:00 2001 From: Anna R Date: Mon, 22 Jan 2018 20:07:42 -0800 Subject: [PATCH 084/258] Adding tf_export decorators/calls to TensorFlow functions and constants. PiperOrigin-RevId: 182877401 --- tensorflow/python/ops/distributions/bernoulli.py | 2 ++ tensorflow/python/ops/distributions/beta.py | 2 ++ tensorflow/python/ops/distributions/bijector_impl.py | 2 ++ tensorflow/python/ops/distributions/categorical.py | 2 ++ tensorflow/python/ops/distributions/dirichlet.py | 2 ++ .../python/ops/distributions/dirichlet_multinomial.py | 2 ++ tensorflow/python/ops/distributions/distribution.py | 7 +++++++ tensorflow/python/ops/distributions/exponential.py | 2 ++ tensorflow/python/ops/distributions/gamma.py | 2 ++ tensorflow/python/ops/distributions/identity_bijector.py | 2 ++ tensorflow/python/ops/distributions/kullback_leibler.py | 3 +++ tensorflow/python/ops/distributions/laplace.py | 2 ++ tensorflow/python/ops/distributions/multinomial.py | 2 ++ tensorflow/python/ops/distributions/normal.py | 2 ++ tensorflow/python/ops/distributions/student_t.py | 2 ++ tensorflow/python/ops/distributions/uniform.py | 2 ++ tensorflow/tools/api/generator/BUILD | 2 ++ 17 files changed, 40 insertions(+) diff --git a/tensorflow/python/ops/distributions/bernoulli.py b/tensorflow/python/ops/distributions/bernoulli.py index b6b20d1b4a..1f300b7147 100644 --- a/tensorflow/python/ops/distributions/bernoulli.py +++ b/tensorflow/python/ops/distributions/bernoulli.py @@ -29,8 +29,10 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import kullback_leibler from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.util.tf_export import tf_export +@tf_export("distributions.Bernoulli") class Bernoulli(distribution.Distribution): """Bernoulli distribution. diff --git a/tensorflow/python/ops/distributions/beta.py b/tensorflow/python/ops/distributions/beta.py index 2b93478cdf..6d6b40b045 100644 --- a/tensorflow/python/ops/distributions/beta.py +++ b/tensorflow/python/ops/distributions/beta.py @@ -33,6 +33,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import kullback_leibler from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -45,6 +46,7 @@ _beta_sample_note = """Note: `x` must have dtype `self.dtype` and be in `[0, 1].` It must have a shape compatible with `self.batch_shape()`.""" +@tf_export("distributions.Beta") class Beta(distribution.Distribution): """Beta distribution. diff --git a/tensorflow/python/ops/distributions/bijector_impl.py b/tensorflow/python/ops/distributions/bijector_impl.py index 8f6d18d91a..44d64070ce 100644 --- a/tensorflow/python/ops/distributions/bijector_impl.py +++ b/tensorflow/python/ops/distributions/bijector_impl.py @@ -32,6 +32,7 @@ from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -111,6 +112,7 @@ class _Mapping(collections.namedtuple( @six.add_metaclass(abc.ABCMeta) +@tf_export("distributions.bijectors.Bijector") class Bijector(object): """Interface for transformations of a `Distribution` sample. diff --git a/tensorflow/python/ops/distributions/categorical.py b/tensorflow/python/ops/distributions/categorical.py index 84ca6db4c4..60a515583e 100644 --- a/tensorflow/python/ops/distributions/categorical.py +++ b/tensorflow/python/ops/distributions/categorical.py @@ -29,6 +29,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import kullback_leibler from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.util.tf_export import tf_export def _broadcast_cat_event_and_params(event, params, base_dtype=dtypes.int32): @@ -58,6 +59,7 @@ def _broadcast_cat_event_and_params(event, params, base_dtype=dtypes.int32): return event, params +@tf_export("distributions.Categorical") class Categorical(distribution.Distribution): """Categorical distribution. diff --git a/tensorflow/python/ops/distributions/dirichlet.py b/tensorflow/python/ops/distributions/dirichlet.py index 2accedf1b9..25afeec936 100644 --- a/tensorflow/python/ops/distributions/dirichlet.py +++ b/tensorflow/python/ops/distributions/dirichlet.py @@ -29,6 +29,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops import special_math_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -42,6 +43,7 @@ dtype `self.dtype` and be in the `(self.event_shape() - 1)`-simplex, i.e., `self.batch_shape() + self.event_shape()`.""" +@tf_export("distributions.Dirichlet") class Dirichlet(distribution.Distribution): """Dirichlet distribution. diff --git a/tensorflow/python/ops/distributions/dirichlet_multinomial.py b/tensorflow/python/ops/distributions/dirichlet_multinomial.py index aa2b511c54..03a98c56ba 100644 --- a/tensorflow/python/ops/distributions/dirichlet_multinomial.py +++ b/tensorflow/python/ops/distributions/dirichlet_multinomial.py @@ -28,6 +28,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops import special_math_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -49,6 +50,7 @@ fractional components, and such that with `self.concentration` and `self.total_count`.""" +@tf_export("distributions.DirichletMultinomial") class DirichletMultinomial(distribution.Distribution): """Dirichlet-Multinomial compound distribution. diff --git a/tensorflow/python/ops/distributions/distribution.py b/tensorflow/python/ops/distributions/distribution.py index 098622c52f..4071e50e81 100644 --- a/tensorflow/python/ops/distributions/distribution.py +++ b/tensorflow/python/ops/distributions/distribution.py @@ -34,6 +34,7 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops.distributions import kullback_leibler from tensorflow.python.ops.distributions import util from tensorflow.python.util import tf_inspect +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -197,6 +198,7 @@ class _DistributionMeta(abc.ABCMeta): return abc.ABCMeta.__new__(mcs, classname, baseclasses, attrs) +@tf_export("distributions.ReparameterizationType") class ReparameterizationType(object): """Instances of this class represent how sampling is reparameterized. @@ -239,15 +241,20 @@ class ReparameterizationType(object): # reparameterized distribution support straight-through gradients with # respect to all parameters. FULLY_REPARAMETERIZED = ReparameterizationType("FULLY_REPARAMETERIZED") +tf_export("distributions.FULLY_REPARAMETERIZED").export_constant( + __name__, "FULLY_REPARAMETERIZED") # Not reparameterized distribution: samples from a non- # reparameterized distribution do not support straight-through gradients for # at least some of the parameters. NOT_REPARAMETERIZED = ReparameterizationType("NOT_REPARAMETERIZED") +tf_export("distributions.NOT_REPARAMETERIZED").export_constant( + __name__, "NOT_REPARAMETERIZED") @six.add_metaclass(_DistributionMeta) +@tf_export("distributions.Distribution") class Distribution(_BaseDistribution): """A generic probability distribution base class. diff --git a/tensorflow/python/ops/distributions/exponential.py b/tensorflow/python/ops/distributions/exponential.py index 281641b915..6345a76d48 100644 --- a/tensorflow/python/ops/distributions/exponential.py +++ b/tensorflow/python/ops/distributions/exponential.py @@ -27,6 +27,7 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import gamma +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -35,6 +36,7 @@ __all__ = [ ] +@tf_export("distributions.Exponential") class Exponential(gamma.Gamma): """Exponential distribution. diff --git a/tensorflow/python/ops/distributions/gamma.py b/tensorflow/python/ops/distributions/gamma.py index 4ac2b9b4ef..8fb218be3a 100644 --- a/tensorflow/python/ops/distributions/gamma.py +++ b/tensorflow/python/ops/distributions/gamma.py @@ -33,6 +33,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import kullback_leibler from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -41,6 +42,7 @@ __all__ = [ ] +@tf_export("distributions.Gamma") class Gamma(distribution.Distribution): """Gamma distribution. diff --git a/tensorflow/python/ops/distributions/identity_bijector.py b/tensorflow/python/ops/distributions/identity_bijector.py index f277eda8bb..2972c3554b 100644 --- a/tensorflow/python/ops/distributions/identity_bijector.py +++ b/tensorflow/python/ops/distributions/identity_bijector.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.ops.distributions import bijector +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -27,6 +28,7 @@ __all__ = [ ] +@tf_export("distributions.bijectors.Identity") class Identity(bijector.Bijector): """Compute Y = g(X) = X. diff --git a/tensorflow/python/ops/distributions/kullback_leibler.py b/tensorflow/python/ops/distributions/kullback_leibler.py index 829b9611cf..e3c6f3e789 100644 --- a/tensorflow/python/ops/distributions/kullback_leibler.py +++ b/tensorflow/python/ops/distributions/kullback_leibler.py @@ -23,6 +23,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.util import tf_inspect +from tensorflow.python.util.tf_export import tf_export _DIVERGENCES = {} @@ -50,6 +51,7 @@ def _registered_kl(type_a, type_b): return kl_fn +@tf_export("distributions.kl_divergence") def kl_divergence(distribution_a, distribution_b, allow_nan_stats=True, name=None): """Get the KL-divergence KL(distribution_a || distribution_b). @@ -142,6 +144,7 @@ def cross_entropy(ref, other, ref, other, allow_nan_stats=allow_nan_stats) +@tf_export("distributions.RegisterKL") class RegisterKL(object): """Decorator to register a KL divergence implementation function. diff --git a/tensorflow/python/ops/distributions/laplace.py b/tensorflow/python/ops/distributions/laplace.py index 5c964ff78a..e98ac855c5 100644 --- a/tensorflow/python/ops/distributions/laplace.py +++ b/tensorflow/python/ops/distributions/laplace.py @@ -33,6 +33,7 @@ from tensorflow.python.ops import nn from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import special_math +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -41,6 +42,7 @@ __all__ = [ ] +@tf_export("distributions.Laplace") class Laplace(distribution.Distribution): """The Laplace distribution with location `loc` and `scale` parameters. diff --git a/tensorflow/python/ops/distributions/multinomial.py b/tensorflow/python/ops/distributions/multinomial.py index 04762565c2..26b5c5aef9 100644 --- a/tensorflow/python/ops/distributions/multinomial.py +++ b/tensorflow/python/ops/distributions/multinomial.py @@ -29,6 +29,7 @@ from tensorflow.python.ops import nn_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -50,6 +51,7 @@ fractional components, and such that with `self.probs` and `self.total_count`.""" +@tf_export("distributions.Multinomial") class Multinomial(distribution.Distribution): """Multinomial distribution. diff --git a/tensorflow/python/ops/distributions/normal.py b/tensorflow/python/ops/distributions/normal.py index 0ef1c91df8..e7f120ea2d 100644 --- a/tensorflow/python/ops/distributions/normal.py +++ b/tensorflow/python/ops/distributions/normal.py @@ -32,6 +32,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import kullback_leibler from tensorflow.python.ops.distributions import special_math +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -40,6 +41,7 @@ __all__ = [ ] +@tf_export("distributions.Normal") class Normal(distribution.Distribution): """The Normal distribution with location `loc` and `scale` parameters. diff --git a/tensorflow/python/ops/distributions/student_t.py b/tensorflow/python/ops/distributions/student_t.py index 073ac4286b..778fefb8c2 100644 --- a/tensorflow/python/ops/distributions/student_t.py +++ b/tensorflow/python/ops/distributions/student_t.py @@ -33,6 +33,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops import special_math_ops from tensorflow.python.ops.distributions import distribution from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -41,6 +42,7 @@ __all__ = [ ] +@tf_export("distributions.StudentT") class StudentT(distribution.Distribution): """Student's t-distribution. diff --git a/tensorflow/python/ops/distributions/uniform.py b/tensorflow/python/ops/distributions/uniform.py index 9b555f87ea..3580af18f2 100644 --- a/tensorflow/python/ops/distributions/uniform.py +++ b/tensorflow/python/ops/distributions/uniform.py @@ -29,8 +29,10 @@ from tensorflow.python.ops import check_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import distribution +from tensorflow.python.util.tf_export import tf_export +@tf_export("distributions.Uniform") class Uniform(distribution.Distribution): """Uniform distribution with `low` and `high` parameters. diff --git a/tensorflow/tools/api/generator/BUILD b/tensorflow/tools/api/generator/BUILD index 26f5223334..8bbd247818 100644 --- a/tensorflow/tools/api/generator/BUILD +++ b/tensorflow/tools/api/generator/BUILD @@ -46,6 +46,8 @@ genrule( "api/bitwise/__init__.py", "api/contrib/__init__.py", "api/contrib/stat_summarizer/__init__.py", + "api/distributions/__init__.py", + "api/distributions/bijectors/__init__.py", "api/image/__init__.py", "api/linalg/__init__.py", "api/nn/__init__.py", -- GitLab From fb2f927841effc420cbb891fec5efd0d329bf20e Mon Sep 17 00:00:00 2001 From: Yunxing Dai Date: Mon, 22 Jan 2018 20:43:06 -0800 Subject: [PATCH 085/258] [XLA] Make kokoro happy in prng_test Open source builds don't support bit_cast yet, use reinterpret cast instead. RELNOTES: n/a PiperOrigin-RevId: 182879589 --- tensorflow/compiler/xla/tests/prng_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/compiler/xla/tests/prng_test.cc b/tensorflow/compiler/xla/tests/prng_test.cc index d8d7272c3b..6aafb9fa6c 100644 --- a/tensorflow/compiler/xla/tests/prng_test.cc +++ b/tensorflow/compiler/xla/tests/prng_test.cc @@ -26,7 +26,6 @@ limitations under the License. #include "tensorflow/compiler/xla/tests/test_macros.h" #include "tensorflow/compiler/xla/util.h" #include "tensorflow/compiler/xla/xla_data.pb.h" -#include "tensorflow/core/lib/core/casts.h" #include "tensorflow/core/lib/gtl/array_slice.h" #include "tensorflow/core/platform/protobuf.h" #include "tensorflow/core/platform/test.h" @@ -87,7 +86,8 @@ XLA_TEST_F(PrngTest, DISABLED_ON_GPU(DISABLED_ON_CPU_PARALLEL( for (int64 seed = 0; seed < 100; ++seed) { // The largest negative number smaller than zero in bf16 that's not // denormalized. - float low = bit_cast(0x80800000); + int32 low_raw = 0x80800000; + const float low = reinterpret_cast(low_raw); float high = 0.0f; UniformTest(static_cast(low), static_cast(high), {}, /*seed=*/seed); -- GitLab From d16b06c6967c0e29c2cd0f7a170f316163c58f31 Mon Sep 17 00:00:00 2001 From: Jianwei Xie Date: Mon, 22 Jan 2018 22:06:10 -0800 Subject: [PATCH 086/258] Puts the iterations_per_loop, which controls how many steps the TPU system to run for each training/evaluatoin loop, into local variable collection. PiperOrigin-RevId: 182884955 --- tensorflow/contrib/tpu/python/tpu/tpu_estimator.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index bb35f4ece6..b25ab1707e 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -92,7 +92,8 @@ def _create_global_step(graph): def _create_or_get_iterations_per_loop(): graph = ops.get_default_graph() - iter_vars = graph.get_collection(_TPU_ESTIMATOR) + collection_name = '{}_{}'.format(_TPU_ESTIMATOR, _ITERATIONS_PER_LOOP_VAR) + iter_vars = graph.get_collection(collection_name) if len(iter_vars) == 1: return iter_vars[0] elif len(iter_vars) > 1: @@ -107,7 +108,7 @@ def _create_or_get_iterations_per_loop(): shape=[], dtype=dtypes.int32, trainable=False, - collections=[_TPU_ESTIMATOR], + collections=[collection_name, ops.GraphKeys.LOCAL_VARIABLES], use_resource=True) -- GitLab From 26cdf8e3fdb0a13d19b2aedfc6c0ef1eb94c4c44 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Mon, 22 Jan 2018 22:56:04 -0800 Subject: [PATCH 087/258] [XLA] Speed up HloEvaluator's convolution routine. Skip two integer divisions when the window has no dilation. This is good for a ~30% speedup on my machine. PiperOrigin-RevId: 182887749 --- .../compiler/xla/service/hlo_evaluator.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_evaluator.cc b/tensorflow/compiler/xla/service/hlo_evaluator.cc index 3a846a7529..2112cf57c7 100644 --- a/tensorflow/compiler/xla/service/hlo_evaluator.cc +++ b/tensorflow/compiler/xla/service/hlo_evaluator.cc @@ -945,14 +945,21 @@ class HloEvaluator::TypedVisitor : public DfsHloVisitorWithDefault { out_index[output_spatial_dim] * window_dim.stride() - window_dim.padding_low() + rhs_spatial_index[ki] * window_dim.window_dilation(); - // Skip if the lhs (input) index is to be dilated. - if (undilated_index % window_dim.base_dilation() != 0) { + // Skip if the lhs (input) index is to be dilated. As an + // optimization, skip this mod if there's no dilation. + if (window_dim.base_dilation() > 1 && + undilated_index % window_dim.base_dilation() != 0) { goto cnt; } - // Calculate the actual lhs (input) index after dilation. - lhs_index[input_spatial_dim] = - undilated_index / window_dim.base_dilation(); + // Calculate the actual lhs (input) index after dilation. As an + // optimization, skip this integer divide if there's no dilation. + if (window_dim.base_dilation() > 1) { + lhs_index[input_spatial_dim] = + undilated_index / window_dim.base_dilation(); + } else { + lhs_index[input_spatial_dim] = undilated_index; + } // Skip if input index is not in bound. if (!(lhs_index[input_spatial_dim] >= 0 && -- GitLab From 4c28fbf2c0d20ed714fd0209913b868a7955ac5a Mon Sep 17 00:00:00 2001 From: starsblinking <32723536+starsblinking@users.noreply.github.com> Date: Tue, 23 Jan 2018 15:02:17 +0800 Subject: [PATCH 088/258] Repair compilation error of tensorflow built with MKL-DNN (#16280) --- tensorflow/core/kernels/mkl_lrn_op.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/kernels/mkl_lrn_op.cc b/tensorflow/core/kernels/mkl_lrn_op.cc index 66bc7dd8ee..95e0404ba8 100644 --- a/tensorflow/core/kernels/mkl_lrn_op.cc +++ b/tensorflow/core/kernels/mkl_lrn_op.cc @@ -43,7 +43,7 @@ limitations under the License. using mkldnn::lrn_forward; using mkldnn::lrn_backward; using mkldnn::prop_kind; -using mkldnn::algorithm::lrn_across_channels; +using mkldnn::lrn_across_channels; using mkldnn::stream; #endif -- GitLab From b5a1ac0dbaed5b3e0e2a620379a68f42edc87fb8 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Mon, 22 Jan 2018 23:29:57 -0800 Subject: [PATCH 089/258] [XLA] Inline definitions of NativeToPrimitiveType. These functions are hot in the evaluator, and that's silly, because they're pure constants. Just inline them. PiperOrigin-RevId: 182889992 --- tensorflow/compiler/xla/primitive_util.cc | 73 ----------------------- tensorflow/compiler/xla/primitive_util.h | 62 ++++++++++++++----- 2 files changed, 47 insertions(+), 88 deletions(-) diff --git a/tensorflow/compiler/xla/primitive_util.cc b/tensorflow/compiler/xla/primitive_util.cc index 2bce56b7bd..143c9a2366 100644 --- a/tensorflow/compiler/xla/primitive_util.cc +++ b/tensorflow/compiler/xla/primitive_util.cc @@ -20,79 +20,6 @@ limitations under the License. namespace xla { namespace primitive_util { -template <> -PrimitiveType NativeToPrimitiveType() { - return PRED; -} - -// Unsigned integer -template <> -PrimitiveType NativeToPrimitiveType() { - return U8; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return U16; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return U32; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return U64; -} - -// Signed integer -template <> -PrimitiveType NativeToPrimitiveType() { - return S8; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return S16; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return S32; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return S64; -} - -// Floating point -template <> -PrimitiveType NativeToPrimitiveType() { - return F32; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return F64; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return BF16; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return F16; -} - -template <> -PrimitiveType NativeToPrimitiveType() { - return C64; -} - bool IsFloatingPointType(PrimitiveType type) { return type == F16 || type == F32 || type == F64 || type == BF16; } diff --git a/tensorflow/compiler/xla/primitive_util.h b/tensorflow/compiler/xla/primitive_util.h index cb4583d198..b26a10ade6 100644 --- a/tensorflow/compiler/xla/primitive_util.h +++ b/tensorflow/compiler/xla/primitive_util.h @@ -47,49 +47,81 @@ PrimitiveType NativeToPrimitiveType() { } // Declarations of specializations for each native type which correspond to a -// XLA primitive type. +// XLA primitive type. As an optimization, these are declared inline in the +// header. template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return PRED; +} // Unsigned integer template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return U8; +} template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return U16; +} template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return U32; +} template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return U64; +} // Signed integer template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return S8; +} template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return S16; +} template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return S32; +} template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return S64; +} // Floating point template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return F32; +} + template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return F64; +} + template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return F16; +} + template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return BF16; +} // Complex template <> -PrimitiveType NativeToPrimitiveType(); +inline PrimitiveType NativeToPrimitiveType() { + return C64; +} bool IsFloatingPointType(PrimitiveType type); -- GitLab From ee2010ade01e7705157e2845643b664b5719db53 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 00:10:52 -0800 Subject: [PATCH 090/258] Turn off address sanitizer checking for tensorflow/python/kernel_tests:sparse_ops_test It getting too many timeouts. PiperOrigin-RevId: 182892876 --- tensorflow/python/kernel_tests/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/python/kernel_tests/BUILD b/tensorflow/python/kernel_tests/BUILD index c6a4510e8f..8c1d16c2a8 100644 --- a/tensorflow/python/kernel_tests/BUILD +++ b/tensorflow/python/kernel_tests/BUILD @@ -2490,6 +2490,7 @@ cuda_py_test( "//tensorflow/python:sparse_ops", ], shard_count = 5, + tags = ["noasan"], ) cuda_py_test( -- GitLab From 592d2d67daca18db98c7f67b0a55ef487ed76f1c Mon Sep 17 00:00:00 2001 From: Valentin Khrulkov Date: Tue, 23 Jan 2018 17:19:36 +0300 Subject: [PATCH 091/258] Transpose for high dimensional tensors using eigen (#15893) * speeding up transpose on CPU --- .../core/kernels/transpose_functor_cpu.cc | 12 +++++++++++ .../core/kernels/transpose_functor_gpu.cu.cc | 21 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tensorflow/core/kernels/transpose_functor_cpu.cc b/tensorflow/core/kernels/transpose_functor_cpu.cc index 41b73fdaf4..6594f7ee7b 100644 --- a/tensorflow/core/kernels/transpose_functor_cpu.cc +++ b/tensorflow/core/kernels/transpose_functor_cpu.cc @@ -88,6 +88,18 @@ struct Transpose { internal::TransposeUsingEigen(d, in, perm, conjugate, out); break; + case 6: + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + break; + case 7: + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + break; + case 8: + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + break; default: TransposeSimple(d, in, perm, out); break; diff --git a/tensorflow/core/kernels/transpose_functor_gpu.cu.cc b/tensorflow/core/kernels/transpose_functor_gpu.cu.cc index 493dac9a7c..d6a237d6c1 100644 --- a/tensorflow/core/kernels/transpose_functor_gpu.cu.cc +++ b/tensorflow/core/kernels/transpose_functor_gpu.cu.cc @@ -201,6 +201,27 @@ struct Transpose { out); } break; + case 6: + if (!internal::TransposeUsingTile::run(d, in, perm, + out)) { + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + } + break; + case 7: + if (!internal::TransposeUsingTile::run(d, in, perm, + out)) { + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + } + break; + case 8: + if (!internal::TransposeUsingTile::run(d, in, perm, + out)) { + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + } + break; default: internal::TransposeSimple(d, in, perm, out); break; -- GitLab From 22c0a40e2f1980445b9616ea969931fb096595ff Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 09:18:11 -0800 Subject: [PATCH 092/258] Correct handling of dtype for Categorical sampling. PiperOrigin-RevId: 182943806 --- .../python/kernel_tests/distributions/categorical_test.py | 4 ++++ tensorflow/python/ops/distributions/categorical.py | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/kernel_tests/distributions/categorical_test.py b/tensorflow/python/kernel_tests/distributions/categorical_test.py index 019c1bc353..ca2358fe99 100644 --- a/tensorflow/python/kernel_tests/distributions/categorical_test.py +++ b/tensorflow/python/kernel_tests/distributions/categorical_test.py @@ -100,6 +100,10 @@ class CategoricalTest(test.TestCase): self.assertEqual( dist.logits.dtype, dist.log_prob(np.array( 0, dtype=np.int64)).dtype) + for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: + dist = make_categorical([], 5, dtype=dtype) + self.assertEqual(dist.dtype, dtype) + self.assertEqual(dist.dtype, dist.sample(5).dtype) def testUnknownShape(self): with self.test_session(): diff --git a/tensorflow/python/ops/distributions/categorical.py b/tensorflow/python/ops/distributions/categorical.py index 60a515583e..9161e3fa9f 100644 --- a/tensorflow/python/ops/distributions/categorical.py +++ b/tensorflow/python/ops/distributions/categorical.py @@ -265,7 +265,9 @@ class Categorical(distribution.Distribution): logits_2d = self.logits else: logits_2d = array_ops.reshape(self.logits, [-1, self.event_size]) - draws = random_ops.multinomial(logits_2d, n, seed=seed) + sample_dtype = dtypes.int64 if self.dtype.size > 4 else dtypes.int32 + draws = random_ops.multinomial( + logits_2d, n, seed=seed, output_dtype=sample_dtype) draws = array_ops.reshape( array_ops.transpose(draws), array_ops.concat([[n], self.batch_shape_tensor()], 0)) -- GitLab From ab8f0b711feb8dc375a8d29ad5f76dc8df3effad Mon Sep 17 00:00:00 2001 From: dssgsra Date: Wed, 24 Jan 2018 01:35:39 +0800 Subject: [PATCH 093/258] fix typo (#16142) --- tensorflow/core/kernels/pooling_ops_common.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/kernels/pooling_ops_common.cc b/tensorflow/core/kernels/pooling_ops_common.cc index 6a52a15c93..d4241b5809 100644 --- a/tensorflow/core/kernels/pooling_ops_common.cc +++ b/tensorflow/core/kernels/pooling_ops_common.cc @@ -222,7 +222,7 @@ void DnnPoolingOp::Compute( output_desc, &output_data) .ok(); OP_REQUIRES(context, status, - errors::Internal("cudnn PoolBackward launch failed")); + errors::Internal("cudnn PoolForward launch failed")); if (data_format == FORMAT_NHWC) { /// Transform the output data from NCHW back to NHWC -- GitLab From d9df9121827706d99641cd80875875f69befa0f1 Mon Sep 17 00:00:00 2001 From: Robin Richtsfeld Date: Wed, 27 Dec 2017 23:21:12 +0100 Subject: [PATCH 094/258] Turn check_futures_test into a sanity check --- tensorflow/tools/ci_build/ci_sanity.sh | 9 +++++++-- tensorflow/tools/test/BUILD | 9 --------- tensorflow/tools/test/check_futures_test.py | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tensorflow/tools/ci_build/ci_sanity.sh b/tensorflow/tools/ci_build/ci_sanity.sh index 06421c6bb5..eedc931afe 100755 --- a/tensorflow/tools/ci_build/ci_sanity.sh +++ b/tensorflow/tools/ci_build/ci_sanity.sh @@ -511,9 +511,14 @@ do_cmake_python_sanity() { python -m unittest -v python_sanity_test } +do_check_futures_test() { + cd "$ROOT_DIR/tensorflow/tools/test" + python check_futures_test.py +} + # Supply all sanity step commands and descriptions -SANITY_STEPS=("do_pylint PYTHON2" "do_pylint PYTHON3" "do_buildifier" "do_bazel_nobuild" "do_pip_package_licenses_check" "do_lib_package_licenses_check" "do_java_package_licenses_check" "do_pip_smoke_test" "do_check_load_py_test" "do_code_link_check" "do_cmake_python_sanity") -SANITY_STEPS_DESC=("Python 2 pylint" "Python 3 pylint" "buildifier check" "bazel nobuild" "pip: license check for external dependencies" "C library: license check for external dependencies" "Java Native Library: license check for external dependencies" "Pip Smoke Test: Checking py_test dependencies exist in pip package" "Check load py_test: Check that BUILD files with py_test target properly load py_test" "Code Link Check: Check there are no broken links" "Test entries in /tensorflow/contrib/cmake/python_{modules|protos|protos_cc}.txt for validity and consistency") +SANITY_STEPS=("do_pylint PYTHON2" "do_pylint PYTHON3" "do_check_futures_test" "do_buildifier" "do_bazel_nobuild" "do_pip_package_licenses_check" "do_lib_package_licenses_check" "do_java_package_licenses_check" "do_pip_smoke_test" "do_check_load_py_test" "do_code_link_check" "do_cmake_python_sanity") +SANITY_STEPS_DESC=("Python 2 pylint" "Python 3 pylint" "Check that python files have certain __future__ imports" "buildifier check" "bazel nobuild" "pip: license check for external dependencies" "C library: license check for external dependencies" "Java Native Library: license check for external dependencies" "Pip Smoke Test: Checking py_test dependencies exist in pip package" "Check load py_test: Check that BUILD files with py_test target properly load py_test" "Code Link Check: Check there are no broken links" "Test entries in /tensorflow/contrib/cmake/python_{modules|protos|protos_cc}.txt for validity and consistency") INCREMENTAL_FLAG="" DEFAULT_BAZEL_CONFIGS="--config=hdfs --config=gcp" diff --git a/tensorflow/tools/test/BUILD b/tensorflow/tools/test/BUILD index 28d651e910..159a8c1cfb 100644 --- a/tensorflow/tools/test/BUILD +++ b/tensorflow/tools/test/BUILD @@ -104,12 +104,3 @@ filegroup( ), visibility = ["//tensorflow:__subpackages__"], ) - -py_test( - name = "check_futures_test", - size = "small", - srcs = ["check_futures_test.py"], - data = ["//tensorflow:all_opensource_files"], - srcs_version = "PY2AND3", - deps = ["@six_archive//:six"], -) diff --git a/tensorflow/tools/test/check_futures_test.py b/tensorflow/tools/test/check_futures_test.py index 1c07511888..9181c9bd4a 100644 --- a/tensorflow/tools/test/check_futures_test.py +++ b/tensorflow/tools/test/check_futures_test.py @@ -33,7 +33,7 @@ import re import six -BASE_DIR = os.path.normpath(os.path.join(__file__, '../../..')) +BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')) FUTURES_PATTERN = re.compile(r'^from __future__ import (\w+)\s*$') FUTURES_PATTERN_2 = re.compile( r'^from __future__ import (\w+), (\w+), (\w+)\s*$') -- GitLab From 03760b7ad6e43e7f84cb4beb17814c58fe60f667 Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Tue, 23 Jan 2018 09:46:25 -0800 Subject: [PATCH 095/258] The link translator expects "@{" for API links. This is currently not rendering: https://www.tensorflow.org/api_docs/python/tf/contrib/tpu/TPUEstimatorSpec PiperOrigin-RevId: 182947562 --- tensorflow/contrib/tpu/python/tpu/tpu_estimator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index b25ab1707e..b6d685b3fc 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -388,7 +388,7 @@ class TPUEstimatorSpec(collections.namedtuple('TPUEstimatorSpec', [ `metric_fn` runs on CPU to generate metrics and `tensors` represents the `Tensor`s transferred from TPU system to CPU host and passed to `metric_fn`. To be precise, TPU evaluation expects a slightly different signature from the - ${tf.estimator.Estimator}. While `EstimatorSpec.eval_metric_ops` expects a + @{tf.estimator.Estimator}. While `EstimatorSpec.eval_metric_ops` expects a dict, `TPUEstimatorSpec.eval_metrics` is a tuple of `metric_fn` and `tensors`. The `tensors` could be a list of `Tensor`s or dict of names to `Tensor`s. The `tensors` usually specify the model logits, which are transferred back from -- GitLab From d1d88f6ec0ecc412d2d47eccdcbf3426601ebcfb Mon Sep 17 00:00:00 2001 From: Robin Richtsfeld Date: Thu, 28 Dec 2017 02:23:58 +0100 Subject: [PATCH 096/258] De-Bazel check_load_py_test sanity check --- tensorflow/tools/ci_build/ci_sanity.sh | 11 ++--------- tensorflow/tools/pip_package/BUILD | 9 --------- tensorflow/tools/pip_package/check_load_py_test.py | 3 +++ 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/tensorflow/tools/ci_build/ci_sanity.sh b/tensorflow/tools/ci_build/ci_sanity.sh index 06421c6bb5..d7a3433871 100755 --- a/tensorflow/tools/ci_build/ci_sanity.sh +++ b/tensorflow/tools/ci_build/ci_sanity.sh @@ -495,15 +495,8 @@ do_clang_format_check() { } do_check_load_py_test() { - BUILD_CMD="bazel build ${BAZEL_FLAGS} //tensorflow/tools/pip_package:check_load_py_test" - ${BUILD_CMD} - cmd_status \ - "check_load_py_test failed to build." - - BUILD_CMD="bazel-bin/tensorflow/tools/pip_package/check_load_py_test" - ${BUILD_CMD} - cmd_status \ - "check_load_py_test failed." + cd "$ROOT_DIR/tensorflow/tools/pip_package" + python check_load_py_test.py } do_cmake_python_sanity() { diff --git a/tensorflow/tools/pip_package/BUILD b/tensorflow/tools/pip_package/BUILD index c5f39ef7aa..c789e2ba0c 100644 --- a/tensorflow/tools/pip_package/BUILD +++ b/tensorflow/tools/pip_package/BUILD @@ -47,15 +47,6 @@ py_binary( deps = ["//tensorflow:tensorflow_py"], ) -py_binary( - name = "check_load_py_test", - srcs = ["check_load_py_test.py"], - data = [ - "//tensorflow:all_opensource_files", - ], - srcs_version = "PY2AND3", -) - # On Windows, python binary is a zip file of runfiles tree. # Add everything to its data dependency for generating a runfiles tree # for building the pip package on Windows. diff --git a/tensorflow/tools/pip_package/check_load_py_test.py b/tensorflow/tools/pip_package/check_load_py_test.py index 79d11b08ce..e2fe1121d7 100644 --- a/tensorflow/tools/pip_package/check_load_py_test.py +++ b/tensorflow/tools/pip_package/check_load_py_test.py @@ -22,6 +22,9 @@ import os import subprocess +os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))) + + def check_output_despite_error(args): """Get output of args from command line, even if there are errors. -- GitLab From 297ae45a079eedbf4fd32105d7c7ed95b072a0fa Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 23 Jan 2018 09:51:19 -0800 Subject: [PATCH 097/258] Add C++ toolchain for portable Linux builds (#16173) See #15777 --- tensorflow/workspace.bzl | 2 + third_party/toolchains/clang6/BUILD | 1 + third_party/toolchains/clang6/CROSSTOOL.tpl | 587 ++++++++++++++++++++ third_party/toolchains/clang6/README.md | 101 ++++ third_party/toolchains/clang6/clang.BUILD | 162 ++++++ third_party/toolchains/clang6/repo.bzl | 30 + 6 files changed, 883 insertions(+) create mode 100644 third_party/toolchains/clang6/BUILD create mode 100644 third_party/toolchains/clang6/CROSSTOOL.tpl create mode 100644 third_party/toolchains/clang6/README.md create mode 100644 third_party/toolchains/clang6/clang.BUILD create mode 100644 third_party/toolchains/clang6/repo.bzl diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 25702087dc..9811aa72fe 100644 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -5,6 +5,7 @@ load("//third_party/mkl:build_defs.bzl", "mkl_repository") load("//third_party/git:git_configure.bzl", "git_configure") load("//third_party/py:python_configure.bzl", "python_configure") load("//third_party/sycl:sycl_configure.bzl", "sycl_configure") +load("//third_party/toolchains/clang6:repo.bzl", "clang6_configure") load("//third_party/toolchains/cpus/arm:arm_compiler_configure.bzl", "arm_compiler_configure") load("//third_party:repo.bzl", "tf_http_archive") load("@io_bazel_rules_closure//closure/private:java_import_external.bzl", "java_import_external") @@ -65,6 +66,7 @@ def tf_workspace(path_prefix="", tf_repo_name=""): # files, in case the parsing of those build files depends on the bazel # version we require here. check_bazel_version_at_least("0.5.4") + clang6_configure(name="local_config_clang6") cuda_configure(name="local_config_cuda") git_configure(name="local_config_git") sycl_configure(name="local_config_sycl") diff --git a/third_party/toolchains/clang6/BUILD b/third_party/toolchains/clang6/BUILD new file mode 100644 index 0000000000..ffd0fb0cdc --- /dev/null +++ b/third_party/toolchains/clang6/BUILD @@ -0,0 +1 @@ +package(default_visibility = ["//visibility:public"]) diff --git a/third_party/toolchains/clang6/CROSSTOOL.tpl b/third_party/toolchains/clang6/CROSSTOOL.tpl new file mode 100644 index 0000000000..2f3e662f02 --- /dev/null +++ b/third_party/toolchains/clang6/CROSSTOOL.tpl @@ -0,0 +1,587 @@ +major_version: "v1" +minor_version: "llvm:6.0.0" +default_target_cpu: "k8" + +default_toolchain { + cpu: "k8" + toolchain_identifier: "k8-clang-6.0-cxx-4.8-linux-gnu" +} + +toolchain { + compiler: "clang6" # bazel build --compiler=clang6 + target_cpu: "k8" # bazel build --cpu=k8 + target_libc: "GLIBC_2.19" # bazel build --glibc=GLIBC_2.19 + + abi_libc_version: "2.19" + abi_version: "gcc-4.8-cxx11" + builtin_sysroot: "" + cc_target_os: "linux-gnu" + default_python_version: "python2.7" + dynamic_runtimes_filegroup: "dynamic-runtime-libs-k8" + host_system_name: "x86_64-unknown-linux-gnu" + needsPic: true + static_runtimes_filegroup: "static-runtime-libs-k8" + supports_embedded_runtimes: true + supports_fission: true + supports_gold_linker: true + supports_incremental_linker: true + supports_interface_shared_objects: true + supports_normalizing_ar: true + supports_start_end_lib: true + supports_thin_archives: true + target_system_name: "x86_64-unknown-linux-gnu" + toolchain_identifier: "k8-clang-6.0-cxx-4.8-linux-gnu" + + tool_path { name: "ar" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-ar" } + tool_path { name: "as" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-as" } + tool_path { name: "compat-ld" path: "%package(@local_config_clang6//clang6)%/llvm/bin/ld.lld" } + tool_path { name: "cpp" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-cpp" } + tool_path { name: "dwp" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-dwp" } + tool_path { name: "gcc" path: "%package(@local_config_clang6//clang6)%/llvm/bin/clang" } + tool_path { name: "gcov" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-cov" } + tool_path { name: "ld" path: "%package(@local_config_clang6//clang6)%/llvm/bin/ld.lld" } + tool_path { name: "llvm-profdata" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-profdata" } + tool_path { name: "nm" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-nm" } + tool_path { name: "objcopy" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-objcopy" } + tool_path { name: "objdump" path: "%package(@local_config_clang6//clang6)%/sbin/objdump" } + tool_path { name: "strip" path: "%package(@local_config_clang6//clang6)%/sbin/strip" } + + unfiltered_cxx_flag: "-no-canonical-prefixes" + + # Make C++ compilation deterministic. Use linkstamping instead of these + # compiler symbols. + unfiltered_cxx_flag: "-Wno-builtin-macro-redefined" + unfiltered_cxx_flag: "-D__DATE__=\"redacted\"" + unfiltered_cxx_flag: "-D__TIMESTAMP__=\"redacted\"" + unfiltered_cxx_flag: "-D__TIME__=\"redacted\"" + + objcopy_embed_flag: "-I" + objcopy_embed_flag: "binary" + + # This action_config makes features flags propagate + # to CC_FLAGS for genrules, and eventually skylark. + action_config { + action_name: "cc-flags-make-variable" + config_name: "cc-flags-make-variable" + } + + # Security hardening on by default. + # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. + # We need to undef it before redefining it as some distributions now have + # it enabled by default. + compiler_flag: "-U_FORTIFY_SOURCE" + compiler_flag: "-D_FORTIFY_SOURCE=1" + compiler_flag: "-fstack-protector" + linker_flag: "-Wl,-z,relro,-z,now" + + # This adds a little bit more durability to our Clang build. + # + # At the moment, this only only be needed for: + # - add_boringssl_s390x.patch: --Wa,--noexecstack + # + # Folks who do maintenance work on TF Bazel Clang should consider + # commenting out these lines, while doing that work, to gain a better + # understanding of what the intersection of support looks like between GCC + # and Clang. Please note that, unlike Blaze, Bazel does not support + # -Xclang-only / -Xgcc-only. + compiler_flag: "-Wno-unknown-warning-option" + compiler_flag: "-Wno-unused-command-line-argument" + compiler_flag: "-Wno-ignored-optimization-argument" + + #### Common compiler options. #### + compiler_flag: "-D_REENTRANT" + compiler_flag: "-D__STDC_FORMAT_MACROS" + compiler_flag: "-DSUPPRESS_USE_FILE_OFFSET64" + compiler_flag: "-Wall" + compiler_flag: "-Wformat-security" + compiler_flag: "-Wframe-larger-than=16384" + compiler_flag: "-Wno-char-subscripts" + compiler_flag: "-Wno-error=deprecated-declarations" + compiler_flag: "-Wno-uninitialized" + compiler_flag: "-Wno-sign-compare" + compiler_flag: "-Wno-strict-overflow" + compiler_flag: "-Wno-unused-function" + compiler_flag: "-fdiagnostics-show-option" + compiler_flag: "-fmessage-length=0" + compiler_flag: "-fno-exceptions" + compiler_flag: "-fno-omit-frame-pointer" + compiler_flag: "-fno-strict-aliasing" + compiler_flag: "-fno-use-init-array" + compiler_flag: "-funsigned-char" + compiler_flag: "-gmlt" + cxx_flag: "-Wno-deprecated" + cxx_flag: "-Wno-invalid-offsetof" # Needed for protobuf code (2017-11-07) + cxx_flag: "-fshow-overloads=best" + compiler_flag: "-Wthread-safety-analysis" + + # Python extensions unfortunately make this go wild. + compiler_flag: "-Wno-writable-strings" + + # GCC's warning produces too many false positives: + cxx_flag: "-Woverloaded-virtual" + cxx_flag: "-Wnon-virtual-dtor" + + # Enable coloring even if there's no attached terminal. Bazel removes the + # escape sequences if --nocolor is specified. This isn't supported by gcc + # on Ubuntu 14.04. + compiler_flag: "-fcolor-diagnostics" + + # Disable some broken warnings from Clang. + compiler_flag: "-Wno-ambiguous-member-template" + compiler_flag: "-Wno-pointer-sign" + + # These warnings have a low signal to noise ratio. + compiler_flag: "-Wno-reserved-user-defined-literal" + compiler_flag: "-Wno-return-type-c-linkage" + compiler_flag: "-Wno-invalid-source-encoding" + + # Per default we switch off any layering related warnings. + compiler_flag: "-Wno-private-header" + + # Clang-specific warnings that we explicitly enable for TensorFlow. Some of + # these aren't on by default, or under -Wall, or are subsets of warnings + # turned off above. + compiler_flag: "-Wfloat-overflow-conversion" + compiler_flag: "-Wfloat-zero-conversion" + compiler_flag: "-Wfor-loop-analysis" + compiler_flag: "-Wgnu-redeclared-enum" + compiler_flag: "-Winfinite-recursion" + compiler_flag: "-Wliteral-conversion" + compiler_flag: "-Wself-assign" + compiler_flag: "-Wstring-conversion" + compiler_flag: "-Wtautological-overlap-compare" + compiler_flag: "-Wunused-comparison" + compiler_flag: "-Wvla" + cxx_flag: "-Wdeprecated-increment-bool" + + # Clang code-generation flags for performance optimization. + compiler_flag: "-faligned-allocation" + compiler_flag: "-fnew-alignment=8" + + # Clang defaults to C99 while GCC defaults to C89. GCC plugins are written in + # C89 and don't have a BUILD rule we could add a copts flag to. + gcc_plugin_compiler_flag: "-std=gnu89" + + compilation_mode_flags { + mode: FASTBUILD + } + + compilation_mode_flags { + mode: DBG + compiler_flag: "-g" + } + + compilation_mode_flags { + mode: OPT + compiler_flag: "-g0" + compiler_flag: "-fdebug-types-section" + compiler_flag: "-DNDEBUG" + compiler_flag: "-fno-split-dwarf-inlining" + compiler_flag: "-Os" + compiler_flag: "-fexperimental-new-pass-manager" + compiler_flag: "-fdebug-info-for-profiling" + compiler_flag: "-ffunction-sections" + compiler_flag: "-fdata-sections" + linker_flag: "-Wl,--gc-sections" + linker_flag: "-Wl,-z,relro,-z,now" + } + + # Features indicating whether this is a host compile or not. Exactly one of + # these will be implicitly provided by blaze. + feature { name: "host" } + feature { name: "nonhost" } + + # Features indicating which compiler will be used for code generation. + feature { + name: "llvm_codegen" + provides: "codegen" + enabled: true + } + + # Features for compilation modes. Exactly one of these will be implicitly + # provided by blaze. + feature { name: "fastbuild" } + feature { name: "dbg" } + feature { name: "opt" } + + # Features controlling the C++ language mode. + feature { + name: "c++11" + provides: "c++std" + flag_set { + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++11" + flag: "-Wc++14-extensions" + flag: "-Wc++2a-extensions" + flag: "-Wno-binary-literal" + } + } + } + feature { + name: "c++14" + provides: "c++std" + flag_set { + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++14" + flag: "-Wc++11-compat" + flag: "-Wno-c++11-compat-binary-literal" + flag: "-Wc++2a-extensions" + } + } + } + feature { + name: "c++17" + provides: "c++std" + flag_set { + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++17" + flag: "-Wc++11-compat" + flag: "-Wno-c++11-compat-binary-literal" + flag: "-Wc++2a-extensions" + } + } + } + feature { + name: "c++2a" + provides: "c++std" + flag_set { + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++2a" + flag: "-Wc++11-compat" + flag: "-Wno-c++11-compat-binary-literal" + } + } + } + feature { + name: "c++default" + enabled: true + flag_set { + # Provide the c++11 flags if no standard is selected + with_feature { + not_feature: "c++11" + not_feature: "c++14" + not_feature: "c++17" + not_feature: "c++2a" + } + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++11" + flag: "-Wc++14-extensions" + flag: "-Wc++2a-extensions" + flag: "-Wno-binary-literal" + } + } + } + + feature { + name: "use_compiler_rt" + requires { feature: "llvm_codegen" } + # TODO(saugustine): At the moment, "use_compiler_rt" also + # requires "linking_mode_flags { mode: FULLY_STATIC" ... }, + # but that isn't a feature. We should probably convert it. + flag_set { + action: "c++-link" + action: "c++-link-interface-dynamic-library" + action: "c++-link-dynamic-library" + action: "c++-link-executable" + # "link" is a misnomer for these actions. They are really just + # invocations of ar. + #action: "c++-link-pic-static-library" + #action: "c++-link-static-library" + #action: "c++-link-alwayslink-static-library" + #action: "c++-link-pic-static-library" + #action: "c++-link-alwayslink-pic-static-library" + flag_group { + flag: "-rtlib=compiler-rt" + flag: "-lunwind" + } + } + } + + feature { + name: "pie" + flag_set { + action: "assemble" + action: "preprocess-assemble" + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "c++-module-codegen" + action: "cc-flags-make-variable" + action: "lto-backend" + action: "linkstamp-compile" + flag_group { + flag: "-mpie-copy-relocations" + flag: "-fPIE" + } + } + flag_set { + action: "cc-flags-make-variable" + action: "c++-link-executable" + flag_group { + flag: "-pie" + } + } + } + + # Pic must appear after pie, because pic may need to override pie, and blaze + # turns it on selectively. These don't interact with other options. + # + # TODO: In practice, normal vs pic vs pie is a ternary mode. We should + # implement it that way. This will require changes to blaze, which only + # calculates whether or not pic is needed, not pie. + # + # NOTE: Bazel might make this all a moot point. + feature { + name: "pic" + flag_set { + action: "assemble" + action: "preprocess-assemble" + action: "c-compile" + action: "c++-compile" + action: "c++-module-codegen" + action: "c++-module-compile" + action: "linkstamp-compile" + expand_if_all_available: "pic" + flag_group { + flag: "-fPIC" + } + } + } + + feature { + name: "gold" + enabled: true + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-interface-dynamic-library" + flag_group { + expand_if_none_available: "lto" + flag: "-fuse-ld=gold" + } + } + } + + # This is great if you want linking TensorFlow to take ten minutes. + feature { + name: "lto" + requires { feature: "nonhost" } + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-flto=thin" + } + } + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-interface-dynamic-library" + flag_group { + flag: "-flto=thin" + } + } + } + + feature { + name: "parse_headers" + flag_set { + action: "c++-header-parsing" + flag_group { + flag: "-xc++-header" + flag: "-fsyntax-only" + } + } + } + + feature { + name: "preprocess_headers" + flag_set { + action: "c++-header-preprocessing" + flag_group { + flag: "-xc++" + flag: "-E" + } + } + } + + feature { + name: "per_object_debug_info" + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-module-codegen" + action: "assemble" + action: "preprocess-assemble" + action: "lto-backend" + flag_group { + flag: "-gsplit-dwarf" + flag: "-ggnu-pubnames" + } + } + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-interface-dynamic-library" + flag_group { + expand_if_all_available: "is_using_fission" + flag: "-Wl,--gdb-index" + } + } + } + + feature { + name: "xray" + requires { + feature: "llvm_codegen" + feature: "nonhost" + } + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "c++-link-interface-dynamic-library" + action: "c++-link-dynamic-library" + action: "c++-link-executable" + flag_group { + flag: "-fxray-instrument" + } + } + } + + feature { + name: "minimal_ubsan" + requires { feature: "llvm_codegen" } + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "c++-module-codegen" + flag_group { + flag: "-fsanitize=return,returns-nonnull-attribute,vla-bound,unreachable,float-cast-overflow" + flag: "-fsanitize-trap=all" + flag: "-DUNDEFINED_BEHAVIOR_SANITIZER" + } + } + } + + feature { + name: "minimal_ubsan_enabled_by_default" + requires { + feature: "llvm_codegen" + feature: "fastbuild" + } + enabled: true + implies: "minimal_ubsan" + } + + cxx_builtin_include_directory: "%package(@local_config_clang6//clang6)%/llvm/lib/clang/6.0.0/include" + cxx_builtin_include_directory: "/usr/include" + + unfiltered_cxx_flag: "-cxx-isystem" + unfiltered_cxx_flag: "/usr/include/c++/4.8" + unfiltered_cxx_flag: "-cxx-isystem" + unfiltered_cxx_flag: "/usr/include/x86_64-linux-gnu/c++/4.8" + unfiltered_cxx_flag: "-isystem" + unfiltered_cxx_flag: "%package(@local_config_clang6//clang6)%/llvm/lib/clang/6.0.0/include" + unfiltered_cxx_flag: "-isystem" + unfiltered_cxx_flag: "/usr/include/x86_64-linux-gnu" + unfiltered_cxx_flag: "-isystem" + unfiltered_cxx_flag: "/usr/include" + + linker_flag: "-Wl,--build-id=md5" + linker_flag: "-Wl,--fatal-warnings" + linker_flag: "-Wl,--hash-style=gnu" + linker_flag: "-no-canonical-prefixes" + linker_flag: "--target=x86_64-unknown-linux-gnu" + + linker_flag: "-L/usr/lib/gcc/x86_64-linux-gnu/4.8" + + # This is the minimum x86 architecture TensorFlow supports. + compiler_flag: "-DARCH_K8" + compiler_flag: "-m64" + + # These are for Linux. + ld_embed_flag: "-melf_x86_64" + linker_flag: "-Wl,--eh-frame-hdr" + linker_flag: "-Wl,-z,max-page-size=0x1000" + + # Google never uses the stack like a heap, e.g. alloca(), because tcmalloc + # and jemalloc are so fast. However copts=["$(STACK_FRAME_UNLIMITED)"] can be + # specified when that can't be the case. + make_variable { + name: "STACK_FRAME_UNLIMITED" + value: "-Wframe-larger-than=100000000 -Wno-vla" + } + + # These flags are for folks who build C/C++ code inside genrules. + make_variable { + name: "CC_FLAGS" + value: "-no-canonical-prefixes --target=x86_64-unknown-linux-gnu -fno-omit-frame-pointer -fno-tree-vrp -msse3" + } + + feature { + name: "copts" + flag_set { + expand_if_all_available: "copts" + action: "assemble" + action: "preprocess-assemble" + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "c++-module-codegen" + action: "lto-backend" + flag_group { + iterate_over: "copts" + flag: "%{copts}" + } + } + } + + # Please do not statically link libstdc++. This would probably lead to a lot + # of bloat since OpKernels need to use linkstatic=1 because b/27630669 and + # it could cause memory leaks since Python uses dlopen() on our libraries: + # https://stackoverflow.com/a/35015415 + linker_flag: "-lstdc++" + linker_flag: "-lm" + linker_flag: "-lpthread" + linker_flag: "-l:/lib/x86_64-linux-gnu/libc-2.19.so" +} diff --git a/third_party/toolchains/clang6/README.md b/third_party/toolchains/clang6/README.md new file mode 100644 index 0000000000..0c6be25a0e --- /dev/null +++ b/third_party/toolchains/clang6/README.md @@ -0,0 +1,101 @@ +# TensorFlow Bazel Clang + +This is a specialized toolchain that uses an old Debian with a new Clang that +can cross compile to any x86_64 microarchitecture. It's intended to build Linux +binaries that only require the following ABIs: + +- GLIBC_2.18 +- CXXABI_1.3.7 (GCC 4.8.3) +- GCC_4.2.0 + +Which are available on at least the following Linux platforms: + +- Ubuntu 14+ +- CentOS 7+ +- Debian 8+ +- SuSE 13.2+ +- Mint 17.3+ +- Manjaro 0.8.11 + +# System Install + +On Debian 8 (Jessie) Clang 6.0 can be installed as follows: + +```sh +cat >>/etc/apt/sources.list <<'EOF' +deb http://apt.llvm.org/jessie/ llvm-toolchain-jessie main +deb-src http://apt.llvm.org/jessie/ llvm-toolchain-jessie main +EOF +wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - +apt-key fingerprint |& grep '6084 F3CF 814B 57C1 CF12 EFD5 15CF 4D18 AF4F 7421' +apt-get update +apt-get install clang lld +``` + +# Bazel Configuration + +This toolchain can compile TensorFlow in 2m30s on a 96-core Skylake GCE VM if +the following `.bazelrc` settings are added: + +``` +startup --host_jvm_args=-Xmx30G +startup --host_jvm_args=-Xms30G +startup --host_jvm_args=-XX:MaxNewSize=3g +startup --host_jvm_args=-XX:-UseAdaptiveSizePolicy +startup --host_jvm_args=-XX:+UseConcMarkSweepGC +startup --host_jvm_args=-XX:TargetSurvivorRatio=70 +startup --host_jvm_args=-XX:SurvivorRatio=6 +startup --host_jvm_args=-XX:+UseCMSInitiatingOccupancyOnly +startup --host_jvm_args=-XX:CMSFullGCsBeforeCompaction=1 +startup --host_jvm_args=-XX:CMSInitiatingOccupancyFraction=75 + +build --jobs=100 +build --local_resources=200000,100,100 +build --crosstool_top=@local_config_clang6//clang6 +build --noexperimental_check_output_files +build --nostamp +build --config=opt +build --noexperimental_check_output_files +build --copt=-march=native +build --host_copt=-march=native +``` + +# x86_64 Microarchitectures + +## Intel CPU Line + +- 2003 P6 M SSE SSE2 +- 2004 prescott SSE3 SSSE3 (-march=prescott) +- 2006 core X64 SSE4.1 (only on 45nm variety) (-march=core2) +- 2008 nehalem SSE4.2 VT-x VT-d (-march=nehalem) +- 2010 westmere CLMUL AES (-march=westmere) +- 2012 sandybridge AVX TXT (-march=sandybridge) +- 2012 ivybridge F16C MOVBE (-march=ivybridge) +- 2013 haswell AVX2 TSX BMI2 FMA (-march=haswell) +- 2014 broadwell RDSEED ADCX PREFETCHW (-march=broadwell - works on trusty gcc4.9) +- 2015 skylake SGX ADX MPX AVX-512[xeon-only] (-march=skylake / -march=skylake-avx512 - needs gcc7) +- 2018 cannonlake AVX-512 SHA (-march=cannonlake - needs clang5) + +## Intel Low Power CPU Line + +- 2013 silvermont SSE4.1 SSE4.2 VT-x (-march=silvermont) +- 2016 goldmont SHA (-march=goldmont - needs clang5) + +## AMD CPU Line + +- 2003 k8 SSE SSE2 (-march=k8) +- 2005 k8 (Venus) SSE3 (-march=k8-sse3) +- 2008 barcelona SSE4a?! (-march=barcelona) +- 2011 bulldozer SSE4.1 SSE4.2 CLMUL AVX AES FMA4?! (-march=bdver1) +- 2011 piledriver FMA (-march=bdver2) +- 2015 excavator AVX2 BMI2 MOVBE (-march=bdver4) + +## Google Compute Engine Supported CPUs + +- 2012 sandybridge 2.6gHz -march=sandybridge +- 2012 ivybridge 2.5gHz -march=ivybridge +- 2013 haswell 2.3gHz -march=haswell +- 2014 broadwell 2.2gHz -march=broadwell +- 2015 skylake 2.0gHz -march=skylake-avx512 + +See: diff --git a/third_party/toolchains/clang6/clang.BUILD b/third_party/toolchains/clang6/clang.BUILD new file mode 100644 index 0000000000..ba45c6fc09 --- /dev/null +++ b/third_party/toolchains/clang6/clang.BUILD @@ -0,0 +1,162 @@ +package(default_visibility = ["//visibility:public"]) + +# Please note that the output of these tools is unencumbered. +licenses(["restricted"]) # NCSA, GPLv3 (e.g. gold) + +filegroup( + name = "ar", + srcs = ["llvm/bin/llvm-ar"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "as", + srcs = ["llvm/bin/llvm-as"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "cpp", + srcs = ["llvm/bin/llvm-cpp"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "dwp", + srcs = ["llvm/bin/llvm-dwp"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "gcc", + srcs = ["llvm/bin/clang"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "gcov", + srcs = ["llvm/bin/llvm-cov"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "ld", + srcs = ["llvm/bin/ld.lld"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "nm", + srcs = ["llvm/bin/llvm-nm"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "objcopy", + srcs = ["llvm/bin/llvm-objcopy"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "objdump", + srcs = ["llvm/bin/llvm-objdump"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "profdata", + srcs = ["llvm/bin/llvm-profdata"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "strip", + srcs = ["sbin/strip"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "xray", + srcs = ["llvm/bin/llvm-xray"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "includes", + srcs = glob(["llvm/lib/clang/6.0.0/include/**"]), + output_licenses = ["unencumbered"], +) + +filegroup( + name = "libraries", + srcs = glob([ + "lib/*.*", + "lib/clang/6.0.0/lib/linux/*.*", + ]), + output_licenses = ["unencumbered"], +) + +filegroup( + name = "compiler_files", + srcs = [ + ":as", + ":gcc", + ":includes", + ], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "linker_files", + srcs = [ + ":ar", + ":ld", + ":libraries", + ], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "all_files", + srcs = [ + ":compiler_files", + ":dwp", + ":gcov", + ":linker_files", + ":nm", + ":objcopy", + ":objdump", + ":profdata", + ":strip", + ":xray", + ], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "empty", + srcs = [], # bazel crashes without this + output_licenses = ["unencumbered"], +) + +cc_toolchain_suite( + name = "clang6", + toolchains = { + "k8|clang6": ":clang6-k8", + }, +) + +cc_toolchain( + name = "clang6-k8", + all_files = ":all_files", + compiler_files = ":compiler_files", + cpu = "k8", + dwp_files = ":dwp", + dynamic_runtime_libs = [":empty"], + linker_files = ":linker_files", + objcopy_files = ":objcopy", + output_licenses = ["unencumbered"], + static_runtime_libs = [":empty"], + strip_files = ":strip", + supports_param_files = 1, +) diff --git a/third_party/toolchains/clang6/repo.bzl b/third_party/toolchains/clang6/repo.bzl new file mode 100644 index 0000000000..b81f44506f --- /dev/null +++ b/third_party/toolchains/clang6/repo.bzl @@ -0,0 +1,30 @@ +"""Repository rule for Debian 8 Jessie Clang-6.0 portable Linux builds.""" + +def _clang6_configure(ctx): + # TODO(jart): It'd probably be better to use Bazel's struct.to_proto() + # method to generate a gigantic CROSSTOOL file that allows + # Clang to support everything. + ctx.symlink( + ctx.os.environ.get('TF_LLVM_PATH', + '/usr/lib/llvm-6.0'), + 'clang6/llvm') + ctx.symlink( + ctx.os.environ.get('STRIP', '/usr/bin/strip'), + 'clang6/sbin/strip') + ctx.symlink( + ctx.os.environ.get('OBJDUMP', '/usr/bin/objdump'), + 'clang6/sbin/objdump') + ctx.symlink(ctx.attr._build, 'clang6/BUILD') + ctx.template('clang6/CROSSTOOL', ctx.attr._crosstool, { + '%package(@local_config_clang6//clang6)%': str(ctx.path('clang6')), + }) + +clang6_configure = repository_rule( + implementation = _clang6_configure, + attrs = { + '_build': attr.label( + default=str(Label('//third_party/toolchains/clang6:clang.BUILD'))), + '_crosstool': attr.label( + default=str(Label('//third_party/toolchains/clang6:CROSSTOOL.tpl'))), + }, +) -- GitLab From a73a6cff9aa1ee3a6db00cbeccbebe192372b05a Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Tue, 23 Jan 2018 10:00:18 -0800 Subject: [PATCH 098/258] Fix `tf.pow(x, y)` edge case with integer x and negative integer y (#15607) * Fix `tf.pow(x, y)` edge case with integer x and negative integer y This fix tries to address the issue raised in 12156 where pow(x, y) hangs with an integer x and a negative value of y. This fix tries to throw out an error like numpy in this case: ``` >>> np.power([5, 5], [2, -2]) Traceback (most recent call last): File "", line 1, in ValueError: Integers to negative integer powers are not allowed. ``` This fix adds error to the C++ functor like safe div/mod so that and InvalidArgument error could be triggered if any one of the values of y is negative. This fix fix 12156. This fix is also related to 9560. Signed-off-by: Yong Tang Signed-off-by: Yong Tang * Add test cases for edge case of pow(x, y) where x is an integer and y is an negative integer Signed-off-by: Yong Tang * Add DataTypeIsSigned implementation And have a tight constraint on tf.pow error Signed-off-by: Yong Tang * Sanitize with clang-format -i --style=Google Signed-off-by: Yong Tang --- tensorflow/core/framework/types.h | 7 ++++ tensorflow/core/kernels/cwise_op_pow.cc | 7 ++-- tensorflow/core/kernels/cwise_ops.h | 35 +++++++++++++++++++ tensorflow/core/kernels/cwise_ops_common.cc | 5 +++ .../python/kernel_tests/cwise_ops_test.py | 27 ++++++++++++++ 5 files changed, 78 insertions(+), 3 deletions(-) diff --git a/tensorflow/core/framework/types.h b/tensorflow/core/framework/types.h index cb8e77f1df..ded6aa0991 100644 --- a/tensorflow/core/framework/types.h +++ b/tensorflow/core/framework/types.h @@ -453,6 +453,13 @@ inline bool DataTypeIsInteger(DataType dt) { return kDataTypeIsInteger.Contains(dt); } +// Is the dtype a signed integral type? +constexpr DataTypeSet kDataTypeIsSigned = + ToSet(DT_INT8) | ToSet(DT_INT16) | ToSet(DT_INT32) | ToSet(DT_INT64); +inline bool DataTypeIsSigned(DataType dt) { + return kDataTypeIsSigned.Contains(dt); +} + // Is the dtype an unsigned integral type? constexpr DataTypeSet kDataTypeIsUnsigned = ToSet(DT_UINT8) | ToSet(DT_UINT16) | ToSet(DT_UINT32) | ToSet(DT_UINT64); diff --git a/tensorflow/core/kernels/cwise_op_pow.cc b/tensorflow/core/kernels/cwise_op_pow.cc index 5fb0735ac1..cf86478b0f 100644 --- a/tensorflow/core/kernels/cwise_op_pow.cc +++ b/tensorflow/core/kernels/cwise_op_pow.cc @@ -16,8 +16,9 @@ limitations under the License. #include "tensorflow/core/kernels/cwise_ops_common.h" namespace tensorflow { -REGISTER7(BinaryOp, CPU, "Pow", functor::pow, float, Eigen::half, double, int32, - int64, complex64, complex128); +REGISTER5(BinaryOp, CPU, "Pow", functor::pow, float, Eigen::half, double, + complex64, complex128); +REGISTER2(BinaryOp, CPU, "Pow", functor::safe_pow, int32, int64); #if GOOGLE_CUDA REGISTER4(BinaryOp, GPU, "Pow", functor::pow, float, Eigen::half, double, @@ -25,5 +26,5 @@ REGISTER4(BinaryOp, GPU, "Pow", functor::pow, float, Eigen::half, double, #endif #ifdef TENSORFLOW_USE_SYCL REGISTER2(BinaryOp, SYCL, "Pow", functor::pow, float, double); -#endif // TENSORFLOW_USE_SYCL +#endif // TENSORFLOW_USE_SYCL } // namespace tensorflow diff --git a/tensorflow/core/kernels/cwise_ops.h b/tensorflow/core/kernels/cwise_ops.h index da70b1e314..06918075a4 100644 --- a/tensorflow/core/kernels/cwise_ops.h +++ b/tensorflow/core/kernels/cwise_ops.h @@ -21,6 +21,7 @@ limitations under the License. #include #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" + #include "tensorflow/core/framework/numeric_types.h" #include "tensorflow/core/framework/tensor_types.h" #include "tensorflow/core/kernels/bounds_check.h" @@ -115,6 +116,35 @@ struct functor_traits> { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; +template +struct safe_scalar_binary_pow_op { + static_assert(std::is_integral::value, "Integer type expected"); + static_assert(std::is_integral::value && + std::is_signed::value, + "Signed integer type expected"); + + bool* const error; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE safe_scalar_binary_pow_op(bool* error) + : error(error) {} + + EIGEN_DEVICE_FUNC inline Scalar operator()(const Scalar& a, + const Exponent& b) const { + const Exponent safe_b = tensorflow::internal::SubtleMustCopy(b); + if (TF_PREDICT_TRUE(safe_b >= 0)) { + return numext::pow(a, safe_b); + } else { + *error = true; + return 0; + } + } +}; + +template +struct functor_traits> { + enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; +}; + template struct safe_div_or_mod_op { static_assert(std::is_integral::value, "Integer type expected"); @@ -741,6 +771,11 @@ struct floor_div_real : base> {}; template struct pow : base> {}; +template +struct safe_pow : base> { + static const bool has_errors = true; +}; + template struct maximum : base> {}; diff --git a/tensorflow/core/kernels/cwise_ops_common.cc b/tensorflow/core/kernels/cwise_ops_common.cc index 693c6467ac..e561e59cf5 100644 --- a/tensorflow/core/kernels/cwise_ops_common.cc +++ b/tensorflow/core/kernels/cwise_ops_common.cc @@ -40,6 +40,11 @@ void BinaryOpShared::SetComputeError(OpKernelContext* ctx) { if ((op == "Div" || op == "Mod" || op == "FloorMod" || op == "FloorDiv") && DataTypeIsInteger(ctx->op_kernel().input_type(0))) { ctx->CtxFailure(errors::InvalidArgument("Integer division by zero")); + } else if ((op == "Pow") && + DataTypeIsInteger(ctx->op_kernel().input_type(0)) && + DataTypeIsSigned(ctx->op_kernel().input_type(1))) { + ctx->CtxFailure(errors::InvalidArgument( + "Integers to negative integer powers are not allowed")); } else { ctx->CtxFailure( errors::Internal("Unexpected error in binary operator " diff --git a/tensorflow/python/kernel_tests/cwise_ops_test.py b/tensorflow/python/kernel_tests/cwise_ops_test.py index cea12ea8ec..a91917b27f 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes as dtypes_lib +from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.ops import array_ops @@ -1168,6 +1169,32 @@ class BinaryOpTest(test.TestCase): self._compareCpu(x1, x2, np.arctan2, math_ops.atan2) self._compareGpu(x1, x2, np.arctan2, math_ops.atan2) + def testPowNegativeExponent(self): + for dtype in [np.int32, np.int64]: + with self.test_session(use_gpu=False) as sess: + with self.assertRaisesRegexp( + errors_impl.InvalidArgumentError, + "Integers to negative integer powers are not allowed"): + x = np.array([5, 2]).astype(dtype) + y = np.array([-2, 3]).astype(dtype) + sess.run(math_ops.pow(x, y)) + + with self.test_session(use_gpu=False) as sess: + with self.assertRaisesRegexp( + errors_impl.InvalidArgumentError, + "Integers to negative integer powers are not allowed"): + x = np.array([5, 2]).astype(dtype) + y = np.array([2, -3]).astype(dtype) + sess.run(math_ops.pow(x, y)) + + with self.test_session(use_gpu=False) as sess: + with self.assertRaisesRegexp( + errors_impl.InvalidArgumentError, + "Integers to negative integer powers are not allowed"): + x = np.array([5, 2]).astype(dtype) + y = -3 + sess.run(math_ops.pow(x, y)) + class ComparisonOpTest(test.TestCase): -- GitLab From 7c53bc7fbec18e8c6157832d89737bcc881ecfed Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Tue, 23 Jan 2018 10:01:18 -0800 Subject: [PATCH 099/258] Propagate the error string of GIF processing for decode_gif (#16113) * Propagate the error message to exception of `InvalidArgumentError` for `decode_gif` This fix tries to improve the error thrown by `decode_gif` to include the error string generated by GIF processing. Previously, the error was not very indicative as the error string returned by GIF processing was hidden: ``` .......... InvalidArgumentError (see above for traceback): Invalid GIF data, size 2091369 [[Node: DecodeGif = DecodeGif[_device="/job:localhost/replica:0/task:0/device:CPU:0"](ReadFile)]] ``` This fix propagate the error string to be part of the `InvalidArgumentError`: ``` InvalidArgumentError (see above for traceback): Invalid GIF data (size 2091369), can't process optimized gif [[Node: DecodeGif = DecodeGif[_device="/job:localhost/replica:0/task:0/device:CPU:0"](ReadFile)]] ``` This fix fixes 15838. Signed-off-by: Yong Tang * Reformat with clang-format -i --style=Google Signed-off-by: Yong Tang * Add unit test for decode_gif to cover changes so that error messages like `can't process optimized gif` are propagated to the exception of `InvalidArgumentError`. Signed-off-by: Yong Tang --- tensorflow/core/kernels/decode_image_op.cc | 39 +++++++++++----------- tensorflow/core/lib/gif/gif_io.cc | 16 +++++---- tensorflow/core/lib/gif/gif_io.h | 3 +- tensorflow/python/ops/image_ops_test.py | 10 ++++++ 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/tensorflow/core/kernels/decode_image_op.cc b/tensorflow/core/kernels/decode_image_op.cc index ceb152c3f0..44dcbf834c 100644 --- a/tensorflow/core/kernels/decode_image_op.cc +++ b/tensorflow/core/kernels/decode_image_op.cc @@ -87,11 +87,10 @@ class DecodeImageOp : public OpKernel { channels_ = 3; } else { OP_REQUIRES_OK(context, context->GetAttr("channels", &channels_)); - OP_REQUIRES( - context, - channels_ == 0 || channels_ == 1 || channels_ == 3 || channels_ == 4, - errors::InvalidArgument("channels must be 0, 1, 3, or 4, got ", - channels_)); + OP_REQUIRES(context, channels_ == 0 || channels_ == 1 || channels_ == 3 || + channels_ == 4, + errors::InvalidArgument( + "channels must be 0, 1, 3, or 4, got ", channels_)); } flags_.components = channels_; @@ -115,9 +114,8 @@ class DecodeImageOp : public OpKernel { if (format_ == kJpgFormat) { OP_REQUIRES_OK(context, context->GetAttr("ratio", &flags_.ratio)); - OP_REQUIRES(context, - flags_.ratio == 1 || flags_.ratio == 2 || flags_.ratio == 4 || - flags_.ratio == 8, + OP_REQUIRES(context, flags_.ratio == 1 || flags_.ratio == 2 || + flags_.ratio == 4 || flags_.ratio == 8, errors::InvalidArgument("ratio must be 1, 2, 4, or 8, got ", flags_.ratio)); OP_REQUIRES_OK(context, context->GetAttr("fancy_upscaling", @@ -132,9 +130,8 @@ class DecodeImageOp : public OpKernel { string dct_method; OP_REQUIRES_OK(context, context->GetAttr("dct_method", &dct_method)); OP_REQUIRES( - context, - (dct_method.empty() || dct_method == "INTEGER_FAST" || - dct_method == "INTEGER_ACCURATE"), + context, (dct_method.empty() || dct_method == "INTEGER_FAST" || + dct_method == "INTEGER_ACCURATE"), errors::InvalidArgument("dct_method must be one of " "{'', 'INTEGER_FAST', 'INTEGER_ACCURATE'}")); if (dct_method == "INTEGER_FAST") { @@ -160,9 +157,9 @@ class DecodeImageOp : public OpKernel { errors::InvalidArgument("Expected image (JPEG, PNG, or GIF), got ", FileFormatString(magic, input))); OP_REQUIRES(context, input.size() <= std::numeric_limits::max(), - errors::InvalidArgument( - FileFormatString(magic, input), - " contents are too large for int: ", input.size())); + errors::InvalidArgument(FileFormatString(magic, input), + " contents are too large for int: ", + input.size())); OP_REQUIRES(context, magic == kPngFormat || channel_bits_ == 8, errors::InvalidArgument(FileFormatString(magic, input), " does not support uint16 output")); @@ -215,10 +212,9 @@ class DecodeImageOp : public OpKernel { input.data(), input.size(), flags, nullptr /* nwarn */, [=, &output](int width, int height, int channels) -> uint8* { Status status(context->allocate_output( - 0, - format_ == kGifFormat - ? TensorShape({1, height, width, channels}) - : TensorShape({height, width, channels}), + 0, format_ == kGifFormat + ? TensorShape({1, height, width, channels}) + : TensorShape({height, width, channels}), &output)); if (!status.ok()) { VLOG(1) << status; @@ -294,6 +290,7 @@ class DecodeImageOp : public OpKernel { // Decode GIF, allocating tensor once the size is known. Tensor* output = nullptr; + string error_string; OP_REQUIRES( context, gif::Decode(input.data(), input.size(), @@ -320,8 +317,10 @@ class DecodeImageOp : public OpKernel { return nullptr; } return output->flat().data(); - }), - errors::InvalidArgument("Invalid GIF data, size ", input.size())); + }, + &error_string), + errors::InvalidArgument("Invalid GIF data (size ", input.size(), "), ", + error_string)); } private: diff --git a/tensorflow/core/lib/gif/gif_io.cc b/tensorflow/core/lib/gif/gif_io.cc index b5c0d9f621..1666a02f7d 100644 --- a/tensorflow/core/lib/gif/gif_io.cc +++ b/tensorflow/core/lib/gif/gif_io.cc @@ -17,6 +17,7 @@ limitations under the License. #include "tensorflow/core/lib/gif/gif_io.h" #include "tensorflow/core/lib/gtl/cleanup.h" +#include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/gif.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/mem.h" @@ -44,7 +45,8 @@ int input_callback(GifFileType* gif_file, GifByteType* buf, int size) { } uint8* Decode(const void* srcdata, int datasize, - std::function allocate_output) { + std::function allocate_output, + std::string* error_string) { int error_code = D_GIF_SUCCEEDED; InputBufferInfo info = {reinterpret_cast(srcdata), datasize}; GifFileType* gif_file = @@ -57,17 +59,17 @@ uint8* Decode(const void* srcdata, int datasize, } }); if (error_code != D_GIF_SUCCEEDED) { - LOG(ERROR) << "Fail to open gif file, reason: " - << GifErrorString(error_code); + *error_string = strings::StrCat("failed to open gif file: ", + GifErrorString(error_code)); return nullptr; } if (DGifSlurp(gif_file) != GIF_OK) { - LOG(ERROR) << "Fail to slurp gif file, reason: " - << GifErrorString(gif_file->Error); + *error_string = strings::StrCat("failed to slurp gif file: ", + GifErrorString(gif_file->Error)); return nullptr; } if (gif_file->ImageCount <= 0) { - LOG(ERROR) << "Gif file does not contain any image"; + *error_string = strings::StrCat("gif file does not contain any image"); return nullptr; } @@ -83,7 +85,7 @@ uint8* Decode(const void* srcdata, int datasize, GifImageDesc* img_desc = &this_image->ImageDesc; if (img_desc->Left != 0 || img_desc->Top != 0 || img_desc->Width != width || img_desc->Height != height) { - LOG(ERROR) << "Can't process optimized gif."; + *error_string = strings::StrCat("can't process optimized gif"); return nullptr; } diff --git a/tensorflow/core/lib/gif/gif_io.h b/tensorflow/core/lib/gif/gif_io.h index 5399e6a538..e4073f1edb 100644 --- a/tensorflow/core/lib/gif/gif_io.h +++ b/tensorflow/core/lib/gif/gif_io.h @@ -43,7 +43,8 @@ namespace tensorflow { namespace gif { uint8* Decode(const void* srcdata, int datasize, - std::function allocate_output); + std::function allocate_output, + std::string* error_string); } // namespace gif } // namespace tensorflow diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index 3a49d41c9e..80911ffe07 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -2833,6 +2833,16 @@ class PngTest(test_util.TensorFlowTestCase): class GifTest(test_util.TensorFlowTestCase): + def testOptimizedGifErrorString(self): + filename = "tensorflow/core/lib/gif/testdata/optimized.gif" + + with self.test_session(use_gpu=True) as sess: + gif = io_ops.read_file(filename) + image = image_ops.decode_gif(gif) + with self.assertRaisesRegexp( + errors.InvalidArgumentError, "can't process optimized gif"): + gif, image = sess.run([gif, image]) + def testValid(self): # Read some real GIFs prefix = "tensorflow/core/lib/gif/testdata/" -- GitLab From 5b97fda3612ccfc6f4c477e624e13a40f5e1ddad Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Tue, 23 Jan 2018 10:02:08 -0800 Subject: [PATCH 100/258] Fix unicode string conversion issue in Python 2 (#16168) * Fix unicode string conversion issue in Python 2 This fix tries to address the issue raised in 16149 where the unicode string conversion with Python 2 does not match the behavior with Python 3. The issue was that in Python 3, TensorFlow tries to do a unicode conversion in UTF8 while in Python 2 the default conversion was used. This fix addresses the issue so that behaviors of TensorFlow with Python 2 and Python 3 match. This fix fixes 16149. Signed-off-by: Yong Tang * Format py_func.cc with clang-foramt -i --style=Google Signed-off-by: Yong Tang * Add test case for unicode string conversion issue in Python 2 Signed-off-by: Yong Tang * Update NULL -> `nullptr` Signed-off-by: Yong Tang --- .../kernel_tests/batch_dataset_op_test.py | 22 +++++++++++++++++++ tensorflow/python/lib/core/py_func.cc | 19 ++++++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py index 53c8be1d1d..eac1c1960d 100644 --- a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright 2017 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -301,6 +302,27 @@ class BatchDatasetTest(test.TestCase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + def testPaddedBatchDatasetUnicode(self): + # See GitHub issue 16149 + def generator(): + data = [ + [u'Простой', u'тест', u'юникода'], + [u'никогда', u'не', u'бывает', u'простым']] + + for seq in data: + yield seq, [0, 1, 2, 3] + + dataset = dataset_ops.Dataset.from_generator( + generator, + (dtypes.string, dtypes.int32), + (tensor_shape.TensorShape([None]), tensor_shape.TensorShape([None]))) + padded_dataset = dataset.padded_batch(2, padded_shapes=([None], [None]), + padding_values=('', 0)) + with self.test_session() as sess: + next_element = padded_dataset.make_one_shot_iterator().get_next() + sess.run(next_element) + + def testPaddedBatchDatasetShapeSpecifications(self): int_placeholder = array_ops.placeholder(dtypes.int32) float_placeholder = array_ops.placeholder(dtypes.float32) diff --git a/tensorflow/python/lib/core/py_func.cc b/tensorflow/python/lib/core/py_func.cc index dc56b39486..d3bfa0ee33 100644 --- a/tensorflow/python/lib/core/py_func.cc +++ b/tensorflow/python/lib/core/py_func.cc @@ -31,6 +31,7 @@ limitations under the License. #include "tensorflow/python/lib/core/ndarray_tensor_bridge.h" #include "tensorflow/python/lib/core/py_util.h" #include "tensorflow/python/lib/core/safe_ptr.h" + #include namespace tensorflow { @@ -141,7 +142,8 @@ bool IsSingleNone(PyObject* obj) { return false; } std::array indices; - char* item_ptr = static_cast(PyArray_GetPtr(array_obj, indices.data())); + char* item_ptr = + static_cast(PyArray_GetPtr(array_obj, indices.data())); PyObject* item = PyArray_GETITEM(array_obj, item_ptr); CHECK(item); return item == Py_None; @@ -301,13 +303,22 @@ Status ConvertNdarrayToTensor(PyObject* obj, Tensor* ret) { if (PyBytes_AsStringAndSize(input_data[i], &el, &el_size) == -1) { #if PY_MAJOR_VERSION >= 3 el = PyUnicode_AsUTF8AndSize(input_data[i], &el_size); - if (!el) { +#else + el = nullptr; + if (PyUnicode_Check(input_data[i])) { + PyObject* unicode = PyUnicode_AsUTF8String(input_data[i]); + if (unicode) { + if (PyString_AsStringAndSize(unicode, &el, &el_size) == -1) { + Py_DECREF(unicode); + el = nullptr; + } + } + } #endif + if (!el) { return errors::Unimplemented("Unsupported object type ", input_data[i]->ob_type->tp_name); -#if PY_MAJOR_VERSION >= 3 } -#endif } tflat(i) = string(el, el_size); } -- GitLab From af528e6e2ca9b30ffde5c3f3c7ea6208753b0a95 Mon Sep 17 00:00:00 2001 From: eladweiss <31474666+eladweiss@users.noreply.github.com> Date: Tue, 23 Jan 2018 21:05:39 +0300 Subject: [PATCH 101/258] Fix compilation error and warnings with CUDA=0 (#16267) * [Verbs] - Fix compilation error when GOOGLE_CUDA=0. Signed-off-by: Elad Weiss * [Verbs] - Fix compilation warnings. Signed-off-by: Elad Weiss --- tensorflow/contrib/verbs/rdma.cc | 42 ++++++++++++++++++++------------ tensorflow/contrib/verbs/rdma.h | 1 + 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/tensorflow/contrib/verbs/rdma.cc b/tensorflow/contrib/verbs/rdma.cc index 948398ec03..ec5271abe0 100644 --- a/tensorflow/contrib/verbs/rdma.cc +++ b/tensorflow/contrib/verbs/rdma.cc @@ -335,7 +335,7 @@ uint32_t set_param(uint32_t default_val, const char* env_param) { enum ibv_mtu set_mtu(uint8_t port_num, ibv_context* context) { ibv_port_attr port_attr; - enum ibv_mtu mtu; + enum ibv_mtu mtu = IBV_MTU_512; string mtu_s; int rc, mtu_i; @@ -878,6 +878,7 @@ void RdmaMessageBuffer::SendNextItem() { } } +#if GOOGLE_CUDA static void CountCopies(const std::string& key, void* src_addr, void* dst_addr, size_t tensor_bytes, bool is_gpu_to_cpu) { #ifdef RDMA_COUNT_COPIES @@ -903,9 +904,11 @@ static void CountCopies(const std::string& key, void* src_addr, void* dst_addr, } RDMA_LOG(2) << "Copying tensor " << key << " From: " << src_addr << " To: " << dst_addr; -#endif +#endif // RDMA_COUNT_COPIES } +#endif // GOOGLE_CUDA +#ifdef RDMA_DATA_VALIDATION static uint64_t Checksum(Device* device, const DeviceContext* device_context, const Tensor& in) { uint64 checksum = 0; @@ -917,7 +920,7 @@ static uint64_t Checksum(Device* device, const DeviceContext* device_context, checksum = (device_context != nullptr) ? GPUUtil::Checksum(device, device_context, in) : GPUUtil::Checksum(in); -#endif +#endif // GOOGLE_CUDA } else { string s = in.SummarizeValue(999999); checksum = Hash64(s.c_str(), s.size(), 0); @@ -952,7 +955,9 @@ static void ValidateChecksum(uint64_t expected, uint64_t actual, } } } +#endif // RDMA_DATA_VALIDATION +#if GOOGLE_CUDA // Sync the 'done' operation on the GPU stream, but without all the data // copying. static void StreamGPUOp(Device* gpu_device, @@ -962,6 +967,7 @@ static void StreamGPUOp(Device* gpu_device, GPUUtil::CopyGPUTensorToCPU( gpu_device, device_context, &dummy1, &dummy2, done); } +#endif // GOOGLE_CUDA RdmaTensorResponse* RdmaChannel::AddTensorResponse(const RdmaMessage& rm) { mutex_lock lock{mu_}; @@ -1032,8 +1038,7 @@ void RdmaTensorResponse::RecvHandler(Rendezvous::ParsedKey parsed, const Rendezvous::Args& send_args, const Rendezvous::Args& recv_args, const Tensor& in, bool is_dead) { - Device* src_dev = nullptr; - Status s = PrepareRecvTensor(parsed, &src_dev); + Status s = PrepareRecvTensor(parsed, &src_dev_); if (!s.ok()) { SendErrorStatus(s); return; @@ -1043,19 +1048,19 @@ void RdmaTensorResponse::RecvHandler(Rendezvous::ParsedKey parsed, #ifdef RDMA_DATA_VALIDATION // Always send a meta data message with the source checksum meta_data_changed_ = rm_.type_ == RDMA_MESSAGE_TENSOR_REQUEST; - checksum_ = Checksum(src_dev, send_args.device_context, in); + checksum_ = Checksum(src_dev_, send_args.device_context, in); #endif bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); // string tensor needs to be serialized Tensor copy; TensorProto proto; const bool on_host = send_args.alloc_attrs.on_host(); - if (src_dev->tensorflow_gpu_device_info() && !on_host) { + if (src_dev_->tensorflow_gpu_device_info() && !on_host) { #if GOOGLE_CUDA DeviceContext* send_dev_context = send_args.device_context; CHECK(send_dev_context) - << "send dev name: " << src_dev->name() - << " gpu_info: " << src_dev->tensorflow_gpu_device_info(); + << "send dev name: " << src_dev_->name() + << " gpu_info: " << src_dev_->tensorflow_gpu_device_info(); if (can_memcpy) { // If the tensor is located on a GDR compatible GPU, there is no need to @@ -1068,7 +1073,7 @@ void RdmaTensorResponse::RecvHandler(Rendezvous::ParsedKey parsed, if ((in.TotalBytes() > 0) && !meta_data_changed_ && (RdmaMemoryMgr::Singleton().FindMemoryRegion( (void*)DMAHelper::base(&in), in.TotalBytes()) != nullptr)) { - StreamGPUOp(src_dev, send_dev_context, + StreamGPUOp(src_dev_, send_dev_context, [this, in, proto, is_dead](const Status& s) { Send(in, proto, is_dead, s); }); @@ -1083,13 +1088,13 @@ void RdmaTensorResponse::RecvHandler(Rendezvous::ParsedKey parsed, CountCopies(rm_.name_, (void*)DMAHelper::base(&in), (void*)DMAHelper::base(©), in.TotalBytes(), true); GPUUtil::CopyGPUTensorToCPU( - src_dev, send_dev_context, &in, ©, + src_dev_, send_dev_context, &in, ©, [this, copy, proto, is_dead](const Status& s) { Send(copy, proto, is_dead, s); }); } else { GPUUtil::SetProtoFromGPU( - in, src_dev, send_args.device_context, &proto, is_dead, + in, src_dev_, send_args.device_context, &proto, is_dead, [this, in, proto, is_dead](const Status& s) mutable { Send(in, proto, is_dead, s); }); @@ -1137,7 +1142,10 @@ void RdmaTensorResponse::Clone(const Tensor& in, const TensorProto& proto, // tensor content may change before re-request was completed. bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); if (can_memcpy && (in.TotalBytes() > 0)) { - Allocator* allocator = ProcessState::singleton()->GetCPUAllocator(0); + AllocatorAttributes host_alloc_attrs; + host_alloc_attrs.set_nic_compatible(true); + host_alloc_attrs.set_on_host(true); + Allocator* allocator = src_dev_->GetAllocator(host_alloc_attrs); tensor_ = new Tensor(allocator, in.dtype(), in.shape()); memcpy(DMAHelper::base(tensor_), DMAHelper::base(&in), in.TotalBytes()); } else { @@ -1243,9 +1251,8 @@ void RdmaTensorResponse::SendErrorStatus(const Status& status) { } void RdmaTensorResponse::Destroy() { - bool res = false; if (src_buffer_ != nullptr) { - res = src_buffer_->Unref(); + src_buffer_->Unref(); } if (tensor_ != nullptr) { delete tensor_; @@ -1333,7 +1340,8 @@ string RdmaMessage::CreateMessage(const RdmaMessage& rm) { << kErrorStatusMaxSize << " bytes). Truncated."; gsProtoSize = kErrorStatusMaxSize - 4; } - *(uint32_t*)&message[kErrorStatusStartIndex] = gsProtoSize; + uint32_t* proto_size = (uint32_t*)&message[kErrorStatusStartIndex]; + *proto_size = gsProtoSize; gsProto.SerializeToArray(&message[kErrorStatusStartIndex + 4], gsProtoSize); message_size += gsProtoSize + 4; @@ -1557,8 +1565,10 @@ void RdmaTensorRequest::AllocateTensorsAsync(StatusCallback done) { bool on_host = recv_args_.alloc_attrs.on_host(); if (dst_dev_->tensorflow_gpu_device_info() && !on_host && (proxy_tensor_ == nullptr)) { +#if GOOGLE_CUDA // We need to sync the memory allocation on the GPU: StreamGPUOp(dst_dev_, recv_args_.device_context, done); +#endif } else { done(Status::OK()); } diff --git a/tensorflow/contrib/verbs/rdma.h b/tensorflow/contrib/verbs/rdma.h index dd7643de94..68b3d59f56 100644 --- a/tensorflow/contrib/verbs/rdma.h +++ b/tensorflow/contrib/verbs/rdma.h @@ -358,6 +358,7 @@ class RdmaTensorResponse { RdmaChannel* channel_; RdmaMessage rm_; // The request message + Device* src_dev_ = nullptr; TensorBuffer* src_buffer_ = nullptr; void* src_addr_ = nullptr; ibv_mr* mr_ = nullptr; -- GitLab From aa0f7fabfcfa43c2a95deb8b9b73bccd9ad7531d Mon Sep 17 00:00:00 2001 From: Clemens Schulz Date: Tue, 23 Jan 2018 19:22:08 +0100 Subject: [PATCH 102/258] Support for large number of classes when using tf.metrics.mean_per_class_accuracy() (#15946) * Switched to using two 1-D variables instead of 2-D matrix for tf.metrics.mean_per_class_accuracy to reduce memory usage and allow larger number of classes. * Fixed implementation and documentation of tf.metrics.mean_per_class_accuracy by: - Casting labels to int64 - Handling weights correctly - Changing return value of update op to per class accuracy tensor - Updating outdated statements in documentation Also removed reliance on confusion matrix in tests. --- .../python/kernel_tests/metrics_test.py | 29 +++------- tensorflow/python/ops/metrics_impl.py | 56 ++++++++++++------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/tensorflow/python/kernel_tests/metrics_test.py b/tensorflow/python/kernel_tests/metrics_test.py index 3358b78efd..e0e752147c 100644 --- a/tensorflow/python/kernel_tests/metrics_test.py +++ b/tensorflow/python/kernel_tests/metrics_test.py @@ -3628,7 +3628,8 @@ class MeanPerClassAccuracyTest(test.TestCase): predictions=array_ops.ones([10, 1]), labels=array_ops.ones([10, 1]), num_classes=2) - _assert_metric_variables(self, ('mean_accuracy/total_confusion_matrix:0',)) + _assert_metric_variables(self, ('mean_accuracy/count:0', + 'mean_accuracy/total:0')) def testMetricsCollections(self): my_collection_name = '__metrics__' @@ -3797,23 +3798,6 @@ class MeanPerClassAccuracyTest(test.TestCase): desired_output = np.mean([1.0 / 2.0, 2.0 / 3.0, 0.]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) - def testUpdateOpEvalIsAccumulatedConfusionMatrix(self): - predictions = array_ops.concat([ - constant_op.constant(0, shape=[5]), constant_op.constant(1, shape=[5]) - ], 0) - labels = array_ops.concat([ - constant_op.constant(0, shape=[3]), constant_op.constant(1, shape=[7]) - ], 0) - num_classes = 2 - with self.test_session() as sess: - mean_accuracy, update_op = metrics.mean_per_class_accuracy( - labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) - confusion_matrix = update_op.eval() - self.assertAllEqual([[3, 0], [2, 5]], confusion_matrix) - desired_mean_accuracy = np.mean([3. / 3., 5. / 7.]) - self.assertAlmostEqual(desired_mean_accuracy, mean_accuracy.eval()) - def testAllCorrect(self): predictions = array_ops.zeros([40]) labels = array_ops.zeros([40]) @@ -3822,7 +3806,7 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) sess.run(variables.local_variables_initializer()) - self.assertEqual(40, update_op.eval()[0]) + self.assertEqual(1.0, update_op.eval()[0]) self.assertEqual(1.0, mean_accuracy.eval()) def testAllWrong(self): @@ -3833,7 +3817,7 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) sess.run(variables.local_variables_initializer()) - self.assertAllEqual([[0, 0], [40, 0]], update_op.eval()) + self.assertAllEqual([0.0, 0.0], update_op.eval()) self.assertEqual(0., mean_accuracy.eval()) def testResultsWithSomeMissing(self): @@ -3852,8 +3836,9 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes, weights=weights) sess.run(variables.local_variables_initializer()) - self.assertAllEqual([[2, 0], [2, 4]], update_op.eval()) - desired_mean_accuracy = np.mean([2. / 2., 4. / 6.]) + desired_accuracy = np.array([2. / 2., 4. / 6.], dtype=np.float32) + self.assertAllEqual(desired_accuracy, update_op.eval()) + desired_mean_accuracy = np.mean(desired_accuracy) self.assertAlmostEqual(desired_mean_accuracy, mean_accuracy.eval()) diff --git a/tensorflow/python/ops/metrics_impl.py b/tensorflow/python/ops/metrics_impl.py index 92b3ff2250..2d77e26081 100644 --- a/tensorflow/python/ops/metrics_impl.py +++ b/tensorflow/python/ops/metrics_impl.py @@ -831,8 +831,8 @@ def mean_per_class_accuracy(labels, Calculates the accuracy for each class, then takes the mean of that. For estimation of the metric over a stream of data, the function creates an - `update_op` operation that updates these variables and returns the - `mean_accuracy`. + `update_op` operation that updates the accuracy of each class and returns + them. If `weights` is `None`, weights default to 1. Use weights of 0 to mask values. @@ -843,8 +843,8 @@ def mean_per_class_accuracy(labels, shape is [batch size] and type `int32` or `int64`. The tensor will be flattened if its rank > 1. num_classes: The possible number of labels the prediction task can - have. This value must be provided, since a confusion matrix of - dimension = [num_classes, num_classes] will be allocated. + have. This value must be provided, since two variables with shape = + [num_classes] will be allocated. weights: Optional `Tensor` whose rank is either 0, or the same rank as `labels`, and must be broadcastable to `labels` (i.e., all dimensions must be either `1`, or the same as the corresponding `labels` dimension). @@ -857,7 +857,7 @@ def mean_per_class_accuracy(labels, Returns: mean_accuracy: A `Tensor` representing the mean per class accuracy. - update_op: An operation that increments the confusion matrix. + update_op: An operation that updates the accuracy tensor. Raises: ValueError: If `predictions` and `labels` have mismatched shapes, or if @@ -872,27 +872,43 @@ def mean_per_class_accuracy(labels, with variable_scope.variable_scope(name, 'mean_accuracy', (predictions, labels, weights)): + labels = math_ops.to_int64(labels) + + # Flatten the input if its rank > 1. + if labels.get_shape().ndims > 1: + labels = array_ops.reshape(labels, [-1]) + + if predictions.get_shape().ndims > 1: + predictions = array_ops.reshape(predictions, [-1]) + # Check if shape is compatible. predictions.get_shape().assert_is_compatible_with(labels.get_shape()) - total_cm, update_op = _streaming_confusion_matrix( - labels, predictions, num_classes, weights=weights) + total = metric_variable([num_classes], dtypes.float32, name='total') + count = metric_variable([num_classes], dtypes.float32, name='count') - def compute_mean_accuracy(name): - """Compute the mean per class accuracy via the confusion matrix.""" - per_row_sum = math_ops.to_float(math_ops.reduce_sum(total_cm, 1)) - cm_diag = math_ops.to_float(array_ops.diag_part(total_cm)) - denominator = per_row_sum + ones = array_ops.ones([array_ops.size(labels)], dtypes.float32) - # If the value of the denominator is 0, set it to 1 to avoid - # zero division. - denominator = array_ops.where( - math_ops.greater(denominator, 0), denominator, - array_ops.ones_like(denominator)) - accuracies = math_ops.div(cm_diag, denominator) - return math_ops.reduce_mean(accuracies, name=name) + if labels.dtype != predictions.dtype: + predictions = math_ops.cast(predictions, labels.dtype) + is_correct = math_ops.to_float(math_ops.equal(predictions, labels)) + + if weights is not None: + if weights.get_shape().ndims > 1: + weights = array_ops.reshape(weights, [-1]) + weights = math_ops.to_float(weights) + + is_correct = is_correct * weights + ones = ones * weights + + update_total_op = state_ops.scatter_add(total, labels, ones) + update_count_op = state_ops.scatter_add(count, labels, is_correct) + + per_class_accuracy = _safe_div(count, total, None) - mean_accuracy_v = compute_mean_accuracy('mean_accuracy') + mean_accuracy_v = math_ops.reduce_mean(per_class_accuracy, + name='mean_accuracy') + update_op = _safe_div(update_count_op, update_total_op, name='update_op') if metrics_collections: ops.add_to_collections(metrics_collections, mean_accuracy_v) -- GitLab From 0bcbe479b4adaaa5b16000df4e703dd1389eaea2 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 10:19:19 -0800 Subject: [PATCH 103/258] Increase shard count of tensorflow/contrib/learn:linear_test to avoid test timeouts. The test tensorflow/contrib/learn:linear_test has been getting flaky timeouts t a low rate for some time, but they increased greatly under the address sanitizer due to a recent change there. This CL increases the test's shard count to bring the time for each shard well under the 5 minute timeout. PiperOrigin-RevId: 182953078 --- tensorflow/contrib/learn/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/learn/BUILD b/tensorflow/contrib/learn/BUILD index ee3611ca93..3c782b54a8 100644 --- a/tensorflow/contrib/learn/BUILD +++ b/tensorflow/contrib/learn/BUILD @@ -494,7 +494,7 @@ py_test( name = "linear_test", size = "medium", srcs = ["python/learn/estimators/linear_test.py"], - shard_count = 4, + shard_count = 20, srcs_version = "PY2AND3", tags = ["no_pip"], deps = [ -- GitLab From 72bdd3db56b8fc6cdd4306c15bd1e71b313ab2f6 Mon Sep 17 00:00:00 2001 From: Netzeband Date: Tue, 23 Jan 2018 19:26:22 +0100 Subject: [PATCH 104/258] =?UTF-8?q?Clarify=20the=20description=20of=20batc?= =?UTF-8?q?h=5Fnorm=20in=20order=20to=20highlight=20the=20dimen=E2=80=A6?= =?UTF-8?q?=20(#15728)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Clarify the description of batch_norm in order to highlight the dimension selection for normalization. * mention `data_format` Reworded a little, as the effect depends on the `data_format`. --- tensorflow/contrib/layers/python/layers/layers.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/layers/python/layers/layers.py b/tensorflow/contrib/layers/python/layers/layers.py index f3229a1605..ef2b673074 100644 --- a/tensorflow/contrib/layers/python/layers/layers.py +++ b/tensorflow/contrib/layers/python/layers/layers.py @@ -479,8 +479,12 @@ def batch_norm(inputs, Sergey Ioffe, Christian Szegedy - Can be used as a normalizer function for conv2d and fully_connected. - + Can be used as a normalizer function for conv2d and fully_connected. The + normalization is over all but the last dimension if `data_format` is `NHWC` + and all but the second dimension if `data_format` is `NCHW`. In case of a 2D + tensor this corresponds to the batch dimension, while in case of a 4D tensor this + corresponds to the batch and space dimensions. + Note: when training, the moving_mean and moving_variance need to be updated. By default the update ops are placed in `tf.GraphKeys.UPDATE_OPS`, so they need to be added as a dependency to the `train_op`. For example: -- GitLab From 44610da6d4403b816af79e0245bcca9517963464 Mon Sep 17 00:00:00 2001 From: Mohammad Ashraf Bhuiyan Date: Tue, 23 Jan 2018 10:28:08 -0800 Subject: [PATCH 105/258] fixed a bug related to feature column test in python (#16064) --- tensorflow/core/kernels/mkl_aggregate_ops.cc | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tensorflow/core/kernels/mkl_aggregate_ops.cc b/tensorflow/core/kernels/mkl_aggregate_ops.cc index 44b94be3a0..bb5eceab27 100644 --- a/tensorflow/core/kernels/mkl_aggregate_ops.cc +++ b/tensorflow/core/kernels/mkl_aggregate_ops.cc @@ -61,6 +61,18 @@ class MklAddNOp : public OpKernel { GetMklShape(ctx, src2_idx, &(mkl_context.input2_shape)); bool input2_in_mkl_format = mkl_context.input2_shape.IsMklTensor(); + // if the shapes of two tensors are not same raise op error + TensorShape src1_shape, src2_shape; + src1_shape = input0.shape(); + src2_shape = input1.shape(); + if (!src1_shape.IsSameSize(src2_shape) ){ + ctx->SetStatus( + errors::InvalidArgument( + "Inputs to operation ", this->name(), " of type ", this->type_string(), + " must have the same size and shape. Input 0: ", + src1_shape.DebugString(), " != input 1: ", + src2_shape.DebugString())); + } // handle the case of a scalar if (!input1_in_mkl_format && input0.dims() == 0) { const TensorShape& o_shape = input0.shape(); @@ -307,6 +319,18 @@ class MklAddNOp : public OpKernel { src1_mkl_shape.GetDimension(): src1_tensor.dims(); int src2_dims_size = input2_in_mkl_format? src2_mkl_shape.GetDimension(): src2_tensor.dims(); + // if the shapes of two tensors are not same raise op error + TensorShape src1_shape, src2_shape; + src1_shape = src1_tensor.shape(); + src2_shape = src2_tensor.shape(); + if (!src1_shape.IsSameSize(src2_shape) ){ + ctx->SetStatus( + errors::InvalidArgument( + "Inputs to operation ", this->name(), " of type ", this->type_string(), + " must have the same size and shape. Input 0: ", + src1_shape.DebugString(), " != input 1: ", + src2_shape.DebugString())); + } if (!input1_in_mkl_format && src1_dims_size == 0) { Tensor* dst_tensor = nullptr; -- GitLab From f52fc39c31b03cecc97cf64f732b44c6f95a2bef Mon Sep 17 00:00:00 2001 From: Steven Hickson Date: Tue, 23 Jan 2018 13:28:27 -0500 Subject: [PATCH 106/258] Update download_dependencies.sh to prevent crash from 403 (#16084) * Update download_dependencies.sh for eigen The eigen bitbucket seems to have changed causing the scrip to crash with a unrecognized archive error. Changing to grep -v mirror.bazel seems to fix this because otherwise we get a 403 forbidden error. * Update download_dependencies.sh --- tensorflow/contrib/lite/download_dependencies.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tensorflow/contrib/lite/download_dependencies.sh b/tensorflow/contrib/lite/download_dependencies.sh index 362e5bee25..e1b7b3613a 100755 --- a/tensorflow/contrib/lite/download_dependencies.sh +++ b/tensorflow/contrib/lite/download_dependencies.sh @@ -22,7 +22,14 @@ cd "$SCRIPT_DIR/../../.." DOWNLOADS_DIR=tensorflow/contrib/lite/downloads BZL_FILE_PATH=tensorflow/workspace.bzl -EIGEN_URL="$(grep -o 'http.*bitbucket.org/eigen/eigen/get/.*tar\.gz' "${BZL_FILE_PATH}" | grep -v bazel-mirror | head -n1)" +# Ensure it is being run from repo root +if [ ! -f $BZL_FILE_PATH ]; then + echo "Could not find ${BZL_FILE_PATH}": + echo "Likely you are not running this from the root directory of the repository."; + exit 1; +fi + +EIGEN_URL="$(grep -o 'http.*bitbucket.org/eigen/eigen/get/.*tar\.gz' "${BZL_FILE_PATH}" | grep -v mirror.bazel | head -n1)" GEMMLOWP_URL="$(grep -o 'https://mirror.bazel.build/github.com/google/gemmlowp/.*zip' "${BZL_FILE_PATH}" | head -n1)" GOOGLETEST_URL="https://github.com/google/googletest/archive/release-1.8.0.tar.gz" ABSL_URL="$(grep -o 'https://github.com/abseil/abseil-cpp/.*tar.gz' "${BZL_FILE_PATH}" | head -n1)" -- GitLab From 7eb68b86e039e5b173c8ed156689b58dbc765793 Mon Sep 17 00:00:00 2001 From: Victor Costan Date: Tue, 23 Jan 2018 10:29:38 -0800 Subject: [PATCH 107/258] Minor improvements to TFRecord format docs. (#16118) --- tensorflow/docs_src/api_guides/python/python_io.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tensorflow/docs_src/api_guides/python/python_io.md b/tensorflow/docs_src/api_guides/python/python_io.md index a5444408fe..06282e49d5 100644 --- a/tensorflow/docs_src/api_guides/python/python_io.md +++ b/tensorflow/docs_src/api_guides/python/python_io.md @@ -14,16 +14,16 @@ suitable if fast sharding or other non-sequential access is desired. ## TFRecords Format Details -A TFRecords file contains a sequence of strings with CRC hashes. Each record -has the format +A TFRecords file contains a sequence of strings with CRC32C (32-bit CRC using +the Castagnoli polynomial) hashes. Each record has the format uint64 length uint32 masked_crc32_of_length byte data[length] uint32 masked_crc32_of_data -and the records are concatenated together to produce the file. The CRC32s -are [described here](https://en.wikipedia.org/wiki/Cyclic_redundancy_check), -and the mask of a CRC is +and the records are concatenated together to produce the file. CRCs are +[described here](https://en.wikipedia.org/wiki/Cyclic_redundancy_check), and +the mask of a CRC is masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul -- GitLab From 9b7b8813961caa4d2c1cc011e54a4efafd69cc5f Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Tue, 23 Jan 2018 10:34:27 -0800 Subject: [PATCH 108/258] Load region from `~/.aws/config` if possible in S3 (#15723) * Load region from `~/.aws/config` if possible in S3 This fix tries to address the issue raised in comment 15562 where TensorFlow does not load region from `~/.aws/config` if exists. The reason was that AWS C++ SDK does not use the config file by default. This fix adds the loading of config file (`~/.aws/config`) explicitly, if either AWS_REGION or S3_REGION is not available. In case none of the `AWS_REGION`, `S3_REGION`, `~/.aws/config` is available, then the default `use-east-1` is used (by AWS C++ SDK). This fix is related to 15562. Signed-off-by: Yong Tang * Load config from ~/.aws/config if AWS_SDK_LOAD_CONFIG is set and config file location could be overwritten by AWS_CONFIG_FILE Signed-off-by: Yong Tang * Reformat s3_file_system.cc with clang-format Signed-off-by: Yong Tang --- tensorflow/core/platform/s3/s3_file_system.cc | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/tensorflow/core/platform/s3/s3_file_system.cc b/tensorflow/core/platform/s3/s3_file_system.cc index 58ea315670..ebda3a2065 100644 --- a/tensorflow/core/platform/s3/s3_file_system.cc +++ b/tensorflow/core/platform/s3/s3_file_system.cc @@ -14,11 +14,13 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/platform/s3/s3_file_system.h" #include "tensorflow/core/lib/io/path.h" +#include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/core/platform/mutex.h" #include "tensorflow/core/platform/s3/aws_logging.h" #include "tensorflow/core/platform/s3/s3_crypto.h" #include +#include #include #include #include @@ -54,13 +56,37 @@ Aws::Client::ClientConfiguration& GetDefaultClientConfig() { cfg.endpointOverride = Aws::String(endpoint); } const char* region = getenv("AWS_REGION"); + if (!region) { + // TODO (yongtang): `S3_REGION` should be deprecated after 2.0. + region = getenv("S3_REGION"); + } if (region) { cfg.region = Aws::String(region); } else { - // TODO (yongtang): `S3_REGION` should be deprecated after 2.0. - const char* region = getenv("S3_REGION"); - if (region) { - cfg.region = Aws::String(region); + // Load config file (e.g., ~/.aws/config) only if AWS_SDK_LOAD_CONFIG + // is set with a truthy value. + const char* load_config_env = getenv("AWS_SDK_LOAD_CONFIG"); + string load_config = + load_config_env ? str_util::Lowercase(load_config_env) : ""; + if (load_config == "true" || load_config == "1") { + Aws::String config_file; + // If AWS_CONFIG_FILE is set then use it, otherwise use ~/.aws/config. + const char* config_file_env = getenv("AWS_CONFIG_FILE"); + if (config_file_env) { + config_file = config_file_env; + } else { + const char* home_env = getenv("HOME"); + if (home_env) { + config_file = home_env; + config_file += "/.aws/config"; + } + } + Aws::Config::AWSConfigFileProfileConfigLoader loader(config_file); + loader.Load(); + auto profiles = loader.GetProfiles(); + if (!profiles["default"].GetRegion().empty()) { + cfg.region = profiles["default"].GetRegion(); + } } } const char* use_https = getenv("S3_USE_HTTPS"); -- GitLab From d2c3b873c6f8ff999a2e4ee707a84ff00d9c15a5 Mon Sep 17 00:00:00 2001 From: Jacky Ko Date: Wed, 24 Jan 2018 02:51:28 +0800 Subject: [PATCH 109/258] tpu contrib fix (#16321) --- tensorflow/contrib/cmake/tf_core_framework.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tensorflow/contrib/cmake/tf_core_framework.cmake b/tensorflow/contrib/cmake/tf_core_framework.cmake index 24d7fb82a2..129c208ecd 100644 --- a/tensorflow/contrib/cmake/tf_core_framework.cmake +++ b/tensorflow/contrib/cmake/tf_core_framework.cmake @@ -126,7 +126,9 @@ endfunction() file(GLOB_RECURSE tf_protos_cc_srcs RELATIVE ${tensorflow_source_dir} "${tensorflow_source_dir}/tensorflow/core/*.proto" "${tensorflow_source_dir}/tensorflow/contrib/boosted_trees/proto/*.proto" + "${tensorflow_source_dir}/tensorflow/contrib/tpu/proto/*.proto" ) + RELATIVE_PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${tensorflow_source_dir} ${tf_protos_cc_srcs} ) -- GitLab From 144bfce5be3d27d61c6370a2dd822e32815454ad Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Tue, 23 Jan 2018 10:59:00 -0800 Subject: [PATCH 110/258] Removed unecessary dependency PiperOrigin-RevId: 182959711 --- tensorflow/cc/BUILD | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow/cc/BUILD b/tensorflow/cc/BUILD index ddcee3deee..c9ade5fb83 100644 --- a/tensorflow/cc/BUILD +++ b/tensorflow/cc/BUILD @@ -673,7 +673,6 @@ cc_library( "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "//tensorflow/core:protos_all_cc", - "//tensorflow/core:tensorflow", ], ) -- GitLab From 7da6a83b74f467929032dce95794ef0197d46b20 Mon Sep 17 00:00:00 2001 From: Akshay Agrawal Date: Tue, 23 Jan 2018 11:05:50 -0800 Subject: [PATCH 111/258] TFE usability: Implement `ndim` for `EagerTensor`+NumPy compatibility Third party libraries like matplotlib often access `ndim`. PiperOrigin-RevId: 182961097 --- tensorflow/python/eager/tensor_test.py | 13 +++++++++++++ tensorflow/python/framework/ops.py | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/tensorflow/python/eager/tensor_test.py b/tensorflow/python/eager/tensor_test.py index 2568d3dc05..0bd5a5dbaf 100644 --- a/tensorflow/python/eager/tensor_test.py +++ b/tensorflow/python/eager/tensor_test.py @@ -112,6 +112,19 @@ class TFETensorTest(test_util.TensorFlowTestCase): numpy_tensor = np.asarray(tensor, dtype=np.int32) self.assertAllEqual(numpy_tensor, [1, 2, 3]) + def testNdimsAgreesWithNumpy(self): + numpy_tensor = np.asarray(1.0) + tensor = constant_op.constant(numpy_tensor) + self.assertAllEqual(numpy_tensor.ndim, tensor.ndim) + + numpy_tensor = np.asarray([1.0, 2.0, 3.0]) + tensor = constant_op.constant(numpy_tensor) + self.assertAllEqual(numpy_tensor.ndim, tensor.ndim) + + numpy_tensor = np.asarray([[1.0, 2.0, 3.0], [1.0, 2.0, 3.0]]) + tensor = constant_op.constant(numpy_tensor) + self.assertAllEqual(numpy_tensor.ndim, tensor.ndim) + def testCopy(self): t = constant_op.constant(1.0) tt = copy.copy(t) diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index 0eb06ae913..2489982d93 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -775,6 +775,11 @@ class _EagerTensorBase(Tensor): """The shape of the tensor as a list.""" return list(self._shape_tuple()) + @property + def ndim(self): + """Returns the number of Tensor dimensions.""" + return self.shape.ndims + def cpu(self): """A copy of this Tensor with contents backed by host memory.""" return self._copy(context.context(), "CPU:0") -- GitLab From d1020bfdedadc3da7c89a69651c45cc790922b69 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Tue, 23 Jan 2018 11:09:26 -0800 Subject: [PATCH 112/258] Run TF opensource presubmits with sanybridge CPU optimizations. PiperOrigin-RevId: 182961789 --- tensorflow/tools/ci_build/builds/libtensorflow.sh | 2 +- tensorflow/tools/ci_build/linux/cpu/run_cc_core.sh | 3 ++- tensorflow/tools/ci_build/linux/cpu/run_py2_core.sh | 3 ++- tensorflow/tools/ci_build/linux/cpu/run_py3_contrib.sh | 3 ++- tensorflow/tools/ci_build/linux/cpu/run_py3_core.sh | 3 ++- tensorflow/tools/ci_build/linux/gpu/run_cc_core.sh | 3 ++- tensorflow/tools/ci_build/linux/gpu/run_py3_core.sh | 3 ++- tensorflow/tools/ci_build/osx/cpu/run_contrib.sh | 3 ++- tensorflow/tools/ci_build/osx/cpu/run_py2_cc_core.sh | 3 ++- 9 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tensorflow/tools/ci_build/builds/libtensorflow.sh b/tensorflow/tools/ci_build/builds/libtensorflow.sh index 26713dded8..aadf480d37 100755 --- a/tensorflow/tools/ci_build/builds/libtensorflow.sh +++ b/tensorflow/tools/ci_build/builds/libtensorflow.sh @@ -51,8 +51,8 @@ function build_libtensorflow_tarball() { rm -rf ${DIR} TARBALL_SUFFIX="${1}" - BAZEL="bazel --bazelrc ./tensorflow/tools/ci_build/install/.bazelrc" BAZEL_OPTS="-c opt" + export CC_OPT_FLAGS='-mavx' if [ "${TF_NEED_CUDA}" == "1" ]; then BAZEL_OPTS="${BAZEL_OPTS} --config=cuda" fi diff --git a/tensorflow/tools/ci_build/linux/cpu/run_cc_core.sh b/tensorflow/tools/ci_build/linux/cpu/run_cc_core.sh index e3e6b2f316..51e10f81f8 100755 --- a/tensorflow/tools/ci_build/linux/cpu/run_cc_core.sh +++ b/tensorflow/tools/ci_build/linux/cpu/run_cc_core.sh @@ -26,12 +26,13 @@ echo "" # Run configure. export TF_NEED_CUDA=0 +export CC_OPT_FLAGS='-mavx' # Only running cc tests, python version does not matter. export PYTHON_BIN_PATH=`which python` yes "" | $PYTHON_BIN_PATH configure.py # Run bazel test command. Double test timeouts to avoid flakes. bazel test --test_tag_filters=-no_oss,-gpu,-benchmark-test --test_lang_filters=cc,java -k \ - --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 \ + --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 --config=opt \ --test_output=errors -- \ //tensorflow/... -//tensorflow/compiler/... -//tensorflow/contrib/... diff --git a/tensorflow/tools/ci_build/linux/cpu/run_py2_core.sh b/tensorflow/tools/ci_build/linux/cpu/run_py2_core.sh index 5110d52f31..ea14848b1a 100755 --- a/tensorflow/tools/ci_build/linux/cpu/run_py2_core.sh +++ b/tensorflow/tools/ci_build/linux/cpu/run_py2_core.sh @@ -26,11 +26,12 @@ echo "" # Run configure. export TF_NEED_CUDA=0 +export CC_OPT_FLAGS='-mavx' export PYTHON_BIN_PATH=`which python2` yes "" | $PYTHON_BIN_PATH configure.py # Run bazel test command. Double test timeouts to avoid flakes. bazel test --test_tag_filters=-no_oss,-oss_serial,-gpu,-benchmark-test --test_lang_filters=py -k \ - --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 --build_tests_only \ + --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 --build_tests_only --config=opt \ --test_output=errors -- \ //tensorflow/... -//tensorflow/compiler/... -//tensorflow/contrib/... diff --git a/tensorflow/tools/ci_build/linux/cpu/run_py3_contrib.sh b/tensorflow/tools/ci_build/linux/cpu/run_py3_contrib.sh index df6016504c..6d017c8a1f 100755 --- a/tensorflow/tools/ci_build/linux/cpu/run_py3_contrib.sh +++ b/tensorflow/tools/ci_build/linux/cpu/run_py3_contrib.sh @@ -26,12 +26,13 @@ echo "" # Run configure. export TF_NEED_CUDA=0 +export CC_OPT_FLAGS='-mavx' export PYTHON_BIN_PATH=`which python3` yes "" | $PYTHON_BIN_PATH configure.py # Run bazel test command. Double test timeouts to avoid flakes. bazel test --test_tag_filters=-no_oss,-oss_serial,-gpu,-benchmark-test -k \ - --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 \ + --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 --config=opt \ --test_output=errors -- \ //tensorflow/contrib/... \ -//tensorflow/contrib/lite/... \ diff --git a/tensorflow/tools/ci_build/linux/cpu/run_py3_core.sh b/tensorflow/tools/ci_build/linux/cpu/run_py3_core.sh index ea9e102936..a9accb9dd5 100755 --- a/tensorflow/tools/ci_build/linux/cpu/run_py3_core.sh +++ b/tensorflow/tools/ci_build/linux/cpu/run_py3_core.sh @@ -26,11 +26,12 @@ echo "" # Run configure. export TF_NEED_CUDA=0 +export CC_OPT_FLAGS='-mavx' export PYTHON_BIN_PATH=`which python3` yes "" | $PYTHON_BIN_PATH configure.py # Run bazel test command. Double test timeouts to avoid flakes. bazel test --test_tag_filters=-no_oss,-oss_serial,-gpu,-benchmark-test --test_lang_filters=py -k \ - --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 --build_tests_only \ + --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 --build_tests_only --config=opt \ --test_output=errors -- \ //tensorflow/... -//tensorflow/compiler/... -//tensorflow/contrib/... diff --git a/tensorflow/tools/ci_build/linux/gpu/run_cc_core.sh b/tensorflow/tools/ci_build/linux/gpu/run_cc_core.sh index df196f829c..02224d8e9d 100755 --- a/tensorflow/tools/ci_build/linux/gpu/run_cc_core.sh +++ b/tensorflow/tools/ci_build/linux/gpu/run_cc_core.sh @@ -26,6 +26,7 @@ echo "" # Run configure. export PYTHON_BIN_PATH=`which python3` +export CC_OPT_FLAGS='-mavx' export TF_NEED_CUDA=1 export TF_CUDA_COMPUTE_CAPABILITIES=3.7 @@ -35,6 +36,6 @@ yes "" | $PYTHON_BIN_PATH configure.py # Run bazel test command. Double test timeouts to avoid flakes. bazel test --config=cuda --test_tag_filters=-no_oss,-oss_serial,-no_gpu,-benchmark-test -k \ --test_lang_filters=cc --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 \ - --build_tests_only --test_output=errors --local_test_jobs=8 \ + --build_tests_only --test_output=errors --local_test_jobs=8 --config=opt \ --run_under=//tensorflow/tools/ci_build/gpu_build:parallel_gpu_execute -- \ //tensorflow/... -//tensorflow/compiler/... -//tensorflow/contrib/... diff --git a/tensorflow/tools/ci_build/linux/gpu/run_py3_core.sh b/tensorflow/tools/ci_build/linux/gpu/run_py3_core.sh index abd256a895..0367a53d14 100755 --- a/tensorflow/tools/ci_build/linux/gpu/run_py3_core.sh +++ b/tensorflow/tools/ci_build/linux/gpu/run_py3_core.sh @@ -26,6 +26,7 @@ echo "" # Run configure. export PYTHON_BIN_PATH=`which python3` +export CC_OPT_FLAGS='-mavx' export TF_NEED_CUDA=1 export TF_CUDA_COMPUTE_CAPABILITIES=3.7 @@ -35,6 +36,6 @@ yes "" | $PYTHON_BIN_PATH configure.py # Run bazel test command. Double test timeouts to avoid flakes. bazel test --config=cuda --test_tag_filters=-no_oss,-oss_serial,-no_gpu,-benchmark-test -k \ --test_lang_filters=py --jobs=${N_JOBS} --test_timeout 300,450,1200,3600 \ - --build_tests_only --test_output=errors --local_test_jobs=8 \ + --build_tests_only --test_output=errors --local_test_jobs=8 --config=opt \ --run_under=//tensorflow/tools/ci_build/gpu_build:parallel_gpu_execute -- \ //tensorflow/... -//tensorflow/compiler/... -//tensorflow/contrib/... diff --git a/tensorflow/tools/ci_build/osx/cpu/run_contrib.sh b/tensorflow/tools/ci_build/osx/cpu/run_contrib.sh index ddaaddc917..509ee38ec4 100755 --- a/tensorflow/tools/ci_build/osx/cpu/run_contrib.sh +++ b/tensorflow/tools/ci_build/osx/cpu/run_contrib.sh @@ -27,11 +27,12 @@ echo "" # Run configure. export TF_NEED_CUDA=0 +export CC_OPT_FLAGS='-mavx' export PYTHON_BIN_PATH=$(which python2) yes "" | $PYTHON_BIN_PATH configure.py which bazel bazel test --test_tag_filters=-no_oss,-gpu,-benchmark-test,-nomac \ --test_timeout 300,450,1200,3600 \ - --test_size_filters=small,medium \ + --test_size_filters=small,medium --config=opt \ --jobs=${N_JOBS} --build_tests_only --test_output=errors -k -- \ //tensorflow/contrib/... -//tensorflow/contrib/lite/... diff --git a/tensorflow/tools/ci_build/osx/cpu/run_py2_cc_core.sh b/tensorflow/tools/ci_build/osx/cpu/run_py2_cc_core.sh index e026dcd08f..0554713670 100755 --- a/tensorflow/tools/ci_build/osx/cpu/run_py2_cc_core.sh +++ b/tensorflow/tools/ci_build/osx/cpu/run_py2_cc_core.sh @@ -27,11 +27,12 @@ echo "" # Run configure. export TF_NEED_CUDA=0 +export CC_OPT_FLAGS='-mavx' export PYTHON_BIN_PATH=$(which python2) yes "" | $PYTHON_BIN_PATH configure.py which bazel bazel test --test_tag_filters=-no_oss,-gpu,-benchmark-test,-nomac \ - --test_timeout 300,450,1200,3600 \ + --test_timeout 300,450,1200,3600 --config=opt \ --test_size_filters=small,medium \ --jobs=${N_JOBS} --build_tests_only --test_output=errors -k -- \ //tensorflow/... -//tensorflow/compiler/... -//tensorflow/contrib/... -- GitLab From 2a3559feb6564e4e46a56a71b200f6a17afe69e7 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Tue, 23 Jan 2018 11:20:29 -0800 Subject: [PATCH 113/258] Moves batch ops to core and exposes tf.contrib.batching PiperOrigin-RevId: 182963906 --- tensorflow/BUILD | 3 - tensorflow/contrib/BUILD | 2 - tensorflow/contrib/__init__.py | 1 + tensorflow/contrib/batching/BUILD | 47 ++--- tensorflow/contrib/batching/kernels/BUILD | 34 ---- tensorflow/contrib/batching/ops/batch_ops.cc | 164 ------------------ .../contrib/batching/python/ops/batch_ops.py | 12 +- tensorflow/contrib/cmake/python_modules.txt | 1 - tensorflow/contrib/cmake/tf_core_ops.cmake | 1 + tensorflow/contrib/cmake/tf_python.cmake | 1 + tensorflow/core/BUILD | 3 + .../core/api_def/base_api/api_def_Batch.pbtxt | 42 +++++ .../api_def/base_api/api_def_Unbatch.pbtxt | 24 +++ .../base_api/api_def_UnbatchGrad.pbtxt | 20 +++ tensorflow/core/kernels/BUILD | 17 ++ .../kernels/batch_kernels.cc | 6 +- tensorflow/core/ops/batch_ops.cc | 84 +++++++++ tensorflow/python/BUILD | 7 + 18 files changed, 218 insertions(+), 251 deletions(-) delete mode 100644 tensorflow/contrib/batching/kernels/BUILD delete mode 100644 tensorflow/contrib/batching/ops/batch_ops.cc create mode 100644 tensorflow/core/api_def/base_api/api_def_Batch.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_Unbatch.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_UnbatchGrad.pbtxt rename tensorflow/{contrib/batching => core}/kernels/batch_kernels.cc (99%) create mode 100644 tensorflow/core/ops/batch_ops.cc diff --git a/tensorflow/BUILD b/tensorflow/BUILD index 84ef1447dd..1bf7c741b7 100644 --- a/tensorflow/BUILD +++ b/tensorflow/BUILD @@ -434,9 +434,6 @@ filegroup( "//tensorflow/contrib/all_reduce:all_files", "//tensorflow/contrib/android:all_files", "//tensorflow/contrib/batching:all_files", - "//tensorflow/contrib/batching/kernels:all_files", - "//tensorflow/contrib/batching/test_util:all_files", - "//tensorflow/contrib/batching/util:all_files", "//tensorflow/contrib/bayesflow:all_files", "//tensorflow/contrib/boosted_trees:all_files", "//tensorflow/contrib/boosted_trees/estimator_batch:all_files", diff --git a/tensorflow/contrib/BUILD b/tensorflow/contrib/BUILD index 8bed0fabd7..f1e54432fa 100644 --- a/tensorflow/contrib/BUILD +++ b/tensorflow/contrib/BUILD @@ -111,7 +111,6 @@ cc_library( name = "contrib_kernels", visibility = ["//visibility:public"], deps = [ - "//tensorflow/contrib/batching:batch_ops_kernels", "//tensorflow/contrib/boosted_trees:boosted_trees_kernels", "//tensorflow/contrib/coder:all_kernels", "//tensorflow/contrib/cudnn_rnn:cudnn_rnn_kernels", @@ -134,7 +133,6 @@ cc_library( name = "contrib_ops_op_lib", visibility = ["//visibility:public"], deps = [ - "//tensorflow/contrib/batching:batch_ops_op_lib", "//tensorflow/contrib/boosted_trees:boosted_trees_ops_op_lib", "//tensorflow/contrib/coder:all_ops", "//tensorflow/contrib/cudnn_rnn:cudnn_rnn_ops_op_lib", diff --git a/tensorflow/contrib/__init__.py b/tensorflow/contrib/__init__.py index f600a8a998..8f6a3cb1ca 100644 --- a/tensorflow/contrib/__init__.py +++ b/tensorflow/contrib/__init__.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function # Add projects here, they will show up under tf.contrib. +from tensorflow.contrib import batching from tensorflow.contrib import bayesflow from tensorflow.contrib import cloud from tensorflow.contrib import cluster_resolver diff --git a/tensorflow/contrib/batching/BUILD b/tensorflow/contrib/batching/BUILD index cd98f0e703..ee67909133 100644 --- a/tensorflow/contrib/batching/BUILD +++ b/tensorflow/contrib/batching/BUILD @@ -67,48 +67,14 @@ load( ) load("//tensorflow:tensorflow.bzl", "tf_custom_op_py_library") -tf_custom_op_library( - name = "python/ops/_batch_ops.so", - srcs = ["ops/batch_ops.cc"], - deps = [ - "//tensorflow/contrib/batching/kernels:batch_kernels", - ], -) - -tf_gen_op_libs( - op_lib_names = ["batch_ops"], -) - -tf_gen_op_wrapper_py( - name = "batch_ops", - deps = [":batch_ops_op_lib"], -) - -tf_kernel_library( - name = "batch_ops_kernels", - deps = [ - "//tensorflow/contrib/batching/kernels:batch_kernels", - "//tensorflow/contrib/batching/util:periodic_function", - "//tensorflow/core/kernels:concat_lib", - "//tensorflow/core/kernels:ops_util", - "//tensorflow/core/kernels:split_lib", - ], - alwayslink = 1, -) - -tf_custom_op_py_library( +py_library( name = "batch_py", srcs = glob(["python/ops/*.py"]) + ["__init__.py"], - dso = [":python/ops/_batch_ops.so"], - kernels = [ - ":batch_ops_kernels", - ":batch_ops_op_lib", - ], srcs_version = "PY2AND3", deps = [ - ":batch_ops", "//tensorflow/contrib/util:util_py", "//tensorflow/python:array_ops", + "//tensorflow/python:batch_ops_gen", "//tensorflow/python:client_testlib", "//tensorflow/python:framework_for_generated_wrappers", "//tensorflow/python:gradients", @@ -118,6 +84,14 @@ tf_custom_op_py_library( ], ) +cc_library( + name = "batch_ops_kernels", + deps = [ + "//tensorflow/core/kernels:batch_kernels", + ], + alwayslink = 1, +) + py_test( name = "batch_ops_test", size = "small", @@ -133,6 +107,7 @@ py_test( "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", + "//tensorflow/python:framework", "//tensorflow/python:gradients", "//tensorflow/python:script_ops", ], diff --git a/tensorflow/contrib/batching/kernels/BUILD b/tensorflow/contrib/batching/kernels/BUILD deleted file mode 100644 index 6e53dd9a5f..0000000000 --- a/tensorflow/contrib/batching/kernels/BUILD +++ /dev/null @@ -1,34 +0,0 @@ -# Description: -# Contains kernels for the batching ops. - -package(default_visibility = ["//tensorflow:__subpackages__"]) - -licenses(["notice"]) # Apache 2.0 - -exports_files(["LICENSE"]) - -cc_library( - name = "batch_kernels", - srcs = ["batch_kernels.cc"], - deps = [ - "//tensorflow/contrib/batching:shared_batch_scheduler_hdrs", - "//tensorflow/contrib/batching/util:periodic_function_dynamic", - "//tensorflow/core:framework_headers_lib", - "//tensorflow/core:protos_all_cc", - "//tensorflow/core/kernels:concat_lib_hdrs", - "//tensorflow/core/kernels:ops_util_hdrs", - "//tensorflow/core/kernels:split_lib_hdrs", - ], - alwayslink = 1, -) - -filegroup( - name = "all_files", - srcs = glob( - ["**/*"], - exclude = [ - "**/METADATA", - "**/OWNERS", - ], - ), -) diff --git a/tensorflow/contrib/batching/ops/batch_ops.cc b/tensorflow/contrib/batching/ops/batch_ops.cc deleted file mode 100644 index 85e0ccba4a..0000000000 --- a/tensorflow/contrib/batching/ops/batch_ops.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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/framework/common_shape_fns.h" -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/shape_inference.h" - -namespace tensorflow { - -REGISTER_OP("Batch") - .Input("in_tensors: T") - .Output("batched_tensors: T") - .Output("batch_index: int64") - .Output("id: int64") - .Attr("num_batch_threads: int") - .Attr("max_batch_size: int") - .Attr("batch_timeout_micros: int") - .Attr("allowed_batch_sizes: list(int) = []") - .Attr("grad_timeout_micros: int") - .Attr("container: string = ''") - .Attr("shared_name: string = ''") - .Attr("batching_queue: string = ''") - .Attr("T: list(type)") - .SetShapeFn([](shape_inference::InferenceContext* c) { - std::vector in_shapes; - TF_RETURN_IF_ERROR(c->input("in_tensors", &in_shapes)); - std::vector out_shapes(in_shapes.size()); - for (int i = 0; i < in_shapes.size(); ++i) { - TF_RETURN_IF_ERROR( - c->ReplaceDim(in_shapes[i], 0, c->UnknownDim(), &out_shapes[i])); - } - TF_RETURN_IF_ERROR(c->set_output("batched_tensors", out_shapes)); - TF_RETURN_IF_ERROR(c->set_output("id", {c->Scalar()})); - TF_RETURN_IF_ERROR(c->set_output( - "batch_index", - {c->MakeShape({shape_inference::DimensionOrConstant(c->UnknownDim()), - shape_inference::DimensionOrConstant(3)})})); - return Status::OK(); - }) - .Doc(R"doc( -Batches all input tensors nondeterministically. - -When many instances of this Op are being run concurrently with the same -container/shared_name in the same device, some will output zero-shaped Tensors -and others will output Tensors of size up to max_batch_size. - -All Tensors in in_tensors are batched together (so, for example, labels and -features should be batched with a single instance of this operation. - -Each invocation of batch emits an `id` scalar which will be used to identify -this particular invocation when doing unbatch or its gradient. - -Each op which emits a non-empty batch will also emit a non-empty batch_index -Tensor, which, is a [K, 3] matrix where each row contains the invocation's id, -start, and length of elements of each set of Tensors present in batched_tensors. - -Batched tensors are concatenated along the first dimension, and all tensors in -in_tensors must have the first dimension of the same size. - -in_tensors: The tensors to be batched. -num_batch_threads: Number of scheduling threads for processing batches of work. - Determines the number of batches processed in parallel. -max_batch_size: Batch sizes will never be bigger than this. -batch_timeout_micros: Maximum number of microseconds to wait before outputting - an incomplete batch. -allowed_batch_sizes: Optional list of allowed batch sizes. If left empty, does - nothing. Otherwise, supplies a list of batch sizes, causing the op to pad - batches up to one of those sizes. The entries must increase monotonically, and - the final entry must equal max_batch_size. -grad_timeout_micros: The timeout to use for the gradient. See Unbatch. -batched_tensors: Either empty tensors or a batch of concatenated Tensors. -batch_index: If out_tensors is non-empty, has information to invert it. -container: Controls the scope of sharing of this batch. -id: always contains a scalar with a unique ID for this invocation of Batch. -shared_name: Concurrently running instances of batch in the same device with the - same container and shared_name will batch their elements together. If left - empty, the op name will be used as the shared name. -T: the types of tensors to be batched. -)doc"); - -REGISTER_OP("Unbatch") - .Input("batched_tensor: T") - .Input("batch_index: int64") - .Input("id: int64") - .Output("unbatched_tensor: T") - .Attr("timeout_micros: int") - .Attr("container: string = ''") - .Attr("shared_name: string = ''") - .Attr("T: type") - .SetShapeFn([](shape_inference::InferenceContext* c) { - shape_inference::ShapeHandle out_shape; - TF_RETURN_IF_ERROR( - c->ReplaceDim(c->input(0), 0, c->UnknownDim(), &out_shape)); - c->set_output(0, out_shape); - return Status::OK(); - }) - .Doc(R"doc( -Reverses the operation of Batch for a single output Tensor. - -An instance of Unbatch either receives an empty batched_tensor, in which case it -asynchronously waits until the values become available from a concurrently -running instance of Unbatch with the same container and shared_name, or receives -a non-empty batched_tensor in which case it finalizes all other concurrently -running instances and outputs its own element from the batch. - -batched_tensor: The possibly transformed output of Batch. The size of the first - dimension should remain unchanged by the transformations for the operation to - work. -batch_index: The matching batch_index obtained from Batch. -id: The id scalar emitted by Batch. -unbatched_tensor: The Tensor corresponding to this execution. -timeout_micros: Maximum amount of time (in microseconds) to wait to receive the - batched input tensor associated with a given invocation of the op. -container: Container to control resource sharing. -shared_name: Instances of Unbatch with the same container and shared_name are - assumed to possibly belong to the same batch. If left empty, the op name will - be used as the shared name. -)doc"); - -REGISTER_OP("UnbatchGrad") - .Input("original_input: T") - .Input("batch_index: int64") - .Input("grad: T") - .Input("id: int64") - .Output("batched_grad: T") - .Attr("container: string = ''") - .Attr("shared_name: string = ''") - .Attr("T: type") - .SetShapeFn([](shape_inference::InferenceContext* c) { - c->set_output(0, c->UnknownShapeOfRank(c->Rank(c->input(2)))); - return Status::OK(); - }) - .Doc(R"doc( -Gradient of Unbatch. - -Acts like Batch but using the given batch_index index of batching things as they -become available. This ensures that the gradients are propagated back in the -same session which did the forward pass. - -original_input: The input to the Unbatch operation this is the gradient of. -batch_index: The batch_index given to the Unbatch operation this is the gradient -of. -grad: The downstream gradient. -id: The id scalar emitted by Batch. -batched_grad: The return value, either an empty tensor or the batched gradient. -container: Container to control resource sharing. -shared_name: Instances of UnbatchGrad with the same container and shared_name - are assumed to possibly belong to the same batch. If left empty, the op name - will be used as the shared name. - )doc"); - -} // namespace tensorflow diff --git a/tensorflow/contrib/batching/python/ops/batch_ops.py b/tensorflow/contrib/batching/python/ops/batch_ops.py index cee4d7b4a9..4e0b3f9af9 100644 --- a/tensorflow/contrib/batching/python/ops/batch_ops.py +++ b/tensorflow/contrib/batching/python/ops/batch_ops.py @@ -18,18 +18,12 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.batching.ops import gen_batch_ops +from tensorflow.python.framework import ops +from tensorflow.python.ops import gen_batch_ops # go/tf-wildcard-import # pylint: disable=wildcard-import -from tensorflow.contrib.batching.ops.gen_batch_ops import * +from tensorflow.python.ops.gen_batch_ops import * # pylint: enable=wildcard-import -from tensorflow.contrib.util import loader -from tensorflow.python.framework import ops -from tensorflow.python.platform import resource_loader - - -_batch_ops = loader.load_op_library( - resource_loader.get_path_to_datafile("_batch_ops.so")) @ops.RegisterGradient("Batch") diff --git a/tensorflow/contrib/cmake/python_modules.txt b/tensorflow/contrib/cmake/python_modules.txt index e37d059a84..dec6c513ba 100644 --- a/tensorflow/contrib/cmake/python_modules.txt +++ b/tensorflow/contrib/cmake/python_modules.txt @@ -109,7 +109,6 @@ tensorflow/contrib/android/java/org/tensorflow/contrib tensorflow/contrib/android/java/org/tensorflow/contrib/android tensorflow/contrib/android/jni tensorflow/contrib/batching -tensorflow/contrib/batching/kernels tensorflow/contrib/batching/python tensorflow/contrib/batching/python/ops tensorflow/contrib/bayesflow diff --git a/tensorflow/contrib/cmake/tf_core_ops.cmake b/tensorflow/contrib/cmake/tf_core_ops.cmake index 6f56e9d086..138993db35 100644 --- a/tensorflow/contrib/cmake/tf_core_ops.cmake +++ b/tensorflow/contrib/cmake/tf_core_ops.cmake @@ -15,6 +15,7 @@ set(tf_op_lib_names "audio_ops" "array_ops" + "batch_ops" "bitwise_ops" "candidate_sampling_ops" "checkpoint_ops" diff --git a/tensorflow/contrib/cmake/tf_python.cmake b/tensorflow/contrib/cmake/tf_python.cmake index 17bbdb1a86..b62a031749 100755 --- a/tensorflow/contrib/cmake/tf_python.cmake +++ b/tensorflow/contrib/cmake/tf_python.cmake @@ -314,6 +314,7 @@ endfunction() GENERATE_PYTHON_OP_LIB("audio_ops") GENERATE_PYTHON_OP_LIB("array_ops") +GENERATE_PYTHON_OP_LIB("batch_ops") GENERATE_PYTHON_OP_LIB("bitwise_ops") GENERATE_PYTHON_OP_LIB("math_ops") GENERATE_PYTHON_OP_LIB("functional_ops") diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 232f7d9b3c..d73f003a1d 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -593,6 +593,7 @@ cc_library( tf_gen_op_libs( is_external = False, op_lib_names = [ + "batch_ops", "bitwise_ops", "candidate_sampling_ops", "checkpoint_ops", @@ -674,6 +675,7 @@ cc_library( deps = [ ":array_ops_op_lib", ":audio_ops_op_lib", + ":batch_ops_op_lib", ":bitwise_ops_op_lib", ":candidate_sampling_ops_op_lib", ":checkpoint_ops_op_lib", @@ -809,6 +811,7 @@ cc_library( deps = [ "//tensorflow/core/kernels:array", "//tensorflow/core/kernels:audio", + "//tensorflow/core/kernels:batch_kernels", "//tensorflow/core/kernels:bincount_op", "//tensorflow/core/kernels:candidate_sampler_ops", "//tensorflow/core/kernels:checkpoint_ops", diff --git a/tensorflow/core/api_def/base_api/api_def_Batch.pbtxt b/tensorflow/core/api_def/base_api/api_def_Batch.pbtxt new file mode 100644 index 0000000000..aea11b64fd --- /dev/null +++ b/tensorflow/core/api_def/base_api/api_def_Batch.pbtxt @@ -0,0 +1,42 @@ +op { + graph_op_name: "Batch" + summary: "Batches all input tensors nondeterministically." + description: < in_shapes; + TF_RETURN_IF_ERROR(c->input("in_tensors", &in_shapes)); + std::vector out_shapes(in_shapes.size()); + for (int i = 0; i < in_shapes.size(); ++i) { + TF_RETURN_IF_ERROR( + c->ReplaceDim(in_shapes[i], 0, c->UnknownDim(), &out_shapes[i])); + } + TF_RETURN_IF_ERROR(c->set_output("batched_tensors", out_shapes)); + TF_RETURN_IF_ERROR(c->set_output("id", {c->Scalar()})); + TF_RETURN_IF_ERROR(c->set_output( + "batch_index", + {c->MakeShape({shape_inference::DimensionOrConstant(c->UnknownDim()), + shape_inference::DimensionOrConstant(3)})})); + return Status::OK(); + }); + +REGISTER_OP("Unbatch") + .Input("batched_tensor: T") + .Input("batch_index: int64") + .Input("id: int64") + .Output("unbatched_tensor: T") + .Attr("timeout_micros: int") + .Attr("container: string = ''") + .Attr("shared_name: string = ''") + .Attr("T: type") + .SetShapeFn([](shape_inference::InferenceContext* c) { + shape_inference::ShapeHandle out_shape; + TF_RETURN_IF_ERROR( + c->ReplaceDim(c->input(0), 0, c->UnknownDim(), &out_shape)); + c->set_output(0, out_shape); + return Status::OK(); + }); + +REGISTER_OP("UnbatchGrad") + .Input("original_input: T") + .Input("batch_index: int64") + .Input("grad: T") + .Input("id: int64") + .Output("batched_grad: T") + .Attr("container: string = ''") + .Attr("shared_name: string = ''") + .Attr("T: type") + .SetShapeFn([](shape_inference::InferenceContext* c) { + c->set_output(0, c->UnknownShapeOfRank(c->Rank(c->input(2)))); + return Status::OK(); + }); + +} // namespace tensorflow diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index a0193ca6ca..01b3e92d2d 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -1387,6 +1387,13 @@ tf_gen_op_wrapper_private_py( ], ) +tf_gen_op_wrapper_private_py( + name = "batch_ops_gen", + visibility = [ + "//tensorflow:__subpackages__", + ], +) + tf_gen_op_wrapper_private_py( name = "math_ops_gen", visibility = [ -- GitLab From 25006a71a4a668049f338b396ba410d851c13c9d Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Tue, 23 Jan 2018 11:23:35 -0800 Subject: [PATCH 114/258] Make feature_column_test.py run with the C API enabled. I only enabled running the C API with test classes that other testing found failures in to avoid increasing the test time unnecessarily. PiperOrigin-RevId: 182964349 --- .../feature_column/feature_column_test.py | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/feature_column/feature_column_test.py b/tensorflow/python/feature_column/feature_column_test.py index 2374680b96..d78d74c8ca 100644 --- a/tensorflow/python/feature_column/feature_column_test.py +++ b/tensorflow/python/feature_column/feature_column_test.py @@ -1072,6 +1072,7 @@ def get_linear_model_column_var(column): 'linear_model/' + column.name)[0] +@test_util.with_c_api class LinearModelTest(test.TestCase): def test_raises_if_empty_feature_columns(self): @@ -1325,10 +1326,16 @@ class LinearModelTest(test.TestCase): price = fc.numeric_column('price', shape=2) with ops.Graph().as_default(): features = {'price': [[1.], [5.]]} - predictions = fc.linear_model(features, [price]) - with _initialized_session(): - with self.assertRaisesRegexp(Exception, 'requested shape has 4'): - predictions.eval() + if ops._USE_C_API: + with self.assertRaisesRegexp( + Exception, + r'Cannot reshape a tensor with 2 elements to shape \[2,2\]'): + predictions = fc.linear_model(features, [price]) + else: + predictions = fc.linear_model(features, [price]) + with _initialized_session(): + with self.assertRaisesRegexp(Exception, 'requested shape has 4'): + predictions.eval() def test_dense_reshaping(self): price = fc.numeric_column('price', shape=[1, 2]) @@ -1791,6 +1798,7 @@ class InputLayerTest(test.TestCase): self.assertAllEqual([[2, 2], [2, 2], [2, 2]], gradient) +@test_util.with_c_api class FunctionalInputLayerTest(test.TestCase): def test_raises_if_empty_feature_columns(self): @@ -1855,10 +1863,16 @@ class FunctionalInputLayerTest(test.TestCase): price = fc.numeric_column('price', shape=2) with ops.Graph().as_default(): features = {'price': [[1.], [5.]]} - net = fc.input_layer(features, [price]) - with _initialized_session(): - with self.assertRaisesRegexp(Exception, 'requested shape has 4'): - net.eval() + if ops._USE_C_API: + with self.assertRaisesRegexp( + Exception, + r'Cannot reshape a tensor with 2 elements to shape \[2,2\]'): + net = fc.input_layer(features, [price]) + else: + net = fc.input_layer(features, [price]) + with _initialized_session(): + with self.assertRaisesRegexp(Exception, 'requested shape has 4'): + net.eval() def test_reshaping(self): price = fc.numeric_column('price', shape=[1, 2]) -- GitLab From 95f6860767116e1a831362c7d6233087fcee47dd Mon Sep 17 00:00:00 2001 From: "Joshua V. Dillon" Date: Tue, 23 Jan 2018 11:37:58 -0800 Subject: [PATCH 115/258] Add `tf.contrib.distributions.Autoregressive`. PiperOrigin-RevId: 182966827 --- tensorflow/contrib/distributions/BUILD | 13 ++ tensorflow/contrib/distributions/__init__.py | 2 + .../kernel_tests/autoregressive_test.py | 94 ++++++++ .../python/ops/autoregressive.py | 208 ++++++++++++++++++ 4 files changed, 317 insertions(+) create mode 100644 tensorflow/contrib/distributions/python/kernel_tests/autoregressive_test.py create mode 100644 tensorflow/contrib/distributions/python/ops/autoregressive.py diff --git a/tensorflow/contrib/distributions/BUILD b/tensorflow/contrib/distributions/BUILD index 95848af699..7d785c3636 100644 --- a/tensorflow/contrib/distributions/BUILD +++ b/tensorflow/contrib/distributions/BUILD @@ -128,6 +128,19 @@ cuda_py_test( tags = ["no_pip"], ) +cuda_py_test( + name = "autoregressive_test", + size = "small", + srcs = ["python/kernel_tests/autoregressive_test.py"], + additional_deps = [ + ":distributions_py", + "//third_party/py/numpy", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:platform_test", + ], +) + cuda_py_test( name = "binomial_test", size = "small", diff --git a/tensorflow/contrib/distributions/__init__.py b/tensorflow/contrib/distributions/__init__.py index 7b401e178f..59cc5eae06 100644 --- a/tensorflow/contrib/distributions/__init__.py +++ b/tensorflow/contrib/distributions/__init__.py @@ -23,6 +23,7 @@ from __future__ import print_function # pylint: disable=unused-import,wildcard-import,line-too-long,g-importing-member from tensorflow.contrib.distributions.python.ops import bijectors +from tensorflow.contrib.distributions.python.ops.autoregressive import * from tensorflow.contrib.distributions.python.ops.binomial import * from tensorflow.contrib.distributions.python.ops.cauchy import * from tensorflow.contrib.distributions.python.ops.chi2 import * @@ -92,6 +93,7 @@ _allowed_symbols = [ 'NOT_REPARAMETERIZED', 'ReparameterizationType', 'Distribution', + 'Autoregressive', 'Binomial', 'Bernoulli', 'BernoulliWithSigmoidProbs', diff --git a/tensorflow/contrib/distributions/python/kernel_tests/autoregressive_test.py b/tensorflow/contrib/distributions/python/kernel_tests/autoregressive_test.py new file mode 100644 index 0000000000..0928dc3f35 --- /dev/null +++ b/tensorflow/contrib/distributions/python/kernel_tests/autoregressive_test.py @@ -0,0 +1,94 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.contrib.distributions.python.ops import autoregressive as autoregressive_lib +from tensorflow.contrib.distributions.python.ops import independent as independent_lib +from tensorflow.contrib.distributions.python.ops import test_util +from tensorflow.contrib.distributions.python.ops.bijectors.affine import Affine +from tensorflow.contrib.distributions.python.ops.bijectors.masked_autoregressive import MaskedAutoregressiveFlow +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops.distributions import normal as normal_lib +from tensorflow.python.ops.distributions import transformed_distribution as transformed_distribution_lib +from tensorflow.python.ops.distributions import util as distribution_util +from tensorflow.python.platform import test + + +class AutogressiveTest(test_util.VectorDistributionTestHelpers, test.TestCase): + """Tests the Autoregressive distribution.""" + + def setUp(self): + self._rng = np.random.RandomState(42) + + def _random_scale_tril(self, event_size): + n = np.int32(event_size * (event_size + 1) // 2) + p = 2. * self._rng.random_sample(n).astype(np.float32) - 1. + return distribution_util.fill_triangular(0.25 * p) + + def _normal_fn(self, affine_bijector): + def _fn(samples): + scale = math_ops.exp(affine_bijector.forward(samples)) + return independent_lib.Independent( + normal_lib.Normal(loc=0., scale=scale, validate_args=True), + reinterpreted_batch_ndims=1) + return _fn + + def testSampleAndLogProbConsistency(self): + batch_shape = [] + event_size = 2 + with self.test_session() as sess: + batch_event_shape = np.concatenate([batch_shape, [event_size]], axis=0) + sample0 = array_ops.zeros(batch_event_shape) + affine = Affine(scale_tril=self._random_scale_tril(event_size)) + ar = autoregressive_lib.Autoregressive( + self._normal_fn(affine), sample0, validate_args=True) + self.run_test_sample_consistent_log_prob( + sess.run, ar, radius=1., center=0., rtol=0.01) + + def testCompareToBijector(self): + """Demonstrates equivalence between TD, Bijector approach and AR dist.""" + sample_shape = np.int32([4, 5]) + batch_shape = np.int32([]) + event_size = np.int32(2) + with self.test_session() as sess: + batch_event_shape = np.concatenate([batch_shape, [event_size]], axis=0) + sample0 = array_ops.zeros(batch_event_shape) + affine = Affine(scale_tril=self._random_scale_tril(event_size)) + ar = autoregressive_lib.Autoregressive( + self._normal_fn(affine), sample0, validate_args=True) + ar_flow = MaskedAutoregressiveFlow( + is_constant_jacobian=True, + shift_and_log_scale_fn=lambda x: [None, affine.forward(x)], + validate_args=True) + td = transformed_distribution_lib.TransformedDistribution( + distribution=normal_lib.Normal(loc=0., scale=1.), + bijector=ar_flow, + event_shape=[event_size], + batch_shape=batch_shape, + validate_args=True) + x_shape = np.concatenate( + [sample_shape, batch_shape, [event_size]], axis=0) + x = 2. * self._rng.random_sample(x_shape).astype(np.float32) - 1. + td_log_prob_, ar_log_prob_ = sess.run([td.log_prob(x), ar.log_prob(x)]) + self.assertAllClose(td_log_prob_, ar_log_prob_, atol=0., rtol=1e-6) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/contrib/distributions/python/ops/autoregressive.py b/tensorflow/contrib/distributions/python/ops/autoregressive.py new file mode 100644 index 0000000000..852298bf33 --- /dev/null +++ b/tensorflow/contrib/distributions/python/ops/autoregressive.py @@ -0,0 +1,208 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""The Autoregressive distribution.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.python.framework import ops +from tensorflow.python.ops.distributions import distribution as distribution_lib +from tensorflow.python.ops.distributions import util as distribution_util + + +class Autoregressive(distribution_lib.Distribution): + """Autoregressive distributions. + + The Autoregressive distribution enables learning (often) richer multivariate + distributions by repeatedly applying a [diffeomorphic]( + https://en.wikipedia.org/wiki/Diffeomorphism) transformation (such as + implemented by `Bijector`s). Regarding terminology, + + "Autoregressive models decompose the joint density as a product of + conditionals, and model each conditional in turn. Normalizing flows + transform a base density (e.g. a standard Gaussian) into the target density + by an invertible transformation with tractable Jacobian." [1] + + In other words, the "autoregressive property" is equivalent to the + decomposition, `p(x) = prod{ p(x[i] | x[0:i]) : i=0, ..., d }`. The provided + `shift_and_log_scale_fn`, `masked_autoregressive_default_template`, achieves + this property by zeroing out weights in its `masked_dense` layers. + + Practically speaking the autoregressive property means that there exists a + permutation of the event coordinates such that each coordinate is a + diffeomorphic function of only preceding coordinates. [2] + + #### Mathematical Details + + The probability function is, + + ```none + prob(x; fn, n) = fn(x).prob(x) + ``` + + And a sample is generated by, + + ```none + x = fn(...fn(fn(x0).sample()).sample()).sample() + ``` + + where the ellipses (`...`) represent `n-2` composed calls to `fn`, `fn` + constructs a `tf.distributions.Distribution`-like instance, and `x0` is a + fixed initializing `Tensor`. + + #### Examples + + ```python + tfd = tf.contrib.distributions + + def normal_fn(self, event_size): + n = event_size * (event_size + 1) / 2 + p = tf.Variable(tfd.Normal(loc=0., scale=1.).sample(n)) + affine = tfd.bijectors.Affine( + scale_tril=tfd.fill_triangular(0.25 * p)) + def _fn(samples): + scale = math_ops.exp(affine.forward(samples)).eval() + return independent_lib.Independent( + normal_lib.Normal(loc=0., scale=scale, validate_args=True), + reinterpreted_batch_ndims=1) + return _fn + + batch_and_event_shape = [3, 2, 4] + sample0 = array_ops.zeros(batch_and_event_shape) + ar = autoregressive_lib.Autoregressive( + self._normal_fn(batch_and_event_shape[-1]), sample0) + x = ar.sample([6, 5]) + # ==> x.shape = [6, 5, 3, 2, 4] + prob_x = ar.prob(x) + # ==> x.shape = [6, 5, 3, 2] + + ``` + + [1]: "Masked Autoregressive Flow for Density Estimation." + George Papamakarios, Theo Pavlakou, Iain Murray. Arxiv. 2017. + https://arxiv.org/abs/1705.07057 + + [2]: "Conditional Image Generation with PixelCNN Decoders." + Aaron van den Oord, Nal Kalchbrenner, Oriol Vinyals, Lasse Espeholt, Alex + Graves, Koray Kavukcuoglu. Arxiv, 2016. + https://arxiv.org/abs/1606.05328 + """ + + def __init__(self, + distribution_fn, + sample0=None, + num_steps=None, + validate_args=False, + allow_nan_stats=True, + name="Autoregressive"): + """Construct an `Autoregressive` distribution. + + Args: + distribution_fn: Python `callable` which constructs a + `tf.distributions.Distribution`-like instance from a `Tensor` (e.g., + `sample0`). The function must respect the "autoregressive property", + i.e., there exists a permutation of event such that each coordinate is a + diffeomorphic function of on preceding coordinates. + sample0: Initial input to `distribution_fn`; used to + build the distribution in `__init__` which in turn specifies this + distribution's properties, e.g., `event_shape`, `batch_shape`, `dtype`. + If unspecified, then `distribution_fn` should be default constructable. + num_steps: Number of times `distribution_fn` is composed from samples, + e.g., `num_steps=2` implies + `distribution_fn(distribution_fn(sample0).sample(n)).sample()`. + validate_args: Python `bool`. Whether to validate input with asserts. + If `validate_args` is `False`, and the inputs are invalid, + correct behavior is not guaranteed. + allow_nan_stats: Python `bool`, default `True`. When `True`, statistics + (e.g., mean, mode, variance) use the value "`NaN`" to indicate the + result is undefined. When `False`, an exception is raised if one or + more of the statistic's batch members are undefined. + name: Python `str` name prefixed to Ops created by this class. + Default value: "Autoregressive". + + Raises: + ValueError: if `num_steps` and + `distribution_fn(sample0).event_shape.num_elements()` are both `None`. + ValueError: if `num_steps < 1`. + """ + parameters = locals() + with ops.name_scope(name): + self._distribution_fn = distribution_fn + self._sample0 = sample0 + self._distribution0 = (distribution_fn() if sample0 is None + else distribution_fn(sample0)) + if num_steps is None: + num_steps = self._distribution0.event_shape.num_elements() + if num_steps is None: + raise ValueError("distribution_fn must generate a distribution " + "with fully known `event_shape`.") + if num_steps < 1: + raise ValueError("num_steps ({}) must be at least 1.".format(num_steps)) + self._num_steps = num_steps + super(Autoregressive, self).__init__( + dtype=self._distribution0.dtype, + reparameterization_type=self._distribution0.reparameterization_type, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + parameters=parameters, + graph_parents=self._distribution0._graph_parents, # pylint: disable=protected-access + name=name) + + @property + def distribution_fn(self): + return self._distribution_fn + + @property + def sample0(self): + return self._sample0 + + @property + def num_steps(self): + return self._num_steps + + @property + def distribution0(self): + return self._distribution0 + + def _batch_shape(self): + return self.distribution0.batch_shape + + def _batch_shape_tensor(self): + return self.distribution0.batch_shape_tensor() + + def _event_shape(self): + return self.distribution0.event_shape + + def _event_shape_tensor(self): + return self.distribution0.event_shape_tensor() + + def _sample_n(self, n, seed=None): + if seed is None: + seed = distribution_util.gen_new_seed( + seed=np.random.randint(2**32 - 1), + salt="autoregressive") + samples = self.distribution0.sample(n, seed=seed) + for _ in range(self._num_steps): + samples = self.distribution_fn(samples).sample(seed=seed) + return samples + + def _log_prob(self, value): + return self.distribution_fn(value).log_prob(value) + + def _prob(self, value): + return self.distribution_fn(value).prob(value) -- GitLab From 8c08ef800149c51076431d63477faa48bd1e5877 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Tue, 23 Jan 2018 11:46:18 -0800 Subject: [PATCH 116/258] [XLA] Remove LiteralTestUtil::EqualTuple / NearTuple. Instead, simply DTRT when you pass a tuple to Equal/Near. PiperOrigin-RevId: 182968283 --- .../xla/tests/client_library_test_base.cc | 4 +- .../compiler/xla/tests/literal_test_util.cc | 132 +++++------------- .../compiler/xla/tests/literal_test_util.h | 31 ++-- 3 files changed, 47 insertions(+), 120 deletions(-) diff --git a/tensorflow/compiler/xla/tests/client_library_test_base.cc b/tensorflow/compiler/xla/tests/client_library_test_base.cc index 7c9494f133..a677986cd9 100644 --- a/tensorflow/compiler/xla/tests/client_library_test_base.cc +++ b/tensorflow/compiler/xla/tests/client_library_test_base.cc @@ -387,7 +387,7 @@ void ClientLibraryTestBase::ComputeAndCompareTuple( return; } auto actual = actual_status.ConsumeValueOrDie(); - LiteralTestUtil::ExpectEqualTuple(expected, *actual); + LiteralTestUtil::ExpectEqual(expected, *actual); } void ClientLibraryTestBase::ComputeAndCompareTuple( @@ -399,7 +399,7 @@ void ClientLibraryTestBase::ComputeAndCompareTuple( return; } auto actual = actual_status.ConsumeValueOrDie(); - LiteralTestUtil::ExpectNearTuple(expected, *actual, error); + LiteralTestUtil::ExpectNear(expected, *actual, error); } void ClientLibraryTestBase::ComputeAndCompare( diff --git a/tensorflow/compiler/xla/tests/literal_test_util.cc b/tensorflow/compiler/xla/tests/literal_test_util.cc index dd91dbe8b9..975feaa050 100644 --- a/tensorflow/compiler/xla/tests/literal_test_util.cc +++ b/tensorflow/compiler/xla/tests/literal_test_util.cc @@ -313,6 +313,10 @@ bool ExpectLiteralsEqual(const Literal& expected, const Literal& actual, case TUPLE: { bool tuple_match = true; for (int i = 0; i < ShapeUtil::TupleElementCount(expected.shape()); ++i) { + SCOPED_TRACE(tensorflow::strings::StrCat( + "Tuple index ", i, " in ", + ShapeUtil::HumanString(expected.shape()))); + // Create LiteralViews of the expected and actual elements. auto result = Equal(LiteralView::Create(expected, {i}), LiteralView::Create(actual, {i})); @@ -336,47 +340,6 @@ bool ExpectLiteralsEqual(const Literal& expected, const Literal& actual, return result; } -/* static */ ::testing::AssertionResult LiteralTestUtil::EqualTuple( - const Literal& expected, const Literal& actual) { - VLOG(1) << "expected: " << expected.ToString(); - VLOG(1) << "actual: " << actual.ToString(); - - if (!ShapeUtil::IsTuple(expected.shape()) || - !ShapeUtil::IsTuple(actual.shape())) { - return ::testing::AssertionFailure() - << "tuples expected shape = " << expected.shape().ShortDebugString() - << " actual shape = " << actual.shape().ShortDebugString(); - } - AssertEqualShapes(expected.shape(), actual.shape()); - - ::testing::AssertionResult err = ::testing::AssertionSuccess(); - for (int64 i = 0; i < ShapeUtil::TupleElementCount(expected.shape()); ++i) { - SCOPED_TRACE(tensorflow::strings::StrCat( - "Tuple index ", i, " in ", ShapeUtil::HumanString(expected.shape()))); - const auto expected_element = LiteralView::Create(expected, {i}); - const auto actual_element = LiteralView::Create(actual, {i}); - - ::testing::AssertionResult res = [&] { - if (ShapeUtil::IsTuple(expected_element.shape())) { - return EqualTuple(expected_element, actual_element); - } else { - return Equal(expected_element, actual_element); - } - }(); - - if (!res && err) { - err = res; - } - } - - return err; -} - -/* static */ void LiteralTestUtil::ExpectEqualTuple(const Literal& expected, - const Literal& actual) { - EXPECT_TRUE(EqualTuple(expected, actual)); -} - namespace { // Helper class for comparing floating-point literals within an error bound. @@ -613,10 +576,37 @@ bool NearComparator::ExpectValuesNear(bfloat16 expected, /* static */ ::testing::AssertionResult LiteralTestUtil::Near( const Literal& expected, const Literal& actual, const ErrorSpec& error) { - NearComparator comparator(error); - return comparator.ExpectNear(expected, actual) - ? ::testing::AssertionSuccess() - : ::testing::AssertionFailure() << "values were not near"; + ::testing::AssertionResult err = + EqualShapes(expected.shape(), actual.shape()); + if (!err) { + return err; + } + + if (ShapeUtil::IsTuple(expected.shape())) { + for (int64 i = 0; i < ShapeUtil::TupleElementCount(expected.shape()); ++i) { + SCOPED_TRACE(tensorflow::strings::StrCat( + "Tuple index ", i, " in ", ShapeUtil::HumanString(expected.shape()))); + const auto expected_element = LiteralView::Create(expected, {i}); + const auto actual_element = LiteralView::Create(actual, {i}); + + ::testing::AssertionResult res = + Near(expected_element, actual_element, error); + if (err && !res) { + err = res; + } + } + return err; + } + + if (ShapeUtil::ElementIsFloating(expected.shape()) || + ShapeUtil::ElementIsComplex(expected.shape())) { + NearComparator comparator(error); + return comparator.ExpectNear(expected, actual) + ? ::testing::AssertionSuccess() + : ::testing::AssertionFailure() << "values were not near"; + } + + return Equal(expected, actual); } /* static */ void LiteralTestUtil::ExpectNear(const Literal& expected, @@ -629,65 +619,13 @@ bool NearComparator::ExpectValuesNear(bfloat16 expected, : tensorflow::strings::StrCat("\nmessage: ", message)); } -/* static */ ::testing::AssertionResult LiteralTestUtil::NearTuple( - const Literal& expected, const Literal& actual, const ErrorSpec& error) { - VLOG(1) << "expected: " << expected.ToString(); - VLOG(1) << "actual: " << actual.ToString(); - - if (!ShapeUtil::IsTuple(expected.shape()) || - !ShapeUtil::IsTuple(actual.shape())) { - return ::testing::AssertionFailure() - << "tuples expected shape = " << expected.shape().ShortDebugString() - << " actual shape = " << actual.shape().ShortDebugString(); - } - AssertEqualShapes(expected.shape(), actual.shape()); - - ::testing::AssertionResult err = ::testing::AssertionSuccess(); - for (int64 i = 0; i < ShapeUtil::TupleElementCount(expected.shape()); ++i) { - SCOPED_TRACE(tensorflow::strings::StrCat( - "Tuple index ", i, " in ", ShapeUtil::HumanString(expected.shape()))); - const auto expected_element = LiteralView::Create(expected, {i}); - const auto actual_element = LiteralView::Create(actual, {i}); - - ::testing::AssertionResult res = [&] { - if (ShapeUtil::IsTuple(expected_element.shape())) { - return NearTuple(expected_element, actual_element, error); - } else if (ShapeUtil::ElementIsFloating(expected_element.shape())) { - return Near(expected_element, actual_element, error); - } else { - return Equal(expected_element, actual_element); - } - }(); - - if (err && !res) { - err = res; - } - } - return err; -} - -/* static */ void LiteralTestUtil::ExpectNearTuple(const Literal& expected, - const Literal& actual, - const ErrorSpec& error) { - EXPECT_TRUE(NearTuple(expected, actual, error)); -} - /*static*/ ::testing::AssertionResult LiteralTestUtil::NearOrEqual( const Literal& expected, const Literal& actual, const tensorflow::gtl::optional& error) { - bool is_tuple = ShapeUtil::IsTuple(expected.shape()); if (error.has_value()) { - if (is_tuple) { - VLOG(1) << "Expects near tuple"; - return NearTuple(expected, actual, *error); - } VLOG(1) << "Expects near"; return Near(expected, actual, *error); } - if (is_tuple) { - VLOG(1) << "Expects equal tuple"; - return EqualTuple(expected, actual); - } VLOG(1) << "Expects equal"; return Equal(expected, actual); } diff --git a/tensorflow/compiler/xla/tests/literal_test_util.h b/tensorflow/compiler/xla/tests/literal_test_util.h index f53553c701..9b0724262d 100644 --- a/tensorflow/compiler/xla/tests/literal_test_util.h +++ b/tensorflow/compiler/xla/tests/literal_test_util.h @@ -111,17 +111,18 @@ class LiteralTestUtil { static void ExpectR4EqualArray4D(const Array4D& expected, const Literal& actual); - // Returns whether the two tuples are equal. - static ::testing::AssertionResult EqualTuple( - const Literal& expected, const Literal& actual) TF_MUST_USE_RESULT; - - // Expects that the values of the elements in the expected and actual tuples - // are equal. Tuples are matched recursively. - static void ExpectEqualTuple(const Literal& expected, const Literal& actual); - // Asserts that the expected and actual literals are within the given error // bound for all elements. Also, asserts that the rank, dimensions sizes, and - // bounds are equivalent. Only supported for floating point values. + // bounds are equivalent. + // + // Tuples are matched recursively. When comparing tensors of + // non-floating-point type, checks for exact equality, ignoring the ErroSpec. + // + // If the shape of the literals is neither a complex/floating-point tensor nor + // a tuple which contains a complex/floating-point tensor, Near() is + // equivalent to Equal(). We don't raise an error in this case, because we + // want to allow callers to call Near() even if they have no preconceptions + // about the shapes being compared. static ::testing::AssertionResult Near( const Literal& expected, const Literal& actual, const ErrorSpec& error) TF_MUST_USE_RESULT; @@ -170,18 +171,6 @@ class LiteralTestUtil { const Literal& actual, const ErrorSpec& error); - // Returns whether the values of the elements in the expected and actual - // tuples are within the given error bound. Tuples are matched recursively. - // If the elements of the tuple are not floating-point types, the error spec - // is ignored and exact equality is checked. - static ::testing::AssertionResult NearTuple( - const Literal& expected, const Literal& actual, - const ErrorSpec& error) TF_MUST_USE_RESULT; - - // Expects that the expected and actual values are near. - static void ExpectNearTuple(const Literal& expected, const Literal& actual, - const ErrorSpec& error); - // If the error spec is given, returns whether the expected and the actual are // within the error bound; otherwise, returns whether they are equal. Tuples // will be compared recursively. -- GitLab From 75a849fafbe69a036eb7f5f79b91413641784560 Mon Sep 17 00:00:00 2001 From: Anthony Platanios Date: Tue, 23 Jan 2018 14:50:26 -0500 Subject: [PATCH 117/258] Fixes #16314 (#16332) * Fixes the ABI issue for the CI libraries. * Fixes the ABI issue for the CI libraries. --- tensorflow/tools/ci_build/builds/libtensorflow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/tools/ci_build/builds/libtensorflow.sh b/tensorflow/tools/ci_build/builds/libtensorflow.sh index 26713dded8..a86ecc4297 100755 --- a/tensorflow/tools/ci_build/builds/libtensorflow.sh +++ b/tensorflow/tools/ci_build/builds/libtensorflow.sh @@ -52,7 +52,7 @@ function build_libtensorflow_tarball() { TARBALL_SUFFIX="${1}" BAZEL="bazel --bazelrc ./tensorflow/tools/ci_build/install/.bazelrc" - BAZEL_OPTS="-c opt" + BAZEL_OPTS="-c opt --cxxopt=-D_GLIBCXX_USE_CXX11_ABI=0" if [ "${TF_NEED_CUDA}" == "1" ]; then BAZEL_OPTS="${BAZEL_OPTS} --config=cuda" fi -- GitLab From 612d2c3c595eaceec230c2d383049b789d005e32 Mon Sep 17 00:00:00 2001 From: ngc92 <7938269+ngc92@users.noreply.github.com> Date: Tue, 23 Jan 2018 21:03:44 +0100 Subject: [PATCH 118/258] Assert3DImage function that automatically adds a control dependency for the shape check. (#15926) --- tensorflow/python/ops/image_ops_impl.py | 46 ++++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index d860a3b618..b713c44717 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -148,6 +148,28 @@ def _Check3DImage(image, require_static=True): return [] +def _Assert3DImage(image): + """Assert that we are working with a properly shaped image. + + Performs the check statically if possible (i.e. if the shape + is statically known). Otherwise adds a control dependency + to an assert op that checks the dynamic shape. + + Args: + image: 3-D Tensor of shape [height, width, channels] + + Raises: + ValueError: if `image.shape` is not a 3-vector. + + Returns: + If the shape of `image` could be verified statically, `image` is + returned unchanged, otherwise there will be a control dependency + added that asserts the correct dynamic shape. + """ + return control_flow_ops.with_dependencies( + _Check3DImage(image, require_static=False), image) + + def _CheckAtLeast3DImage(image, require_static=True): """Assert that we are working with properly shaped image. @@ -223,8 +245,7 @@ def random_flip_up_down(image, seed=None): """ with ops.name_scope(None, 'random_flip_up_down', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) result = control_flow_ops.cond(mirror_cond, @@ -255,8 +276,7 @@ def random_flip_left_right(image, seed=None): """ with ops.name_scope(None, 'random_flip_left_right', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) result = control_flow_ops.cond(mirror_cond, @@ -286,8 +306,7 @@ def flip_left_right(image): """ with ops.name_scope(None, 'flip_left_right', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) return fix_image_flip_shape(image, array_ops.reverse(image, [1], name=scope)) @@ -312,8 +331,7 @@ def flip_up_down(image): """ with ops.name_scope(None, 'flip_up_down', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) return fix_image_flip_shape(image, array_ops.reverse(image, [0], name=scope)) @@ -332,8 +350,7 @@ def rot90(image, k=1, name=None): """ with ops.name_scope(name, 'rot90', [image, k]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) k = ops.convert_to_tensor(k, dtype=dtypes.int32, name='k') k.get_shape().assert_has_rank(0) k = math_ops.mod(k, 4) @@ -373,8 +390,7 @@ def transpose_image(image): """ with ops.name_scope(None, 'transpose_image', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) return array_ops.transpose(image, [1, 0, 2], name=scope) @@ -410,8 +426,7 @@ def central_crop(image, central_fraction): if central_fraction == 1.0: return image - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) img_shape = array_ops.shape(image) depth = image.get_shape()[2] @@ -848,8 +863,7 @@ def per_image_standardization(image): """ with ops.name_scope(None, 'per_image_standardization', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) num_pixels = math_ops.reduce_prod(array_ops.shape(image)) image = math_ops.cast(image, dtype=dtypes.float32) -- GitLab From 64d42bf9d1a952e4dd00283f396d09f3328a6127 Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Tue, 23 Jan 2018 12:01:11 -0800 Subject: [PATCH 119/258] Correctly incref items put into the tuple to keep msan happy. PiperOrigin-RevId: 182970703 --- tensorflow/python/eager/pywrap_tfe_src.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/eager/pywrap_tfe_src.cc b/tensorflow/python/eager/pywrap_tfe_src.cc index b3ce09ce90..6162644036 100644 --- a/tensorflow/python/eager/pywrap_tfe_src.cc +++ b/tensorflow/python/eager/pywrap_tfe_src.cc @@ -1091,8 +1091,9 @@ bool MaybeRunRecordGradientCallback(const tensorflow::OpDef* op_def, PyObject* inputs = PyTuple_New(op_def->input_arg_size()); for (int i = 0; i < op_def->input_arg_size(); i++) { - PyTuple_SET_ITEM( - inputs, i, PyTuple_GET_ITEM(args, kFastPathExecuteInputStartIndex + i)); + auto* input = PyTuple_GET_ITEM(args, kFastPathExecuteInputStartIndex + i); + Py_INCREF(input); + PyTuple_SET_ITEM(inputs, i, input); } int args_size = PyTuple_GET_SIZE(args); @@ -1100,9 +1101,10 @@ bool MaybeRunRecordGradientCallback(const tensorflow::OpDef* op_def, args_size - op_def->input_arg_size() - kFastPathExecuteInputStartIndex; PyObject* attrs = PyTuple_New(num_attrs); for (int i = 0; i < num_attrs; i++) { - PyTuple_SET_ITEM(attrs, i, - PyTuple_GET_ITEM(args, kFastPathExecuteInputStartIndex + - op_def->input_arg_size() + i)); + auto* attr = PyTuple_GET_ITEM( + args, kFastPathExecuteInputStartIndex + op_def->input_arg_size() + i); + Py_INCREF(attr); + PyTuple_SET_ITEM(attrs, i, attr); } PyObject* callback_args = Py_BuildValue("OOO", inputs, attrs, result); -- GitLab From 93035bd163b7f609c0a2023259f5dfb826e1c033 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 12:14:52 -0800 Subject: [PATCH 120/258] Allow fisher-vector multiplies on 1D vectors for CategoricalLogitsNegativeLogProbLoss. PiperOrigin-RevId: 182972901 --- .../kernel_tests/loss_functions_test.py | 36 +++++++++++++++++++ .../contrib/kfac/python/ops/loss_functions.py | 7 ++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/tensorflow/contrib/kfac/python/kernel_tests/loss_functions_test.py b/tensorflow/contrib/kfac/python/kernel_tests/loss_functions_test.py index 63f45ea55b..ae787b6f1a 100644 --- a/tensorflow/contrib/kfac/python/kernel_tests/loss_functions_test.py +++ b/tensorflow/contrib/kfac/python/kernel_tests/loss_functions_test.py @@ -113,6 +113,42 @@ class CategoricalLogitsNegativeLogProbLossTest(test.TestCase): self.assertListEqual(loss.input_minibatches, tower_logits) self.assertEqual(loss.num_registered_minibatches, num_towers) + def testMultiplyFisherSingleVector(self): + with ops.Graph().as_default(), self.test_session() as sess: + logits = np.array([1., 2., 3.]) + loss = loss_functions.CategoricalLogitsNegativeLogProbLoss(logits) + + # the LossFunction.multiply_fisher docstring only says it supports the + # case where the vector is the same shape as the input natural parameters + # (i.e. the logits here), but here we also test leading dimensions + vector = np.array([1., 2., 3.]) + vectors = [vector, vector.reshape(1, -1), np.stack([vector] * 4)] + + probs = np.exp(logits - np.logaddexp.reduce(logits)) + fisher = np.diag(probs) - np.outer(probs, probs) + + for vector in vectors: + result = loss.multiply_fisher(vector) + expected_result = np.dot(vector, fisher) + self.assertAllClose(expected_result, sess.run(result)) + + def testMultiplyFisherBatch(self): + with ops.Graph().as_default(), self.test_session() as sess: + logits = np.array([[1., 2., 3.], [4., 6., 8.]]) + loss = loss_functions.CategoricalLogitsNegativeLogProbLoss(logits) + + vector = np.array([[1., 2., 3.], [5., 3., 1.]]) + + na = np.newaxis + probs = np.exp(logits - np.logaddexp.reduce(logits, axis=-1, + keepdims=True)) + fishers = probs[..., na] * np.eye(3) - probs[..., na] * probs[..., na, :] + + result = loss.multiply_fisher(vector) + expected_result = np.matmul(vector[..., na, :], fishers)[..., 0, :] + self.assertEqual(sess.run(result).shape, logits.shape) + self.assertAllClose(expected_result, sess.run(result)) + class OnehotCategoricalLogitsNegativeLogProbLossTest(test.TestCase): diff --git a/tensorflow/contrib/kfac/python/ops/loss_functions.py b/tensorflow/contrib/kfac/python/ops/loss_functions.py index 2daead2a71..cb3e698b9c 100644 --- a/tensorflow/contrib/kfac/python/ops/loss_functions.py +++ b/tensorflow/contrib/kfac/python/ops/loss_functions.py @@ -660,19 +660,20 @@ class CategoricalLogitsNegativeLogProbLoss(DistributionNegativeLogProbLoss, def multiply_fisher(self, vector): probs = self._probs - return vector * probs - math_ops.reduce_sum(vector * probs, axis=1) * probs + return vector * probs - probs * math_ops.reduce_sum( + vector * probs, axis=-1, keep_dims=True) def multiply_fisher_factor(self, vector): probs = self._probs sqrt_probs = self._sqrt_probs return sqrt_probs * vector - probs * math_ops.reduce_sum( - sqrt_probs * vector, axis=1, keep_dims=True) + sqrt_probs * vector, axis=-1, keep_dims=True) def multiply_fisher_factor_transpose(self, vector): probs = self._probs sqrt_probs = self._sqrt_probs return sqrt_probs * vector - sqrt_probs * math_ops.reduce_sum( - probs * vector, axis=1, keep_dims=True) + probs * vector, axis=-1, keep_dims=True) def multiply_fisher_factor_replicated_one_hot(self, index): assert len(index) == 1, "Length of index was {}".format(len(index)) -- GitLab From f9462e82ac3981d7a3b5bf392477a585fb6e6912 Mon Sep 17 00:00:00 2001 From: "freedom\" Koan-Sin Tan" Date: Wed, 24 Jan 2018 04:19:07 +0800 Subject: [PATCH 121/258] fix doc for benchmark_model for android (#15639) after configure.py set framework_shared_object=true, benchmark_model won't build for Android without tweeks. Add '--config monolithic' to avoid confusion. --- tensorflow/tools/benchmark/BUILD | 3 ++- tensorflow/tools/benchmark/README.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tensorflow/tools/benchmark/BUILD b/tensorflow/tools/benchmark/BUILD index caa6629c49..6ed2594e6a 100644 --- a/tensorflow/tools/benchmark/BUILD +++ b/tensorflow/tools/benchmark/BUILD @@ -61,10 +61,11 @@ tf_cc_test( # 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 \ +# bazel build tensorflow/core:android_tensorflow_lib \ # --crosstool_top=//external:android/crosstool \ # --cpu=armeabi-v7a \ # --host_crosstool_top=@bazel_tools//tools/cpp:toolchain +# --config monolithic tf_cc_binary( name = "benchmark_model", testonly = 1, diff --git a/tensorflow/tools/benchmark/README.md b/tensorflow/tools/benchmark/README.md index ca0da2d41b..e64af2bfe1 100644 --- a/tensorflow/tools/benchmark/README.md +++ b/tensorflow/tools/benchmark/README.md @@ -17,6 +17,7 @@ bazel build -c opt \ --crosstool_top=//external:android/crosstool \ --cpu=armeabi-v7a \ --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \ + --config monolithic \ tensorflow/tools/benchmark:benchmark_model ``` -- GitLab From b47119257b76bdec542121aaed056c8b010fd19f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 12:19:06 -0800 Subject: [PATCH 122/258] Update ops-related pbtxt files. PiperOrigin-RevId: 182973494 --- .../core/ops/compat/ops_history.v1.pbtxt | 152 ++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 152 ++++++++++++++++++ 2 files changed, 304 insertions(+) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index 438882dc9e..c2e2793760 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -7903,6 +7903,76 @@ op { } } } +op { + name: "Batch" + input_arg { + name: "in_tensors" + type_list_attr: "T" + } + output_arg { + name: "batched_tensors" + type_list_attr: "T" + } + output_arg { + name: "batch_index" + type: DT_INT64 + } + output_arg { + name: "id" + type: DT_INT64 + } + attr { + name: "num_batch_threads" + type: "int" + } + attr { + name: "max_batch_size" + type: "int" + } + attr { + name: "batch_timeout_micros" + type: "int" + } + attr { + name: "allowed_batch_sizes" + type: "list(int)" + default_value { + list { + } + } + } + attr { + name: "grad_timeout_micros" + type: "int" + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "batching_queue" + type: "string" + default_value { + s: "" + } + } + attr { + name: "T" + type: "list(type)" + has_minimum: true + minimum: 1 + } +} op { name: "BatchCholesky" input_arg { @@ -64232,6 +64302,88 @@ op { } is_stateful: true } +op { + name: "Unbatch" + input_arg { + name: "batched_tensor" + type_attr: "T" + } + input_arg { + name: "batch_index" + type: DT_INT64 + } + input_arg { + name: "id" + type: DT_INT64 + } + output_arg { + name: "unbatched_tensor" + type_attr: "T" + } + attr { + name: "timeout_micros" + type: "int" + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "T" + type: "type" + } +} +op { + name: "UnbatchGrad" + input_arg { + name: "original_input" + type_attr: "T" + } + input_arg { + name: "batch_index" + type: DT_INT64 + } + input_arg { + name: "grad" + type_attr: "T" + } + input_arg { + name: "id" + type: DT_INT64 + } + output_arg { + name: "batched_grad" + type_attr: "T" + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "T" + type: "type" + } +} op { name: "UniformCandidateSampler" input_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index 45eb1a9cac..60da36a939 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -2737,6 +2737,76 @@ op { } } } +op { + name: "Batch" + input_arg { + name: "in_tensors" + type_list_attr: "T" + } + output_arg { + name: "batched_tensors" + type_list_attr: "T" + } + output_arg { + name: "batch_index" + type: DT_INT64 + } + output_arg { + name: "id" + type: DT_INT64 + } + attr { + name: "num_batch_threads" + type: "int" + } + attr { + name: "max_batch_size" + type: "int" + } + attr { + name: "batch_timeout_micros" + type: "int" + } + attr { + name: "allowed_batch_sizes" + type: "list(int)" + default_value { + list { + } + } + } + attr { + name: "grad_timeout_micros" + type: "int" + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "batching_queue" + type: "string" + default_value { + s: "" + } + } + attr { + name: "T" + type: "list(type)" + has_minimum: true + minimum: 1 + } +} op { name: "BatchCholesky" input_arg { @@ -30381,6 +30451,88 @@ op { } is_stateful: true } +op { + name: "Unbatch" + input_arg { + name: "batched_tensor" + type_attr: "T" + } + input_arg { + name: "batch_index" + type: DT_INT64 + } + input_arg { + name: "id" + type: DT_INT64 + } + output_arg { + name: "unbatched_tensor" + type_attr: "T" + } + attr { + name: "timeout_micros" + type: "int" + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "T" + type: "type" + } +} +op { + name: "UnbatchGrad" + input_arg { + name: "original_input" + type_attr: "T" + } + input_arg { + name: "batch_index" + type: DT_INT64 + } + input_arg { + name: "grad" + type_attr: "T" + } + input_arg { + name: "id" + type: DT_INT64 + } + output_arg { + name: "batched_grad" + type_attr: "T" + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "T" + type: "type" + } +} op { name: "UniformCandidateSampler" input_arg { -- GitLab From ba4aec48268d02f111cd7e2c2666f4e7b077e68a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 12:24:21 -0800 Subject: [PATCH 123/258] Internal Change PiperOrigin-RevId: 182974191 --- .../lite/toco/allocate_transient_arrays.cc | 8 +- tensorflow/contrib/lite/toco/dump_graphviz.cc | 8 +- .../contrib/lite/toco/export_tensorflow.cc | 46 ++--- .../convert_expanddims_to_reshape.cc | 6 +- .../convert_pure_conv_to_depthwise.cc | 2 +- .../convert_trivial_transpose_to_reshape.cc | 4 +- .../create_im2col_arrays.cc | 2 +- .../toco/graph_transformations/dequantize.cc | 4 +- .../graph_transformations/drop_fake_quant.cc | 2 +- .../drop_im2col_arrays.cc | 2 +- .../fuse_activation_functions.cc | 2 +- .../fuse_binary_into_following_affine.cc | 4 +- .../fuse_binary_into_preceding_affine.cc | 4 +- .../graph_transformations.cc | 19 +- .../identify_l2_normalization.cc | 12 +- .../graph_transformations/identify_l2_pool.cc | 4 +- .../graph_transformations/identify_relu1.cc | 6 +- .../propagate_array_data_types.cc | 20 +- .../propagate_fixed_sizes.cc | 174 +++++++++--------- .../toco/graph_transformations/quantize.cc | 2 +- .../read_fake_quant_min_max.cc | 2 +- .../remove_final_dequantize_op.cc | 2 +- .../remove_trivial_binary.cc | 2 +- .../remove_trivial_concatenation_input.cc | 2 +- .../remove_trivial_passthrough.cc | 2 +- .../graph_transformations/remove_unused_op.cc | 6 +- .../resolve_batch_normalization.cc | 6 +- .../resolve_batch_to_space_nd_attributes.cc | 4 +- .../resolve_constant_binary.cc | 11 +- .../resolve_constant_concatenation.cc | 2 +- .../resolve_constant_fake_quant.cc | 2 +- .../resolve_constant_fill.cc | 4 +- .../resolve_constant_range.cc | 14 +- .../resolve_constant_shape_or_rank.cc | 2 +- .../resolve_constant_stack.cc | 2 +- .../resolve_constant_strided_slice.cc | 2 +- .../resolve_constant_unary.cc | 2 +- .../resolve_mean_attributes.cc | 2 +- .../resolve_pad_attributes.cc | 2 +- .../resolve_reorder_axes.cc | 2 +- .../resolve_reshape_attributes.cc | 2 +- .../resolve_slice_attributes.cc | 4 +- .../resolve_space_to_batch_nd_attributes.cc | 5 +- .../resolve_strided_slice_attributes.cc | 6 +- .../resolve_tensorflow_concat.cc | 2 +- .../resolve_tensorflow_matmul.cc | 4 +- .../resolve_tensorflow_merge.cc | 2 +- .../resolve_tensorflow_switch.cc | 4 +- .../resolve_tensorflow_tile.cc | 4 +- .../resolve_transpose_attributes.cc | 2 +- .../resolve_constant_concatenation_test.cc | 19 +- .../unfuse_activation_functions.cc | 2 +- .../contrib/lite/toco/import_tensorflow.cc | 2 +- tensorflow/contrib/lite/toco/model.h | 39 +++- tensorflow/contrib/lite/toco/tflite/export.cc | 4 +- .../contrib/lite/toco/tflite/import_test.cc | 2 +- tensorflow/contrib/lite/toco/toco_tooling.cc | 2 +- tensorflow/contrib/lite/toco/tooling_util.cc | 49 ++--- 58 files changed, 288 insertions(+), 270 deletions(-) diff --git a/tensorflow/contrib/lite/toco/allocate_transient_arrays.cc b/tensorflow/contrib/lite/toco/allocate_transient_arrays.cc index d4da8f5dfe..5961d30bf5 100644 --- a/tensorflow/contrib/lite/toco/allocate_transient_arrays.cc +++ b/tensorflow/contrib/lite/toco/allocate_transient_arrays.cc @@ -148,7 +148,7 @@ std::size_t TransientArraySize(const Model& model, const string& array_name, if (!IsAllocatableTransientArray(model, array_name)) { return 0; } - const auto& array = model.arrays.at(array_name); + const auto& array = &model.GetArray(array_name); CHECK(array->has_shape()) << "Array '" << array_name << "' doesn't have a shape"; if (array->data_type == ArrayDataType::kNone) { @@ -185,7 +185,7 @@ void AllocateTransientArray(const Model& model, const string& array_name, } const std::size_t size = TransientArraySize(model, array_name, transient_data_alignment); - const auto& array = model.arrays.at(array_name); + const auto& array = &model.GetArray(array_name); CHECK(!array->alloc); allocator->Allocate(size, &array->GetOrCreateAlloc()); } @@ -197,7 +197,7 @@ void DeallocateTransientArray(const Model& model, const string& array_name, if (!IsAllocatableTransientArray(model, array_name)) { return; } - const auto& array = model.arrays.at(array_name); + const auto& array = &model.GetArray(array_name); CHECK(!!array->alloc); allocator->Deallocate(*array->alloc); } @@ -231,7 +231,7 @@ void AllocateTransientArrays(Model* model, // Construct a sorted map of array names, so that other layout engines can // match exactly. std::map ordered_arrays_map; - for (const auto& pair : model->arrays) { + for (const auto& pair : model->GetArrayMap()) { ordered_arrays_map[pair.first] = pair.second.get(); } diff --git a/tensorflow/contrib/lite/toco/dump_graphviz.cc b/tensorflow/contrib/lite/toco/dump_graphviz.cc index 39809216c7..c726eb6d86 100644 --- a/tensorflow/contrib/lite/toco/dump_graphviz.cc +++ b/tensorflow/contrib/lite/toco/dump_graphviz.cc @@ -278,8 +278,8 @@ std::vector OperatorsToDump(const Model& model) { if (last_specified) { // Return only the part of the graph between graphviz_first_array // and graphviz_last_array. - CHECK(model.arrays.count(dump_options.graphviz_first_array)); - CHECK(model.arrays.count(dump_options.graphviz_last_array)); + CHECK(model.HasArray(dump_options.graphviz_first_array)); + CHECK(model.HasArray(dump_options.graphviz_last_array)); std::unordered_set arrays_already_produced; std::vector arrays_to_produce; arrays_to_produce.push_back(dump_options.graphviz_last_array); @@ -336,7 +336,7 @@ void DumpGraphviz(const Model& model, string* output_file_contents) { op_properties.color.TextColorString().c_str()); // Add nodes and edges for all inputs of the operator. for (const auto& input : op.inputs) { - if (model.arrays.count(input) == 0) { + if (!model.HasArray(input)) { // Arrays should _always_ exist. Except, perhaps, during development. continue; } @@ -352,7 +352,7 @@ void DumpGraphviz(const Model& model, string* output_file_contents) { } // Add nodes and edges for all outputs of the operator. for (const auto& output : op.outputs) { - if (model.arrays.count(output) == 0) { + if (!model.HasArray(output)) { // Arrays should _always_ exist. Except, perhaps, during development. continue; } diff --git a/tensorflow/contrib/lite/toco/export_tensorflow.cc b/tensorflow/contrib/lite/toco/export_tensorflow.cc index 90fa442746..4fc01dbc20 100644 --- a/tensorflow/contrib/lite/toco/export_tensorflow.cc +++ b/tensorflow/contrib/lite/toco/export_tensorflow.cc @@ -156,8 +156,8 @@ void ConvertFloatTensorConst(const Model& model, const string& name, const_op->set_name(name); (*const_op->mutable_attr())["dtype"].set_type(DT_FLOAT); auto* tensor = (*const_op->mutable_attr())["value"].mutable_tensor(); - CHECK(model.arrays.count(name)); - const auto& input_array = *model.arrays.at(name); + CHECK(model.HasArray(name)); + const auto& input_array = model.GetArray(name); const auto& input_shape = input_array.shape(); CHECK(input_array.buffer); CHECK(input_array.buffer->type == ArrayDataType::kFloat); @@ -177,8 +177,8 @@ void ConvertFloatTensorConst(const Model& model, const string& name, const_op->set_name(name); (*const_op->mutable_attr())["dtype"].set_type(DT_FLOAT); auto* tensor = (*const_op->mutable_attr())["value"].mutable_tensor(); - CHECK(model.arrays.count(name)); - const auto& input_array = *model.arrays.at(name); + CHECK(model.HasArray(name)); + const auto& input_array = model.GetArray(name); const auto& input_shape = input_array.shape(); CHECK(input_array.buffer); CHECK(input_array.buffer->type == ArrayDataType::kFloat); @@ -193,8 +193,8 @@ void ConvertIntTensorConst(const Model& model, const string& name, if (HasAlreadyExportedConst(name, *tensorflow_graph)) { return; } - CHECK(model.arrays.count(name)); - const auto& array = *model.arrays.at(name); + CHECK(model.HasArray(name)); + const auto& array = model.GetArray(name); auto* const_op = tensorflow_graph->add_node(); const_op->set_op("Const"); const_op->set_name(name); @@ -324,7 +324,7 @@ void ConvertConvOperator(const Model& model, const ConvOperator& src_op, biasadd_op->add_input(conv_output); biasadd_op->add_input(src_op.inputs[2]); (*biasadd_op->mutable_attr())["T"].set_type(DT_FLOAT); - CHECK(model.arrays.count(src_op.inputs[2])); + CHECK(model.HasArray(src_op.inputs[2])); const string& bias_array_name = WalkUpToConstantArray(model, src_op.inputs[2]); const auto& bias_array = model.GetArray(bias_array_name); @@ -361,7 +361,7 @@ void ConvertDepthwiseConvOperator(const Model& model, // We need to convert that to H x W x InputDepth x Multiplier. // That's only a matter of constructing a Dims object; the actual // array layout is the same. - CHECK(model.arrays.count(src_op.inputs[1])); + CHECK(model.HasArray(src_op.inputs[1])); const string& src_weights_name = WalkUpToConstantArray(model, src_op.inputs[1]); const auto& src_weights_array = model.GetArray(src_weights_name); @@ -404,7 +404,7 @@ void ConvertDepthwiseConvOperator(const Model& model, biasadd_op->add_input(conv_output); biasadd_op->add_input(src_op.inputs[2]); (*biasadd_op->mutable_attr())["T"].set_type(DT_FLOAT); - CHECK(model.arrays.count(src_op.inputs[2])); + CHECK(model.HasArray(src_op.inputs[2])); const string& bias_name = WalkUpToConstantArray(model, src_op.inputs[2]); const auto& bias_array = model.GetArray(bias_name); // TODO(b/62904716) Bias arrays should be 1-D, and used directly. @@ -469,10 +469,10 @@ void ConvertFullyConnectedOperator(const Model& model, (*matmul_op->mutable_attr())["T"].set_type(DT_FLOAT); (*matmul_op->mutable_attr())["transpose_a"].set_b(false); (*matmul_op->mutable_attr())["transpose_b"].set_b(false); - CHECK(model.arrays.count(src_op.inputs[1])); + CHECK(model.HasArray(src_op.inputs[1])); const string& fc_weights_name = WalkUpToConstantArray(model, src_op.inputs[1]); - const auto& fc_weights_array = *model.arrays.at(fc_weights_name); + const auto& fc_weights_array = model.GetArray(fc_weights_name); const auto& fc_weights_shape = fc_weights_array.shape(); CHECK_EQ(fc_weights_shape.dimensions_count(), 2); CreateMatrixShapeTensorConst(reshape_shape, fc_weights_shape.dims(1), -1, @@ -492,8 +492,8 @@ void ConvertFullyConnectedOperator(const Model& model, biasadd_op->add_input(matmul_output); biasadd_op->add_input(src_op.inputs[2]); (*biasadd_op->mutable_attr())["T"].set_type(DT_FLOAT); - CHECK(model.arrays.count(src_op.inputs[2])); - const auto& bias_array = *model.arrays.at(src_op.inputs[2]); + CHECK(model.HasArray(src_op.inputs[2])); + const auto& bias_array = model.GetArray(src_op.inputs[2]); // TODO(b/62904716) Bias arrays should be 1-D, and used directly. Shape bias_shape_1d = bias_array.shape(); UnextendShape(&bias_shape_1d, 1); @@ -625,7 +625,7 @@ void ConvertSoftmaxOperator(const Model& model, const SoftmaxOperator& src_op, *reshape_op->add_input() = softmax_size; (*reshape_op->mutable_attr())["T"].set_type(DT_FLOAT); - const auto& input_shape = model.arrays.at(src_op.inputs[0])->shape(); + const auto& input_shape = model.GetArray(src_op.inputs[0]).shape(); int32 flattened_size = 1; for (int i = 0; i < input_shape.dimensions_count() - 1; ++i) { flattened_size *= input_shape.dims(i); @@ -1013,8 +1013,8 @@ void ConvertLstmCellOperator(const Model& model, const LstmCellOperator& src_op, // Op names have been chosen to match the tf.slim LSTM naming // as closely as possible. const int axis = - model.arrays.at(src_op.inputs[LstmCellOperator::PREV_ACTIV_INPUT]) - ->shape() + model.GetArray(src_op.inputs[LstmCellOperator::PREV_ACTIV_INPUT]) + .shape() .dimensions_count() - 1; // Note that DATA_INPUT may have extra size 1 dimensions, but TF concat @@ -1033,9 +1033,9 @@ void ConvertLstmCellOperator(const Model& model, const LstmCellOperator& src_op, // Write weights const string weights_output = base + "weights"; - CHECK(model.arrays.count(src_op.inputs[LstmCellOperator::WEIGHTS_INPUT])); + CHECK(model.HasArray(src_op.inputs[LstmCellOperator::WEIGHTS_INPUT])); const auto& weights_array = - *model.arrays.at(src_op.inputs[LstmCellOperator::WEIGHTS_INPUT]); + model.GetArray(src_op.inputs[LstmCellOperator::WEIGHTS_INPUT]); // Convert 4D FullyConnected weights into 2D matrix const auto& weights_shape = weights_array.shape(); CHECK_EQ(weights_shape.dimensions_count(), 2); @@ -1059,9 +1059,9 @@ void ConvertLstmCellOperator(const Model& model, const LstmCellOperator& src_op, // Write biases const string biases_output = base + "biases"; - CHECK(model.arrays.count(src_op.inputs[LstmCellOperator::BIASES_INPUT])); + CHECK(model.HasArray(src_op.inputs[LstmCellOperator::BIASES_INPUT])); const auto& bias_array = - *model.arrays.at(src_op.inputs[LstmCellOperator::BIASES_INPUT]); + model.GetArray(src_op.inputs[LstmCellOperator::BIASES_INPUT]); // TODO(b/62904716) Bias arrays should be 1-D, and used directly. Shape bias_shape_1d = bias_array.shape(); UnextendShape(&bias_shape_1d, 1); @@ -1557,7 +1557,7 @@ void AddPlaceholderForRNNState(const Model& model, const string& name, int size, (*placeholder->mutable_attr())["dtype"].set_type(DT_FLOAT); auto* shape = (*placeholder->mutable_attr())["shape"].mutable_shape(); - const auto& state_array = *model.arrays.at(name); + const auto& state_array = model.GetArray(name); if (state_array.has_shape()) { const auto& state_shape = state_array.shape(); const int kDims = state_shape.dimensions_count(); @@ -1574,7 +1574,7 @@ void ExportTensorFlowGraphDefImplementation(const Model& model, GraphDef* tensorflow_graph) { for (const auto& input_array : model.flags.input_arrays()) { AddPlaceholder(input_array.name(), - model.arrays.at(input_array.name())->data_type, + model.GetArray(input_array.name()).data_type, tensorflow_graph); } for (const auto& rnn_state : model.flags.rnn_states()) { @@ -1588,7 +1588,7 @@ void ExportTensorFlowGraphDefImplementation(const Model& model, // by the above operators export. It's important that this comes // after, as some operators need to export arrays that they reference // in a specific way, rather than in the generic way done below. - for (const auto& array_pair : model.arrays) { + for (const auto& array_pair : model.GetArrayMap()) { const string& array_name = array_pair.first; const auto& array = *array_pair.second; if (array.buffer) { diff --git a/tensorflow/contrib/lite/toco/graph_transformations/convert_expanddims_to_reshape.cc b/tensorflow/contrib/lite/toco/graph_transformations/convert_expanddims_to_reshape.cc index 3bde9b0169..56f48d47de 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/convert_expanddims_to_reshape.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/convert_expanddims_to_reshape.cc @@ -35,7 +35,7 @@ bool ConvertExpandDimsToReshape::Run(Model* model, std::size_t op_index) { CHECK_EQ(expand_op->inputs.size(), 2); CHECK_EQ(expand_op->outputs.size(), 1); - const auto& input_array = *model->arrays[expand_op->inputs[0]]; + const auto& input_array = model->GetArray(expand_op->inputs[0]); if (!input_array.has_shape()) { // Yield until input dims have been resolved. return false; @@ -46,7 +46,7 @@ bool ConvertExpandDimsToReshape::Run(Model* model, std::size_t op_index) { return false; } - const auto& axis_array = *model->arrays[expand_op->inputs[1]]; + const auto& axis_array = model->GetArray(expand_op->inputs[1]); if (!axis_array.has_shape()) { // Yield until input axis array shape has been resolved. return false; @@ -86,7 +86,7 @@ bool ConvertExpandDimsToReshape::Run(Model* model, std::size_t op_index) { if (IsDiscardableArray(*model, axis_array_name) && CountOpsWithInput(*model, axis_array_name) == 1 && !GetOpWithOutput(*model, axis_array_name)) { - model->arrays.erase(axis_array_name); + model->EraseArray(axis_array_name); } // Replace the operator in the graph. diff --git a/tensorflow/contrib/lite/toco/graph_transformations/convert_pure_conv_to_depthwise.cc b/tensorflow/contrib/lite/toco/graph_transformations/convert_pure_conv_to_depthwise.cc index bf454c40c7..d38db85280 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/convert_pure_conv_to_depthwise.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/convert_pure_conv_to_depthwise.cc @@ -58,7 +58,7 @@ bool ConvertPureConvToDepthwise::Run(Model* model, std::size_t op_index) { depthwiseconv_op->outputs = {conv_op->outputs[0]}; if (conv_op->outputs.size() > 1) { // delete the im2col array. - model->arrays.erase(conv_op->outputs[1]); + model->EraseArray(conv_op->outputs[1]); } depthwiseconv_op->fused_activation_function = conv_op->fused_activation_function; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/convert_trivial_transpose_to_reshape.cc b/tensorflow/contrib/lite/toco/graph_transformations/convert_trivial_transpose_to_reshape.cc index a234c20924..c2b166033c 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/convert_trivial_transpose_to_reshape.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/convert_trivial_transpose_to_reshape.cc @@ -29,7 +29,7 @@ bool ConvertTrivialTransposeToReshape::Run(Model* model, std::size_t op_index) { TransposeOperator* transpose_op = static_cast(transpose_it->get()); - const auto& output_array = *model->arrays[transpose_op->outputs[0]]; + const auto& output_array = model->GetArray(transpose_op->outputs[0]); if (!output_array.has_shape()) { // Yield until PropagateFixedSizes has been run on this op. return false; @@ -70,7 +70,7 @@ bool ConvertTrivialTransposeToReshape::Run(Model* model, std::size_t op_index) { // Delete perm array if unused if (IsDiscardableArray(*model, perm_array_name) && CountOpsWithInput(*model, perm_array_name) == 1) { - model->arrays.erase(perm_array_name); + model->EraseArray(perm_array_name); } // Replace the operator in the graph. diff --git a/tensorflow/contrib/lite/toco/graph_transformations/create_im2col_arrays.cc b/tensorflow/contrib/lite/toco/graph_transformations/create_im2col_arrays.cc index 1735b51e5b..076415ece8 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/create_im2col_arrays.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/create_im2col_arrays.cc @@ -35,7 +35,7 @@ bool CreateIm2colArrays::Run(Model* model, std::size_t op_index) { // We already have an im2col array return false; } - const auto& weights_array = *model->arrays[conv_op->inputs[1]]; + const auto& weights_array = model->GetArray(conv_op->inputs[1]); if (!weights_array.has_shape()) { // We need to yield until weights dims have been resolved, because // from the weights dims we determine whether an im2col array is diff --git a/tensorflow/contrib/lite/toco/graph_transformations/dequantize.cc b/tensorflow/contrib/lite/toco/graph_transformations/dequantize.cc index 79854cba34..498c864bde 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/dequantize.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/dequantize.cc @@ -53,7 +53,7 @@ std::vector>::iterator FindFirstOpWithInput( } void ClearArrayQuantizationParams(const string& array_name, Model* model) { - auto* array = model->arrays.at(array_name).get(); + auto* array = &model->GetArray(array_name); CHECK(array->quantization_params); for (auto& input_array : *model->flags.mutable_input_arrays()) { if (input_array.name() == array_name) { @@ -77,7 +77,7 @@ void ClearArrayQuantizationParams(const string& array_name, Model* model) { bool DequantizeArray(const string& array_name, GraphTransformation* transformation, Model* model) { - auto* array = model->arrays.at(array_name).get(); + auto* array = &model->GetArray(array_name); if (!array->quantization_params) { return false; } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/drop_fake_quant.cc b/tensorflow/contrib/lite/toco/graph_transformations/drop_fake_quant.cc index fea360740f..95558ef5ec 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/drop_fake_quant.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/drop_fake_quant.cc @@ -45,7 +45,7 @@ bool DropFakeQuant::Run(Model* model, std::size_t op_index) { // Drop min/max inputs for (int i = 1; i < fakequant_op->inputs.size(); i++) { if (CountOpsWithInput(*model, fakequant_op->inputs[i]) == 1) { - model->arrays.erase(fakequant_op->inputs[i]); + model->EraseArray(fakequant_op->inputs[i]); } } fakequant_op->inputs.resize(1); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/drop_im2col_arrays.cc b/tensorflow/contrib/lite/toco/graph_transformations/drop_im2col_arrays.cc index a3ed6663bc..f7fd878b7e 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/drop_im2col_arrays.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/drop_im2col_arrays.cc @@ -32,7 +32,7 @@ bool DropIm2colArrays::Run(Model* model, std::size_t op_index) { // Drop the im2col array. CHECK_EQ(conv_op->outputs.size(), 2); - model->arrays.erase(conv_op->outputs[1]); + model->EraseArray(conv_op->outputs[1]); conv_op->outputs.resize(1); AddMessageF("Dropped an im2col array for %s", LogName(*conv_op)); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/fuse_activation_functions.cc b/tensorflow/contrib/lite/toco/graph_transformations/fuse_activation_functions.cc index ad4a6f9b78..88e59664ec 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/fuse_activation_functions.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/fuse_activation_functions.cc @@ -91,7 +91,7 @@ bool FuseActivationFunctions::Run(Model* model, std::size_t op_index) { } else { LOG(FATAL) << "Unhandled activation function type"; } - model->arrays.erase(ac_op->inputs[0]); + model->EraseArray(ac_op->inputs[0]); op->outputs[0] = ac_op->outputs[0]; model->operators.erase(ac_it); return true; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/fuse_binary_into_following_affine.cc b/tensorflow/contrib/lite/toco/graph_transformations/fuse_binary_into_following_affine.cc index 4619d8bbee..dcbbead517 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/fuse_binary_into_following_affine.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/fuse_binary_into_following_affine.cc @@ -285,13 +285,13 @@ bool FuseBinaryIntoFollowingAffine::Run(Model* model, std::size_t op_index) { AddMessageF("Fusing %s into the following %s", LogName(*binary_op), LogName(*following_op)); - model->arrays.erase(binary_op->outputs[0]); + model->EraseArray(binary_op->outputs[0]); following_op->inputs[0] = binary_op->inputs[index_of_variable_input]; const auto& old_constant_param_name = binary_op->inputs[index_of_constant_input]; CHECK(IsConstantParameterArray(*model, old_constant_param_name)); if (CountOpsWithInput(*model, old_constant_param_name) == 1) { - model->arrays.erase(old_constant_param_name); + model->EraseArray(old_constant_param_name); } model->operators.erase(binary_it); return true; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/fuse_binary_into_preceding_affine.cc b/tensorflow/contrib/lite/toco/graph_transformations/fuse_binary_into_preceding_affine.cc index 8948653ec3..5b57178b18 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/fuse_binary_into_preceding_affine.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/fuse_binary_into_preceding_affine.cc @@ -309,7 +309,7 @@ bool FuseBinaryIntoPrecedingAffine::Run(Model* model, std::size_t op_index) { LOG(FATAL) << "should not get here"; } - model->arrays.erase(preceding_op->outputs[0]); + model->EraseArray(preceding_op->outputs[0]); preceding_op->outputs[0] = binary_op->outputs[0]; preceding_op->fused_activation_function = binary_op->fused_activation_function; @@ -317,7 +317,7 @@ bool FuseBinaryIntoPrecedingAffine::Run(Model* model, std::size_t op_index) { binary_op->inputs[index_of_constant_input]; CHECK(IsConstantParameterArray(*model, old_constant_param_name)); if (CountOpsWithInput(*model, old_constant_param_name) == 1) { - model->arrays.erase(old_constant_param_name); + model->EraseArray(old_constant_param_name); } model->operators.erase(binary_it); return true; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc index f861c4147a..2340f0e850 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc @@ -31,13 +31,13 @@ namespace { void PrintModelStats(const string& label, const Model& model) { int quantized_arrays = 0; - for (const auto& array : model.arrays) { + for (const auto& array : model.GetArrayMap()) { if (array.second->quantization_params) { quantized_arrays++; } } LOG(INFO) << label << ": " << model.operators.size() << " operators, " - << model.arrays.size() << " arrays (" << quantized_arrays + << model.GetArrayMap().size() << " arrays (" << quantized_arrays << " quantized)"; } @@ -91,14 +91,9 @@ void DiscardUselessConnectedComponentsAndRNNBackEdges(Model* model) { } } while (found_new_useful_arrays); // Erase arrays that aren't useful, and that are discardable. - for (auto it = model->arrays.begin(); it != model->arrays.end();) { - if (useful_arrays.count(it->first) || - !IsDiscardableArray(*model, it->first)) { - ++it; - } else { - it = model->arrays.erase(it); - } - } + model->EraseArrays([&](const string& name) { + return (!useful_arrays.count(name) && IsDiscardableArray(*model, name)); + }); // Erase operators that do not produce a useful output array. for (auto it = model->operators.begin(); it != model->operators.end();) { // Only need to test the first output, as we simultaneously added all of @@ -118,8 +113,8 @@ void DiscardUselessConnectedComponentsAndRNNBackEdges(Model* model) { std::vector rnn_states_to_keep; for (const auto& rnn_state : model->flags.rnn_states()) { const bool dangling = - !model->arrays.count(rnn_state.back_edge_source_array()) || - !model->arrays.count(rnn_state.state_array()); + !model->HasArray(rnn_state.back_edge_source_array()) || + !model->HasArray(rnn_state.state_array()); if (dangling) { CHECK(rnn_state.discardable()); } else { diff --git a/tensorflow/contrib/lite/toco/graph_transformations/identify_l2_normalization.cc b/tensorflow/contrib/lite/toco/graph_transformations/identify_l2_normalization.cc index 01b75e37c6..419a0776a6 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/identify_l2_normalization.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/identify_l2_normalization.cc @@ -150,19 +150,19 @@ bool IdentifyL2Normalization::Run(Model* model, std::size_t op_index) { // Erase the subgraph that is now replaced by L2Normalization model->operators.erase(FindOperator(model, square_op)); - model->arrays.erase(sum_op->inputs[0]); + model->EraseArray(sum_op->inputs[0]); if (sum_op->inputs.size() > 1) { - model->arrays.erase(sum_op->inputs[1]); + model->EraseArray(sum_op->inputs[1]); } model->operators.erase(FindOperator(model, sum_op)); if (add_op) { - model->arrays.erase(add_op->inputs[0]); - model->arrays.erase(add_op->inputs[1]); + model->EraseArray(add_op->inputs[0]); + model->EraseArray(add_op->inputs[1]); model->operators.erase(FindOperator(model, add_op)); } - model->arrays.erase(sqrt_or_rsqrt_op->inputs[0]); + model->EraseArray(sqrt_or_rsqrt_op->inputs[0]); model->operators.erase(FindOperator(model, sqrt_or_rsqrt_op)); - model->arrays.erase(div_or_mul_op->inputs[1]); + model->EraseArray(div_or_mul_op->inputs[1]); model->operators.erase(FindOperator(model, div_or_mul_op)); return true; } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/identify_l2_pool.cc b/tensorflow/contrib/lite/toco/graph_transformations/identify_l2_pool.cc index 1865416fc2..e4d52476c6 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/identify_l2_pool.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/identify_l2_pool.cc @@ -92,8 +92,8 @@ bool IdentifyL2Pool::Run(Model* model, std::size_t op_index) { AddMessageF("Creating %s replacing equivalent subgraph", LogName(*l2pool_op)); // Erase intermediate arrays, keeping input to square op. - model->arrays.erase(avpool_op->inputs[0]); - model->arrays.erase(sqrt_op->inputs[0]); + model->EraseArray(avpool_op->inputs[0]); + model->EraseArray(sqrt_op->inputs[0]); // Erase three operators being replaced. model->operators.erase(FindOperator(model, square_op)); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/identify_relu1.cc b/tensorflow/contrib/lite/toco/graph_transformations/identify_relu1.cc index cfc77024e7..d36e950609 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/identify_relu1.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/identify_relu1.cc @@ -89,12 +89,12 @@ bool IdentifyRelu1::Run(Model* model, std::size_t op_index) { AddMessageF("Creating %s replacing equivalent subgraph", LogName(*relu1_op)); // Erase Maximum scalar input & operator - model->arrays.erase(maximum_op->inputs[scalar_input_index]); + model->EraseArray(maximum_op->inputs[scalar_input_index]); model->operators.erase(FindOperator(model, maximum_op)); // Erase Minimum inputs & operator - model->arrays.erase(minimum_op->inputs[0]); - model->arrays.erase(minimum_op->inputs[1]); + model->EraseArray(minimum_op->inputs[0]); + model->EraseArray(minimum_op->inputs[1]); model->operators.erase(FindOperator(model, minimum_op)); return true; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/propagate_array_data_types.cc b/tensorflow/contrib/lite/toco/graph_transformations/propagate_array_data_types.cc index 29b55d9bfc..f0d107232b 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/propagate_array_data_types.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/propagate_array_data_types.cc @@ -27,7 +27,7 @@ namespace { void SetDataTypeForAllOutputs(Model* model, Operator* op, ArrayDataType data_type) { for (const auto& output : op->outputs) { - model->arrays[output]->data_type = data_type; + model->GetArray(output).data_type = data_type; } } } // namespace @@ -39,7 +39,7 @@ bool PropagateArrayDataTypes::Run(Model* model, std::size_t op_index) { // If the data type of some input is unknown, we need to yield. for (const auto& input : op->inputs) { if (!model->IsOptionalArray(input) && - model->arrays[input]->data_type == ArrayDataType::kNone) { + model->GetArray(input).data_type == ArrayDataType::kNone) { return false; } } @@ -47,7 +47,7 @@ bool PropagateArrayDataTypes::Run(Model* model, std::size_t op_index) { // end if we changed anything, and return the correct boolean value. std::unordered_map old_output_data_types; for (const auto& output : op->outputs) { - old_output_data_types[output] = model->arrays[output]->data_type; + old_output_data_types[output] = model->GetArray(output).data_type; } // Do the actual output data types propagation. if (op->type == OperatorType::kDequantize || @@ -69,18 +69,18 @@ bool PropagateArrayDataTypes::Run(Model* model, std::size_t op_index) { op->type == OperatorType::kFill) { // These operators produce an output with the same type as their 2nd input CHECK_GE(op->inputs.size(), 2); - const ArrayDataType data_type = model->arrays[op->inputs[1]]->data_type; + const ArrayDataType data_type = model->GetArray(op->inputs[1]).data_type; SetDataTypeForAllOutputs(model, op, data_type); } else if (op->type == OperatorType::kCast) { // Data type of the Cast op is specified. CHECK_EQ(op->outputs.size(), 1); auto* cast_op = static_cast(op); - model->arrays[op->outputs[0]]->data_type = cast_op->dst_data_type; + model->GetArray(op->outputs[0]).data_type = cast_op->dst_data_type; } else if (op->type == OperatorType::kArgMax) { // Data type of the ArgMax op is specified. CHECK_EQ(op->outputs.size(), 1); auto* argmax_op = static_cast(op); - model->arrays[op->outputs[0]]->data_type = argmax_op->output_data_type; + model->GetArray(op->outputs[0]).data_type = argmax_op->output_data_type; } else if (op->type == OperatorType::kRange) { auto* range_op = static_cast(op); // Output type of the Range op can be set via an attribute @@ -91,7 +91,7 @@ bool PropagateArrayDataTypes::Run(Model* model, std::size_t op_index) { } else { // Otherwise use the first input CHECK_GE(op->inputs.size(), 1); - data_type = model->arrays[op->inputs[0]]->data_type; + data_type = model->GetArray(op->inputs[0]).data_type; } CHECK_EQ(op->outputs.size(), 1); SetDataTypeForAllOutputs(model, op, data_type); @@ -103,7 +103,7 @@ bool PropagateArrayDataTypes::Run(Model* model, std::size_t op_index) { for (int i = 0; i < unsupported_op->output_data_types.size(); ++i) { auto output = op->outputs[i]; auto data_type = unsupported_op->output_data_types[i]; - model->arrays[output]->data_type = data_type; + model->GetArray(output).data_type = data_type; } } else if (op->type == OperatorType::kExpandDims) { // Yield on ExpandDim until it is converted to Reshape @@ -111,12 +111,12 @@ bool PropagateArrayDataTypes::Run(Model* model, std::size_t op_index) { } else { // These operators produce outputs with the same type as their 1st input CHECK_GT(op->inputs.size(), 0); - const ArrayDataType data_type = model->arrays[op->inputs[0]]->data_type; + const ArrayDataType data_type = model->GetArray(op->inputs[0]).data_type; SetDataTypeForAllOutputs(model, op, data_type); } // Return true if any output data type changed, false if none changed. for (const auto& output : op->outputs) { - if (old_output_data_types[output] != model->arrays[output]->data_type) { + if (old_output_data_types[output] != model->GetArray(output).data_type) { return true; } } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc b/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc index a939efb4db..ff0a3bd881 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc @@ -85,7 +85,7 @@ void ComputeBinaryOperatorOutputSize(const Shape& input_shape1, int GetOutputDepthFromWeights(const Model& model, const Operator& op) { const string& weights_name = op.inputs[1]; - const auto& weights_shape = model.arrays.at(weights_name)->shape(); + const auto& weights_shape = model.GetArray(weights_name).shape(); if (op.type == OperatorType::kConv || op.type == OperatorType::kFullyConnected) { return weights_shape.dims(0); @@ -98,7 +98,7 @@ int GetOutputDepthFromWeights(const Model& model, const Operator& op) { bool EnsureBiasVectorShape(Model* model, Operator* op) { const string& weights_name = op->inputs[1]; - const auto& weights_array = *model->arrays[weights_name]; + const auto& weights_array = model->GetArray(weights_name); // Yield until weights shape has been resolved. if (!weights_array.has_shape()) { return false; @@ -107,7 +107,7 @@ bool EnsureBiasVectorShape(Model* model, Operator* op) { if (op->inputs.size() < 3) { return false; } - auto& bias_array = *model->arrays[op->inputs[2]]; + auto& bias_array = model->GetArray(op->inputs[2]); if (bias_array.has_shape()) { return true; } @@ -126,7 +126,7 @@ void ProcessConvOperator(Model* model, ConvOperator* op) { return; } - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -134,7 +134,7 @@ void ProcessConvOperator(Model* model, ConvOperator* op) { const auto& input_shape = input_array.shape(); CHECK_EQ(input_shape.dimensions_count(), 4); - const auto& weights_array = *model->arrays[op->inputs[1]]; + const auto& weights_array = model->GetArray(op->inputs[1]); // Yield until weights dims have been resolved. if (!weights_array.has_shape()) { return; @@ -156,7 +156,7 @@ void ProcessConvOperator(Model* model, ConvOperator* op) { if (op->outputs.size() == 2) { const auto& output_shape = output_array.shape(); const int input_depth = weights_shape.dims(3); - auto& im2col_array = *model->arrays[op->outputs[1]]; + auto& im2col_array = model->GetArray(op->outputs[1]); im2col_array.copy_shape(Shape{output_shape.dims(0), output_shape.dims(1), output_shape.dims(2), input_depth * kheight * kwidth}); @@ -168,7 +168,7 @@ void ProcessDepthwiseConvOperator(Model* model, DepthwiseConvOperator* op) { return; } - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -176,7 +176,7 @@ void ProcessDepthwiseConvOperator(Model* model, DepthwiseConvOperator* op) { const auto& input_shape = input_array.shape(); CHECK_EQ(input_shape.dimensions_count(), 4); - const auto& weights_array = *model->arrays[op->inputs[1]]; + const auto& weights_array = model->GetArray(op->inputs[1]); // Yield until weights dims have been resolved. if (!weights_array.has_shape()) { return; @@ -209,7 +209,7 @@ void ProcessDepthwiseConvOperator(Model* model, DepthwiseConvOperator* op) { } void ProcessDepthToSpaceOperator(Model* model, DepthToSpaceOperator* op) { - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -232,7 +232,7 @@ void ProcessDepthToSpaceOperator(Model* model, DepthToSpaceOperator* op) { } void ProcessSpaceToDepthOperator(Model* model, SpaceToDepthOperator* op) { - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -258,7 +258,7 @@ void ProcessSpaceToDepthOperator(Model* model, SpaceToDepthOperator* op) { void ProcessFillOperator(Model* model, FillOperator* op) { CHECK_EQ(op->inputs.size(), 2); CHECK_EQ(op->outputs.size(), 1); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) { // We have already run return; @@ -287,7 +287,7 @@ void ProcessFullyConnectedOperator(Model* model, FullyConnectedOperator* op) { return; } - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -295,7 +295,7 @@ void ProcessFullyConnectedOperator(Model* model, FullyConnectedOperator* op) { const auto& input_shape = input_array.shape(); CHECK_GE(input_shape.dimensions_count(), 1); - const auto& weights_array = *model->arrays[op->inputs[1]]; + const auto& weights_array = model->GetArray(op->inputs[1]); // Yield until weights dims have been resolved. if (!weights_array.has_shape()) { return; @@ -315,13 +315,13 @@ void ProcessFullyConnectedOperator(Model* model, FullyConnectedOperator* op) { void ProcessTensorFlowReshapeOperator(Model* model, TensorFlowReshapeOperator* op) { - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) { // We have already run return; } - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); if (!input_array.has_shape()) { // Yield until input dims have been resolved. return; @@ -377,14 +377,14 @@ void ProcessTensorFlowReshapeOperator(Model* model, } void ProcessSimpleOperator(Model* model, Operator* op) { - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; } const string& output_name = op->outputs[0]; - auto& output_array = *model->arrays[output_name]; + auto& output_array = model->GetArray(output_name); if (output_array.has_shape()) { return; } @@ -394,14 +394,14 @@ void ProcessSimpleOperator(Model* model, Operator* op) { void ProcessSimpleBinaryOperator(Model* model, Operator* op) { CHECK_EQ(op->inputs.size(), 2); - const auto& input0_array = *model->arrays[op->inputs[0]]; - const auto& input1_array = *model->arrays[op->inputs[1]]; + const auto& input0_array = model->GetArray(op->inputs[0]); + const auto& input1_array = model->GetArray(op->inputs[1]); // Yield until input dims have been resolved. if (!input0_array.has_shape() || !input1_array.has_shape()) { return; } const string& output_name = op->outputs[0]; - auto& output_array = *model->arrays[output_name]; + auto& output_array = model->GetArray(output_name); ComputeBinaryOperatorOutputSize(input0_array.shape(), input1_array.shape(), &output_array); } @@ -424,11 +424,11 @@ bool KeepDims(const Operator& op) { void ProcessTensorFlowReductionOperator(Model* model, Operator* op) { CHECK_LE(op->inputs.size(), 2); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) { return; } - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); if (!input_array.has_shape()) { return; } @@ -436,7 +436,7 @@ void ProcessTensorFlowReductionOperator(Model* model, Operator* op) { const bool keep_dims = KeepDims(*op); if (op->inputs.size() == 2) { // There is a reduction_indices input. - const auto& reduction_array = *model->arrays[op->inputs[1]]; + const auto& reduction_array = model->GetArray(op->inputs[1]); if (!reduction_array.buffer) { return; } @@ -476,11 +476,11 @@ void ProcessSliceOperator(Model* model, SliceOperator* op) { if (op->begin.empty()) return; // Yield until input dims have been resolved. - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); if (!input_array.has_shape()) return; const Shape& input_shape = input_array.shape(); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) return; CHECK_EQ(input_shape.dims().size(), op->size.size()); @@ -500,7 +500,7 @@ void ProcessSliceOperator(Model* model, SliceOperator* op) { void ProcessReorderAxesOperator(Model* model, ReorderAxesOperator* op) { const string& input_name = op->inputs[0]; - const auto& input_array = *model->arrays[input_name]; + const auto& input_array = model->GetArray(input_name); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -515,20 +515,20 @@ void ProcessReorderAxesOperator(Model* model, ReorderAxesOperator* op) { void ProcessConcatenationOperator(Model* model, ConcatenationOperator* op) { // Yield until input dims have been resolved. for (const auto& input_name : op->inputs) { - auto& input_array = *model->arrays[input_name]; + auto& input_array = model->GetArray(input_name); if (!input_array.has_shape()) { return; } } auto& output_array = model->GetArray(op->outputs[0]); // Use 0 input as basis for output dimensions. - const auto& first_input_array = *model->arrays[op->inputs[0]]; + const auto& first_input_array = model->GetArray(op->inputs[0]); output_array.copy_shape(first_input_array.shape()); // Determine the concat size, and enfore that all inputs have // the same dimensions count. int concat_size = 0; for (const auto& input_name : op->inputs) { - auto& input_array = *model->arrays[input_name]; + auto& input_array = model->GetArray(input_name); CHECK(input_array.has_shape()); if (input_array.shape().dimensions_count() == 0) { continue; @@ -548,16 +548,16 @@ void ProcessConcatenationOperator(Model* model, ConcatenationOperator* op) { void ProcessRangeOperator(Model* model, RangeOperator* op) { CHECK_EQ(op->inputs.size(), 3); - const auto& start_array = *model->arrays[op->inputs[0]]; + const auto& start_array = model->GetArray(op->inputs[0]); if (!start_array.has_shape()) { // Yield until input dims have been resolved. return; } - const auto& limit_array = *model->arrays[op->inputs[1]]; + const auto& limit_array = model->GetArray(op->inputs[1]); if (!limit_array.has_shape()) { return; } - const auto& delta_array = *model->arrays[op->inputs[2]]; + const auto& delta_array = model->GetArray(op->inputs[2]); if (!delta_array.has_shape()) { return; } @@ -599,7 +599,7 @@ void ProcessRangeOperator(Model* model, RangeOperator* op) { void ProcessTensorFlowSplitOperator(Model* model, TensorFlowSplitOperator* op) { CHECK_EQ(op->inputs.size(), 2); const string& input_name = op->inputs[1]; - const auto& input_array = *model->arrays[input_name]; + const auto& input_array = model->GetArray(input_name); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -618,13 +618,13 @@ void ProcessTensorFlowSplitOperator(Model* model, TensorFlowSplitOperator* op) { CHECK_EQ(op->outputs.size(), op->num_split); for (const auto& output : op->outputs) { - model->arrays[output]->copy_shape(output_shape); + model->GetArray(output).copy_shape(output_shape); } } void ProcessAveragePoolOperator(Model* model, AveragePoolOperator* op) { const string& input_name = op->inputs[0]; - const auto& input_array = *model->arrays[input_name]; + const auto& input_array = model->GetArray(input_name); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -641,7 +641,7 @@ void ProcessAveragePoolOperator(Model* model, AveragePoolOperator* op) { void ProcessMaxPoolOperator(Model* model, MaxPoolOperator* op) { const string& input_name = op->inputs[0]; - const auto& input_array = *model->arrays[input_name]; + const auto& input_array = model->GetArray(input_name); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -658,7 +658,7 @@ void ProcessMaxPoolOperator(Model* model, MaxPoolOperator* op) { void ProcessL2PoolOperator(Model* model, L2PoolOperator* op) { const string& input_name = op->inputs[0]; - const auto& input_array = *model->arrays[input_name]; + const auto& input_array = model->GetArray(input_name); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -679,14 +679,14 @@ void ProcessResizeBilinearOperator(Model* model, ResizeBilinearOperator* op) { CHECK_EQ(op->inputs.size(), 2); CHECK_EQ(op->outputs.size(), 1); - if (!model->arrays[op->inputs[0]]->has_shape() || - !model->arrays[op->inputs[1]]->has_shape()) { + if (!model->GetArray(op->inputs[0]).has_shape() || + !model->GetArray(op->inputs[1]).has_shape()) { return; } - const auto& input_data_shape = model->arrays[op->inputs[0]]->shape(); + const auto& input_data_shape = model->GetArray(op->inputs[0]).shape(); const string& output_size_name = op->inputs[1]; - const auto& output_size_array = *model->arrays[output_size_name]; + const auto& output_size_array = model->GetArray(output_size_name); CHECK(output_size_array.data_type == ArrayDataType::kInt32); CHECK(output_size_array.has_shape()); const auto& output_size_shape = output_size_array.shape(); @@ -697,9 +697,9 @@ void ProcessResizeBilinearOperator(Model* model, ResizeBilinearOperator* op) { } std::vector output_shape = output_size_array.GetBuffer().data; - model->arrays[op->outputs[0]]->copy_shape( - Shape({input_data_shape.dims(0), output_shape[0], output_shape[1], - input_data_shape.dims(3)})); + model->GetArray(op->outputs[0]) + .copy_shape(Shape({input_data_shape.dims(0), output_shape[0], + output_shape[1], input_data_shape.dims(3)})); } void ProcessLstmCellOperator(Model* model, LstmCellOperator* op) { @@ -708,7 +708,7 @@ void ProcessLstmCellOperator(Model* model, LstmCellOperator* op) { QCHECK_EQ(op->outputs.size(), LstmCellOperator::NUM_OUTPUTS); const auto& input_array = - *model->arrays[op->inputs[LstmCellOperator::DATA_INPUT]]; + model->GetArray(op->inputs[LstmCellOperator::DATA_INPUT]); // Yield until all input dims have been resolved. if (!input_array.has_shape()) { return; @@ -717,7 +717,7 @@ void ProcessLstmCellOperator(Model* model, LstmCellOperator* op) { CHECK_GE(input_shape.dimensions_count(), 2); const auto& prev_activ_array = - *model->arrays[op->inputs[LstmCellOperator::PREV_ACTIV_INPUT]]; + model->GetArray(op->inputs[LstmCellOperator::PREV_ACTIV_INPUT]); // Yield until all input dims have been resolved. if (!prev_activ_array.has_shape()) { return; @@ -726,7 +726,7 @@ void ProcessLstmCellOperator(Model* model, LstmCellOperator* op) { CHECK_GE(prev_activ_shape.dimensions_count(), 2); const auto& weights_array = - *model->arrays[op->inputs[LstmCellOperator::WEIGHTS_INPUT]]; + model->GetArray(op->inputs[LstmCellOperator::WEIGHTS_INPUT]); // Yield until weights dims have been resolved. if (!weights_array.has_shape()) { return; @@ -735,7 +735,7 @@ void ProcessLstmCellOperator(Model* model, LstmCellOperator* op) { CHECK_EQ(weights_shape.dimensions_count(), 2); const auto& bias_array = - *model->arrays[op->inputs[LstmCellOperator::BIASES_INPUT]]; + model->GetArray(op->inputs[LstmCellOperator::BIASES_INPUT]); // Yield until bias dims have been resolved. if (!bias_array.has_shape()) { return; @@ -744,7 +744,7 @@ void ProcessLstmCellOperator(Model* model, LstmCellOperator* op) { CHECK_GE(bias_shape.dimensions_count(), 1); const auto& prev_state_array = - *model->arrays[op->inputs[LstmCellOperator::PREV_STATE_INPUT]]; + model->GetArray(op->inputs[LstmCellOperator::PREV_STATE_INPUT]); // Yield until all input dims have been resolved. if (!prev_state_array.has_shape()) { return; @@ -784,7 +784,7 @@ void ProcessLstmCellOperator(Model* model, LstmCellOperator* op) { } void ProcessSpaceToBatchNDOperator(Model* model, SpaceToBatchNDOperator* op) { - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -797,8 +797,8 @@ void ProcessSpaceToBatchNDOperator(Model* model, SpaceToBatchNDOperator* op) { const auto input_height = input_shape.dims(1); const auto input_width = input_shape.dims(2); - const auto& block_shape_array = *model->arrays[op->inputs[1]]; - const auto& paddings_array = *model->arrays[op->inputs[2]]; + const auto& block_shape_array = model->GetArray(op->inputs[1]); + const auto& paddings_array = model->GetArray(op->inputs[2]); const auto& block_shape_array_shape = block_shape_array.shape(); const auto& paddings_array_shape = paddings_array.shape(); QCHECK_EQ(block_shape_array_shape.dimensions_count(), 1); @@ -830,13 +830,13 @@ void ProcessSpaceToBatchNDOperator(Model* model, SpaceToBatchNDOperator* op) { int output_height = height_with_paddings / block_height; int output_width = width_with_paddings / block_width; - model->arrays[op->outputs[0]]->copy_shape( - Shape({input_shape.dims(0) * block_height * block_width, output_height, - output_width, input_shape.dims(3)})); + model->GetArray(op->outputs[0]) + .copy_shape(Shape({input_shape.dims(0) * block_height * block_width, + output_height, output_width, input_shape.dims(3)})); } void ProcessBatchToSpaceNDOperator(Model* model, BatchToSpaceNDOperator* op) { - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -846,8 +846,8 @@ void ProcessBatchToSpaceNDOperator(Model* model, BatchToSpaceNDOperator* op) { const auto input_height = input_shape.dims(1); const auto input_width = input_shape.dims(2); - const auto& block_shape_array = *model->arrays[op->inputs[1]]; - const auto& crops_array = *model->arrays[op->inputs[2]]; + const auto& block_shape_array = model->GetArray(op->inputs[1]); + const auto& crops_array = model->GetArray(op->inputs[2]); const auto& block_shape_array_shape = block_shape_array.shape(); const auto& crops_array_shape = crops_array.shape(); QCHECK_EQ(block_shape_array_shape.dimensions_count(), 1); @@ -882,15 +882,15 @@ void ProcessBatchToSpaceNDOperator(Model* model, BatchToSpaceNDOperator* op) { int output_height = input_height * block_height; int output_width = input_width * block_width; - model->arrays[op->outputs[0]]->copy_shape( - Shape({input_shape.dims(0) / (block_height * block_width), output_height, - output_width, input_shape.dims(3)})); + model->GetArray(op->outputs[0]) + .copy_shape(Shape({input_shape.dims(0) / (block_height * block_width), + output_height, output_width, input_shape.dims(3)})); } void ProcessGatherOperator(Model* model, GatherOperator* op) { - const auto& input_array = *model->arrays[op->inputs[0]]; - const auto& indices_array = *model->arrays[op->inputs[1]]; - auto& output_array = *model->arrays[op->outputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); + const auto& indices_array = model->GetArray(op->inputs[1]); + auto& output_array = model->GetArray(op->outputs[0]); // Bail if we already know the output shape. if (output_array.has_shape()) { @@ -924,7 +924,7 @@ void ProcessPadOperator(Model* model, PadOperator* op) { CHECK_EQ(op->inputs.size(), 2); CHECK_EQ(op->outputs.size(), 1); - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) return; @@ -932,7 +932,7 @@ void ProcessPadOperator(Model* model, PadOperator* op) { if (op->left_padding.empty()) return; CHECK_EQ(op->left_padding.size(), op->right_padding.size()); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) return; Shape output_shape = input_array.shape(); @@ -949,13 +949,13 @@ void ProcessPadOperator(Model* model, PadOperator* op) { void ProcessRankOperator(Model* model, RankOperator* op) { CHECK_GE(op->inputs.size(), 1); CHECK_EQ(op->outputs.size(), 1); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) { // Shape already propagated return; } - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); if (!input_array.has_shape()) { // Yield until input dims have been resolved. return; @@ -970,13 +970,13 @@ void ProcessRankOperator(Model* model, RankOperator* op) { void ProcessShapeOperator(Model* model, TensorFlowShapeOperator* op) { CHECK_GE(op->inputs.size(), 1); CHECK_EQ(op->outputs.size(), 1); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) { // Shape already propagated return; } - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); if (!input_array.has_shape()) { // Yield until input dims have been resolved. return; @@ -991,7 +991,7 @@ void ProcessShapeOperator(Model* model, TensorFlowShapeOperator* op) { void ProcessStackOperator(Model* model, StackOperator* op) { CHECK_GE(op->inputs.size(), 1); CHECK_EQ(op->outputs.size(), 1); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) { // Shape already propagated return; @@ -1032,7 +1032,7 @@ void ProcessStackOperator(Model* model, StackOperator* op) { void ProcessStridedSliceOperator(Model* model, StridedSliceOperator* op) { CHECK_GE(op->inputs.size(), 1); CHECK_EQ(op->outputs.size(), 1); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) { // Shape already propagated return; @@ -1112,12 +1112,12 @@ void ProcessSqueezeOperator(Model* model, SqueezeOperator* op) { CHECK_EQ(op->inputs.size(), 1); CHECK_EQ(op->outputs.size(), 1); - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) return; - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) return; const std::vector& input_dims = input_array.shape().dims(); @@ -1136,18 +1136,18 @@ void ProcessSqueezeOperator(Model* model, SqueezeOperator* op) { void ProcessSvdfOperator(Model* model, SvdfOperator* op) { CHECK(op->inputs.size() == 3 || op->inputs.size() == 4); - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); if (!input_array.has_shape()) return; - auto& weights_feature_array = *model->arrays[op->inputs[1]]; + auto& weights_feature_array = model->GetArray(op->inputs[1]); if (!weights_feature_array.has_shape()) return; - const auto& weights_time_array = *model->arrays[op->inputs[2]]; + const auto& weights_time_array = model->GetArray(op->inputs[2]); if (!weights_time_array.has_shape()) return; const bool has_bias = (op->inputs.size() == 4); if (has_bias) { - const auto& bias_array = *model->arrays[op->inputs[3]]; + const auto& bias_array = model->GetArray(op->inputs[3]); if (!bias_array.has_shape()) return; } @@ -1164,13 +1164,13 @@ void ProcessSvdfOperator(Model* model, SvdfOperator* op) { } void ProcessTransposeOperator(Model* model, TransposeOperator* op) { - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.has_shape()) { // We have already run return; } - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); if (!input_array.has_shape()) { // Yield until input dims have been resolved. return; @@ -1204,7 +1204,7 @@ void ProcessTransposeOperator(Model* model, TransposeOperator* op) { void ProcessArgMaxOperator(Model* model, ArgMaxOperator* op) { CHECK_EQ(op->inputs.size(), 2); - const auto& input_array = *model->arrays[op->inputs[0]]; + const auto& input_array = model->GetArray(op->inputs[0]); // Yield until input dims have been resolved. if (!input_array.has_shape()) { return; @@ -1222,7 +1222,7 @@ void ProcessArgMaxOperator(Model* model, ArgMaxOperator* op) { } output_dims.push_back(1); const string& output_name = op->outputs[0]; - auto& output_array = *model->arrays[output_name]; + auto& output_array = model->GetArray(output_name); if (output_array.has_shape()) { return; } @@ -1236,8 +1236,8 @@ bool PropagateFixedSizes::Run(Model* model, std::size_t op_index) { auto* op = it->get(); std::unordered_map> old_output_dims; for (const auto& output : op->outputs) { - if (model->arrays[output]->has_shape()) { - old_output_dims[output] = model->arrays[output]->shape().dims(); + if (model->GetArray(output).has_shape()) { + old_output_dims[output] = model->GetArray(output).shape().dims(); } } @@ -1433,10 +1433,10 @@ bool PropagateFixedSizes::Run(Model* model, std::size_t op_index) { // Return true if any output dim changed, false if none changed. // Assumption: no transformation clears an output shape, they only add shapes. for (const auto& output : op->outputs) { - if (model->arrays[output]->has_shape() && - (old_output_dims[output] != model->arrays[output]->shape().dims())) { + if (model->GetArray(output).has_shape() && + (old_output_dims[output] != model->GetArray(output).shape().dims())) { AddMessageF("Set shape of %s to [%s]", output, - absl::StrJoin(model->arrays[output]->shape().dims(), ",")); + absl::StrJoin(model->GetArray(output).shape().dims(), ",")); return true; } } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc b/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc index 56082b965a..b973b2b813 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc @@ -412,7 +412,7 @@ bool Quantize::Run(Model* model, std::size_t op_index) { model->flags.set_output_arrays(i, dequantize_op->inputs[0]); } } - model->arrays.erase(dequantize_op->outputs[0]); + model->EraseArray(dequantize_op->outputs[0]); model->operators.erase(dequantize_it); } } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/read_fake_quant_min_max.cc b/tensorflow/contrib/lite/toco/graph_transformations/read_fake_quant_min_max.cc index 371ced388a..11f8d4b6ee 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/read_fake_quant_min_max.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/read_fake_quant_min_max.cc @@ -80,7 +80,7 @@ bool ReadFakeQuantMinMax::Run(Model* model, std::size_t op_index) { // else. for (int i = 1; i <= 2; i++) { if (CountOpsWithInput(*model, fakequant_op->inputs[i]) == 1) { - model->arrays.erase(fakequant_op->inputs[i]); + model->EraseArray(fakequant_op->inputs[i]); } } fakequant_op->inputs.resize(1); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/remove_final_dequantize_op.cc b/tensorflow/contrib/lite/toco/graph_transformations/remove_final_dequantize_op.cc index 3992e7d1ef..c3b2709a33 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/remove_final_dequantize_op.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/remove_final_dequantize_op.cc @@ -51,7 +51,7 @@ bool RemoveFinalDequantizeOp::Run(Model* model, std::size_t op_index) { // Remove the node and its output array. AddMessageF("Removed final %s", LogName(*dequantize_op)); - model->arrays.erase(output); + model->EraseArray(output); model->operators.erase(dequantize_it); return true; } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_binary.cc b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_binary.cc index 6add443f2d..8512e6bb5a 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_binary.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_binary.cc @@ -81,7 +81,7 @@ bool RemoveTrivialBinaryOperator::Run(Model* model, std::size_t op_index) { // Now check if the constant operand makes this binary // operator trivial. const auto& constant_input_array = - *model->arrays[binary_op->inputs[index_of_constant_input]]; + model->GetArray(binary_op->inputs[index_of_constant_input]); // For now, we only handle floats here. if (constant_input_array.data_type != ArrayDataType::kFloat) { return false; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_concatenation_input.cc b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_concatenation_input.cc index 23a5c857e8..936854a04f 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_concatenation_input.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_concatenation_input.cc @@ -59,7 +59,7 @@ bool RemoveTrivialConcatenationInput::Run(Model* model, std::size_t op_index) { for (const string& input : trivial_inputs) { if (IsDiscardableArray(*model, input) && CountOpsWithInput(*model, input) == 1) { - model->arrays.erase(input); + model->EraseArray(input); } } concat_op->inputs = nontrivial_inputs; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_passthrough.cc b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_passthrough.cc index 047389f69a..587f171bbf 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_passthrough.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_passthrough.cc @@ -124,7 +124,7 @@ bool RemoveTrivialPassthroughOp(GraphTransformation* transformation, } } if (!is_referenced) { - model->arrays.erase(removal_candidate); + model->EraseArray(removal_candidate); } } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/remove_unused_op.cc b/tensorflow/contrib/lite/toco/graph_transformations/remove_unused_op.cc index e6cca8acf3..aa2c293382 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/remove_unused_op.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/remove_unused_op.cc @@ -33,7 +33,7 @@ bool RemoveUnusedOp::Run(Model* model, std::size_t op_index) { // the model. We allow specifying an arbitrary input_array, // treating the part of the graph leading up to it as unused. for (const auto& output : op->outputs) { - CHECK(model->arrays.count(output)); + CHECK(model->HasArray(output)); // If this output is provided as the model's input array, // then we don't need this operator to produce its contents. if (IsInputArray(*model, output)) { @@ -93,7 +93,7 @@ bool RemoveUnusedOp::Run(Model* model, std::size_t op_index) { if (IsDiscardableArray(*model, input) && CountOpsWithInput(*model, input) == 1 && !GetOpWithOutput(*model, input)) { - model->arrays.erase(input); + model->EraseArray(input); } } @@ -116,7 +116,7 @@ bool RemoveUnusedOp::Run(Model* model, std::size_t op_index) { continue; } // Generic case: do delete this output array. - model->arrays.erase(output); + model->EraseArray(output); } model->operators.erase(it); return true; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_normalization.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_normalization.cc index 3eb7fa3896..fb109eb91b 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_normalization.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_normalization.cc @@ -121,9 +121,9 @@ bool ResolveBatchNormalization::Run(Model* model, std::size_t op_index) { } // Remove the old param arrays - model->arrays.erase(bn_op->inputs[1]); - model->arrays.erase(bn_op->inputs[2]); - model->arrays.erase(bn_op->inputs[3]); + model->EraseArray(bn_op->inputs[1]); + model->EraseArray(bn_op->inputs[2]); + model->EraseArray(bn_op->inputs[3]); // Remove the old operator DCHECK_EQ(bn_it->get(), bn_op); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_to_space_nd_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_to_space_nd_attributes.cc index 7777d4f543..a06919e228 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_to_space_nd_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_batch_to_space_nd_attributes.cc @@ -42,7 +42,7 @@ bool ResolveBatchToSpaceNDAttributes::Run(Model* model, std::size_t op_index) { return false; // Handle crops - const auto& crops_array = *model->arrays[op->inputs[2]]; + const auto& crops_array = model->GetArray(op->inputs[2]); if (!crops_array.has_shape()) return false; const std::vector& crops_dims = crops_array.shape().dims(); if (crops_dims.size() != 2) { @@ -58,7 +58,7 @@ bool ResolveBatchToSpaceNDAttributes::Run(Model* model, std::size_t op_index) { } // Handle block_shape - const auto& block_shape_array = *model->arrays[op->inputs[1]]; + const auto& block_shape_array = model->GetArray(op->inputs[1]); if (!block_shape_array.has_shape()) return false; const std::vector& block_shape_dims = block_shape_array.shape().dims(); CHECK_EQ(block_shape_dims.size(), 1); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_binary.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_binary.cc index fd51df4058..5e779f6765 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_binary.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_binary.cc @@ -166,8 +166,9 @@ void EvaluateBinaryOperatorOnConstantInputs(Model* model, void EvaluateBinaryOperatorOnConstantInputs(Model* model, const Operator* binary_op) { - const auto inputs_data_type = model->arrays[binary_op->inputs[0]]->data_type; - const auto output_data_type = model->arrays[binary_op->outputs[0]]->data_type; + const auto inputs_data_type = model->GetArray(binary_op->inputs[0]).data_type; + const auto output_data_type = + model->GetArray(binary_op->outputs[0]).data_type; #define TOCO_HANDLE_CASE(InputsDataType, OutputDataType) \ if (inputs_data_type == InputsDataType && \ output_data_type == OutputDataType) { \ @@ -214,7 +215,7 @@ bool ResolveConstantBinaryOperator::Run(Model* model, std::size_t op_index) { return false; } - auto& output_array = *model->arrays[binary_op->outputs[0]]; + auto& output_array = model->GetArray(binary_op->outputs[0]); // Yield until the output array dims have been resolved. if (!output_array.has_shape()) { return false; @@ -239,10 +240,10 @@ bool ResolveConstantBinaryOperator::Run(Model* model, std::size_t op_index) { // Remove the binary operator and its inputs if (CountOpsWithInput(*model, binary_op->inputs[0]) == 1) { - model->arrays.erase(binary_op->inputs[0]); + model->EraseArray(binary_op->inputs[0]); } if (CountOpsWithInput(*model, binary_op->inputs[1]) == 1) { - model->arrays.erase(binary_op->inputs[1]); + model->EraseArray(binary_op->inputs[1]); } AddMessageF("Resolved constant %s to the equivalent constant array", LogName(*binary_op)); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_concatenation.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_concatenation.cc index 9835f86398..833c97c758 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_concatenation.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_concatenation.cc @@ -189,7 +189,7 @@ bool ResolveConstantConcatenation::Run(Model* model, std::size_t op_index) { // Remove all the resolved arrays. for (const string& input_name : concat_op->inputs) { - model->arrays.erase(input_name); + model->EraseArray(input_name); } // Remove concatenate operator diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_fake_quant.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_fake_quant.cc index 244adcc4c4..81fe37d7e0 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_fake_quant.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_fake_quant.cc @@ -66,7 +66,7 @@ bool ResolveConstantFakeQuant::Run(Model* model, std::size_t op_index) { output_buffer.data[i] = dst_val; } if (CountOpsWithInput(*model, fakequant_op->inputs[0]) == 1) { - model->arrays.erase(fakequant_op->inputs[0]); + model->EraseArray(fakequant_op->inputs[0]); } model->operators.erase(fakequant_it); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_fill.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_fill.cc index 9da51d9147..f6f95481b5 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_fill.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_fill.cc @@ -104,11 +104,11 @@ bool ResolveConstantFill::Run(Model* model, std::size_t op_index) { // Erase input arrays if no longer used if (IsDiscardableArray(*model, op->inputs[0]) && CountOpsWithInput(*model, op->inputs[0]) == 1) { - model->arrays.erase(op->inputs[0]); + model->EraseArray(op->inputs[0]); } if (IsDiscardableArray(*model, op->inputs[1]) && CountOpsWithInput(*model, op->inputs[1]) == 1) { - model->arrays.erase(op->inputs[1]); + model->EraseArray(op->inputs[1]); } // Erase the operator diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_range.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_range.cc index 383d54aa5a..1a0ba9e2bc 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_range.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_range.cc @@ -28,17 +28,17 @@ bool ResolveConstantRange::Run(Model* model, std::size_t op_index) { auto* op = static_cast(base_op); CHECK_EQ(op->inputs.size(), 3); - const auto& start_array = *model->arrays[op->inputs[0]]; + const auto& start_array = model->GetArray(op->inputs[0]); if (!start_array.has_shape()) { // Yield until all input dims have been resolved. return false; } - const auto& limit_array = *model->arrays[op->inputs[1]]; + const auto& limit_array = model->GetArray(op->inputs[1]); if (!limit_array.has_shape()) { // Yield until all input dims have been resolved. return false; } - const auto& delta_array = *model->arrays[op->inputs[2]]; + const auto& delta_array = model->GetArray(op->inputs[2]); if (!delta_array.has_shape()) { // Yield until all input dims have been resolved. return false; @@ -52,7 +52,7 @@ bool ResolveConstantRange::Run(Model* model, std::size_t op_index) { } CHECK_EQ(op->outputs.size(), 1); - auto& output_array = *model->arrays[op->outputs[0]]; + auto& output_array = model->GetArray(op->outputs[0]); if (output_array.data_type == ArrayDataType::kNone) { // Yield until the output type has been set by PropagateArrayDataTypes return false; @@ -87,15 +87,15 @@ bool ResolveConstantRange::Run(Model* model, std::size_t op_index) { // Delete the input array if no longer used if (IsDiscardableArray(*model, op->inputs[0]) && CountOpsWithInput(*model, op->inputs[0]) == 1) { - model->arrays.erase(op->inputs[0]); + model->EraseArray(op->inputs[0]); } if (IsDiscardableArray(*model, op->inputs[1]) && CountOpsWithInput(*model, op->inputs[1]) == 1) { - model->arrays.erase(op->inputs[1]); + model->EraseArray(op->inputs[1]); } if (IsDiscardableArray(*model, op->inputs[2]) && CountOpsWithInput(*model, op->inputs[2]) == 1) { - model->arrays.erase(op->inputs[2]); + model->EraseArray(op->inputs[2]); } // Delete the operator diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_shape_or_rank.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_shape_or_rank.cc index 35b81dd550..9ea01acd05 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_shape_or_rank.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_shape_or_rank.cc @@ -62,7 +62,7 @@ bool ResolveConstantShapeOrRank::Run(Model* model, std::size_t op_index) { // Delete the input array if no longer used if (IsDiscardableArray(*model, op->inputs[0]) && CountOpsWithInput(*model, op->inputs[0]) == 1) { - model->arrays.erase(op->inputs[0]); + model->EraseArray(op->inputs[0]); } model->operators.erase(it); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_stack.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_stack.cc index 86c76141a4..ea0d6dc820 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_stack.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_stack.cc @@ -101,7 +101,7 @@ bool ResolveConstantStack::Run(Model* model, std::size_t op_index) { for (const auto& input : op->inputs) { if (IsDiscardableArray(*model, input) && CountOpsWithInput(*model, input) == 1) { - model->arrays.erase(input); + model->EraseArray(input); } } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_strided_slice.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_strided_slice.cc index 3976d9cbb4..a0cfc3d597 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_strided_slice.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_strided_slice.cc @@ -186,7 +186,7 @@ bool ResolveConstantStridedSlice::Run(Model* model, std::size_t op_index) { // Erase input array if no longer used if (IsDiscardableArray(*model, op->inputs[0]) && CountOpsWithInput(*model, op->inputs[0]) == 1) { - model->arrays.erase(op->inputs[0]); + model->EraseArray(op->inputs[0]); } // Erase the operator diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_unary.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_unary.cc index 26ff9d887b..1cd2aff28c 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_unary.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_unary.cc @@ -199,7 +199,7 @@ bool ResolveConstantUnaryOperator::Run(Model* model, std::size_t op_index) { } for (const auto& input : unary_op->inputs) { if (CountOpsWithInput(*model, input) == 1) { - model->arrays.erase(input); + model->EraseArray(input); } } AddMessageF("Resolved constant %s to the equivalent constant array", diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_mean_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_mean_attributes.cc index b77be3f5c0..013b50ac9b 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_mean_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_mean_attributes.cc @@ -36,7 +36,7 @@ bool ResolveMeanAttributes::Run(Model* model, std::size_t op_index) { if (op->inputs.size() != 2) return false; if (!IsConstantParameterArray(*model, op->inputs[1])) return false; - const auto& indices_array = *model->arrays[op->inputs[1]]; + const auto& indices_array = model->GetArray(op->inputs[1]); if (!indices_array.has_shape()) return false; op->axis = indices_array.GetBuffer().data; return true; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_pad_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_pad_attributes.cc index d5f5869c62..8a8e723cf7 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_pad_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_pad_attributes.cc @@ -35,7 +35,7 @@ bool ResolvePadAttributes::Run(Model* model, std::size_t op_index) { CHECK_EQ(op->inputs.size(), 2); if (!IsConstantParameterArray(*model, op->inputs[1])) return false; - const auto& array = *model->arrays[op->inputs[1]]; + const auto& array = model->GetArray(op->inputs[1]); if (!array.has_shape()) return false; const std::vector& dims = array.shape().dims(); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_reorder_axes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_reorder_axes.cc index b5093bc4c7..5c68f87f6c 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_reorder_axes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_reorder_axes.cc @@ -103,7 +103,7 @@ bool ResolveReorderAxes::Run(Model* model, std::size_t op_index) { AddMessageF("Reordered axes for array %s", input_array_name); // Remove the op and output array. - model->arrays.erase(output_array_name); + model->EraseArray(output_array_name); model->operators.erase(reorder_it); return true; } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_reshape_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_reshape_attributes.cc index bed2a85bd2..2e063e3554 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_reshape_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_reshape_attributes.cc @@ -37,7 +37,7 @@ bool ResolveReshapeAttributes::Run(Model* model, std::size_t op_index) { if (!op->shape.empty()) return false; if (IsConstantParameterArray(*model, reshape_op->inputs[1])) { - const auto& constant_input_array = *model->arrays[reshape_op->inputs[1]]; + const auto& constant_input_array = model->GetArray(reshape_op->inputs[1]); op->shape = constant_input_array.GetBuffer().data; } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_slice_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_slice_attributes.cc index 1d0a2ec8f6..e760d08e5a 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_slice_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_slice_attributes.cc @@ -36,10 +36,10 @@ bool ResolveSliceAttributes::Run(Model* model, std::size_t op_index) { if (!IsConstantParameterArray(*model, op->inputs[1])) return false; if (!IsConstantParameterArray(*model, op->inputs[2])) return false; - const auto& begin_array = *model->arrays[op->inputs[1]]; + const auto& begin_array = model->GetArray(op->inputs[1]); if (!begin_array.has_shape()) return false; - const auto& size_array = *model->arrays[op->inputs[2]]; + const auto& size_array = model->GetArray(op->inputs[2]); if (!size_array.has_shape()) return false; op->begin = begin_array.GetBuffer().data; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_space_to_batch_nd_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_space_to_batch_nd_attributes.cc index a73f16735c..dad6aceccf 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_space_to_batch_nd_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_space_to_batch_nd_attributes.cc @@ -45,7 +45,7 @@ bool ResolveSpaceToBatchNDAttributes::Run(Model* model, std::size_t op_index) { return false; // Handle paddings. - const auto& paddings_array = *model->arrays[op->inputs[paddings_index]]; + const auto& paddings_array = model->GetArray(op->inputs[paddings_index]); if (!paddings_array.has_shape()) return false; const std::vector& paddings_dims = paddings_array.shape().dims(); if (paddings_dims.size() != 2) { @@ -61,7 +61,8 @@ bool ResolveSpaceToBatchNDAttributes::Run(Model* model, std::size_t op_index) { } // Handle block_shape. - const auto& block_shape_array = *model->arrays[op->inputs[block_shape_index]]; + const auto& block_shape_array = + model->GetArray(op->inputs[block_shape_index]); if (!block_shape_array.has_shape()) return false; const std::vector& block_shape_dims = block_shape_array.shape().dims(); CHECK_EQ(block_shape_dims.size(), 1); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_strided_slice_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_strided_slice_attributes.cc index dbe69adcbd..de4d06be2a 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_strided_slice_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_strided_slice_attributes.cc @@ -31,13 +31,13 @@ bool ResolveStridedSliceAttributes::Run(Model* model, std::size_t op_index) { } CHECK_EQ(op->inputs.size(), 4); - const auto& start_array = *model->arrays[op->inputs[1]]; + const auto& start_array = model->GetArray(op->inputs[1]); if (!start_array.has_shape()) return false; - const auto& stop_array = *model->arrays[op->inputs[2]]; + const auto& stop_array = model->GetArray(op->inputs[2]); if (!stop_array.has_shape()) return false; - const auto& stride_array = *model->arrays[op->inputs[3]]; + const auto& stride_array = model->GetArray(op->inputs[3]); if (!stride_array.has_shape()) return false; if (!IsConstantParameterArray(*model, op->inputs[1])) return false; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_concat.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_concat.cc index c6723a880e..5c0c1e3478 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_concat.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_concat.cc @@ -75,7 +75,7 @@ bool ResolveTensorFlowConcat::Run(Model* model, std::size_t op_index) { // Remove the axis array if it is not used by anything else. if (CountOpsWithInput(*model, axis_name) == 1) { - model->arrays.erase(axis_name); + model->EraseArray(axis_name); } // Remove the TensorFlowConcat op model->operators.erase(concat_it); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_matmul.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_matmul.cc index bea7487051..ad1e56888e 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_matmul.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_matmul.cc @@ -69,7 +69,7 @@ bool ResolveTensorFlowMatMul::Run(Model* model, std::size_t op_index) { LogName(*matmul_op), LogName(*fc_op)); const auto& previous_op_output = previous_op->outputs[0]; if (CountOpsWithInput(*model, previous_op_output) == 1) { - model->arrays.erase(previous_op_output); + model->EraseArray(previous_op_output); } CHECK_EQ(previous_op->inputs.size(), 2); fc_op->inputs = {previous_op->inputs[0], matmul_op->inputs[1]}; @@ -78,7 +78,7 @@ bool ResolveTensorFlowMatMul::Run(Model* model, std::size_t op_index) { const auto& previous_op_shape = previous_op->inputs[1]; if (CountOpsWithInput(*model, previous_op_shape) == 1 && !GetOpWithOutput(*model, previous_op_shape)) { - model->arrays.erase(previous_op_shape); + model->EraseArray(previous_op_shape); } model->operators.erase(previous_op_it); } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_merge.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_merge.cc index cfa5ce0716..477e7f13da 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_merge.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_merge.cc @@ -55,7 +55,7 @@ bool ResolveTensorFlowMerge::Run(Model* model, std::size_t op_index) { // Remove the node and its output array. AddMessageF("Removing already-resolved %s", LogName(*merge_op)); - model->arrays.erase(merge_op->outputs[0]); + model->EraseArray(merge_op->outputs[0]); model->operators.erase(merge_it); return true; } diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_switch.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_switch.cc index 150cf53da3..a418073441 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_switch.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_switch.cc @@ -103,7 +103,7 @@ bool ResolveTensorFlowSwitch::Run(Model* model, std::size_t op_index) { // Remove the output arrays if they are now unused. for (int i = 0; i < 2; i++) { if (!GetOpWithInput(*model, switch_op->outputs[i])) { - model->arrays.erase(switch_op->outputs[i]); + model->EraseArray(switch_op->outputs[i]); } } // Remove input arrays if they are only used by the switch itself and aren't @@ -111,7 +111,7 @@ bool ResolveTensorFlowSwitch::Run(Model* model, std::size_t op_index) { for (const auto& input : switch_op->inputs) { if (CountOpsWithInput(*model, input) == 1 && !GetOpWithOutput(*model, input)) { - model->arrays.erase(input); + model->EraseArray(input); } } // Remove the switch node itself. diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_tile.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_tile.cc index 9f7e7c42a2..1ddf54c778 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_tile.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_tensorflow_tile.cc @@ -45,10 +45,10 @@ void RemoveTileOperator(Model* model, Operator* tile_op, Operator* binary_op, model->operators.erase(tile_it); if (!CountOpsWithInput(*model, tile_multiplier_array) && !GetOpWithOutput(*model, tile_multiplier_array)) { - model->arrays.erase(tile_multiplier_array); + model->EraseArray(tile_multiplier_array); } if (!CountOpsWithInput(*model, tile_output_array)) { - model->arrays.erase(tile_output_array); + model->EraseArray(tile_output_array); } } } // namespace diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_transpose_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_transpose_attributes.cc index 12d966b261..a657ee00af 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_transpose_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_transpose_attributes.cc @@ -35,7 +35,7 @@ bool ResolveTransposeAttributes::Run(Model* model, std::size_t op_index) { if (!IsConstantParameterArray(*model, op->inputs[1])) return false; // Handling perm. - const auto& perm_array = *model->arrays[op->inputs[1]]; + const auto& perm_array = model->GetArray(op->inputs[1]); if (!perm_array.has_shape()) return false; const std::vector& perm_dims = perm_array.shape().dims(); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/tests/resolve_constant_concatenation_test.cc b/tensorflow/contrib/lite/toco/graph_transformations/tests/resolve_constant_concatenation_test.cc index a14016e8e2..3a1d175b98 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/tests/resolve_constant_concatenation_test.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/tests/resolve_constant_concatenation_test.cc @@ -19,7 +19,6 @@ limitations under the License. #include #include -//#include "tensorflow/contrib/lite/kernels/test_util.h" #include "tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h" #include "tensorflow/contrib/lite/toco/model.h" #include "tensorflow/contrib/lite/toco/tooling_util.h" @@ -168,11 +167,11 @@ TEST_F(ResolveConstantConcatenationTest, ConcatAtAxis0) { GraphTransformationsSet graph_transformation_set; graph_transformation_set.Add(new toco::ResolveConstantConcatenation); - EXPECT_THAT(model.arrays.size(), 5); + EXPECT_THAT(model.GetArrayMap().size(), 5); (*graph_transformation_set.begin())->Run(&model, /*op_index=*/0); - EXPECT_THAT(model.arrays.size(), 1); + EXPECT_THAT(model.GetArrayMap().size(), 1); - auto& concatenated_array = (*model.arrays.begin()).second; + auto& concatenated_array = (*model.GetArrayMap().begin()).second; EXPECT_THAT(concatenated_array->GetBuffer().data, ElementsAreArray(ArrayFloatNear( {0., 1., 2., 3., 4., 5., 6., 7., 10., 11., 12., @@ -187,11 +186,11 @@ TEST_F(ResolveConstantConcatenationTest, ConcatAtAxis1) { GraphTransformationsSet graph_transformation_set; graph_transformation_set.Add(new toco::ResolveConstantConcatenation); - EXPECT_THAT(model.arrays.size(), 5); + EXPECT_THAT(model.GetArrayMap().size(), 5); (*graph_transformation_set.begin())->Run(&model, /*op_index=*/0); - EXPECT_THAT(model.arrays.size(), 1); + EXPECT_THAT(model.GetArrayMap().size(), 1); - auto& concatenated_array = (*model.arrays.begin()).second; + auto& concatenated_array = (*model.GetArrayMap().begin()).second; EXPECT_THAT(concatenated_array->GetBuffer().data, ElementsAreArray(ArrayFloatNear( {0., 1., 2., 3., 10., 11., 12., 13., 20., 21., 22., @@ -206,11 +205,11 @@ TEST_F(ResolveConstantConcatenationTest, ConcatAtAxis2) { GraphTransformationsSet graph_transformation_set; graph_transformation_set.Add(new toco::ResolveConstantConcatenation); - EXPECT_THAT(model.arrays.size(), 5); + EXPECT_THAT(model.GetArrayMap().size(), 5); (*graph_transformation_set.begin())->Run(&model, /*op_index=*/0); - EXPECT_THAT(model.arrays.size(), 1); + EXPECT_THAT(model.GetArrayMap().size(), 1); - auto& concatenated_array = (*model.arrays.begin()).second; + auto& concatenated_array = (*model.GetArrayMap().begin()).second; EXPECT_THAT(concatenated_array->GetBuffer().data, ElementsAreArray(ArrayFloatNear( {0., 1., 10., 11., 20., 21., 30., 31., 2., 3., 12., diff --git a/tensorflow/contrib/lite/toco/graph_transformations/unfuse_activation_functions.cc b/tensorflow/contrib/lite/toco/graph_transformations/unfuse_activation_functions.cc index 4e273343df..2c7046c8c7 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/unfuse_activation_functions.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/unfuse_activation_functions.cc @@ -63,7 +63,7 @@ bool UnfuseActivationFunctions::Run(Model* model, std::size_t op_index) { ac_op->outputs = op->outputs; const string& tmp_array_name = AvailableArrayName(*model, op->outputs[0] + "_unfused"); - CHECK(!model->arrays.count(tmp_array_name)); + CHECK(!model->HasArray(tmp_array_name)); model->GetOrCreateArray(tmp_array_name); ac_op->inputs = {tmp_array_name}; op->outputs = {tmp_array_name}; diff --git a/tensorflow/contrib/lite/toco/import_tensorflow.cc b/tensorflow/contrib/lite/toco/import_tensorflow.cc index 995e9d67ca..1947271f55 100644 --- a/tensorflow/contrib/lite/toco/import_tensorflow.cc +++ b/tensorflow/contrib/lite/toco/import_tensorflow.cc @@ -1652,7 +1652,7 @@ void StripCaretFromArrayNames(Model* model) { output = string(absl::StripPrefix(output, "^")); } } - for (auto& array : model->arrays) { + for (auto& array : model->GetArrayMap()) { if (absl::StartsWith(array.first, "^")) { LOG(FATAL) << "What?"; } diff --git a/tensorflow/contrib/lite/toco/model.h b/tensorflow/contrib/lite/toco/model.h index b079750bed..54fbba7381 100644 --- a/tensorflow/contrib/lite/toco/model.h +++ b/tensorflow/contrib/lite/toco/model.h @@ -1521,15 +1521,19 @@ struct Array { // Our Model struct, represents an entire model (our "top-level" struct). // Owns everything. -struct Model { +class Model { + public: + using ArrayMap = std::unordered_map>; + + bool HasArray(const string& name) const { return arrays.count(name) > 0; } Array& GetArray(const string& name) const { - DCHECK(arrays.count(name)); + DCHECK(HasArray(name)); return *arrays.at(name); } Array& GetOrCreateArray(const string& name) { // Make sure name is not used by an optional array DCHECK(!optional_arrays.count(name)); - if (!arrays.count(name)) { + if (!HasArray(name)) { Array* ptr = new Array; arrays[name] = std::unique_ptr(ptr); } @@ -1544,18 +1548,27 @@ struct Model { return optional_arrays.count(name); } + // Note that this invalidates all array iterators. + void EraseArray(const string& name) { arrays.erase(name); } + void EraseArrays(std::function discardable) { + for (auto it = arrays.begin(); it != arrays.end();) { + if (discardable(it->first)) { + it = arrays.erase(it); + } else { + ++it; + } + } + } + const ArrayMap& GetArrayMap() const { return arrays; } + // Optional arrays are used for optional tensors, // these tensors do not have data, but with reserved names as op inputs. std::set optional_arrays; + // The list of operators. Notice how it's a list of unique_ptr's, implying // that the Model is what owns Operator's and keeps them alive. std::vector> operators; - // The associative array mapping names to Array's. - // Notice how it's a container of unique_ptr's, implying - // that the Model is what owns Array's and keeps them alive. - // The Operator's refer to these Array's by their name strings, not by their - // addresses. See Operator::inputs, Operator::outputs. - std::unordered_map> arrays; + // Generic flags, a place where we combine information passed to us via // command-line parameters (e.g. --input_width=N) with information that // we may or may not find in the input model file. @@ -1564,6 +1577,14 @@ struct Model { std::size_t transient_data_size = 0; // For code-generation only: required alignment of the transient_data buffer std::size_t transient_data_alignment = 0; + + private: + // The associative array mapping names to Array's. + // Notice how it's a container of unique_ptr's, implying + // that the Model is what owns Array's and keeps them alive. + // The Operator's refer to these Array's by their name strings, not by their + // addresses. See Operator::inputs, Operator::outputs. + std::unordered_map> arrays; }; } // namespace toco diff --git a/tensorflow/contrib/lite/toco/tflite/export.cc b/tensorflow/contrib/lite/toco/tflite/export.cc index 440353203e..391ef87029 100644 --- a/tensorflow/contrib/lite/toco/tflite/export.cc +++ b/tensorflow/contrib/lite/toco/tflite/export.cc @@ -62,7 +62,7 @@ namespace details { void LoadTensorsMap(const Model& model, TensorsMap* tensors_map) { // First find a list of unique array names. std::set names; - for (const auto& array_pair : model.arrays) { + for (const auto& array_pair : model.GetArrayMap()) { names.insert(array_pair.first); } @@ -96,7 +96,7 @@ Offset>> ExportTensors( // tensors in the tensors_map. std::map> ordered_tensors; - for (const auto& array_pair : model.arrays) { + for (const auto& array_pair : model.GetArrayMap()) { const string& tensor_name = array_pair.first; const toco::Array& array = *array_pair.second; diff --git a/tensorflow/contrib/lite/toco/tflite/import_test.cc b/tensorflow/contrib/lite/toco/tflite/import_test.cc index 309fa6d7f6..aad6e780d5 100644 --- a/tensorflow/contrib/lite/toco/tflite/import_test.cc +++ b/tensorflow/contrib/lite/toco/tflite/import_test.cc @@ -114,7 +114,7 @@ TEST_F(ImportTest, Tensors) { auto model = Import(ModelFlags(), InputModelAsString()); - ASSERT_GT(model->arrays.count("tensor_one"), 0); + ASSERT_GT(model->HasArray("tensor_one"), 0); Array& a1 = model->GetArray("tensor_one"); EXPECT_EQ(ArrayDataType::kFloat, a1.data_type); EXPECT_THAT(a1.GetBuffer().data, diff --git a/tensorflow/contrib/lite/toco/toco_tooling.cc b/tensorflow/contrib/lite/toco/toco_tooling.cc index 94b4d14696..afaa0fd0c7 100644 --- a/tensorflow/contrib/lite/toco/toco_tooling.cc +++ b/tensorflow/contrib/lite/toco/toco_tooling.cc @@ -133,7 +133,7 @@ void SetFinalDataTypeOnInputs(const TocoFlags& toco_flags, Model* model) { for (int i = 0; i < model->flags.input_arrays_size(); i++) { string const& array_name = model->flags.input_arrays(i).name(); - auto* array = model->arrays[array_name].get(); + auto* array = &model->GetArray(array_name); // Note that the notion of changing data types only applies to real-numbers // arrays (see the documentation for inference_input_type). // TODO(benoitjacob) this is assuming that uint8 arrays are quantized, diff --git a/tensorflow/contrib/lite/toco/tooling_util.cc b/tensorflow/contrib/lite/toco/tooling_util.cc index f9093ab973..900c60bd90 100644 --- a/tensorflow/contrib/lite/toco/tooling_util.cc +++ b/tensorflow/contrib/lite/toco/tooling_util.cc @@ -93,7 +93,7 @@ int CountOpsWithInput(const Model& model, const string& array_name) { bool DeleteArrayIfUnused(const string& array_name, Model* model) { if (CountOpsWithInput(*model, array_name) == 0) { - model->arrays.erase(array_name); + model->EraseArray(array_name); return true; } return false; @@ -566,11 +566,11 @@ int RequiredBufferSizeForShape(const Shape& shape) { } bool IsConstantParameterArray(const Model& model, const string& name) { - if (!model.arrays.count(name)) { + if (!model.HasArray(name)) { return false; } - return !!model.arrays.at(name)->buffer; + return !!model.GetArray(name).buffer; } namespace { @@ -633,17 +633,17 @@ void CheckNonExistentIOArrays(const Model& model) { return; } for (const auto& input_array : model.flags.input_arrays()) { - CHECK(model.arrays.count(input_array.name())) + CHECK(model.HasArray(input_array.name())) << "Input array not found: " << input_array.name(); } for (const string& output_array : model.flags.output_arrays()) { - CHECK(model.arrays.count(output_array)) + CHECK(model.HasArray(output_array)) << "Output array not found: " << output_array; } for (const auto& rnn_state : model.flags.rnn_states()) { if (!rnn_state.discardable()) { - CHECK(model.arrays.count(rnn_state.state_array())); - CHECK(model.arrays.count(rnn_state.back_edge_source_array())); + CHECK(model.HasArray(rnn_state.state_array())); + CHECK(model.HasArray(rnn_state.back_edge_source_array())); } } } @@ -652,10 +652,10 @@ void CheckNonExistentIOArrays(const Model& model) { void CheckNoMissingArray(const Model& model) { for (const auto& op : model.operators) { for (const auto& input : op->inputs) { - CHECK(model.arrays.count(input) || model.optional_arrays.count(input)); + CHECK(model.HasArray(input) || model.optional_arrays.count(input)); } for (const auto& output : op->outputs) { - CHECK(model.arrays.count(output)); + CHECK(model.HasArray(output)); } } CheckNonExistentIOArrays(model); @@ -664,12 +664,12 @@ void CheckNoMissingArray(const Model& model) { void FixNoMissingArray(Model* model) { for (const auto& op : model->operators) { for (const auto& input : op->inputs) { - if (!model->arrays.count(input)) { + if (!model->HasArray(input)) { model->GetOrCreateArray(input); } } for (const auto& output : op->outputs) { - if (!model->arrays.count(output)) { + if (!model->HasArray(output)) { model->GetOrCreateArray(output); } } @@ -687,7 +687,7 @@ void FixNoMissingArray(Model* model) { void CheckNoOrphanedArray(const Model& model) { std::unordered_set arrays_without_known_use; - for (const auto& array : model.arrays) { + for (const auto& array : model.GetArrayMap()) { if (IsDiscardableArray(model, array.first)) { arrays_without_known_use.insert(array.first); } @@ -714,7 +714,7 @@ void CheckNoOrphanedArray(const Model& model) { void FixNoOrphanedArray(Model* model) { std::unordered_set arrays_without_known_use; - for (const auto& array : model->arrays) { + for (const auto& array : model->GetArrayMap()) { arrays_without_known_use.insert(array.first); } for (const auto& op : model->operators) { @@ -731,13 +731,13 @@ void FixNoOrphanedArray(Model* model) { } for (const auto& array : arrays_without_known_use) { if (IsDiscardableArray(*model, array)) { - model->arrays.erase(array); + model->EraseArray(array); } } } void CheckArrayFieldsConsistent(const Model& model) { - for (const auto& array_entry : model.arrays) { + for (const auto& array_entry : model.GetArrayMap()) { const auto& array = array_entry.second; if (array->has_shape()) { for (int d : array->shape().dims()) { @@ -756,7 +756,7 @@ void CheckArrayFieldsConsistent(const Model& model) { void CheckOperatorOrdering(const Model& model) { std::unordered_set arrays_behind_us; - for (const auto& array_entry : model.arrays) { + for (const auto& array_entry : model.GetArrayMap()) { if (!GetOpWithOutput(model, array_entry.first)) { arrays_behind_us.insert(array_entry.first); } @@ -781,7 +781,7 @@ void CheckOperatorOrdering(const Model& model) { void FixOperatorOrdering(Model* model) { std::unordered_set arrays_behind_us; - for (const auto& array_entry : model->arrays) { + for (const auto& array_entry : model->GetArrayMap()) { if (!GetOpWithOutput(*model, array_entry.first)) { arrays_behind_us.insert(array_entry.first); } @@ -936,7 +936,8 @@ void CheckModelCounts(const Model& model) { if (count_type == "None") { continue; } else if (count_type == "Arrays") { - CheckCountInRange(model_check, model.arrays.size(), "count of arrays"); + CheckCountInRange(model_check, model.GetArrayMap().size(), + "count of arrays"); } else if (count_type == "Total") { CheckCountInRange(model_check, model.operators.size(), "count of all operator instances"); @@ -1297,7 +1298,7 @@ bool IsAllocatableTransientArray(const Model& model, const string& array_name) { return false; } } - const auto& array = model.arrays.at(array_name); + const auto& array = &model.GetArray(array_name); // An array with a constant buffer isn't a transient array. if (!!array->buffer) { return false; @@ -1310,13 +1311,13 @@ bool IsAllocatableTransientArray(const Model& model, const string& array_name) { } string AvailableArrayName(const Model& model, const string& name) { - if (!model.arrays.count(name) && !model.optional_arrays.count(name)) { + if (!model.HasArray(name) && !model.optional_arrays.count(name)) { return name; } const int kNumSuffixesToTry = 1000; for (int i = 0; i < kNumSuffixesToTry; i++) { const string& name_with_suffix = toco::port::StringF("%s_%d", name, i); - if (!model.arrays.count(name_with_suffix)) { + if (!model.HasArray(name_with_suffix)) { return name_with_suffix; } } @@ -1334,12 +1335,12 @@ string ShapeToString(const Shape& shape) { } void PrintArrayShape(Model* model, const string& name) { - if (!model->arrays[name]->has_shape()) { + if (!model->GetArray(name).has_shape()) { LOG(INFO) << name << " has no shape"; return; } LOG(INFO) << name - << " has shape: " << ShapeToString(model->arrays[name]->shape()); + << " has shape: " << ShapeToString(model->GetArray(name).shape()); } bool IsArrayFullyConnectedWeights(const Model& model, const string& name) { @@ -1673,7 +1674,7 @@ bool IsDiscardableArray(const Model& model, const string& array_name) { } void CheckFinalDataTypesSatisfied(const Model& model) { - for (const auto& array_entry : model.arrays) { + for (const auto& array_entry : model.GetArrayMap()) { const auto& array = *array_entry.second; if (array.final_data_type != ArrayDataType::kNone) { CHECK(array.final_data_type == array.data_type) -- GitLab From 5f4bbef22e1cb7841da282b9903a5dd24a6c1bd6 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 23 Jan 2018 12:39:22 -0800 Subject: [PATCH 124/258] [TF:XLA] Bump open source llvm revision to r323181 PiperOrigin-RevId: 182976206 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 25702087dc..d17dc81024 100644 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -473,11 +473,11 @@ def tf_workspace(path_prefix="", tf_repo_name=""): tf_http_archive( name = "llvm", urls = [ - "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/cecc5a23281018f9bbdd6f659462b8c99d8e8926.tar.gz", - "https://github.com/llvm-mirror/llvm/archive/cecc5a23281018f9bbdd6f659462b8c99d8e8926.tar.gz", + "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/95461910b8134c70de1d94f6854b64cfff3615d9.tar.gz", + "https://github.com/llvm-mirror/llvm/archive/95461910b8134c70de1d94f6854b64cfff3615d9.tar.gz", ], - sha256 = "b0960749fe2bf78d7c8350c18d584cf6dd5abeeae20da43d4829cdbc0166626c", - strip_prefix = "llvm-cecc5a23281018f9bbdd6f659462b8c99d8e8926", + sha256 = "2e16617820ec59e3b57b6800aab00238c2e5955182b56a0fbc03bde12b5f2d7b", + strip_prefix = "llvm-95461910b8134c70de1d94f6854b64cfff3615d9", build_file = str(Label("//third_party/llvm:llvm.BUILD")), ) -- GitLab From 9f389fc4d36f0ffb79681817c25b8d7a329fc649 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 12:41:07 -0800 Subject: [PATCH 125/258] internal change PiperOrigin-RevId: 182976445 --- tensorflow/contrib/tpu/profiler/BUILD | 11 +++++++++- .../tpu/profiler/capture_tpu_profile.cc | 4 ++++ tensorflow/contrib/tpu/profiler/version.h | 21 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tensorflow/contrib/tpu/profiler/version.h diff --git a/tensorflow/contrib/tpu/profiler/BUILD b/tensorflow/contrib/tpu/profiler/BUILD index 346c03067d..198da0203a 100644 --- a/tensorflow/contrib/tpu/profiler/BUILD +++ b/tensorflow/contrib/tpu/profiler/BUILD @@ -44,13 +44,22 @@ cc_library( ], ) +cc_library( + name = "version", + hdrs = ["version.h"], + visibility = ["//visibility:public"], +) + tf_cc_binary( name = "capture_tpu_profile", - srcs = ["capture_tpu_profile.cc"], + srcs = [ + "capture_tpu_profile.cc", + ], visibility = ["//visibility:public"], deps = [ ":dump_tpu_profile", ":tpu_profiler_proto_cc", + ":version", "//tensorflow/core:framework_internal", "//tensorflow/core:lib", "//tensorflow/core/distributed_runtime/rpc:grpc_util", diff --git a/tensorflow/contrib/tpu/profiler/capture_tpu_profile.cc b/tensorflow/contrib/tpu/profiler/capture_tpu_profile.cc index b67f2f47a7..1cded9f8cf 100644 --- a/tensorflow/contrib/tpu/profiler/capture_tpu_profile.cc +++ b/tensorflow/contrib/tpu/profiler/capture_tpu_profile.cc @@ -26,6 +26,7 @@ limitations under the License. #include "tensorflow/contrib/tpu/profiler/dump_tpu_profile.h" #include "tensorflow/contrib/tpu/profiler/tpu_profiler.grpc.pb.h" +#include "tensorflow/contrib/tpu/profiler/version.h" #include "tensorflow/core/distributed_runtime/rpc/grpc_util.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/platform/init_main.h" @@ -84,6 +85,9 @@ int main(int argc, char** argv) { "Duration of tracing in ms. Default is 2000ms."), }; + std::cout << "Welcome to the Cloud TPU Profiler v" << TPU_PROFILER_VERSION + << std::endl; + tensorflow::string usage = tensorflow::Flags::Usage(argv[0], flag_list); bool parse_ok = tensorflow::Flags::Parse(&argc, argv, flag_list); if (!parse_ok || FLAGS_service_addr.empty() || FLAGS_logdir.empty()) { diff --git a/tensorflow/contrib/tpu/profiler/version.h b/tensorflow/contrib/tpu/profiler/version.h new file mode 100644 index 0000000000..a6c9a9503d --- /dev/null +++ b/tensorflow/contrib/tpu/profiler/version.h @@ -0,0 +1,21 @@ +/* Copyright 2017 The TensorFlow Authors. 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 THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ +#define THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ + +#define TPU_PROFILER_VERSION "1.4.3" + +#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ -- GitLab From 0eba6b6b6a0a0f0d56afd3e2c6945075706f9abb Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 12:48:00 -0800 Subject: [PATCH 126/258] [XLA:GPU] Support BF16 data type. Add an HLO pass to the GPU backend to implement BF16 operations with F32 operations. Define macro XLA_BACKEND_SUPPORTS_BFLOAT16=1 when building tests for the GPU backend to enable BF16 tests for GPU. Enable bfloat16_test and other BF16 tests for GPU. Add hlo_element_type_converter_test. Add convolution tests and matrix multiplication tests for BF16. PiperOrigin-RevId: 182977358 --- tensorflow/compiler/xla/service/BUILD | 10 ++ tensorflow/compiler/xla/service/gpu/BUILD | 1 + .../compiler/xla/service/gpu/gpu_compiler.cc | 5 + .../xla/service/hlo_element_type_converter.cc | 102 ++++++++++++--- .../hlo_element_type_converter_test.cc | 123 ++++++++++++++++++ .../compiler/xla/service/hlo_matchers.h | 1 + tensorflow/compiler/xla/tests/BUILD | 3 - .../compiler/xla/tests/bfloat16_test.cc | 5 +- .../compiler/xla/tests/convolution_test.cc | 23 ++++ .../xla/tests/matrix_ops_simple_test.cc | 72 ++++++++++ .../compiler/xla/tests/reduce_window_test.cc | 4 +- 11 files changed, 326 insertions(+), 23 deletions(-) create mode 100644 tensorflow/compiler/xla/service/hlo_element_type_converter_test.cc diff --git a/tensorflow/compiler/xla/service/BUILD b/tensorflow/compiler/xla/service/BUILD index 426fead41b..2e0ac256cc 100644 --- a/tensorflow/compiler/xla/service/BUILD +++ b/tensorflow/compiler/xla/service/BUILD @@ -1944,6 +1944,16 @@ cc_library( ], ) +tf_cc_test( + name = "hlo_element_type_converter_test", + srcs = ["hlo_element_type_converter_test.cc"], + deps = [ + ":hlo_element_type_converter", + ":hlo_matchers", + "//tensorflow/compiler/xla/tests:hlo_test_base", + ], +) + cc_library( name = "device_memory_allocator", srcs = ["device_memory_allocator.cc"], diff --git a/tensorflow/compiler/xla/service/gpu/BUILD b/tensorflow/compiler/xla/service/gpu/BUILD index d7ca0f6846..df5e2e35f8 100644 --- a/tensorflow/compiler/xla/service/gpu/BUILD +++ b/tensorflow/compiler/xla/service/gpu/BUILD @@ -475,6 +475,7 @@ cc_library( "//tensorflow/compiler/xla/service:hlo_constant_folding", "//tensorflow/compiler/xla/service:hlo_cse", "//tensorflow/compiler/xla/service:hlo_dce", + "//tensorflow/compiler/xla/service:hlo_element_type_converter", "//tensorflow/compiler/xla/service:hlo_pass", "//tensorflow/compiler/xla/service:hlo_pass_pipeline", "//tensorflow/compiler/xla/service:hlo_proto", diff --git a/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc b/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc index 8ba6f48dcf..21798ed606 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc @@ -58,6 +58,7 @@ limitations under the License. #include "tensorflow/compiler/xla/service/hlo_constant_folding.h" #include "tensorflow/compiler/xla/service/hlo_cse.h" #include "tensorflow/compiler/xla/service/hlo_dce.h" +#include "tensorflow/compiler/xla/service/hlo_element_type_converter.h" #include "tensorflow/compiler/xla/service/hlo_instruction.h" #include "tensorflow/compiler/xla/service/hlo_pass_fix.h" #include "tensorflow/compiler/xla/service/hlo_pass_pipeline.h" @@ -137,6 +138,10 @@ tensorflow::Status OptimizeHloModule(HloModule* hlo_module) { // TODO(b/64094172): make Call work on GPU instead of inlining. pipeline.AddPass(); + // Convert BF16 operations to F32 operations so that the GPU backend can + // support BF16 operations without directly implementing a BF16 lowering for + // most ops. + pipeline.AddPass(BF16, F32); pipeline.AddPass(); { auto& pass = diff --git a/tensorflow/compiler/xla/service/hlo_element_type_converter.cc b/tensorflow/compiler/xla/service/hlo_element_type_converter.cc index 1773bb401d..c782d1b0ad 100644 --- a/tensorflow/compiler/xla/service/hlo_element_type_converter.cc +++ b/tensorflow/compiler/xla/service/hlo_element_type_converter.cc @@ -54,45 +54,96 @@ bool HasOperandType(HloInstruction* hlo, PrimitiveType type) { return false; } +// Finds out the Tuple Shape of the new instruction after converting the element +// type of the operands of the original instruction from `from_type` to +// `to_type`. +// +// This routine assumes the resulting `shape` of the original instruction is a +// non-nested tuple. This assumption is currently safe as only kTuple, kInfeed, +// kOutfeed, kCall, kCustomCall and kBatchNorm* HLO instructions can produce +// results with tuple shapes, and this routine is only called to convert the +// result shapes of kBatchNorm* HLO instructions, which are non-nested tuples. +Shape GetConvertedTupleShape(const Shape& shape, PrimitiveType from_type, + PrimitiveType to_type) { + std::vector new_tuple_subshapes; + for (int64 i = 0; i < ShapeUtil::TupleElementCount(shape); ++i) { + Shape subshape = ShapeUtil::GetTupleElementShape(shape, i); + CHECK(!ShapeUtil::IsTuple(subshape)); + if (subshape.element_type() == from_type) { + subshape = ShapeUtil::ChangeElementType(subshape, to_type); + } + new_tuple_subshapes.push_back(subshape); + } + return ShapeUtil::MakeTupleShape(new_tuple_subshapes); +} + +// Converts the elements of the result of `hlo` to produce a new tuple with +// shape `to_shape`. +// +// This routine assumes `hlo` is an instruction that produces a non-nested Tuple +// as a result. +HloInstruction* ConvertTupleElements(HloInstruction* hlo, + const Shape& to_shape) { + const Shape& shape = hlo->shape(); + HloComputation* computation = hlo->parent(); + std::vector tuple_elements; + for (int64 i = 0; i < ShapeUtil::TupleElementCount(shape); ++i) { + const Shape& ele_shape = ShapeUtil::GetTupleElementShape(shape, i); + HloInstruction* element = computation->AddInstruction( + HloInstruction::CreateGetTupleElement(ele_shape, hlo, i)); + const Shape& to_ele_shape = ShapeUtil::GetTupleElementShape(to_shape, i); + CHECK(!ShapeUtil::IsTuple(ele_shape)); + if (ele_shape.element_type() != to_ele_shape.element_type()) { + element = computation->AddInstruction( + HloInstruction::CreateConvert(to_ele_shape, element)); + } + tuple_elements.push_back(element); + } + return computation->AddInstruction( + HloInstruction::CreateTuple(tuple_elements)); +} + } // namespace HloElementTypeConverter::HloElementTypeConverter( PrimitiveType eliminate_type, PrimitiveType replace_with_type) : eliminate_type_(eliminate_type), replace_with_type_(replace_with_type) {} +// This routine converts the arithmetic operations in the given module that use +// eliminate_type_ to operations that use replace_with_type_. StatusOr HloElementTypeConverter::Run(HloModule* module) { XLA_VLOG_LINES( 3, "HloElementTypeConverter::Run(), before:\n" + module->ToString()); + + if (eliminate_type_ == replace_with_type_) { + return false; + } + bool changed = false; for (auto* computation : module->computations()) { for (auto* hlo : computation->MakeInstructionPostOrder()) { + const auto opcode = hlo->opcode(); // These are ops where it does not make sense to convert them. - if (hlo->opcode() == HloOpcode::kParameter || - hlo->opcode() == HloOpcode::kConstant || - hlo->opcode() == HloOpcode::kTuple || - hlo->opcode() == HloOpcode::kConvert || - hlo->opcode() == HloOpcode::kGetTupleElement || - hlo->opcode() == HloOpcode::kInfeed || - hlo->opcode() == HloOpcode::kOutfeed) { + if (opcode == HloOpcode::kParameter || opcode == HloOpcode::kConstant || + opcode == HloOpcode::kTuple || opcode == HloOpcode::kConvert || + opcode == HloOpcode::kGetTupleElement || + opcode == HloOpcode::kInfeed || opcode == HloOpcode::kOutfeed) { continue; } // We cannot change a CustomCall since we have no way of adjusting the // called binary to expect the updated type. - if (hlo->opcode() == HloOpcode::kCustomCall) { + if (opcode == HloOpcode::kCustomCall) { continue; } // These are ops with embedded computations where it suffices to convert // the embedded computations instead of converting the ops themselves. - if (hlo->opcode() == HloOpcode::kWhile || - hlo->opcode() == HloOpcode::kCall || - hlo->opcode() == HloOpcode::kFusion || - hlo->opcode() == HloOpcode::kMap || - hlo->opcode() == HloOpcode::kReduce || - hlo->opcode() == HloOpcode::kReduceWindow || - hlo->opcode() == HloOpcode::kSelectAndScatter || - hlo->opcode() == HloOpcode::kConditional) { + if (opcode == HloOpcode::kWhile || opcode == HloOpcode::kCall || + opcode == HloOpcode::kFusion || opcode == HloOpcode::kMap || + opcode == HloOpcode::kReduce || opcode == HloOpcode::kReduceWindow || + opcode == HloOpcode::kSelectAndScatter || + opcode == HloOpcode::kConditional) { continue; } TF_RET_CHECK(hlo->called_computations().empty()) << hlo->ToString(); @@ -106,6 +157,11 @@ StatusOr HloElementTypeConverter::Run(HloModule* module) { continue; } + // Handle instructions that perform arithmetic operations and contain + // operands with eliminate_type_. + // + // First, convert the operands with eliminate_type_ to operands with + // replace_with_type_. std::vector new_operands; for (HloInstruction* operand : hlo->operands()) { if (operand->shape().element_type() == eliminate_type_) { @@ -114,6 +170,10 @@ StatusOr HloElementTypeConverter::Run(HloModule* module) { new_operands.push_back(operand); } + // Then find out the result type of the new instruction with the same + // opcode but using the converted operands, create the new instruction, + // and convert the result of the new instruction back to match the result + // type of the original instruction. HloInstruction* new_hlo; if (hlo->shape().element_type() == eliminate_type_) { Shape shape = @@ -121,10 +181,20 @@ StatusOr HloElementTypeConverter::Run(HloModule* module) { new_hlo = computation->AddInstruction( hlo->CloneWithNewOperands(shape, new_operands, hlo->GetModule())); new_hlo = ToElementType(new_hlo, eliminate_type_); + } else if (ShapeUtil::IsTuple(hlo->shape())) { + Shape old_shape = hlo->shape(); + Shape new_shape = GetConvertedTupleShape(hlo->shape(), eliminate_type_, + replace_with_type_); + new_hlo = computation->AddInstruction(hlo->CloneWithNewOperands( + new_shape, new_operands, hlo->GetModule())); + // Convert the elements of the result of `new_hlo` to produce a new + // tuple with shape `old_shape`. + new_hlo = ConvertTupleElements(new_hlo, old_shape); } else { new_hlo = computation->AddInstruction(hlo->CloneWithNewOperands( hlo->shape(), new_operands, hlo->GetModule())); } + TF_RETURN_IF_ERROR(computation->ReplaceInstruction(hlo, new_hlo)); changed = true; } diff --git a/tensorflow/compiler/xla/service/hlo_element_type_converter_test.cc b/tensorflow/compiler/xla/service/hlo_element_type_converter_test.cc new file mode 100644 index 0000000000..2aed82409b --- /dev/null +++ b/tensorflow/compiler/xla/service/hlo_element_type_converter_test.cc @@ -0,0 +1,123 @@ +/* Copyright 2018 The TensorFlow Authors. 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/compiler/xla/service/hlo_element_type_converter.h" +#include "tensorflow/compiler/xla/service/hlo_matchers.h" +#include "tensorflow/compiler/xla/tests/hlo_test_base.h" + +namespace xla { +namespace { + +namespace op = xla::testing::opcode_matchers; + +class HloElementTypeConverterTest : public HloTestBase { + public: + std::unique_ptr CreateModuleFromHloString( + const string& hlo_string) { + return HloRunner::CreateModuleFromString(hlo_string, + GetDebugOptionsForTest()) + .ValueOrDie(); + } +}; + +TEST_F(HloElementTypeConverterTest, CustomCallsNotConverted) { + const string& hlo_string = R"( + HloModule custom_call + ENTRY CustomCall { + constant = bf16[1]{0} constant({12345}) + ROOT custom-call = bf16[1,2,3]{0,2,1} custom-call(constant), + custom_call_target="foo" + } + )"; + auto module = CreateModuleFromHloString(hlo_string); + HloElementTypeConverter type_converter(BF16, F32); + auto converted = type_converter.Run(module.get()).ConsumeValueOrDie(); + EXPECT_TRUE(converted == false); +} + +TEST_F(HloElementTypeConverterTest, InfeedsOutfeedsNotConverted) { + const string& hlo_string = R"( + HloModule InfeedOutfeed + ENTRY RoundTrip16MiBR1.v2 { + ROOT infeed = bf16[4]{0} infeed() + outfeed = () outfeed(infeed) + } + )"; + auto module = CreateModuleFromHloString(hlo_string); + HloElementTypeConverter type_converter(BF16, F32); + auto converted = type_converter.Run(module.get()).ConsumeValueOrDie(); + EXPECT_TRUE(converted == false); +} + +TEST_F(HloElementTypeConverterTest, OperationsInNestedTuplesConverted) { + const string& hlo_string = R"( + HloModule NestedTuples + ENTRY NestedTuples.v5 { + constant.4 = bf16[] constant(42) + constant.2 = f32[2]{0} constant({1, 2}) + constant.3 = bf16[] constant(42) + add = bf16[] add(constant.2, constant.3) + tuple = (f32[2]{0}, bf16[]) tuple(constant.2, add) + constant.5 = bf16[2]{0} constant({22, 44}) + ROOT tuple.1 = ((f32[2]{0}, bf16[]), bf16[2]{0}) tuple(tuple, constant.5) + } + )"; + + auto module = CreateModuleFromHloString(hlo_string); + HloElementTypeConverter type_converter(BF16, F32); + auto converted = type_converter.Run(module.get()).ConsumeValueOrDie(); + EXPECT_TRUE(converted == true); + + const HloInstruction* bf16_op = + module->entry_computation()->root_instruction()->operand(0)->operand(1); + EXPECT_THAT(bf16_op, op::Convert(op::Add(op::Constant(), op::Convert()))); +} + +TEST_F(HloElementTypeConverterTest, BatchNormGradBF16Converted) { + const string& hlo_string = R"( + HloModule BatchNormGrad + ENTRY BatchNormGrad.v6 { + constant.4 = bf16[2,2,2,1]{3,2,1,0} constant(bf16[2,2,2,1] { { /*i0=0*/ + { /*i1=0*/ {0}, {0} }, { /*i1=1*/ {0}, {0} } }, { /*i0=1*/ { /*i1=0*/ {0}, + {0} }, { /*i1=1*/ {0}, {0} } } }) + constant.5 = bf16[2]{0} constant({1, 1}) + constant.6 = bf16[2]{0} constant({0, 0}) + constant.7 = bf16[2]{0} constant({1, 1}) + constant.8 = bf16[2,2,2,1]{3,2,1,0} constant(bf16[2,2,2,1] { { /*i0=0*/ + { /*i1=0*/ {1}, {2} }, { /*i1=1*/ {3}, {4} } }, { /*i0=1*/ { /*i1=0*/ + {5}, {6} }, { /*i1=1*/ {7}, {8} } } }) + ROOT batch-norm-grad = (bf16[2,2,2,1]{3,2,1,0}, bf16[2]{0}, bf16[2]{0}) + batch-norm-grad(constant.4, constant.5, constant.6, constant.7, + constant.8), epsilon=0, feature_index=2 + } + )"; + + auto module = CreateModuleFromHloString(hlo_string); + HloElementTypeConverter type_converter(BF16, F32); + auto converted = type_converter.Run(module.get()).ConsumeValueOrDie(); + EXPECT_TRUE(converted == true); + + const HloInstruction* tuple_instr = + module->entry_computation()->root_instruction(); + ::testing::Matcher batch_norm = + op::BatchNormGrad(); + EXPECT_THAT(tuple_instr, + op::Tuple(op::Convert(op::GetTupleElement(batch_norm, 0)), + op::Convert(op::GetTupleElement(batch_norm, 1)), + op::Convert(op::GetTupleElement(batch_norm, 2)))); +} + +} // namespace +} // namespace xla diff --git a/tensorflow/compiler/xla/service/hlo_matchers.h b/tensorflow/compiler/xla/service/hlo_matchers.h index 992f55788b..9206cdac05 100644 --- a/tensorflow/compiler/xla/service/hlo_matchers.h +++ b/tensorflow/compiler/xla/service/hlo_matchers.h @@ -83,6 +83,7 @@ HLO_MATCHER(Abs); HLO_MATCHER(Add); HLO_MATCHER(Bitcast); HLO_MATCHER(Broadcast); +HLO_MATCHER(BatchNormGrad); HLO_MATCHER(Call); HLO_MATCHER(Ceil); HLO_MATCHER(Clamp); diff --git a/tensorflow/compiler/xla/tests/BUILD b/tensorflow/compiler/xla/tests/BUILD index 3922c779a0..84e7c1770b 100644 --- a/tensorflow/compiler/xla/tests/BUILD +++ b/tensorflow/compiler/xla/tests/BUILD @@ -815,9 +815,6 @@ xla_test( xla_test( name = "bfloat16_test", srcs = ["bfloat16_test.cc"], - blacklisted_backends = [ - "gpu", - ], shard_count = 40, deps = [ ":test_utils", diff --git a/tensorflow/compiler/xla/tests/bfloat16_test.cc b/tensorflow/compiler/xla/tests/bfloat16_test.cc index e47fcad475..b853dfaa15 100644 --- a/tensorflow/compiler/xla/tests/bfloat16_test.cc +++ b/tensorflow/compiler/xla/tests/bfloat16_test.cc @@ -99,8 +99,9 @@ XLA_TEST_F(Bfloat16Test, BatchNormTraining) { auto expected = Literal::MakeTuple( {Literal::CreateR4( - {{{{static_cast(-1.7f)}, {static_cast(-2.04f)}}, - {{static_cast(0.105f)}, {static_cast(0.65f)}}}, + {{{{static_cast(-1.6875f)}, + {static_cast(-2.04f)}}, + {{static_cast(0.105f)}, {static_cast(0.66f)}}}, {{{static_cast(1.89f)}, {static_cast(3.35f)}}, {{static_cast(3.7f)}, {static_cast(6.04f)}}}}) .get(), diff --git a/tensorflow/compiler/xla/tests/convolution_test.cc b/tensorflow/compiler/xla/tests/convolution_test.cc index a10e17dbf3..0ceb9aff37 100644 --- a/tensorflow/compiler/xla/tests/convolution_test.cc +++ b/tensorflow/compiler/xla/tests/convolution_test.cc @@ -608,5 +608,28 @@ INSTANTIATE_TEST_CASE_P( ); +TEST_F(ConvolutionTest, Convolve_bf16_1x1x1x2_1x1x1x2_Valid) { + ComputationBuilder builder(client_, TestName()); + Shape input_shape = ShapeUtil::MakeShape(BF16, {1, 1, 1, 2}); + Shape filter_shape = ShapeUtil::MakeShape(BF16, {1, 1, 1, 2}); + auto input = builder.Parameter(0, input_shape, "input"); + auto filter = builder.Parameter(1, filter_shape, "filter"); + auto conv = builder.Conv(input, filter, {1, 1}, Padding::kValid); + + Array4D input_data(1, 1, 1, 2); + input_data.FillWithYX(Array2D({ + {bfloat16(1), bfloat16(2)}, + })); + Array4D filter_data(1, 1, 1, 2); + filter_data.FillWithYX(Array2D({ + {bfloat16(5), bfloat16(6)}, + })); + + ComputeAndCompare(&builder, conv, + {std::move(*Literal::CreateFromArray(input_data)), + std::move(*Literal::CreateFromArray(filter_data))}, + error_spec_); +} + } // namespace } // namespace xla diff --git a/tensorflow/compiler/xla/tests/matrix_ops_simple_test.cc b/tensorflow/compiler/xla/tests/matrix_ops_simple_test.cc index 0fb87c3c2c..6c86dd5b9e 100644 --- a/tensorflow/compiler/xla/tests/matrix_ops_simple_test.cc +++ b/tensorflow/compiler/xla/tests/matrix_ops_simple_test.cc @@ -221,5 +221,77 @@ INSTANTIATE_TEST_CASE_P(MatOpsDotAddTestInstances, MatOpsDotAddTest, ::testing::Combine(::testing::Bool(), ::testing::Bool(), ::testing::Bool())); +class MatOpsDotAddTest_bf16 + : public ClientLibraryTestBase, + public ::testing::WithParamInterface> {}; + +TEST_P(MatOpsDotAddTest_bf16, Dot_Add_2x2_2x2) { + bool row_major = std::get<0>(GetParam()); + bool add_lhs = std::get<1>(GetParam()); + bool transpose = std::get<2>(GetParam()); + Array2D lhs( + {{bfloat16(1.0f), bfloat16(2.0f)}, {bfloat16(3.0), bfloat16(4.0)}}); + Array2D rhs( + {{bfloat16(10.0f), bfloat16(11.0f)}, {bfloat16(12.0f), bfloat16(13.0f)}}); + + auto minor_to_major = [](bool row_major) -> std::vector { + return {row_major ? 1 : 0, row_major ? 0 : 1}; + }; + + auto prim_type = primitive_util::NativeToPrimitiveType(); + Shape lhs_shape = + ShapeUtil::MakeShape(prim_type, {lhs.height(), lhs.width()}); + Shape rhs_shape = + ShapeUtil::MakeShape(prim_type, {rhs.height(), rhs.width()}); + + TF_ASSERT_OK_AND_ASSIGN( + auto lhs_handle, + client_->TransferToServer( + *Literal::CreateR2FromArray2DWithLayout( + lhs, LayoutUtil::MakeLayout(minor_to_major(row_major))))); + TF_ASSERT_OK_AND_ASSIGN( + auto rhs_handle, + client_->TransferToServer( + *Literal::CreateR2FromArray2DWithLayout( + rhs, LayoutUtil::MakeLayout(minor_to_major(row_major))))); + + ComputationBuilder builder(client_, TestName()); + auto lhs_arg = builder.Parameter(0, lhs_shape, "lhs"); + auto lhs_mat_arg = lhs_arg; + if (transpose) { + lhs_mat_arg = builder.Transpose(lhs_mat_arg, {1, 0}); + } + auto rhs_arg = builder.Parameter(1, rhs_shape, "rhs"); + auto result = builder.Dot(lhs_mat_arg, rhs_arg); + Array2D expected; + if (add_lhs) { + result = builder.Add(result, lhs_arg); + if (transpose) { + expected = Array2D( + {{bfloat16(47), bfloat16(52)}, {bfloat16(71), bfloat16(78)}}); + } else { + expected = Array2D( + {{bfloat16(35), bfloat16(39)}, {bfloat16(81), bfloat16(89)}}); + } + } else { + result = builder.Add(result, rhs_arg); + if (transpose) { + expected = Array2D( + {{bfloat16(56), bfloat16(61)}, {bfloat16(80), bfloat16(87)}}); + } else { + expected = Array2D( + {{bfloat16(44), bfloat16(48)}, {bfloat16(90), bfloat16(98)}}); + } + } + + ComputeAndCompareR2(&builder, expected, + {lhs_handle.get(), rhs_handle.get()}, + ErrorSpec(1e-6)); +} + +INSTANTIATE_TEST_CASE_P(MatOpsDotAddTestInstances, MatOpsDotAddTest_bf16, + ::testing::Combine(::testing::Bool(), ::testing::Bool(), + ::testing::Bool())); + } // namespace } // namespace xla diff --git a/tensorflow/compiler/xla/tests/reduce_window_test.cc b/tensorflow/compiler/xla/tests/reduce_window_test.cc index 51e0765f7f..73b37e201a 100644 --- a/tensorflow/compiler/xla/tests/reduce_window_test.cc +++ b/tensorflow/compiler/xla/tests/reduce_window_test.cc @@ -810,9 +810,9 @@ INSTANTIATE_TEST_CASE_P( class R4ReduceWindowAnyDimsTest : public R4ReduceWindowTest {}; -// TODO(b/72234705): Fix the test cases failed on CPU. +// TODO(b/72234705): Fix the test cases failed on CPU and GPU. XLA_TEST_P(R4ReduceWindowAnyDimsTest, - DISABLED_ON_CPU_PARALLEL(DISABLED_ON_CPU(DoIt))) { + DISABLED_ON_CPU_PARALLEL(DISABLED_ON_CPU(DISABLED_ON_GPU(DoIt)))) { DoIt(); } -- GitLab From fb7ca01cc0dcb11a4805a2018ebb617b28b88d97 Mon Sep 17 00:00:00 2001 From: Anna R Date: Tue, 23 Jan 2018 12:48:44 -0800 Subject: [PATCH 127/258] Adding tf_export decorators/calls to TensorFlow functions and constants. PiperOrigin-RevId: 182977460 --- tensorflow/python/framework/constant_op.py | 2 + tensorflow/python/framework/device.py | 2 + tensorflow/python/framework/dtypes.py | 27 +++++++++++ tensorflow/python/framework/errors_impl.py | 45 ++++++++++++++++++- tensorflow/python/framework/graph_io.py | 2 + .../python/framework/graph_util_impl.py | 6 +++ tensorflow/python/framework/importer.py | 2 + tensorflow/python/framework/load_library.py | 3 ++ tensorflow/python/framework/ops.py | 25 +++++++++++ tensorflow/python/framework/random_seed.py | 3 ++ tensorflow/python/framework/sparse_tensor.py | 4 ++ tensorflow/python/framework/tensor_shape.py | 3 ++ tensorflow/python/framework/tensor_util.py | 3 ++ tensorflow/python/framework/test_util.py | 6 +++ tensorflow/python/framework/versions.py | 9 ++++ tensorflow/tools/api/generator/BUILD | 3 ++ 16 files changed, 144 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/framework/constant_op.py b/tensorflow/python/framework/constant_op.py index ac915157f5..0a56d3f64d 100644 --- a/tensorflow/python/framework/constant_op.py +++ b/tensorflow/python/framework/constant_op.py @@ -52,6 +52,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import tensor_util +from tensorflow.python.util.tf_export import tf_export def _eager_reshape(tensor, shape, ctx): @@ -131,6 +132,7 @@ def convert_to_eager_tensor(value, ctx, dtype=None): return ops.EagerTensor(value, context=handle, device=device, dtype=dtype) +@tf_export("constant") def constant(value, dtype=None, shape=None, name="Const", verify_shape=False): """Creates a constant tensor. diff --git a/tensorflow/python/framework/device.py b/tensorflow/python/framework/device.py index 8f5125dcfe..ab06a2babf 100644 --- a/tensorflow/python/framework/device.py +++ b/tensorflow/python/framework/device.py @@ -19,8 +19,10 @@ from __future__ import division from __future__ import print_function import copy +from tensorflow.python.util.tf_export import tf_export +@tf_export("DeviceSpec") class DeviceSpec(object): """Represents a (possibly partial) specification for a TensorFlow device. diff --git a/tensorflow/python/framework/dtypes.py b/tensorflow/python/framework/dtypes.py index b0422eb6be..67ccf990d6 100644 --- a/tensorflow/python/framework/dtypes.py +++ b/tensorflow/python/framework/dtypes.py @@ -23,11 +23,13 @@ import numpy as np from tensorflow.core.framework import types_pb2 from tensorflow.python import pywrap_tensorflow +from tensorflow.python.util.tf_export import tf_export _np_bfloat16 = pywrap_tensorflow.TF_bfloat16_type() +@tf_export("DType") class DType(object): """Represents the type of the elements in a `Tensor`. @@ -321,32 +323,55 @@ dtype_range = {np.bool_: (False, True), # Define standard wrappers for the types_pb2.DataType enum. resource = DType(types_pb2.DT_RESOURCE) +tf_export("resource").export_constant(__name__, "resource") variant = DType(types_pb2.DT_VARIANT) +tf_export("variant").export_constant(__name__, "variant") float16 = DType(types_pb2.DT_HALF) +tf_export("float16").export_constant(__name__, "float16") half = float16 +tf_export("half").export_constant(__name__, "half") float32 = DType(types_pb2.DT_FLOAT) +tf_export("float32").export_constant(__name__, "float32") float64 = DType(types_pb2.DT_DOUBLE) +tf_export("float64").export_constant(__name__, "float64") double = float64 +tf_export("double").export_constant(__name__, "double") int32 = DType(types_pb2.DT_INT32) +tf_export("int32").export_constant(__name__, "int32") uint8 = DType(types_pb2.DT_UINT8) +tf_export("uint8").export_constant(__name__, "uint8") uint16 = DType(types_pb2.DT_UINT16) +tf_export("uint16").export_constant(__name__, "uint16") uint32 = DType(types_pb2.DT_UINT32) uint64 = DType(types_pb2.DT_UINT64) int16 = DType(types_pb2.DT_INT16) +tf_export("int16").export_constant(__name__, "int16") int8 = DType(types_pb2.DT_INT8) +tf_export("int8").export_constant(__name__, "int8") string = DType(types_pb2.DT_STRING) +tf_export("string").export_constant(__name__, "string") complex64 = DType(types_pb2.DT_COMPLEX64) +tf_export("complex64").export_constant(__name__, "complex64") complex128 = DType(types_pb2.DT_COMPLEX128) +tf_export("complex128").export_constant(__name__, "complex128") int64 = DType(types_pb2.DT_INT64) +tf_export("int64").export_constant(__name__, "int64") bool = DType(types_pb2.DT_BOOL) +tf_export("bool").export_constant(__name__, "bool") qint8 = DType(types_pb2.DT_QINT8) +tf_export("qint8").export_constant(__name__, "qint8") quint8 = DType(types_pb2.DT_QUINT8) +tf_export("quint8").export_constant(__name__, "quint8") qint16 = DType(types_pb2.DT_QINT16) +tf_export("qint16").export_constant(__name__, "qint16") quint16 = DType(types_pb2.DT_QUINT16) +tf_export("quint16").export_constant(__name__, "quint16") qint32 = DType(types_pb2.DT_QINT32) +tf_export("qint32").export_constant(__name__, "qint32") resource_ref = DType(types_pb2.DT_RESOURCE_REF) variant_ref = DType(types_pb2.DT_VARIANT_REF) bfloat16 = DType(types_pb2.DT_BFLOAT16) +tf_export("bfloat16").export_constant(__name__, "bfloat16") float16_ref = DType(types_pb2.DT_HALF_REF) half_ref = float16_ref float32_ref = DType(types_pb2.DT_FLOAT_REF) @@ -578,8 +603,10 @@ _TF_TO_NP = { QUANTIZED_DTYPES = frozenset( [qint8, quint8, qint16, quint16, qint32, qint8_ref, quint8_ref, qint16_ref, quint16_ref, qint32_ref]) +tf_export("QUANTIZED_DTYPES").export_constant(__name__, "QUANTIZED_DTYPES") +@tf_export("as_dtype") def as_dtype(type_value): """Converts the given `type_value` to a `DType`. diff --git a/tensorflow/python/framework/errors_impl.py b/tensorflow/python/framework/errors_impl.py index c3b2c498c3..2a40316d51 100644 --- a/tensorflow/python/framework/errors_impl.py +++ b/tensorflow/python/framework/errors_impl.py @@ -25,8 +25,10 @@ from tensorflow.core.lib.core import error_codes_pb2 from tensorflow.python import pywrap_tensorflow as c_api from tensorflow.python.framework import c_api_util from tensorflow.python.util import compat +from tensorflow.python.util.tf_export import tf_export +@tf_export("OpError", "errors.OpError") class OpError(Exception): """A generic error that is raised when TensorFlow execution fails. @@ -133,25 +135,48 @@ class OpError(Exception): OK = error_codes_pb2.OK +tf_export("errors.OK").export_constant(__name__, "OK") CANCELLED = error_codes_pb2.CANCELLED +tf_export("errors.CANCELLED").export_constant(__name__, "CANCELLED") UNKNOWN = error_codes_pb2.UNKNOWN +tf_export("errors.UNKNOWN").export_constant(__name__, "UNKNOWN") INVALID_ARGUMENT = error_codes_pb2.INVALID_ARGUMENT +tf_export("errors.INVALID_ARGUMENT").export_constant(__name__, + "INVALID_ARGUMENT") DEADLINE_EXCEEDED = error_codes_pb2.DEADLINE_EXCEEDED +tf_export("errors.DEADLINE_EXCEEDED").export_constant(__name__, + "DEADLINE_EXCEEDED") NOT_FOUND = error_codes_pb2.NOT_FOUND +tf_export("errors.NOT_FOUND").export_constant(__name__, "NOT_FOUND") ALREADY_EXISTS = error_codes_pb2.ALREADY_EXISTS +tf_export("errors.ALREADY_EXISTS").export_constant(__name__, "ALREADY_EXISTS") PERMISSION_DENIED = error_codes_pb2.PERMISSION_DENIED +tf_export("errors.PERMISSION_DENIED").export_constant(__name__, + "PERMISSION_DENIED") UNAUTHENTICATED = error_codes_pb2.UNAUTHENTICATED +tf_export("errors.UNAUTHENTICATED").export_constant(__name__, "UNAUTHENTICATED") RESOURCE_EXHAUSTED = error_codes_pb2.RESOURCE_EXHAUSTED +tf_export("errors.RESOURCE_EXHAUSTED").export_constant(__name__, + "RESOURCE_EXHAUSTED") FAILED_PRECONDITION = error_codes_pb2.FAILED_PRECONDITION +tf_export("errors.FAILED_PRECONDITION").export_constant(__name__, + "FAILED_PRECONDITION") ABORTED = error_codes_pb2.ABORTED +tf_export("errors.ABORTED").export_constant(__name__, "ABORTED") OUT_OF_RANGE = error_codes_pb2.OUT_OF_RANGE +tf_export("errors.OUT_OF_RANGE").export_constant(__name__, "OUT_OF_RANGE") UNIMPLEMENTED = error_codes_pb2.UNIMPLEMENTED +tf_export("errors.UNIMPLEMENTED").export_constant(__name__, "UNIMPLEMENTED") INTERNAL = error_codes_pb2.INTERNAL +tf_export("errors.INTERNAL").export_constant(__name__, "INTERNAL") UNAVAILABLE = error_codes_pb2.UNAVAILABLE +tf_export("errors.UNAVAILABLE").export_constant(__name__, "UNAVAILABLE") DATA_LOSS = error_codes_pb2.DATA_LOSS +tf_export("errors.DATA_LOSS").export_constant(__name__, "DATA_LOSS") # pylint: disable=line-too-long +@tf_export("errors.CancelledError") class CancelledError(OpError): """Raised when an operation or step is cancelled. @@ -172,6 +197,7 @@ class CancelledError(OpError): # pylint: enable=line-too-long +@tf_export("errors.UnknownError") class UnknownError(OpError): """Unknown error. @@ -189,6 +215,7 @@ class UnknownError(OpError): super(UnknownError, self).__init__(node_def, op, message, error_code) +@tf_export("errors.InvalidArgumentError") class InvalidArgumentError(OpError): """Raised when an operation receives an invalid argument. @@ -209,6 +236,7 @@ class InvalidArgumentError(OpError): INVALID_ARGUMENT) +@tf_export("errors.DeadlineExceededError") class DeadlineExceededError(OpError): """Raised when a deadline expires before an operation could complete. @@ -223,6 +251,7 @@ class DeadlineExceededError(OpError): DEADLINE_EXCEEDED) +@tf_export("errors.NotFoundError") class NotFoundError(OpError): """Raised when a requested entity (e.g., a file or directory) was not found. @@ -239,6 +268,7 @@ class NotFoundError(OpError): super(NotFoundError, self).__init__(node_def, op, message, NOT_FOUND) +@tf_export("errors.AlreadyExistsError") class AlreadyExistsError(OpError): """Raised when an entity that we attempted to create already exists. @@ -256,6 +286,7 @@ class AlreadyExistsError(OpError): ALREADY_EXISTS) +@tf_export("errors.PermissionDeniedError") class PermissionDeniedError(OpError): """Raised when the caller does not have permission to run an operation. @@ -273,6 +304,7 @@ class PermissionDeniedError(OpError): PERMISSION_DENIED) +@tf_export("errors.UnauthenticatedError") class UnauthenticatedError(OpError): """The request does not have valid authentication credentials. @@ -287,6 +319,7 @@ class UnauthenticatedError(OpError): UNAUTHENTICATED) +@tf_export("errors.ResourceExhaustedError") class ResourceExhaustedError(OpError): """Some resource has been exhausted. @@ -302,6 +335,7 @@ class ResourceExhaustedError(OpError): RESOURCE_EXHAUSTED) +@tf_export("errors.FailedPreconditionError") class FailedPreconditionError(OpError): """Operation was rejected because the system is not in a state to execute it. @@ -318,6 +352,7 @@ class FailedPreconditionError(OpError): FAILED_PRECONDITION) +@tf_export("errors.AbortedError") class AbortedError(OpError): """The operation was aborted, typically due to a concurrent action. @@ -335,6 +370,7 @@ class AbortedError(OpError): super(AbortedError, self).__init__(node_def, op, message, ABORTED) +@tf_export("errors.OutOfRangeError") class OutOfRangeError(OpError): """Raised when an operation iterates past the valid input range. @@ -353,6 +389,7 @@ class OutOfRangeError(OpError): OUT_OF_RANGE) +@tf_export("errors.UnimplementedError") class UnimplementedError(OpError): """Raised when an operation has not been implemented. @@ -371,6 +408,7 @@ class UnimplementedError(OpError): UNIMPLEMENTED) +@tf_export("errors.InternalError") class InternalError(OpError): """Raised when the system experiences an internal error. @@ -385,6 +423,7 @@ class InternalError(OpError): super(InternalError, self).__init__(node_def, op, message, INTERNAL) +@tf_export("errors.UnavailableError") class UnavailableError(OpError): """Raised when the runtime is currently unavailable. @@ -399,6 +438,7 @@ class UnavailableError(OpError): UNAVAILABLE) +@tf_export("errors.DataLossError") class DataLossError(OpError): """Raised when unrecoverable data loss or corruption is encountered. @@ -437,10 +477,12 @@ _EXCEPTION_CLASS_TO_CODE = dict(( (class_, code) for (code, class_) in _CODE_TO_EXCEPTION_CLASS.items())) +@tf_export("errors.exception_type_from_error_code") def exception_type_from_error_code(error_code): return _CODE_TO_EXCEPTION_CLASS[error_code] +@tf_export("errors.error_code_from_exception_type") def error_code_from_exception_type(cls): return _EXCEPTION_CLASS_TO_CODE[cls] @@ -457,7 +499,8 @@ def _make_specific_exception(node_def, op, message, error_code): # Named like a function for backwards compatibility with the # @tf_contextlib.contextmanager version, which was switched to a class to avoid # some object creation overhead. -class raise_exception_on_not_ok_status(object): # pylint: disable=invalid-name +@tf_export("errors.raise_exception_on_not_ok_status") # pylint: disable=invalid-name +class raise_exception_on_not_ok_status(object): """Context manager to check for C API status.""" def __enter__(self): diff --git a/tensorflow/python/framework/graph_io.py b/tensorflow/python/framework/graph_io.py index a0ea4ad48e..be30b16f5f 100644 --- a/tensorflow/python/framework/graph_io.py +++ b/tensorflow/python/framework/graph_io.py @@ -24,8 +24,10 @@ import os.path from google.protobuf import text_format from tensorflow.python.framework import ops from tensorflow.python.lib.io import file_io +from tensorflow.python.util.tf_export import tf_export +@tf_export('train.write_graph') def write_graph(graph_or_graph_def, logdir, name, as_text=True): """Writes a graph proto to a file. diff --git a/tensorflow/python/framework/graph_util_impl.py b/tensorflow/python/framework/graph_util_impl.py index 6c7b455388..5a543317e6 100644 --- a/tensorflow/python/framework/graph_util_impl.py +++ b/tensorflow/python/framework/graph_util_impl.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.util.tf_export import tf_export _VARIABLE_OPS = { "Assign", @@ -49,6 +50,7 @@ def _is_variable_op(op): return op in _VARIABLE_OPS +@tf_export("graph_util.must_run_on_cpu") def must_run_on_cpu(node, pin_variables_on_cpu=False): """Returns True if the given node_def must run on CPU, otherwise False. @@ -147,6 +149,7 @@ def _bfs_for_reachable_nodes(target_nodes, name_to_input_name): return nodes_to_keep +@tf_export("graph_util.extract_sub_graph") def extract_sub_graph(graph_def, dest_nodes): """Extract the subgraph that can reach any of the nodes in 'dest_nodes'. @@ -184,6 +187,7 @@ def extract_sub_graph(graph_def, dest_nodes): return out +@tf_export("graph_util.tensor_shape_from_node_def_name") def tensor_shape_from_node_def_name(graph, input_name): """Convenience function to get a shape from a NodeDef's input string.""" # To get a tensor, the name must be in the form :, for example @@ -198,6 +202,7 @@ def tensor_shape_from_node_def_name(graph, input_name): return shape +@tf_export("graph_util.convert_variables_to_constants") def convert_variables_to_constants(sess, input_graph_def, output_node_names, @@ -270,6 +275,7 @@ def convert_variables_to_constants(sess, return output_graph_def +@tf_export("graph_util.remove_training_nodes") def remove_training_nodes(input_graph, protected_nodes=None): """Prunes out nodes that aren't needed for inference. diff --git a/tensorflow/python/framework/importer.py b/tensorflow/python/framework/importer.py index a3dbe43f06..00fff8d040 100644 --- a/tensorflow/python/framework/importer.py +++ b/tensorflow/python/framework/importer.py @@ -36,6 +36,7 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape from tensorflow.python.util import compat from tensorflow.python.util.deprecation import deprecated_args +from tensorflow.python.util.tf_export import tf_export # TODO(josh11b): SWIG the code from node_def_util instead of duplicating @@ -369,6 +370,7 @@ def _GatherReturnElements(requested_return_elements, graph, results): return combined_return_elements +@tf_export('import_graph_def') @deprecated_args(None, 'Please file an issue at ' 'https://github.com/tensorflow/tensorflow/issues if you depend' ' on this feature.', diff --git a/tensorflow/python/framework/load_library.py b/tensorflow/python/framework/load_library.py index 909e6d4c7b..c997ead829 100644 --- a/tensorflow/python/framework/load_library.py +++ b/tensorflow/python/framework/load_library.py @@ -28,8 +28,10 @@ from tensorflow.core.lib.core import error_codes_pb2 from tensorflow.python import pywrap_tensorflow as py_tf from tensorflow.python.framework import errors_impl from tensorflow.python.util import compat +from tensorflow.python.util.tf_export import tf_export +@tf_export('load_op_library') def load_op_library(library_filename): """Loads a TensorFlow plugin, containing custom ops and kernels. @@ -79,6 +81,7 @@ def load_op_library(library_filename): return module +@tf_export('load_file_system_library') def load_file_system_library(library_filename): """Loads a TensorFlow plugin, containing file system implementation. diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index 2489982d93..ce9ca07215 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -55,6 +55,7 @@ from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import compat from tensorflow.python.util import decorator_utils from tensorflow.python.util import tf_contextlib +from tensorflow.python.util.tf_export import tf_export # Temporary global switch determining if we should enable the work-in-progress @@ -191,6 +192,7 @@ class _TensorLike(object): pass +@tf_export("Tensor") class Tensor(_TensorLike): """Represents one of the outputs of an `Operation`. @@ -871,6 +873,7 @@ _tensor_conversion_func_lock = threading.Lock() register_dense_tensor_like_type(Tensor) +@tf_export("convert_to_tensor") def convert_to_tensor(value, dtype=None, name=None, preferred_dtype=None): """Converts the given `value` to a `Tensor`. @@ -1116,6 +1119,7 @@ def convert_n_to_tensor(values, dtype=None, name=None, preferred_dtype=None): as_ref=False) +@tf_export("convert_to_tensor_or_indexed_slices") def convert_to_tensor_or_indexed_slices(value, dtype=None, name=None): """Converts the given object to a `Tensor` or an `IndexedSlices`. @@ -1246,6 +1250,7 @@ def convert_n_to_tensor_or_indexed_slices(values, dtype=None, name=None): # TODO(josh11b): Add ctx argument to conversion_func() signature. +@tf_export("register_tensor_conversion_function") def register_tensor_conversion_function(base_type, conversion_func, priority=100): @@ -1306,6 +1311,7 @@ def register_tensor_conversion_function(base_type, _tensor_conversion_func_cache = {} +@tf_export("IndexedSlices") class IndexedSlices(_TensorLike): """A sparse representation of a set of tensor slices at given indices. @@ -1486,6 +1492,7 @@ def _create_c_op(graph, node_def, inputs, control_inputs): return c_op +@tf_export("Operation") class Operation(object): """Represents a graph node that performs computation on tensors. @@ -2213,6 +2220,7 @@ class Operation(object): _gradient_registry = registry.Registry("gradient") +@tf_export("RegisterGradient") class RegisterGradient(object): """A decorator for registering the gradient function for an op type. @@ -2255,6 +2263,7 @@ class RegisterGradient(object): return f +@tf_export("NoGradient", "NotDifferentiable") def NotDifferentiable(op_type): """Specifies that ops of type `op_type` is not differentiable. @@ -2574,6 +2583,7 @@ def _name_from_scope_name(name): return name[:-1] if (name and name[-1] == "/") else name +@tf_export("Graph") class Graph(object): """A TensorFlow computation, represented as a dataflow graph. @@ -4591,6 +4601,9 @@ class Graph(object): # TODO(agarwal): currently device directives in an outer eager scope will not # apply to inner graph mode code. Fix that. + + +@tf_export("device") def device(device_name_or_function): """Wrapper for `Graph.device()` using the default graph. @@ -4620,6 +4633,7 @@ def device(device_name_or_function): return context.device(device_name_or_function) +@tf_export("container") def container(container_name): """Wrapper for `Graph.container()` using the default graph. @@ -4633,6 +4647,7 @@ def container(container_name): return get_default_graph().container(container_name) +@tf_export("colocate_with") def colocate_with(op, ignore_existing=False): if context.in_graph_mode(): return get_default_graph().colocate_with(op, ignore_existing) @@ -4643,6 +4658,7 @@ def colocate_with(op, ignore_existing=False): return _NullContextmanager() +@tf_export("control_dependencies") def control_dependencies(control_inputs): """Wrapper for `Graph.control_dependencies()` using the default graph. @@ -4760,6 +4776,7 @@ def default_session(session): return _default_session_stack.get_controller(session) +@tf_export("get_default_session") def get_default_session(): """Returns the default session for the current thread. @@ -5049,6 +5066,7 @@ def eager_run(main=None, argv=None): app.run(main, argv) +@tf_export("reset_default_graph") def reset_default_graph(): """Clears the default graph stack and resets the global default graph. @@ -5067,6 +5085,7 @@ def reset_default_graph(): _default_graph_stack.reset() +@tf_export("get_default_graph") def get_default_graph(): """Returns the default graph for the current thread. @@ -5187,6 +5206,7 @@ def _get_graph_from_inputs(op_input_list, graph=None): return graph or get_default_graph() +@tf_export("GraphKeys") class GraphKeys(object): """Standard names to use for graph collections. @@ -5335,6 +5355,7 @@ class GraphKeys(object): return cls.GLOBAL_VARIABLES +@tf_export("add_to_collection") def add_to_collection(name, value): """Wrapper for `Graph.add_to_collection()` using the default graph. @@ -5371,6 +5392,7 @@ def add_to_collections(names, value): get_default_graph().add_to_collections(names, value) +@tf_export("get_collection_ref") def get_collection_ref(key): """Wrapper for `Graph.get_collection_ref()` using the default graph. @@ -5394,6 +5416,7 @@ def get_collection_ref(key): return get_default_graph().get_collection_ref(key) +@tf_export("get_collection") def get_collection(key, scope=None): """Wrapper for `Graph.get_collection()` using the default graph. @@ -5430,6 +5453,7 @@ def get_all_collection_keys(): # Named like a function for backwards compatibility with the # @tf_contextlib.contextmanager version, which was switched to a class to avoid # some object creation overhead. +@tf_export("name_scope", "keras.backend.name_scope") class name_scope(object): # pylint: disable=invalid-name """A context manager for use when defining a Python op. @@ -5576,6 +5600,7 @@ def prepend_name_scope(name, import_scope): # pylint: disable=g-doc-return-or-yield # pylint: disable=not-context-manager +@tf_export("op_scope") @tf_contextlib.contextmanager def op_scope(values, name, default_name=None): """DEPRECATED. Same as name_scope above, just different argument order.""" diff --git a/tensorflow/python/framework/random_seed.py b/tensorflow/python/framework/random_seed.py index 5f1130570d..1e74a790a3 100644 --- a/tensorflow/python/framework/random_seed.py +++ b/tensorflow/python/framework/random_seed.py @@ -22,6 +22,7 @@ from __future__ import print_function from tensorflow.python.eager import context from tensorflow.python.framework import ops +from tensorflow.python.util.tf_export import tf_export DEFAULT_GRAPH_SEED = 87654321 @@ -32,6 +33,7 @@ def _truncate_seed(seed): return seed % _MAXINT32 # Truncate to fit into 32-bit integer +@tf_export('get_seed') def get_seed(op_seed): """Returns the local seeds an operation should use given an op-specific seed. @@ -78,6 +80,7 @@ def get_seed(op_seed): return seeds +@tf_export('set_random_seed') def set_random_seed(seed): """Sets the graph-level random seed. diff --git a/tensorflow/python/framework/sparse_tensor.py b/tensorflow/python/framework/sparse_tensor.py index 6218cc34ca..1fe81e5f17 100644 --- a/tensorflow/python/framework/sparse_tensor.py +++ b/tensorflow/python/framework/sparse_tensor.py @@ -23,6 +23,7 @@ import collections from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util +from tensorflow.python.util.tf_export import tf_export # pylint: disable=protected-access _TensorLike = ops._TensorLike @@ -31,6 +32,7 @@ _override_helper = ops._override_helper # pylint: enable=protected-access +@tf_export("SparseTensor") class SparseTensor(_TensorLike): """Represents a sparse tensor. @@ -222,8 +224,10 @@ class SparseTensor(_TensorLike): SparseTensorValue = collections.namedtuple( "SparseTensorValue", ["indices", "values", "dense_shape"]) +tf_export("SparseTensorValue")(SparseTensorValue) +@tf_export("convert_to_tensor_or_sparse_tensor") def convert_to_tensor_or_sparse_tensor(value, dtype=None, name=None): """Converts value to a `SparseTensor` or `Tensor`. diff --git a/tensorflow/python/framework/tensor_shape.py b/tensorflow/python/framework/tensor_shape.py index 54ec15ea66..222071cb9e 100644 --- a/tensorflow/python/framework/tensor_shape.py +++ b/tensorflow/python/framework/tensor_shape.py @@ -19,8 +19,10 @@ from __future__ import print_function from tensorflow.core.framework import tensor_shape_pb2 from tensorflow.python.util import compat +from tensorflow.python.util.tf_export import tf_export +@tf_export("Dimension") class Dimension(object): """Represents the value of one dimension in a TensorShape.""" @@ -397,6 +399,7 @@ def as_dimension(value): return Dimension(value) +@tf_export("TensorShape") class TensorShape(object): """Represents the shape of a `Tensor`. diff --git a/tensorflow/python/framework/tensor_util.py b/tensorflow/python/framework/tensor_util.py index 1b90c7ad4d..d2b8e80305 100644 --- a/tensorflow/python/framework/tensor_util.py +++ b/tensorflow/python/framework/tensor_util.py @@ -38,6 +38,7 @@ except ImportError: from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.util.tf_export import tf_export # pylint: enable=g-import-not-at-top @@ -328,6 +329,7 @@ def _AssertCompatible(values, dtype): (dtype.name, repr(mismatch), type(mismatch).__name__)) +@tf_export("make_tensor_proto") def make_tensor_proto(values, dtype=None, shape=None, verify_shape=False): """Create a TensorProto. @@ -515,6 +517,7 @@ def make_tensor_proto(values, dtype=None, shape=None, verify_shape=False): return tensor_proto +@tf_export("make_ndarray") def MakeNdarray(tensor): """Create a numpy ndarray from a tensor. diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py index 729c939870..8124472a83 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py @@ -65,8 +65,10 @@ from tensorflow.python.training import server_lib from tensorflow.python.util import compat from tensorflow.python.util import nest from tensorflow.python.util.protobuf import compare +from tensorflow.python.util.tf_export import tf_export +@tf_export("test.gpu_device_name") def gpu_device_name(): """Returns the name of a GPU device if available or the empty string.""" for x in device_lib.list_local_devices(): @@ -101,6 +103,7 @@ def assert_ops_in_graph(expected_ops, graph): return actual_ops +@tf_export("test.assert_equal_graph_def") def assert_equal_graph_def(actual, expected, checkpoint_v2=False): """Asserts that two `GraphDef`s are (mostly) the same. @@ -630,6 +633,7 @@ def run_in_graph_and_eager_modes( return decorator +@tf_export("test.is_gpu_available") def is_gpu_available(cuda_only=False, min_cuda_compute_capability=None): """Returns whether TensorFlow can access a GPU. @@ -678,6 +682,7 @@ def device(use_gpu): yield +@tf_export("test.TestCase") class TensorFlowTestCase(googletest.TestCase): """Base class for tests that need to test TensorFlow. """ @@ -1326,6 +1331,7 @@ class TensorFlowTestCase(googletest.TestCase): # pylint: enable=invalid-name +@tf_export("test.create_local_cluster") def create_local_cluster(num_workers, num_ps, protocol="grpc", worker_config=None, ps_config=None): """Create and start local servers and return the associated `Server` objects. diff --git a/tensorflow/python/framework/versions.py b/tensorflow/python/framework/versions.py index f03b81eb28..bdcbc15af6 100644 --- a/tensorflow/python/framework/versions.py +++ b/tensorflow/python/framework/versions.py @@ -20,6 +20,7 @@ from __future__ import division from __future__ import print_function from tensorflow.python import pywrap_tensorflow +from tensorflow.python.util.tf_export import tf_export __version__ = pywrap_tensorflow.__version__ __git_version__ = pywrap_tensorflow.__git_version__ @@ -28,16 +29,24 @@ __cxx11_abi_flag__ = pywrap_tensorflow.__cxx11_abi_flag__ __monolithic_build__ = pywrap_tensorflow.__monolithic_build__ VERSION = __version__ +tf_export("VERSION").export_constant(__name__, "VERSION") GIT_VERSION = __git_version__ +tf_export("GIT_VERSION").export_constant(__name__, "GIT_VERSION") COMPILER_VERSION = __compiler_version__ +tf_export("COMPILER_VERSION").export_constant(__name__, "COMPILER_VERSION") CXX11_ABI_FLAG = __cxx11_abi_flag__ MONOLITHIC_BUILD = __monolithic_build__ GRAPH_DEF_VERSION = pywrap_tensorflow.GRAPH_DEF_VERSION +tf_export("GRAPH_DEF_VERSION").export_constant(__name__, "GRAPH_DEF_VERSION") GRAPH_DEF_VERSION_MIN_CONSUMER = ( pywrap_tensorflow.GRAPH_DEF_VERSION_MIN_CONSUMER) +tf_export("GRAPH_DEF_VERSION_MIN_CONSUMER").export_constant( + __name__, "GRAPH_DEF_VERSION_MIN_CONSUMER") GRAPH_DEF_VERSION_MIN_PRODUCER = ( pywrap_tensorflow.GRAPH_DEF_VERSION_MIN_PRODUCER) +tf_export("GRAPH_DEF_VERSION_MIN_PRODUCER").export_constant( + __name__, "GRAPH_DEF_VERSION_MIN_PRODUCER") __all__ = [ "__version__", diff --git a/tensorflow/tools/api/generator/BUILD b/tensorflow/tools/api/generator/BUILD index 8bbd247818..4c47ffe07c 100644 --- a/tensorflow/tools/api/generator/BUILD +++ b/tensorflow/tools/api/generator/BUILD @@ -48,6 +48,7 @@ genrule( "api/contrib/stat_summarizer/__init__.py", "api/distributions/__init__.py", "api/distributions/bijectors/__init__.py", + "api/errors/__init__.py", "api/image/__init__.py", "api/linalg/__init__.py", "api/nn/__init__.py", @@ -55,7 +56,9 @@ genrule( "api/train/__init__.py", "api/app/__init__.py", "api/gfile/__init__.py", + "api/graph_util/__init__.py", "api/keras/__init__.py", + "api/keras/backend/__init__.py", "api/keras/datasets/__init__.py", "api/keras/datasets/boston_housing/__init__.py", "api/keras/datasets/cifar10/__init__.py", -- GitLab From 1ef8e4d519519b0d1bb84e31290db6830fb28887 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 12:52:36 -0800 Subject: [PATCH 128/258] Go: Update generated wrapper functions for TensorFlow ops. PiperOrigin-RevId: 182977979 --- tensorflow/go/op/wrappers.go | 1186 +++++++++++++++++----------------- 1 file changed, 593 insertions(+), 593 deletions(-) diff --git a/tensorflow/go/op/wrappers.go b/tensorflow/go/op/wrappers.go index 8df4e98adc..2f1f3b0be4 100644 --- a/tensorflow/go/op/wrappers.go +++ b/tensorflow/go/op/wrappers.go @@ -163,6 +163,63 @@ func WriteSummary(scope *Scope, writer tf.Output, step tf.Output, tensor tf.Outp return scope.AddOperation(opspec) } +// Creates summary database writer accessible by given resource handle. +// +// This can be used to write tensors from the execution graph directly +// to a database. Only SQLite is supported right now. This function +// will create the schema if it doesn't exist. Entries in the Users, +// Experiments, and Runs tables will be created automatically if they +// don't already exist. +// +// Arguments: +// writer: Handle to SummaryWriter resource to overwrite. +// db_uri: For example "file:/tmp/foo.sqlite". +// experiment_name: Can't contain ASCII control characters or <>. Case +// sensitive. If empty, then the Run will not be associated with any +// Experiment. +// run_name: Can't contain ASCII control characters or <>. Case sensitive. +// If empty, then each Tag will not be associated with any Run. +// user_name: Must be valid as both a DNS label and Linux username. If +// empty, then the Experiment will not be associated with any User. +// +// Returns the created operation. +func CreateSummaryDbWriter(scope *Scope, writer tf.Output, db_uri tf.Output, experiment_name tf.Output, run_name tf.Output, user_name tf.Output) (o *tf.Operation) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "CreateSummaryDbWriter", + Input: []tf.Input{ + writer, db_uri, experiment_name, run_name, user_name, + }, + } + return scope.AddOperation(opspec) +} + +// Creates a summary file writer accessible by the given resource handle. +// +// Arguments: +// writer: A handle to the summary writer resource +// logdir: Directory where the event file will be written. +// max_queue: Size of the queue of pending events and summaries. +// flush_millis: How often, in milliseconds, to flush the pending events and +// summaries to disk. +// filename_suffix: Every event file's name is suffixed with this suffix. +// +// Returns the created operation. +func CreateSummaryFileWriter(scope *Scope, writer tf.Output, logdir tf.Output, max_queue tf.Output, flush_millis tf.Output, filename_suffix tf.Output) (o *tf.Operation) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "CreateSummaryFileWriter", + Input: []tf.Input{ + writer, logdir, max_queue, flush_millis, filename_suffix, + }, + } + return scope.AddOperation(opspec) +} + // Partitions `data` into `num_partitions` tensors using indices from `partitions`. // // For each index tuple `js` of size `partitions.ndim`, the slice `data[js, ...]` @@ -3164,39 +3221,6 @@ func HistogramFixedWidth(scope *Scope, values tf.Output, value_range tf.Output, return op.Output(0) } -// Creates summary database writer accessible by given resource handle. -// -// This can be used to write tensors from the execution graph directly -// to a database. Only SQLite is supported right now. This function -// will create the schema if it doesn't exist. Entries in the Users, -// Experiments, and Runs tables will be created automatically if they -// don't already exist. -// -// Arguments: -// writer: Handle to SummaryWriter resource to overwrite. -// db_uri: For example "file:/tmp/foo.sqlite". -// experiment_name: Can't contain ASCII control characters or <>. Case -// sensitive. If empty, then the Run will not be associated with any -// Experiment. -// run_name: Can't contain ASCII control characters or <>. Case sensitive. -// If empty, then each Tag will not be associated with any Run. -// user_name: Must be valid as both a DNS label and Linux username. If -// empty, then the Experiment will not be associated with any User. -// -// Returns the created operation. -func CreateSummaryDbWriter(scope *Scope, writer tf.Output, db_uri tf.Output, experiment_name tf.Output, run_name tf.Output, user_name tf.Output) (o *tf.Operation) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "CreateSummaryDbWriter", - Input: []tf.Input{ - writer, db_uri, experiment_name, run_name, user_name, - }, - } - return scope.AddOperation(opspec) -} - // Adds Tensor 'bias' to Tensor 'input' for Quantized types. // // Broadcasts the values of bias on dimensions 0..N-2 of 'input'. @@ -7474,30 +7498,6 @@ func VarHandleOp(scope *Scope, dtype tf.DataType, shape tf.Shape, optional ...Va return op.Output(0) } -// Creates a summary file writer accessible by the given resource handle. -// -// Arguments: -// writer: A handle to the summary writer resource -// logdir: Directory where the event file will be written. -// max_queue: Size of the queue of pending events and summaries. -// flush_millis: How often, in milliseconds, to flush the pending events and -// summaries to disk. -// filename_suffix: Every event file's name is suffixed with this suffix. -// -// Returns the created operation. -func CreateSummaryFileWriter(scope *Scope, writer tf.Output, logdir tf.Output, max_queue tf.Output, flush_millis tf.Output, filename_suffix tf.Output) (o *tf.Operation) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "CreateSummaryFileWriter", - Input: []tf.Input{ - writer, logdir, max_queue, flush_millis, filename_suffix, - }, - } - return scope.AddOperation(opspec) -} - // Elementwise computes the bitwise XOR of `x` and `y`. // // The result will have those bits set, that are different in `x` and `y`. The @@ -10955,139 +10955,298 @@ func DepthwiseConv2dNativeBackpropFilter(scope *Scope, input tf.Output, filter_s return op.Output(0) } -// Component-wise divides a SparseTensor by a dense Tensor. -// -// *Limitation*: this Op only broadcasts the dense side to the sparse side, but not -// the other direction. +// Flushes the writer's unwritten events. // // Arguments: -// sp_indices: 2-D. `N x R` matrix with the indices of non-empty values in a -// SparseTensor, possibly not in canonical ordering. -// sp_values: 1-D. `N` non-empty values corresponding to `sp_indices`. -// sp_shape: 1-D. Shape of the input SparseTensor. -// dense: `R`-D. The dense Tensor operand. +// writer: A handle to the summary writer resource. // -// Returns 1-D. The `N` values that are operated on. -func SparseDenseCwiseDiv(scope *Scope, sp_indices tf.Output, sp_values tf.Output, sp_shape tf.Output, dense tf.Output) (output tf.Output) { +// Returns the created operation. +func FlushSummaryWriter(scope *Scope, writer tf.Output) (o *tf.Operation) { if scope.Err() != nil { return } opspec := tf.OpSpec{ - Type: "SparseDenseCwiseDiv", + Type: "FlushSummaryWriter", Input: []tf.Input{ - sp_indices, sp_values, sp_shape, dense, + writer, }, } - op := scope.AddOperation(opspec) - return op.Output(0) + return scope.AddOperation(opspec) } -// ResourceApplyMomentumAttr is an optional argument to ResourceApplyMomentum. -type ResourceApplyMomentumAttr func(optionalAttr) +// QuantizeV2Attr is an optional argument to QuantizeV2. +type QuantizeV2Attr func(optionalAttr) -// ResourceApplyMomentumUseLocking sets the optional use_locking attribute to value. -// -// value: If `True`, updating of the var and accum tensors will be protected -// by a lock; otherwise the behavior is undefined, but may exhibit less -// contention. -// If not specified, defaults to false -func ResourceApplyMomentumUseLocking(value bool) ResourceApplyMomentumAttr { +// QuantizeV2Mode sets the optional mode attribute to value. +// If not specified, defaults to "MIN_COMBINED" +func QuantizeV2Mode(value string) QuantizeV2Attr { return func(m optionalAttr) { - m["use_locking"] = value + m["mode"] = value } } -// ResourceApplyMomentumUseNesterov sets the optional use_nesterov attribute to value. -// -// value: If `True`, the tensor passed to compute grad will be -// var - lr * momentum * accum, so in the end, the var you get is actually -// var - lr * momentum * accum. -// If not specified, defaults to false -func ResourceApplyMomentumUseNesterov(value bool) ResourceApplyMomentumAttr { +// QuantizeV2RoundMode sets the optional round_mode attribute to value. +// If not specified, defaults to "HALF_AWAY_FROM_ZERO" +func QuantizeV2RoundMode(value string) QuantizeV2Attr { return func(m optionalAttr) { - m["use_nesterov"] = value + m["round_mode"] = value } } -// Update '*var' according to the momentum scheme. Set use_nesterov = True if you +// Quantize the 'input' tensor of type float to 'output' tensor of type 'T'. // -// want to use Nesterov momentum. +// [min_range, max_range] are scalar floats that specify the range for +// the 'input' data. The 'mode' attribute controls exactly which calculations are +// used to convert the float values to their quantized equivalents. The +// 'round_mode' attribute controls which rounding tie-breaking algorithm is used +// when rounding float values to their quantized equivalents. // -// accum = accum * momentum + grad -// var -= lr * accum +// In 'MIN_COMBINED' mode, each value of the tensor will undergo the following: // -// Arguments: -// var_: Should be from a Variable(). -// accum: Should be from a Variable(). -// lr: Scaling factor. Must be a scalar. -// grad: The gradient. -// momentum: Momentum. Must be a scalar. +// ``` +// out[i] = (in[i] - min_range) * range(T) / (max_range - min_range) +// if T == qint8, out[i] -= (range(T) + 1) / 2.0 +// ``` +// here `range(T) = numeric_limits::max() - numeric_limits::min()` // -// Returns the created operation. -func ResourceApplyMomentum(scope *Scope, var_ tf.Output, accum tf.Output, lr tf.Output, grad tf.Output, momentum tf.Output, optional ...ResourceApplyMomentumAttr) (o *tf.Operation) { - if scope.Err() != nil { - return - } - attrs := map[string]interface{}{} - for _, a := range optional { - a(attrs) - } - opspec := tf.OpSpec{ - Type: "ResourceApplyMomentum", - Input: []tf.Input{ - var_, accum, lr, grad, momentum, - }, - Attrs: attrs, - } - return scope.AddOperation(opspec) -} - -// Returns the truth value of (x >= y) element-wise. +// *MIN_COMBINED Mode Example* // -// *NOTE*: `GreaterEqual` supports broadcasting. More about broadcasting -// [here](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) -func GreaterEqual(scope *Scope, x tf.Output, y tf.Output) (z tf.Output) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "GreaterEqual", - Input: []tf.Input{ - x, y, - }, - } - op := scope.AddOperation(opspec) - return op.Output(0) -} - -// Conv3DAttr is an optional argument to Conv3D. -type Conv3DAttr func(optionalAttr) - -// Conv3DDataFormat sets the optional data_format attribute to value. +// Assume the input is type float and has a possible range of [0.0, 6.0] and the +// output type is quint8 ([0, 255]). The min_range and max_range values should be +// specified as 0.0 and 6.0. Quantizing from float to quint8 will multiply each +// value of the input by 255/6 and cast to quint8. // -// value: The data format of the input and output data. With the -// default format "NDHWC", the data is stored in the order of: -// [batch, in_depth, in_height, in_width, in_channels]. -// Alternatively, the format could be "NCDHW", the data storage order is: -// [batch, in_channels, in_depth, in_height, in_width]. -// If not specified, defaults to "NDHWC" -func Conv3DDataFormat(value string) Conv3DAttr { - return func(m optionalAttr) { - m["data_format"] = value - } -} - -// Conv3DDilations sets the optional dilations attribute to value. +// If the output type was qint8 ([-128, 127]), the operation will additionally +// subtract each value by 128 prior to casting, so that the range of values aligns +// with the range of qint8. // -// value: 1-D tensor of length 5. The dilation factor for each dimension of -// `input`. If set to k > 1, there will be k-1 skipped cells between each -// filter element on that dimension. The dimension order is determined by the -// value of `data_format`, see above for details. Dilations in the batch and -// depth dimensions must be 1. -// If not specified, defaults to -func Conv3DDilations(value []int64) Conv3DAttr { - return func(m optionalAttr) { - m["dilations"] = value +// If the mode is 'MIN_FIRST', then this approach is used: +// +// ``` +// num_discrete_values = 1 << (# of bits in T) +// range_adjust = num_discrete_values / (num_discrete_values - 1) +// range = (range_max - range_min) * range_adjust +// range_scale = num_discrete_values / range +// quantized = round(input * range_scale) - round(range_min * range_scale) + +// numeric_limits::min() +// quantized = max(quantized, numeric_limits::min()) +// quantized = min(quantized, numeric_limits::max()) +// ``` +// +// The biggest difference between this and MIN_COMBINED is that the minimum range +// is rounded first, before it's subtracted from the rounded value. With +// MIN_COMBINED, a small bias is introduced where repeated iterations of quantizing +// and dequantizing will introduce a larger and larger error. +// +// *SCALED mode Example* +// +// `SCALED` mode matches the quantization approach used in +// `QuantizeAndDequantize{V2|V3}`. +// +// If the mode is `SCALED`, we do not use the full range of the output type, +// choosing to elide the lowest possible value for symmetry (e.g., output range is +// -127 to 127, not -128 to 127 for signed 8 bit quantization), so that 0.0 maps to +// 0. +// +// We first find the range of values in our tensor. The +// range we use is always centered on 0, so we find m such that +// ```c++ +// m = max(abs(input_min), abs(input_max)) +// ``` +// +// Our input tensor range is then `[-m, m]`. +// +// Next, we choose our fixed-point quantization buckets, `[min_fixed, max_fixed]`. +// If T is signed, this is +// ``` +// num_bits = sizeof(T) * 8 +// [min_fixed, max_fixed] = +// [-(1 << (num_bits - 1) - 1), (1 << (num_bits - 1)) - 1] +// ``` +// +// Otherwise, if T is unsigned, the fixed-point range is +// ``` +// [min_fixed, max_fixed] = [0, (1 << num_bits) - 1] +// ``` +// +// From this we compute our scaling factor, s: +// ```c++ +// s = (max_fixed - min_fixed) / (2 * m) +// ``` +// +// Now we can quantize the elements of our tensor: +// ```c++ +// result = round(input * s) +// ``` +// +// One thing to watch out for is that the operator may choose to adjust the +// requested minimum and maximum values slightly during the quantization process, +// so you should always use the output ports as the range for further calculations. +// For example, if the requested minimum and maximum values are close to equal, +// they will be separated by a small epsilon value to prevent ill-formed quantized +// buffers from being created. Otherwise, you can end up with buffers where all the +// quantized values map to the same float value, which causes problems for +// operations that have to perform further calculations on them. +// +// Arguments: +// +// min_range: The minimum scalar value possibly produced for the input. +// max_range: The maximum scalar value possibly produced for the input. +// +// +// Returns The quantized data produced from the float input.The actual minimum scalar value used for the output.The actual maximum scalar value used for the output. +func QuantizeV2(scope *Scope, input tf.Output, min_range tf.Output, max_range tf.Output, T tf.DataType, optional ...QuantizeV2Attr) (output tf.Output, output_min tf.Output, output_max tf.Output) { + if scope.Err() != nil { + return + } + attrs := map[string]interface{}{"T": T} + for _, a := range optional { + a(attrs) + } + opspec := tf.OpSpec{ + Type: "QuantizeV2", + Input: []tf.Input{ + input, min_range, max_range, + }, + Attrs: attrs, + } + op := scope.AddOperation(opspec) + return op.Output(0), op.Output(1), op.Output(2) +} + +// Component-wise divides a SparseTensor by a dense Tensor. +// +// *Limitation*: this Op only broadcasts the dense side to the sparse side, but not +// the other direction. +// +// Arguments: +// sp_indices: 2-D. `N x R` matrix with the indices of non-empty values in a +// SparseTensor, possibly not in canonical ordering. +// sp_values: 1-D. `N` non-empty values corresponding to `sp_indices`. +// sp_shape: 1-D. Shape of the input SparseTensor. +// dense: `R`-D. The dense Tensor operand. +// +// Returns 1-D. The `N` values that are operated on. +func SparseDenseCwiseDiv(scope *Scope, sp_indices tf.Output, sp_values tf.Output, sp_shape tf.Output, dense tf.Output) (output tf.Output) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "SparseDenseCwiseDiv", + Input: []tf.Input{ + sp_indices, sp_values, sp_shape, dense, + }, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + +// ResourceApplyMomentumAttr is an optional argument to ResourceApplyMomentum. +type ResourceApplyMomentumAttr func(optionalAttr) + +// ResourceApplyMomentumUseLocking sets the optional use_locking attribute to value. +// +// value: If `True`, updating of the var and accum tensors will be protected +// by a lock; otherwise the behavior is undefined, but may exhibit less +// contention. +// If not specified, defaults to false +func ResourceApplyMomentumUseLocking(value bool) ResourceApplyMomentumAttr { + return func(m optionalAttr) { + m["use_locking"] = value + } +} + +// ResourceApplyMomentumUseNesterov sets the optional use_nesterov attribute to value. +// +// value: If `True`, the tensor passed to compute grad will be +// var - lr * momentum * accum, so in the end, the var you get is actually +// var - lr * momentum * accum. +// If not specified, defaults to false +func ResourceApplyMomentumUseNesterov(value bool) ResourceApplyMomentumAttr { + return func(m optionalAttr) { + m["use_nesterov"] = value + } +} + +// Update '*var' according to the momentum scheme. Set use_nesterov = True if you +// +// want to use Nesterov momentum. +// +// accum = accum * momentum + grad +// var -= lr * accum +// +// Arguments: +// var_: Should be from a Variable(). +// accum: Should be from a Variable(). +// lr: Scaling factor. Must be a scalar. +// grad: The gradient. +// momentum: Momentum. Must be a scalar. +// +// Returns the created operation. +func ResourceApplyMomentum(scope *Scope, var_ tf.Output, accum tf.Output, lr tf.Output, grad tf.Output, momentum tf.Output, optional ...ResourceApplyMomentumAttr) (o *tf.Operation) { + if scope.Err() != nil { + return + } + attrs := map[string]interface{}{} + for _, a := range optional { + a(attrs) + } + opspec := tf.OpSpec{ + Type: "ResourceApplyMomentum", + Input: []tf.Input{ + var_, accum, lr, grad, momentum, + }, + Attrs: attrs, + } + return scope.AddOperation(opspec) +} + +// Returns the truth value of (x >= y) element-wise. +// +// *NOTE*: `GreaterEqual` supports broadcasting. More about broadcasting +// [here](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) +func GreaterEqual(scope *Scope, x tf.Output, y tf.Output) (z tf.Output) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "GreaterEqual", + Input: []tf.Input{ + x, y, + }, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + +// Conv3DAttr is an optional argument to Conv3D. +type Conv3DAttr func(optionalAttr) + +// Conv3DDataFormat sets the optional data_format attribute to value. +// +// value: The data format of the input and output data. With the +// default format "NDHWC", the data is stored in the order of: +// [batch, in_depth, in_height, in_width, in_channels]. +// Alternatively, the format could be "NCDHW", the data storage order is: +// [batch, in_channels, in_depth, in_height, in_width]. +// If not specified, defaults to "NDHWC" +func Conv3DDataFormat(value string) Conv3DAttr { + return func(m optionalAttr) { + m["data_format"] = value + } +} + +// Conv3DDilations sets the optional dilations attribute to value. +// +// value: 1-D tensor of length 5. The dilation factor for each dimension of +// `input`. If set to k > 1, there will be k-1 skipped cells between each +// filter element on that dimension. The dimension order is determined by the +// value of `data_format`, see above for details. Dilations in the batch and +// depth dimensions must be 1. +// If not specified, defaults to +func Conv3DDilations(value []int64) Conv3DAttr { + return func(m optionalAttr) { + m["dilations"] = value } } @@ -14467,230 +14626,18 @@ func RandomGamma(scope *Scope, shape tf.Output, alpha tf.Output, optional ...Ran return op.Output(0) } -// AvgPool3DGradAttr is an optional argument to AvgPool3DGrad. -type AvgPool3DGradAttr func(optionalAttr) +// QuantizedConv2DAttr is an optional argument to QuantizedConv2D. +type QuantizedConv2DAttr func(optionalAttr) -// AvgPool3DGradDataFormat sets the optional data_format attribute to value. -// -// value: The data format of the input and output data. With the -// default format "NDHWC", the data is stored in the order of: -// [batch, in_depth, in_height, in_width, in_channels]. -// Alternatively, the format could be "NCDHW", the data storage order is: -// [batch, in_channels, in_depth, in_height, in_width]. -// If not specified, defaults to "NDHWC" -func AvgPool3DGradDataFormat(value string) AvgPool3DGradAttr { +// QuantizedConv2DOutType sets the optional out_type attribute to value. +// If not specified, defaults to DT_QINT32 +func QuantizedConv2DOutType(value tf.DataType) QuantizedConv2DAttr { return func(m optionalAttr) { - m["data_format"] = value + m["out_type"] = value } } -// Computes gradients of average pooling function. -// -// Arguments: -// orig_input_shape: The original input dimensions. -// grad: Output backprop of shape `[batch, depth, rows, cols, channels]`. -// ksize: 1-D tensor of length 5. The size of the window for each dimension of -// the input tensor. Must have `ksize[0] = ksize[4] = 1`. -// strides: 1-D tensor of length 5. The stride of the sliding window for each -// dimension of `input`. Must have `strides[0] = strides[4] = 1`. -// padding: The type of padding algorithm to use. -// -// Returns The backprop for input. -func AvgPool3DGrad(scope *Scope, orig_input_shape tf.Output, grad tf.Output, ksize []int64, strides []int64, padding string, optional ...AvgPool3DGradAttr) (output tf.Output) { - if scope.Err() != nil { - return - } - attrs := map[string]interface{}{"ksize": ksize, "strides": strides, "padding": padding} - for _, a := range optional { - a(attrs) - } - opspec := tf.OpSpec{ - Type: "AvgPool3DGrad", - Input: []tf.Input{ - orig_input_shape, grad, - }, - Attrs: attrs, - } - op := scope.AddOperation(opspec) - return op.Output(0) -} - -// ParseSingleSequenceExampleAttr is an optional argument to ParseSingleSequenceExample. -type ParseSingleSequenceExampleAttr func(optionalAttr) - -// ParseSingleSequenceExampleContextSparseTypes sets the optional context_sparse_types attribute to value. -// -// value: A list of Ncontext_sparse types; the data types of data in -// each context Feature given in context_sparse_keys. -// Currently the ParseSingleSequenceExample supports DT_FLOAT (FloatList), -// DT_INT64 (Int64List), and DT_STRING (BytesList). -// If not specified, defaults to <> -// -// REQUIRES: len(value) >= 0 -func ParseSingleSequenceExampleContextSparseTypes(value []tf.DataType) ParseSingleSequenceExampleAttr { - return func(m optionalAttr) { - m["context_sparse_types"] = value - } -} - -// ParseSingleSequenceExampleFeatureListDenseTypes sets the optional feature_list_dense_types attribute to value. -// If not specified, defaults to <> -// -// REQUIRES: len(value) >= 0 -func ParseSingleSequenceExampleFeatureListDenseTypes(value []tf.DataType) ParseSingleSequenceExampleAttr { - return func(m optionalAttr) { - m["feature_list_dense_types"] = value - } -} - -// ParseSingleSequenceExampleContextDenseShapes sets the optional context_dense_shapes attribute to value. -// -// value: A list of Ncontext_dense shapes; the shapes of data in -// each context Feature given in context_dense_keys. -// The number of elements in the Feature corresponding to context_dense_key[j] -// must always equal context_dense_shapes[j].NumEntries(). -// The shape of context_dense_values[j] will match context_dense_shapes[j]. -// If not specified, defaults to <> -// -// REQUIRES: len(value) >= 0 -func ParseSingleSequenceExampleContextDenseShapes(value []tf.Shape) ParseSingleSequenceExampleAttr { - return func(m optionalAttr) { - m["context_dense_shapes"] = value - } -} - -// ParseSingleSequenceExampleFeatureListSparseTypes sets the optional feature_list_sparse_types attribute to value. -// -// value: A list of Nfeature_list_sparse types; the data types -// of data in each FeatureList given in feature_list_sparse_keys. -// Currently the ParseSingleSequenceExample supports DT_FLOAT (FloatList), -// DT_INT64 (Int64List), and DT_STRING (BytesList). -// If not specified, defaults to <> -// -// REQUIRES: len(value) >= 0 -func ParseSingleSequenceExampleFeatureListSparseTypes(value []tf.DataType) ParseSingleSequenceExampleAttr { - return func(m optionalAttr) { - m["feature_list_sparse_types"] = value - } -} - -// ParseSingleSequenceExampleFeatureListDenseShapes sets the optional feature_list_dense_shapes attribute to value. -// -// value: A list of Nfeature_list_dense shapes; the shapes of -// data in each FeatureList given in feature_list_dense_keys. -// The shape of each Feature in the FeatureList corresponding to -// feature_list_dense_key[j] must always equal -// feature_list_dense_shapes[j].NumEntries(). -// If not specified, defaults to <> -// -// REQUIRES: len(value) >= 0 -func ParseSingleSequenceExampleFeatureListDenseShapes(value []tf.Shape) ParseSingleSequenceExampleAttr { - return func(m optionalAttr) { - m["feature_list_dense_shapes"] = value - } -} - -// Transforms a scalar brain.SequenceExample proto (as strings) into typed tensors. -// -// Arguments: -// serialized: A scalar containing a binary serialized SequenceExample proto. -// feature_list_dense_missing_assumed_empty: A vector listing the -// FeatureList keys which may be missing from the SequenceExample. If the -// associated FeatureList is missing, it is treated as empty. By default, -// any FeatureList not listed in this vector must exist in the SequenceExample. -// context_sparse_keys: A list of Ncontext_sparse string Tensors (scalars). -// The keys expected in the Examples' features associated with context_sparse -// values. -// context_dense_keys: A list of Ncontext_dense string Tensors (scalars). -// The keys expected in the SequenceExamples' context features associated with -// dense values. -// feature_list_sparse_keys: A list of Nfeature_list_sparse string Tensors -// (scalars). The keys expected in the FeatureLists associated with sparse -// values. -// feature_list_dense_keys: A list of Nfeature_list_dense string Tensors (scalars). -// The keys expected in the SequenceExamples' feature_lists associated -// with lists of dense values. -// context_dense_defaults: A list of Ncontext_dense Tensors (some may be empty). -// context_dense_defaults[j] provides default values -// when the SequenceExample's context map lacks context_dense_key[j]. -// If an empty Tensor is provided for context_dense_defaults[j], -// then the Feature context_dense_keys[j] is required. -// The input type is inferred from context_dense_defaults[j], even when it's -// empty. If context_dense_defaults[j] is not empty, its shape must match -// context_dense_shapes[j]. -// debug_name: A scalar containing the name of the serialized proto. -// May contain, for example, table key (descriptive) name for the -// corresponding serialized proto. This is purely useful for debugging -// purposes, and the presence of values here has no effect on the output. -// May also be an empty scalar if no name is available. -func ParseSingleSequenceExample(scope *Scope, serialized tf.Output, feature_list_dense_missing_assumed_empty tf.Output, context_sparse_keys []tf.Output, context_dense_keys []tf.Output, feature_list_sparse_keys []tf.Output, feature_list_dense_keys []tf.Output, context_dense_defaults []tf.Output, debug_name tf.Output, optional ...ParseSingleSequenceExampleAttr) (context_sparse_indices []tf.Output, context_sparse_values []tf.Output, context_sparse_shapes []tf.Output, context_dense_values []tf.Output, feature_list_sparse_indices []tf.Output, feature_list_sparse_values []tf.Output, feature_list_sparse_shapes []tf.Output, feature_list_dense_values []tf.Output) { - if scope.Err() != nil { - return - } - attrs := map[string]interface{}{} - for _, a := range optional { - a(attrs) - } - opspec := tf.OpSpec{ - Type: "ParseSingleSequenceExample", - Input: []tf.Input{ - serialized, feature_list_dense_missing_assumed_empty, tf.OutputList(context_sparse_keys), tf.OutputList(context_dense_keys), tf.OutputList(feature_list_sparse_keys), tf.OutputList(feature_list_dense_keys), tf.OutputList(context_dense_defaults), debug_name, - }, - Attrs: attrs, - } - op := scope.AddOperation(opspec) - if scope.Err() != nil { - return - } - var idx int - var err error - if context_sparse_indices, idx, err = makeOutputList(op, idx, "context_sparse_indices"); err != nil { - scope.UpdateErr("ParseSingleSequenceExample", err) - return - } - if context_sparse_values, idx, err = makeOutputList(op, idx, "context_sparse_values"); err != nil { - scope.UpdateErr("ParseSingleSequenceExample", err) - return - } - if context_sparse_shapes, idx, err = makeOutputList(op, idx, "context_sparse_shapes"); err != nil { - scope.UpdateErr("ParseSingleSequenceExample", err) - return - } - if context_dense_values, idx, err = makeOutputList(op, idx, "context_dense_values"); err != nil { - scope.UpdateErr("ParseSingleSequenceExample", err) - return - } - if feature_list_sparse_indices, idx, err = makeOutputList(op, idx, "feature_list_sparse_indices"); err != nil { - scope.UpdateErr("ParseSingleSequenceExample", err) - return - } - if feature_list_sparse_values, idx, err = makeOutputList(op, idx, "feature_list_sparse_values"); err != nil { - scope.UpdateErr("ParseSingleSequenceExample", err) - return - } - if feature_list_sparse_shapes, idx, err = makeOutputList(op, idx, "feature_list_sparse_shapes"); err != nil { - scope.UpdateErr("ParseSingleSequenceExample", err) - return - } - if feature_list_dense_values, idx, err = makeOutputList(op, idx, "feature_list_dense_values"); err != nil { - scope.UpdateErr("ParseSingleSequenceExample", err) - return - } - return context_sparse_indices, context_sparse_values, context_sparse_shapes, context_dense_values, feature_list_sparse_indices, feature_list_sparse_values, feature_list_sparse_shapes, feature_list_dense_values -} - -// QuantizedConv2DAttr is an optional argument to QuantizedConv2D. -type QuantizedConv2DAttr func(optionalAttr) - -// QuantizedConv2DOutType sets the optional out_type attribute to value. -// If not specified, defaults to DT_QINT32 -func QuantizedConv2DOutType(value tf.DataType) QuantizedConv2DAttr { - return func(m optionalAttr) { - m["out_type"] = value - } -} - -// QuantizedConv2DDilations sets the optional dilations attribute to value. +// QuantizedConv2DDilations sets the optional dilations attribute to value. // // value: 1-D tensor of length 4. The dilation factor for each dimension of // `input`. If set to k > 1, there will be k-1 skipped cells between each @@ -18537,34 +18484,6 @@ func ReaderResetV2(scope *Scope, reader_handle tf.Output) (o *tf.Operation) { return scope.AddOperation(opspec) } -// Adjust the hue of one or more images. -// -// `images` is a tensor of at least 3 dimensions. The last dimension is -// interpretted as channels, and must be three. -// -// The input image is considered in the RGB colorspace. Conceptually, the RGB -// colors are first mapped into HSV. A delta is then applied all the hue values, -// and then remapped back to RGB colorspace. -// -// Arguments: -// images: Images to adjust. At least 3-D. -// delta: A float delta to add to the hue. -// -// Returns The hue-adjusted image or images. -func AdjustHue(scope *Scope, images tf.Output, delta tf.Output) (output tf.Output) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "AdjustHue", - Input: []tf.Input{ - images, delta, - }, - } - op := scope.AddOperation(opspec) - return op.Output(0) -} - // ResourceApplyAdamAttr is an optional argument to ResourceApplyAdam. type ResourceApplyAdamAttr func(optionalAttr) @@ -25550,34 +25469,274 @@ func RightShift(scope *Scope, x tf.Output, y tf.Output) (z tf.Output) { return op.Output(0) } -// DecodeWavAttr is an optional argument to DecodeWav. -type DecodeWavAttr func(optionalAttr) - -// DecodeWavDesiredChannels sets the optional desired_channels attribute to value. -// -// value: Number of sample channels wanted. -// If not specified, defaults to -1 -func DecodeWavDesiredChannels(value int64) DecodeWavAttr { - return func(m optionalAttr) { - m["desired_channels"] = value - } -} - -// DecodeWavDesiredSamples sets the optional desired_samples attribute to value. +// Adjust the hue of one or more images. // -// value: Length of audio requested. -// If not specified, defaults to -1 -func DecodeWavDesiredSamples(value int64) DecodeWavAttr { - return func(m optionalAttr) { - m["desired_samples"] = value - } -} - -// Decode a 16-bit PCM WAV file to a float tensor. +// `images` is a tensor of at least 3 dimensions. The last dimension is +// interpretted as channels, and must be three. // -// The -32768 to 32767 signed 16-bit values will be scaled to -1.0 to 1.0 in float. +// The input image is considered in the RGB colorspace. Conceptually, the RGB +// colors are first mapped into HSV. A delta is then applied all the hue values, +// and then remapped back to RGB colorspace. // -// When desired_channels is set, if the input contains fewer channels than this +// Arguments: +// images: Images to adjust. At least 3-D. +// delta: A float delta to add to the hue. +// +// Returns The hue-adjusted image or images. +func AdjustHue(scope *Scope, images tf.Output, delta tf.Output) (output tf.Output) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "AdjustHue", + Input: []tf.Input{ + images, delta, + }, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + +// AvgPool3DGradAttr is an optional argument to AvgPool3DGrad. +type AvgPool3DGradAttr func(optionalAttr) + +// AvgPool3DGradDataFormat sets the optional data_format attribute to value. +// +// value: The data format of the input and output data. With the +// default format "NDHWC", the data is stored in the order of: +// [batch, in_depth, in_height, in_width, in_channels]. +// Alternatively, the format could be "NCDHW", the data storage order is: +// [batch, in_channels, in_depth, in_height, in_width]. +// If not specified, defaults to "NDHWC" +func AvgPool3DGradDataFormat(value string) AvgPool3DGradAttr { + return func(m optionalAttr) { + m["data_format"] = value + } +} + +// Computes gradients of average pooling function. +// +// Arguments: +// orig_input_shape: The original input dimensions. +// grad: Output backprop of shape `[batch, depth, rows, cols, channels]`. +// ksize: 1-D tensor of length 5. The size of the window for each dimension of +// the input tensor. Must have `ksize[0] = ksize[4] = 1`. +// strides: 1-D tensor of length 5. The stride of the sliding window for each +// dimension of `input`. Must have `strides[0] = strides[4] = 1`. +// padding: The type of padding algorithm to use. +// +// Returns The backprop for input. +func AvgPool3DGrad(scope *Scope, orig_input_shape tf.Output, grad tf.Output, ksize []int64, strides []int64, padding string, optional ...AvgPool3DGradAttr) (output tf.Output) { + if scope.Err() != nil { + return + } + attrs := map[string]interface{}{"ksize": ksize, "strides": strides, "padding": padding} + for _, a := range optional { + a(attrs) + } + opspec := tf.OpSpec{ + Type: "AvgPool3DGrad", + Input: []tf.Input{ + orig_input_shape, grad, + }, + Attrs: attrs, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + +// ParseSingleSequenceExampleAttr is an optional argument to ParseSingleSequenceExample. +type ParseSingleSequenceExampleAttr func(optionalAttr) + +// ParseSingleSequenceExampleContextSparseTypes sets the optional context_sparse_types attribute to value. +// +// value: A list of Ncontext_sparse types; the data types of data in +// each context Feature given in context_sparse_keys. +// Currently the ParseSingleSequenceExample supports DT_FLOAT (FloatList), +// DT_INT64 (Int64List), and DT_STRING (BytesList). +// If not specified, defaults to <> +// +// REQUIRES: len(value) >= 0 +func ParseSingleSequenceExampleContextSparseTypes(value []tf.DataType) ParseSingleSequenceExampleAttr { + return func(m optionalAttr) { + m["context_sparse_types"] = value + } +} + +// ParseSingleSequenceExampleFeatureListDenseTypes sets the optional feature_list_dense_types attribute to value. +// If not specified, defaults to <> +// +// REQUIRES: len(value) >= 0 +func ParseSingleSequenceExampleFeatureListDenseTypes(value []tf.DataType) ParseSingleSequenceExampleAttr { + return func(m optionalAttr) { + m["feature_list_dense_types"] = value + } +} + +// ParseSingleSequenceExampleContextDenseShapes sets the optional context_dense_shapes attribute to value. +// +// value: A list of Ncontext_dense shapes; the shapes of data in +// each context Feature given in context_dense_keys. +// The number of elements in the Feature corresponding to context_dense_key[j] +// must always equal context_dense_shapes[j].NumEntries(). +// The shape of context_dense_values[j] will match context_dense_shapes[j]. +// If not specified, defaults to <> +// +// REQUIRES: len(value) >= 0 +func ParseSingleSequenceExampleContextDenseShapes(value []tf.Shape) ParseSingleSequenceExampleAttr { + return func(m optionalAttr) { + m["context_dense_shapes"] = value + } +} + +// ParseSingleSequenceExampleFeatureListSparseTypes sets the optional feature_list_sparse_types attribute to value. +// +// value: A list of Nfeature_list_sparse types; the data types +// of data in each FeatureList given in feature_list_sparse_keys. +// Currently the ParseSingleSequenceExample supports DT_FLOAT (FloatList), +// DT_INT64 (Int64List), and DT_STRING (BytesList). +// If not specified, defaults to <> +// +// REQUIRES: len(value) >= 0 +func ParseSingleSequenceExampleFeatureListSparseTypes(value []tf.DataType) ParseSingleSequenceExampleAttr { + return func(m optionalAttr) { + m["feature_list_sparse_types"] = value + } +} + +// ParseSingleSequenceExampleFeatureListDenseShapes sets the optional feature_list_dense_shapes attribute to value. +// +// value: A list of Nfeature_list_dense shapes; the shapes of +// data in each FeatureList given in feature_list_dense_keys. +// The shape of each Feature in the FeatureList corresponding to +// feature_list_dense_key[j] must always equal +// feature_list_dense_shapes[j].NumEntries(). +// If not specified, defaults to <> +// +// REQUIRES: len(value) >= 0 +func ParseSingleSequenceExampleFeatureListDenseShapes(value []tf.Shape) ParseSingleSequenceExampleAttr { + return func(m optionalAttr) { + m["feature_list_dense_shapes"] = value + } +} + +// Transforms a scalar brain.SequenceExample proto (as strings) into typed tensors. +// +// Arguments: +// serialized: A scalar containing a binary serialized SequenceExample proto. +// feature_list_dense_missing_assumed_empty: A vector listing the +// FeatureList keys which may be missing from the SequenceExample. If the +// associated FeatureList is missing, it is treated as empty. By default, +// any FeatureList not listed in this vector must exist in the SequenceExample. +// context_sparse_keys: A list of Ncontext_sparse string Tensors (scalars). +// The keys expected in the Examples' features associated with context_sparse +// values. +// context_dense_keys: A list of Ncontext_dense string Tensors (scalars). +// The keys expected in the SequenceExamples' context features associated with +// dense values. +// feature_list_sparse_keys: A list of Nfeature_list_sparse string Tensors +// (scalars). The keys expected in the FeatureLists associated with sparse +// values. +// feature_list_dense_keys: A list of Nfeature_list_dense string Tensors (scalars). +// The keys expected in the SequenceExamples' feature_lists associated +// with lists of dense values. +// context_dense_defaults: A list of Ncontext_dense Tensors (some may be empty). +// context_dense_defaults[j] provides default values +// when the SequenceExample's context map lacks context_dense_key[j]. +// If an empty Tensor is provided for context_dense_defaults[j], +// then the Feature context_dense_keys[j] is required. +// The input type is inferred from context_dense_defaults[j], even when it's +// empty. If context_dense_defaults[j] is not empty, its shape must match +// context_dense_shapes[j]. +// debug_name: A scalar containing the name of the serialized proto. +// May contain, for example, table key (descriptive) name for the +// corresponding serialized proto. This is purely useful for debugging +// purposes, and the presence of values here has no effect on the output. +// May also be an empty scalar if no name is available. +func ParseSingleSequenceExample(scope *Scope, serialized tf.Output, feature_list_dense_missing_assumed_empty tf.Output, context_sparse_keys []tf.Output, context_dense_keys []tf.Output, feature_list_sparse_keys []tf.Output, feature_list_dense_keys []tf.Output, context_dense_defaults []tf.Output, debug_name tf.Output, optional ...ParseSingleSequenceExampleAttr) (context_sparse_indices []tf.Output, context_sparse_values []tf.Output, context_sparse_shapes []tf.Output, context_dense_values []tf.Output, feature_list_sparse_indices []tf.Output, feature_list_sparse_values []tf.Output, feature_list_sparse_shapes []tf.Output, feature_list_dense_values []tf.Output) { + if scope.Err() != nil { + return + } + attrs := map[string]interface{}{} + for _, a := range optional { + a(attrs) + } + opspec := tf.OpSpec{ + Type: "ParseSingleSequenceExample", + Input: []tf.Input{ + serialized, feature_list_dense_missing_assumed_empty, tf.OutputList(context_sparse_keys), tf.OutputList(context_dense_keys), tf.OutputList(feature_list_sparse_keys), tf.OutputList(feature_list_dense_keys), tf.OutputList(context_dense_defaults), debug_name, + }, + Attrs: attrs, + } + op := scope.AddOperation(opspec) + if scope.Err() != nil { + return + } + var idx int + var err error + if context_sparse_indices, idx, err = makeOutputList(op, idx, "context_sparse_indices"); err != nil { + scope.UpdateErr("ParseSingleSequenceExample", err) + return + } + if context_sparse_values, idx, err = makeOutputList(op, idx, "context_sparse_values"); err != nil { + scope.UpdateErr("ParseSingleSequenceExample", err) + return + } + if context_sparse_shapes, idx, err = makeOutputList(op, idx, "context_sparse_shapes"); err != nil { + scope.UpdateErr("ParseSingleSequenceExample", err) + return + } + if context_dense_values, idx, err = makeOutputList(op, idx, "context_dense_values"); err != nil { + scope.UpdateErr("ParseSingleSequenceExample", err) + return + } + if feature_list_sparse_indices, idx, err = makeOutputList(op, idx, "feature_list_sparse_indices"); err != nil { + scope.UpdateErr("ParseSingleSequenceExample", err) + return + } + if feature_list_sparse_values, idx, err = makeOutputList(op, idx, "feature_list_sparse_values"); err != nil { + scope.UpdateErr("ParseSingleSequenceExample", err) + return + } + if feature_list_sparse_shapes, idx, err = makeOutputList(op, idx, "feature_list_sparse_shapes"); err != nil { + scope.UpdateErr("ParseSingleSequenceExample", err) + return + } + if feature_list_dense_values, idx, err = makeOutputList(op, idx, "feature_list_dense_values"); err != nil { + scope.UpdateErr("ParseSingleSequenceExample", err) + return + } + return context_sparse_indices, context_sparse_values, context_sparse_shapes, context_dense_values, feature_list_sparse_indices, feature_list_sparse_values, feature_list_sparse_shapes, feature_list_dense_values +} + +// DecodeWavAttr is an optional argument to DecodeWav. +type DecodeWavAttr func(optionalAttr) + +// DecodeWavDesiredChannels sets the optional desired_channels attribute to value. +// +// value: Number of sample channels wanted. +// If not specified, defaults to -1 +func DecodeWavDesiredChannels(value int64) DecodeWavAttr { + return func(m optionalAttr) { + m["desired_channels"] = value + } +} + +// DecodeWavDesiredSamples sets the optional desired_samples attribute to value. +// +// value: Length of audio requested. +// If not specified, defaults to -1 +func DecodeWavDesiredSamples(value int64) DecodeWavAttr { + return func(m optionalAttr) { + m["desired_samples"] = value + } +} + +// Decode a 16-bit PCM WAV file to a float tensor. +// +// The -32768 to 32767 signed 16-bit values will be scaled to -1.0 to 1.0 in float. +// +// When desired_channels is set, if the input contains fewer channels than this // then the last channel will be duplicated to give the requested number, else if // the input has more channels than requested then the additional channels will be // ignored. @@ -28178,162 +28337,3 @@ func FakeQuantWithMinMaxVarsPerChannelGradient(scope *Scope, gradients tf.Output op := scope.AddOperation(opspec) return op.Output(0), op.Output(1), op.Output(2) } - -// QuantizeV2Attr is an optional argument to QuantizeV2. -type QuantizeV2Attr func(optionalAttr) - -// QuantizeV2Mode sets the optional mode attribute to value. -// If not specified, defaults to "MIN_COMBINED" -func QuantizeV2Mode(value string) QuantizeV2Attr { - return func(m optionalAttr) { - m["mode"] = value - } -} - -// QuantizeV2RoundMode sets the optional round_mode attribute to value. -// If not specified, defaults to "HALF_AWAY_FROM_ZERO" -func QuantizeV2RoundMode(value string) QuantizeV2Attr { - return func(m optionalAttr) { - m["round_mode"] = value - } -} - -// Quantize the 'input' tensor of type float to 'output' tensor of type 'T'. -// -// [min_range, max_range] are scalar floats that specify the range for -// the 'input' data. The 'mode' attribute controls exactly which calculations are -// used to convert the float values to their quantized equivalents. The -// 'round_mode' attribute controls which rounding tie-breaking algorithm is used -// when rounding float values to their quantized equivalents. -// -// In 'MIN_COMBINED' mode, each value of the tensor will undergo the following: -// -// ``` -// out[i] = (in[i] - min_range) * range(T) / (max_range - min_range) -// if T == qint8, out[i] -= (range(T) + 1) / 2.0 -// ``` -// here `range(T) = numeric_limits::max() - numeric_limits::min()` -// -// *MIN_COMBINED Mode Example* -// -// Assume the input is type float and has a possible range of [0.0, 6.0] and the -// output type is quint8 ([0, 255]). The min_range and max_range values should be -// specified as 0.0 and 6.0. Quantizing from float to quint8 will multiply each -// value of the input by 255/6 and cast to quint8. -// -// If the output type was qint8 ([-128, 127]), the operation will additionally -// subtract each value by 128 prior to casting, so that the range of values aligns -// with the range of qint8. -// -// If the mode is 'MIN_FIRST', then this approach is used: -// -// ``` -// num_discrete_values = 1 << (# of bits in T) -// range_adjust = num_discrete_values / (num_discrete_values - 1) -// range = (range_max - range_min) * range_adjust -// range_scale = num_discrete_values / range -// quantized = round(input * range_scale) - round(range_min * range_scale) + -// numeric_limits::min() -// quantized = max(quantized, numeric_limits::min()) -// quantized = min(quantized, numeric_limits::max()) -// ``` -// -// The biggest difference between this and MIN_COMBINED is that the minimum range -// is rounded first, before it's subtracted from the rounded value. With -// MIN_COMBINED, a small bias is introduced where repeated iterations of quantizing -// and dequantizing will introduce a larger and larger error. -// -// *SCALED mode Example* -// -// `SCALED` mode matches the quantization approach used in -// `QuantizeAndDequantize{V2|V3}`. -// -// If the mode is `SCALED`, we do not use the full range of the output type, -// choosing to elide the lowest possible value for symmetry (e.g., output range is -// -127 to 127, not -128 to 127 for signed 8 bit quantization), so that 0.0 maps to -// 0. -// -// We first find the range of values in our tensor. The -// range we use is always centered on 0, so we find m such that -// ```c++ -// m = max(abs(input_min), abs(input_max)) -// ``` -// -// Our input tensor range is then `[-m, m]`. -// -// Next, we choose our fixed-point quantization buckets, `[min_fixed, max_fixed]`. -// If T is signed, this is -// ``` -// num_bits = sizeof(T) * 8 -// [min_fixed, max_fixed] = -// [-(1 << (num_bits - 1) - 1), (1 << (num_bits - 1)) - 1] -// ``` -// -// Otherwise, if T is unsigned, the fixed-point range is -// ``` -// [min_fixed, max_fixed] = [0, (1 << num_bits) - 1] -// ``` -// -// From this we compute our scaling factor, s: -// ```c++ -// s = (max_fixed - min_fixed) / (2 * m) -// ``` -// -// Now we can quantize the elements of our tensor: -// ```c++ -// result = round(input * s) -// ``` -// -// One thing to watch out for is that the operator may choose to adjust the -// requested minimum and maximum values slightly during the quantization process, -// so you should always use the output ports as the range for further calculations. -// For example, if the requested minimum and maximum values are close to equal, -// they will be separated by a small epsilon value to prevent ill-formed quantized -// buffers from being created. Otherwise, you can end up with buffers where all the -// quantized values map to the same float value, which causes problems for -// operations that have to perform further calculations on them. -// -// Arguments: -// -// min_range: The minimum scalar value possibly produced for the input. -// max_range: The maximum scalar value possibly produced for the input. -// -// -// Returns The quantized data produced from the float input.The actual minimum scalar value used for the output.The actual maximum scalar value used for the output. -func QuantizeV2(scope *Scope, input tf.Output, min_range tf.Output, max_range tf.Output, T tf.DataType, optional ...QuantizeV2Attr) (output tf.Output, output_min tf.Output, output_max tf.Output) { - if scope.Err() != nil { - return - } - attrs := map[string]interface{}{"T": T} - for _, a := range optional { - a(attrs) - } - opspec := tf.OpSpec{ - Type: "QuantizeV2", - Input: []tf.Input{ - input, min_range, max_range, - }, - Attrs: attrs, - } - op := scope.AddOperation(opspec) - return op.Output(0), op.Output(1), op.Output(2) -} - -// Flushes the writer's unwritten events. -// -// Arguments: -// writer: A handle to the summary writer resource. -// -// Returns the created operation. -func FlushSummaryWriter(scope *Scope, writer tf.Output) (o *tf.Operation) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "FlushSummaryWriter", - Input: []tf.Input{ - writer, - }, - } - return scope.AddOperation(opspec) -} -- GitLab From 07e6ca0ac7cdfcb6105fb3410fc68355c04df1d5 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Tue, 23 Jan 2018 13:12:40 -0800 Subject: [PATCH 129/258] Fix crash on GPU (out of GPU memory) for `softmax_cross_entropy_with_logits` (#16051) * Fix crash on GPU (out of GPU memory) for `softmax_cross_entropy_with_logits` This fix tries to address the issue raised in 6766 where `softmax_cross_entropy_with_logits` will trigger the crash on GPU (out of GPU memory) if the first dimension is 0. This fix fixes 6766. --- tensorflow/core/kernels/xent_op.cc | 10 ++++++---- tensorflow/python/kernel_tests/xent_op_test.py | 10 ++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tensorflow/core/kernels/xent_op.cc b/tensorflow/core/kernels/xent_op.cc index dc21cee3a8..0f8d027caa 100644 --- a/tensorflow/core/kernels/xent_op.cc +++ b/tensorflow/core/kernels/xent_op.cc @@ -67,10 +67,12 @@ class SoftmaxXentWithLogitsOp : public OpKernel { // Try to reuse the logits_in buffer for the backprop output. OP_REQUIRES_OK(context, context->forward_input_or_allocate_output( {0}, 1, logits_in.shape(), &back_out)); - functor::XentFunctor functor; - functor(context->eigen_device(), logits_in.matrix(), - labels_in.matrix(), scratch.matrix(), loss_out->vec(), - back_out->matrix()); + if (logits_in.dim_size(0) > 0) { + functor::XentFunctor functor; + functor(context->eigen_device(), logits_in.matrix(), + labels_in.matrix(), scratch.matrix(), loss_out->vec(), + back_out->matrix()); + } } }; diff --git a/tensorflow/python/kernel_tests/xent_op_test.py b/tensorflow/python/kernel_tests/xent_op_test.py index 43be08f8a1..c6c7c4e26c 100644 --- a/tensorflow/python/kernel_tests/xent_op_test.py +++ b/tensorflow/python/kernel_tests/xent_op_test.py @@ -240,6 +240,16 @@ class XentTest(test.TestCase): self._testXentWrapper(features, labels, dim=-1, use_gpu=False) self._testXentWrapper(features, labels, dim=-1, use_gpu=True) + def testZeroDimension(self): + features = np.zeros([0, 2, 4]).astype(np.float32) + labels = np.zeros([0, 2, 4]).astype(np.float32) + np_loss, _ = self._npXent(features, labels) + with self.test_session(use_gpu=True) as sess: + loss = nn_ops.softmax_cross_entropy_with_logits( + labels=labels, logits=features) + tf_loss = sess.run(loss) + self.assertAllEqual(np_loss, tf_loss) + if __name__ == "__main__": test.main() -- GitLab From 93da81caf6a9b24a1e3299655a51a03f4754cff6 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 13:12:00 -0800 Subject: [PATCH 130/258] Add a test case to validate number of buckets after quantile generation. Add an option to generate quantiles instead of sampled boundaries. This option will always return exactly the number of requested boundaries, regardless of duplicates and fewer inputs than requested boundaries. PiperOrigin-RevId: 182980861 --- tensorflow/contrib/boosted_trees/BUILD | 1 + .../boosted_trees/kernels/quantile_ops.cc | 27 ++++- .../contrib/boosted_trees/ops/quantile_ops.cc | 1 + .../python/kernel_tests/quantile_ops_test.py | 100 +++++++++++++++++- .../boosted_trees/python/ops/quantile_ops.py | 18 +++- .../resources/quantile_stream_resource.h | 16 ++- 6 files changed, 153 insertions(+), 10 deletions(-) diff --git a/tensorflow/contrib/boosted_trees/BUILD b/tensorflow/contrib/boosted_trees/BUILD index 392ac7fa1c..6fdcd0f996 100644 --- a/tensorflow/contrib/boosted_trees/BUILD +++ b/tensorflow/contrib/boosted_trees/BUILD @@ -196,6 +196,7 @@ py_test( name = "quantile_ops_test", size = "small", srcs = ["python/kernel_tests/quantile_ops_test.py"], + shard_count = 3, srcs_version = "PY2AND3", deps = [ ":quantile_ops_py", diff --git a/tensorflow/contrib/boosted_trees/kernels/quantile_ops.cc b/tensorflow/contrib/boosted_trees/kernels/quantile_ops.cc index 8600c8c53c..88f3006407 100644 --- a/tensorflow/contrib/boosted_trees/kernels/quantile_ops.cc +++ b/tensorflow/contrib/boosted_trees/kernels/quantile_ops.cc @@ -46,6 +46,7 @@ const char* const kHandleName = "handle"; const char* const kNextStampTokenName = "next_stamp_token"; const char* const kStampTokenName = "stamp_token"; const char* const kAreBucketsReadyName = "are_buckets_ready"; +const char* const kGenerateQuantiles = "generate_quantiles"; // Names for sparse arguments. const char* const kNumSparseFeaturesName = "num_sparse_features"; const char* const kSparseBucketsName = "sparse_buckets"; @@ -182,6 +183,16 @@ std::vector GenerateBoundaries(const QuantileStream& stream, return boundaries; } +// Generates quantiles on a finalized QuantileStream. +std::vector GenerateQuantiles(const QuantileStream& stream, + int num_quantiles) { + // Do not de-dup boundaries. Exactly num_quantiles+1 boundary values + // will be returned. + std::vector boundaries = stream.GenerateQuantiles(num_quantiles); + CHECK_EQ(boundaries.size(), num_quantiles + 1); + return boundaries; +} + // Copies quantiles to output list. void CopyBoundaries(OpKernelContext* const context, const std::vector& boundaries, const int64 index, @@ -224,6 +235,8 @@ class CreateQuantileAccumulatorOp : public OpKernel { OP_REQUIRES_OK(context, context->GetAttr(kNumQuantilesName, &num_quantiles_)); OP_REQUIRES_OK(context, context->GetAttr(kMaxElementsName, &max_elements_)); + OP_REQUIRES_OK(context, + context->GetAttr(kGenerateQuantiles, &generate_quantiles_)); } void Compute(OpKernelContext* context) override { @@ -231,9 +244,9 @@ class CreateQuantileAccumulatorOp : public OpKernel { // other exceptions. If one already exists, it unrefs the new one. const Tensor* stamp_token_t; OP_REQUIRES_OK(context, context->input(kStampTokenName, &stamp_token_t)); - auto result = - new QuantileStreamResource(epsilon_, num_quantiles_, max_elements_, - stamp_token_t->scalar()()); + auto result = new QuantileStreamResource(epsilon_, num_quantiles_, + max_elements_, generate_quantiles_, + stamp_token_t->scalar()()); auto status = CreateResource(context, HandleFromInput(context, 0), result); if (!status.ok() && status.code() != tensorflow::error::ALREADY_EXISTS) { OP_REQUIRES(context, false, status); @@ -246,6 +259,7 @@ class CreateQuantileAccumulatorOp : public OpKernel { // An upperbound on the number of enteries that the summaries might have // for a feature. int64 max_elements_; + bool generate_quantiles_; }; REGISTER_KERNEL_BUILDER(Name("CreateQuantileAccumulator").Device(DEVICE_CPU), @@ -597,10 +611,15 @@ class QuantileAccumulatorFlushOp : public OpKernel { << "Passed stamp token: " << stamp_token << " " << "Current token: " << streams_resource->stamp(); QuantileStream* stream = streams_resource->stream(stamp_token); + bool generate_quantiles = streams_resource->generate_quantiles(); stream->Finalize(); + streams_resource->set_boundaries( stamp_token, - GenerateBoundaries(*stream, streams_resource->num_quantiles())); + generate_quantiles + ? GenerateQuantiles(*stream, streams_resource->num_quantiles()) + : GenerateBoundaries(*stream, streams_resource->num_quantiles())); + streams_resource->Reset(next_stamp_token); } }; diff --git a/tensorflow/contrib/boosted_trees/ops/quantile_ops.cc b/tensorflow/contrib/boosted_trees/ops/quantile_ops.cc index 1fa70bafdd..bb57dcf8ae 100644 --- a/tensorflow/contrib/boosted_trees/ops/quantile_ops.cc +++ b/tensorflow/contrib/boosted_trees/ops/quantile_ops.cc @@ -39,6 +39,7 @@ REGISTER_OP("CreateQuantileAccumulator") .Attr("max_elements: int = 1099511627776") // 1 << 40 .Attr("epsilon: float") .Attr("num_quantiles: int") + .Attr("generate_quantiles: bool=False") .Input("quantile_accumulator_handle: resource") .Input("stamp_token: int64") .SetShapeFn([](shape_inference::InferenceContext* c) { diff --git a/tensorflow/contrib/boosted_trees/python/kernel_tests/quantile_ops_test.py b/tensorflow/contrib/boosted_trees/python/kernel_tests/quantile_ops_test.py index 888d5c57ed..eefa7ef0dc 100644 --- a/tensorflow/contrib/boosted_trees/python/kernel_tests/quantile_ops_test.py +++ b/tensorflow/contrib/boosted_trees/python/kernel_tests/quantile_ops_test.py @@ -106,9 +106,11 @@ class QuantileBucketsOpTest(test_util.TensorFlowTestCase): | 6 | 16 | [16, 17, 18, 19, 20, 21] """ + num_quantiles = 3 with self.test_session() as sess: accumulator = quantile_ops.QuantileAccumulator( - init_stamp_token=0, num_quantiles=3, epsilon=0.001, name="q1") + init_stamp_token=0, num_quantiles=num_quantiles, + epsilon=0.001, name="q1") resources.initialize_resources(resources.shared_resources()).run() input_column = array_ops.placeholder(dtypes.float32) weights = array_ops.placeholder(dtypes.float32) @@ -131,8 +133,104 @@ class QuantileBucketsOpTest(test_util.TensorFlowTestCase): buckets, are_ready_flush = (sess.run( [buckets, are_ready_flush])) self.assertEqual(True, are_ready_flush) + self.assertEqual(num_quantiles + 1, len(buckets)) self.assertAllEqual([1, 86., 170., 253.], buckets) + def testStreamingQuantileBucketsLowPrecisionInput(self): + """Tests inputs that simulate low precision float16 values.""" + + num_quantiles = 3 + # set generate_quantiles to True since the test will generate fewer + # boundaries otherwise. + with self.test_session() as sess: + accumulator = quantile_ops.QuantileAccumulator( + init_stamp_token=0, num_quantiles=num_quantiles, + epsilon=0.001, name="q1", generate_quantiles=True) + resources.initialize_resources(resources.shared_resources()).run() + input_column = array_ops.placeholder(dtypes.float32) + weights = array_ops.placeholder(dtypes.float32) + update = accumulator.add_summary( + stamp_token=0, + column=input_column, + example_weights=weights) + + with self.test_session() as sess: + # This input is generated by integer in the range [2030, 2060] + # but represented by with float16 precision. Integers <= 2048 are + # exactly represented, whereas numbers > 2048 are rounded; and hence + # numbers > 2048 are repeated. For precision loss / rounding, see: + # https://en.wikipedia.org/wiki/Half-precision_floating-point_format. + # + # The intent of the test is not handling of float16 values, but to + # validate the number of buckets is returned, in cases where the input + # may contain repeated values. + inputs = [ + 2030.0, 2031.0, 2032.0, 2033.0, 2034.0, 2035.0, 2036.0, 2037.0, + 2038.0, 2039.0, 2040.0, 2041.0, 2042.0, 2043.0, 2044.0, 2045.0, + 2046.0, 2047.0, 2048.0, 2048.0, 2050.0, 2052.0, 2052.0, 2052.0, + 2054.0, 2056.0, 2056.0, 2056.0, 2058.0, 2060.0 + ] + sess.run(update, + {input_column: inputs, + weights: [1] * len(inputs)}) + + with self.test_session() as sess: + sess.run(accumulator.flush(stamp_token=0, next_stamp_token=1)) + are_ready_flush, buckets = (accumulator.get_buckets(stamp_token=1)) + buckets, are_ready_flush = (sess.run( + [buckets, are_ready_flush])) + self.assertEqual(True, are_ready_flush) + self.assertEqual(num_quantiles + 1, len(buckets)) + self.assertAllEqual([2030, 2040, 2050, 2060], buckets) + + def _testStreamingQuantileBucketsHelper(self, inputs): + """Helper to test quantile buckets on different inputs.""" + + # Use 3 quantiles, 4 boundaries for simplicity. + num_quantiles = 3 + # set generate_quantiles to True since the test will generate fewer + # boundaries otherwise. + with self.test_session() as sess: + accumulator = quantile_ops.QuantileAccumulator( + init_stamp_token=0, num_quantiles=num_quantiles, + epsilon=0.001, name="q1", generate_quantiles=True) + resources.initialize_resources(resources.shared_resources()).run() + input_column = array_ops.placeholder(dtypes.float32) + weights = array_ops.placeholder(dtypes.float32) + update = accumulator.add_summary( + stamp_token=0, + column=input_column, + example_weights=weights) + + with self.test_session() as sess: + sess.run(update, + {input_column: inputs, + weights: [1] * len(inputs)}) + + with self.test_session() as sess: + sess.run(accumulator.flush(stamp_token=0, next_stamp_token=1)) + are_ready_flush, buckets = (accumulator.get_buckets(stamp_token=1)) + buckets, are_ready_flush = (sess.run( + [buckets, are_ready_flush])) + self.assertEqual(True, are_ready_flush) + self.assertEqual(num_quantiles + 1, len(buckets)) + + def testStreamingQuantileBucketsRepeatedSingleValue(self): + inputs = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + self._testStreamingQuantileBucketsHelper(inputs) + + def testStreamingQ2antileBucketsRepeatedTwoValues(self): + inputs = [1, 1, 1, 2, 2, 2, 2, 2, 1, 1] + self._testStreamingQuantileBucketsHelper(inputs) + + def testStreamingQ2antileBucketsRepeatedTwoValuesUnbalanced(self): + inputs = [7, 7, 7, 2, 7, 7, 2, 2, 7, 7] + self._testStreamingQuantileBucketsHelper(inputs) + + def testStreamingQuantileBucketsFewerInputstThanBuckets(self): + inputs = [5] + self._testStreamingQuantileBucketsHelper(inputs) + def testStreamingQuantileBuckets(self): """Sets up the quantile summary op test as follows. diff --git a/tensorflow/contrib/boosted_trees/python/ops/quantile_ops.py b/tensorflow/contrib/boosted_trees/python/ops/quantile_ops.py index 294e04002a..97d57e8b23 100644 --- a/tensorflow/contrib/boosted_trees/python/ops/quantile_ops.py +++ b/tensorflow/contrib/boosted_trees/python/ops/quantile_ops.py @@ -47,7 +47,8 @@ class QuantileAccumulator(saver.BaseSaverBuilder.SaveableObject): num_quantiles, max_elements=None, name=None, - container=None): + container=None, + generate_quantiles=False): """Creates a QuantileAccumulator object. Args: @@ -57,8 +58,11 @@ class QuantileAccumulator(saver.BaseSaverBuilder.SaveableObject): max_elements: Maximum number of elements added to the accumulator. name: the name to save the accumulator under. container: An optional `string`. Defaults to `""` + generate_quantiles: Generate quantiles instead of approximate boundaries. + If true, exactly `num_quantiles` will be produced in the final summary. """ self._epsilon = epsilon + self._generate_quantiles = generate_quantiles name = _PATTERN.sub("", name) with ops.name_scope(name, "QuantileAccumulator") as name: @@ -70,7 +74,8 @@ class QuantileAccumulator(saver.BaseSaverBuilder.SaveableObject): init_stamp_token, epsilon=epsilon, max_elements=max_elements, - num_quantiles=num_quantiles) + num_quantiles=num_quantiles, + generate_quantiles=generate_quantiles) is_initialized_op = gen_quantile_ops.quantile_accumulator_is_initialized( self._quantile_accumulator_handle) resources.register_resource(self._quantile_accumulator_handle, @@ -176,7 +181,14 @@ class QuantileAccumulator(saver.BaseSaverBuilder.SaveableObject): summaries=summary) def flush(self, stamp_token, next_stamp_token): - """Finalizes quantile summary stream and resets it for next iteration.""" + """Finalizes quantile summary stream and resets it for next iteration. + + Args: + stamp_token: Exepcted current token. + next_stamp_token: Next value for the token. + Returns: + A list of quantiles or approximate boundaries. + """ return gen_quantile_ops.quantile_accumulator_flush( quantile_accumulator_handle=self._quantile_accumulator_handle, stamp_token=stamp_token, diff --git a/tensorflow/contrib/boosted_trees/resources/quantile_stream_resource.h b/tensorflow/contrib/boosted_trees/resources/quantile_stream_resource.h index fb29f79e57..c1fa35eaf1 100644 --- a/tensorflow/contrib/boosted_trees/resources/quantile_stream_resource.h +++ b/tensorflow/contrib/boosted_trees/resources/quantile_stream_resource.h @@ -32,12 +32,14 @@ using QuantileStream = class QuantileStreamResource : public StampedResource { public: QuantileStreamResource(const float epsilon, const int32 num_quantiles, - const int64 max_elements, int64 stamp_token) + const int64 max_elements, bool generate_quantiles, + int64 stamp_token) : stream_(epsilon, max_elements), are_buckets_ready_(false), epsilon_(epsilon), num_quantiles_(num_quantiles), - max_elements_(max_elements) { + max_elements_(max_elements), + generate_quantiles_(generate_quantiles) { set_stamp(stamp_token); } @@ -74,6 +76,11 @@ class QuantileStreamResource : public StampedResource { are_buckets_ready_ = are_buckets_ready; } + bool generate_quantiles() const { return generate_quantiles_; } + void set_generate_quantiles(bool generate_quantiles) { + generate_quantiles_ = generate_quantiles; + } + private: ~QuantileStreamResource() override {} @@ -95,6 +102,11 @@ class QuantileStreamResource : public StampedResource { const int32 num_quantiles_; // An upper-bound for the number of elements. int64 max_elements_; + + // Generate quantiles instead of approximate boundaries. + // If true, exactly `num_quantiles` will be produced in the final summary. + bool generate_quantiles_; + TF_DISALLOW_COPY_AND_ASSIGN(QuantileStreamResource); }; -- GitLab From 8aa3253dbf881538d67e315e5ae6f1458d125416 Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Tue, 23 Jan 2018 13:35:08 -0800 Subject: [PATCH 131/258] Add support for conv and matmul operators with variable filter. PiperOrigin-RevId: 182984061 --- .../contrib/lite/testing/generate_examples.py | 173 ++++++++++++------ tensorflow/contrib/lite/toco/BUILD | 1 + .../convert_reorder_axes.cc | 149 +++++++++++++++ .../graph_transformations.h | 1 + tensorflow/contrib/lite/toco/toco_tooling.cc | 2 +- tensorflow/contrib/lite/toco/tooling_util.cc | 4 +- tensorflow/contrib/lite/toco/tooling_util.h | 5 + 7 files changed, 277 insertions(+), 58 deletions(-) create mode 100644 tensorflow/contrib/lite/toco/graph_transformations/convert_reorder_axes.cc diff --git a/tensorflow/contrib/lite/testing/generate_examples.py b/tensorflow/contrib/lite/testing/generate_examples.py index 9713532326..56e4dfc7a2 100644 --- a/tensorflow/contrib/lite/testing/generate_examples.py +++ b/tensorflow/contrib/lite/testing/generate_examples.py @@ -853,34 +853,55 @@ def make_fused_batch_norm_tests(zip_path): def make_conv_tests(zip_path): """Make a set of tests to do convolution.""" - test_parameters = [{ - "input_shape": [[1, 3, 4, 3]], - "filter_shape": [[1, 1, 3, 2]], - "strides": [[1, 1, 1, 1], [1, 2, 3, 1]], - "padding": ["SAME", "VALID"], - "data_format": ["NHWC"], # TODO(aselle): NCHW would be good - }, { - "input_shape": [[2, 14, 14, 2]], - "filter_shape": [[6, 6, 2, 2]], - "strides": [[1, 1, 1, 1], [1, 2, 3, 1]], - "padding": ["SAME", "VALID"], - "data_format": ["NHWC"], # TODO(aselle): NCHW would be good - }] + test_parameters = [ + { + "input_shape": [[1, 3, 4, 3]], + "filter_shape": [[1, 1, 3, 2]], + "strides": [[1, 1, 1, 1], [1, 2, 3, 1]], + "padding": ["SAME", "VALID"], + "data_format": ["NHWC"], # TODO(aselle): NCHW would be good + "constant_filter": [True, False], + }, + { + "input_shape": [[2, 14, 14, 2]], + "filter_shape": [[6, 6, 2, 2]], + "strides": [[1, 1, 1, 1], [1, 2, 3, 1]], + "padding": ["SAME", "VALID"], + "data_format": ["NHWC"], # TODO(aselle): NCHW would be good + "constant_filter": [True, False], + } + ] def build_graph(parameters): + """Build a conv graph given `parameters`.""" input_tensor = tf.placeholder( dtype=tf.float32, name="input", shape=parameters["input_shape"]) - filter_values = create_tensor_data(np.float32, parameters["filter_shape"]) - out = tf.nn.conv2d(input_tensor, filter_values, - strides=parameters["strides"], - padding=parameters["padding"], - data_format=parameters["data_format"]) - return [input_tensor], [out] + + # Get filter input either as a placeholder or constants. Also get a list of + # the input tensors that are represented as placeholders. + if parameters["constant_filter"]: + filter_input = create_tensor_data(np.float32, parameters["filter_shape"]) + input_tensors = [input_tensor] + else: + filter_input = tf.placeholder( + dtype=tf.float32, name="filter", shape=parameters["filter_shape"]) + input_tensors = [input_tensor, filter_input] + + out = tf.nn.conv2d( + input_tensor, + filter_input, + strides=parameters["strides"], + padding=parameters["padding"], + data_format=parameters["data_format"]) + return input_tensors, [out] def build_inputs(parameters, sess, inputs, outputs): - input_values = create_tensor_data(np.float32, parameters["input_shape"]) - return [input_values], sess.run( - outputs, feed_dict=dict(zip(inputs, [input_values]))) + # Build list of input values either containing 1 tensor (input) or 2 tensors + # (input, filter) based on whether filter is constant or variable input. + values = [create_tensor_data(np.float32, parameters["input_shape"])] + if not parameters["constant_filter"]: + values.append(create_tensor_data(np.float32, parameters["filter_shape"])) + return values, sess.run(outputs, feed_dict=dict(zip(inputs, values))) make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) @@ -889,45 +910,70 @@ def make_depthwiseconv_tests(zip_path): """Make a set of tests to do convolution.""" # Tensorflow only supports equal strides - test_parameters = [{ - "input_shape": [[1, 3, 4, 3], [1, 10, 10, 3]], - "filter_size": [[1, 1], [1, 2], [3, 3]], - "strides": [[1, 1, 1, 1], [1, 3, 3, 1]], - "channel_multiplier": [1, 2], - "rate": [[1, 1]], - "padding": ["SAME", "VALID"], - "data_format": ["NHWC"], - }, { - "input_shape": [[1, 3, 4, 3]], - "filter_size": [[1, 1]], - "strides": [[1, 1, 2, 1]], # TF needs [1, x, x, 1] - "channel_multiplier": [2], - "rate": [[2, 2]], # Only [1, 1] is supported - "padding": ["SAME"], - "data_format": ["NHWC"], - }] + test_parameters = [ + { + "input_shape": [[1, 3, 4, 3], [1, 10, 10, 3]], + "filter_size": [[1, 1], [1, 2], [3, 3]], + "strides": [[1, 1, 1, 1], [1, 3, 3, 1]], + "channel_multiplier": [1, 2], + "rate": [[1, 1]], + "padding": ["SAME", "VALID"], + "data_format": ["NHWC"], + "constant_filter": [True, False], + }, + { + "input_shape": [[1, 3, 4, 3]], + "filter_size": [[1, 1]], + "strides": [[1, 1, 2, 1]], # TF needs [1, x, x, 1] + "channel_multiplier": [2], + "rate": [[2, 2]], # Only [1, 1] is supported + "padding": ["SAME"], + "data_format": ["NHWC"], + "constant_filter": [True, False], + } + ] - def build_graph(parameters): - """Build a depthwise conv graph given `parameters`.""" + def get_tensor_shapes(parameters): input_shape = parameters["input_shape"] filter_size = parameters["filter_size"] + filter_shape = filter_size + [ + input_shape[3], parameters["channel_multiplier"] + ] + return [input_shape, filter_shape] + + def build_graph(parameters): + """Build a depthwise conv graph given `parameters`.""" + input_shape, filter_shape = get_tensor_shapes(parameters) input_tensor = tf.placeholder( dtype=tf.float32, name="input", shape=input_shape) - filter_shape = filter_size + [ - input_shape[3], parameters["channel_multiplier"]] - filter_values = create_tensor_data(np.float32, filter_shape) + + # Get filter input either as a placeholder or constants. Also get a list of + # the input tensors that are represented as placeholders. + if parameters["constant_filter"]: + filter_input = create_tensor_data(np.float32, filter_shape) + input_tensors = [input_tensor] + else: + filter_input = tf.placeholder( + dtype=tf.float32, name="filter", shape=filter_shape) + input_tensors = [input_tensor, filter_input] + out = tf.nn.depthwise_conv2d( - input_tensor, filter_values, + input_tensor, + filter_input, strides=parameters["strides"], rate=parameters["rate"], padding=parameters["padding"], data_format=parameters["data_format"]) - return [input_tensor], [out] + return input_tensors, [out] def build_inputs(parameters, sess, inputs, outputs): - input_values = create_tensor_data(np.float32, parameters["input_shape"]) - return [input_values], sess.run( - outputs, feed_dict=dict(zip(inputs, [input_values]))) + # Build list of input values either containing 1 tensor (input) or 2 tensors + # (input, filter) based on whether filter is constant or variable input. + input_shape, filter_shape = get_tensor_shapes(parameters) + values = [create_tensor_data(np.float32, input_shape)] + if not parameters["constant_filter"]: + values.append(create_tensor_data(np.float32, filter_shape)) + return values, sess.run(outputs, feed_dict=dict(zip(inputs, values))) make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) @@ -978,32 +1024,49 @@ def make_fully_connected_tests(zip_path): "shape2": [[3, 3]], "transpose_a": [True, False], "transpose_b": [True, False], + "constant_filter": [True, False], }, { "shape1": [[4, 4], [1, 4], [4]], "shape2": [[4, 4], [4, 1], [4]], "transpose_a": [False], "transpose_b": [False], + "constant_filter": [True, False], }, { "shape1": [[40, 37]], "shape2": [[37, 40]], "transpose_a": [False], "transpose_b": [False], - + "constant_filter": [True, False], }] def build_graph(parameters): + """Build a matmul graph given `parameters`.""" input_tensor1 = tf.placeholder(dtype=tf.float32, name="input1", shape=parameters["shape1"]) - input_tensor2 = create_tensor_data(np.float32, parameters["shape2"]) + + # Get input_tensor2 either as a placeholder or constants. Also get a list of + # the input tensors that are represented as placeholders. + if parameters["constant_filter"]: + input_tensor2 = create_tensor_data(np.float32, parameters["shape2"]) + input_tensors = [input_tensor1] + else: + input_tensor2 = tf.placeholder( + dtype=tf.float32, name="input2", shape=parameters["shape2"]) + input_tensors = [input_tensor1, input_tensor2] + out = tf.matmul(input_tensor1, input_tensor2, transpose_a=parameters["transpose_a"], transpose_b=parameters["transpose_b"]) - return [input_tensor1], [out] + return input_tensors, [out] def build_inputs(parameters, sess, inputs, outputs): - input_values1 = create_tensor_data(np.float32, shape=parameters["shape1"]) - return [input_values1], sess.run( - outputs, feed_dict=dict(zip(inputs, [input_values1]))) + # Build list of input values either containing 1 tensor (input_values1) or 2 + # tensors (input_values1, input_values2) based on whether the second input + # is a constant or variable input. + values = [create_tensor_data(np.float32, shape=parameters["shape1"])] + if not parameters["constant_filter"]: + values.append(create_tensor_data(np.float32, parameters["shape2"])) + return values, sess.run(outputs, feed_dict=dict(zip(inputs, values))) make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) diff --git a/tensorflow/contrib/lite/toco/BUILD b/tensorflow/contrib/lite/toco/BUILD index 967e304742..ad8f0e4a47 100644 --- a/tensorflow/contrib/lite/toco/BUILD +++ b/tensorflow/contrib/lite/toco/BUILD @@ -171,6 +171,7 @@ cc_library( srcs = [ "graph_transformations/convert_expanddims_to_reshape.cc", "graph_transformations/convert_pure_conv_to_depthwise.cc", + "graph_transformations/convert_reorder_axes.cc", "graph_transformations/convert_trivial_transpose_to_reshape.cc", "graph_transformations/create_im2col_arrays.cc", "graph_transformations/dequantize.cc", diff --git a/tensorflow/contrib/lite/toco/graph_transformations/convert_reorder_axes.cc b/tensorflow/contrib/lite/toco/graph_transformations/convert_reorder_axes.cc new file mode 100644 index 0000000000..0d274fc687 --- /dev/null +++ b/tensorflow/contrib/lite/toco/graph_transformations/convert_reorder_axes.cc @@ -0,0 +1,149 @@ +/* Copyright 2017 The TensorFlow Authors. 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 +#include +#include +#include + +#include "absl/strings/str_cat.h" +#include "tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h" +#include "tensorflow/contrib/lite/toco/model.h" +#include "tensorflow/contrib/lite/toco/tooling_util.h" +#include "tensorflow/core/platform/logging.h" + +namespace toco { + +// Creates a Reshape operator from ReorderAxes operator. +TensorFlowReshapeOperator* CreateReshapeFromReorderAxes( + Model* model, ReorderAxesOperator* reorder_op, const Shape& input_shape) { + auto* reshape_op = new TensorFlowReshapeOperator; + + // Copy inputs and outputs to Reshape. + reshape_op->inputs.push_back(reorder_op->inputs[0]); + reshape_op->outputs = reorder_op->outputs; + + // Create reshape dimensions based on input shape. Conversion from + // ReorderAxes to Reshape requires a 4D input shape. + CHECK_EQ(input_shape.dimensions_count(), 4); + std::vector reshape_dims = {1, input_shape.dims(0), input_shape.dims(1), + input_shape.dims(3) * input_shape.dims(2)}; + + // Create a new input array for Reshape. + string reshape_array_name = + AvailableArrayName(*model, reshape_op->outputs[0]); + reshape_op->inputs.push_back(reshape_array_name); + + Array& reshape_array = model->GetOrCreateArray(reshape_array_name); + *(reshape_array.mutable_shape()->mutable_dims()) = { + 1, static_cast(reshape_dims.size())}; + reshape_array.data_type = ArrayDataType::kInt32; + auto& reshape_buffer = + reshape_array.GetMutableBuffer(); + reshape_buffer.data = reshape_dims; + + return reshape_op; +} + +// Creates a Transpose operator from ReorderAxes operator. +TransposeOperator* CreateTransposeFromReorderAxes( + Model* model, ReorderAxesOperator* reorder_op, const Shape& input_shape, + const AxesOrder& input_axes_order, const AxesOrder& output_axes_order) { + auto* transpose_op = new TransposeOperator; + + // Copy inputs and outputs to Transpose. + transpose_op->inputs.push_back(reorder_op->inputs[0]); + transpose_op->outputs = reorder_op->outputs; + + // Create permutations data based on input and output axes order. + std::vector permutations_data; + GetShuffleShape(input_axes_order, output_axes_order, &permutations_data); + + // Create a new input permutations array for Transpose. + string perm_array_name = AvailableArrayName(*model, transpose_op->outputs[0]); + transpose_op->inputs.push_back(perm_array_name); + + Array& perm_array = model->GetOrCreateArray(perm_array_name); + *(perm_array.mutable_shape()->mutable_dims()) = { + static_cast(permutations_data.size())}; + perm_array.data_type = ArrayDataType::kInt32; + auto& perm_buffer = perm_array.GetMutableBuffer(); + perm_buffer.data = permutations_data; + + return transpose_op; +} + +// Converts ReorderAxes into Transpose and Reshape which are compatible with the +// TFLite interpreter. +bool ConvertReorderAxes::Run(Model* model, std::size_t op_index) { + auto reorder_it = model->operators.begin() + op_index; + if (reorder_it->get()->type != OperatorType::kReorderAxes) return false; + + auto* reorder_op = static_cast(reorder_it->get()); + CHECK_EQ(reorder_op->inputs.size(), 1); + CHECK_EQ(reorder_op->outputs.size(), 1); + + const auto& input_array_name = reorder_op->inputs[0]; + const auto& output_array_name = reorder_op->outputs[0]; + auto& input_array = model->GetArray(input_array_name); + auto& output_array = model->GetArray(output_array_name); + + // Get input array. If kFakeQuant is the input into ReorderAxes, get the input + // array passed into kFakeQuant. kFakeQuant op is dropped when possible. + string constant_input_array_name = input_array_name; + if (!input_array.buffer) { + const auto* op_producing_input = GetOpWithOutput(*model, input_array_name); + if (op_producing_input && + op_producing_input->type == OperatorType::kFakeQuant) { + constant_input_array_name = op_producing_input->inputs[0]; + } + } + + // Yield if input array contains constants or if output array size has not + // been adjusted to reflect the permutations in ReorderAxes. ReorderAxes will + // be merged into a constant array when possible. + if (IsConstantParameterArray(*model, constant_input_array_name)) return false; + if (!output_array.has_shape()) return false; + + const auto input_axes_order = reorder_op->input_axes_order; + const auto output_axes_order = reorder_op->output_axes_order; + const Shape input_shape = input_array.shape(); + + // Creates a Reshape or Transpose operator depending on the conversion. + if (input_axes_order == AxesOrder::kHWIM && + output_axes_order == AxesOrder::k1HWO) { + // Add Reshape operator into the graph. This special case is not just a + // permutation. The input dimensions get merged into 3 dimensions while the + // order of the elements does not change. + auto* reshape_op = + CreateReshapeFromReorderAxes(model, reorder_op, input_shape); + const auto reshape_it = model->operators.emplace(reorder_it, reshape_op); + reorder_it = reshape_it + 1; + } else { + // Add Transpose operator into the graph. + auto* transpose_op = CreateTransposeFromReorderAxes( + model, reorder_op, input_shape, input_axes_order, output_axes_order); + const auto transpose_it = + model->operators.emplace(reorder_it, transpose_op); + reorder_it = transpose_it + 1; + } + + // Remove ReorderAxes operator from the graph. + CHECK_EQ(reorder_it->get(), reorder_op); + model->operators.erase(reorder_it); + + return true; +} + +} // namespace toco diff --git a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h index 9ec9f92c90..d6950cf987 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h +++ b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h @@ -115,6 +115,7 @@ void RunGraphTransformations(Model* model, const string& message, DECLARE_GRAPH_TRANSFORMATION(ConvertExpandDimsToReshape) DECLARE_GRAPH_TRANSFORMATION(ConvertPureConvToDepthwise) DECLARE_GRAPH_TRANSFORMATION(ConvertTrivialTransposeToReshape) +DECLARE_GRAPH_TRANSFORMATION(ConvertReorderAxes) DECLARE_GRAPH_TRANSFORMATION(EnsureBiasVectors) DECLARE_GRAPH_TRANSFORMATION(FuseActivationFunctions) DECLARE_GRAPH_TRANSFORMATION(FuseBinaryIntoFollowingAffine) diff --git a/tensorflow/contrib/lite/toco/toco_tooling.cc b/tensorflow/contrib/lite/toco/toco_tooling.cc index afaa0fd0c7..f2753c84e9 100644 --- a/tensorflow/contrib/lite/toco/toco_tooling.cc +++ b/tensorflow/contrib/lite/toco/toco_tooling.cc @@ -53,6 +53,7 @@ void MakeGeneralGraphTransformationsSet( CHECK(transformations->empty()); transformations->Add(new ConvertExpandDimsToReshape); transformations->Add(new ConvertTrivialTransposeToReshape); + transformations->Add(new ConvertReorderAxes); transformations->Add(new ResolveReshapeAttributes); transformations->Add(new PropagateArrayDataTypes); transformations->Add(new PropagateFixedSizes); @@ -96,7 +97,6 @@ void MakeGeneralGraphTransformationsSet( bool SupportsQuantization(FileFormat format) { return (format == GRAPHVIZ_DOT || format == TFLITE); - ; } bool SupportsFusedActivationFunction(FileFormat format) { diff --git a/tensorflow/contrib/lite/toco/tooling_util.cc b/tensorflow/contrib/lite/toco/tooling_util.cc index 900c60bd90..8543ba4742 100644 --- a/tensorflow/contrib/lite/toco/tooling_util.cc +++ b/tensorflow/contrib/lite/toco/tooling_util.cc @@ -1463,8 +1463,6 @@ bool EstimateArithmeticOpsCount(const Model& model, int64* result) { return true; } -namespace { - void GetShuffleShape(AxesOrder input_axes_order, AxesOrder output_axes_order, std::vector* shuffle) { CHECK_EQ(AxesCount(input_axes_order), AxesCount(output_axes_order)); @@ -1499,6 +1497,8 @@ void GetShuffleShape(AxesOrder input_axes_order, AxesOrder output_axes_order, } } +namespace { + // Extend shuffle is designed to match ExtendShape, which pads the shape with // unit dimensions at the beginning. void ExtendShuffle(const std::vector& input_shuffle, int newdim, diff --git a/tensorflow/contrib/lite/toco/tooling_util.h b/tensorflow/contrib/lite/toco/tooling_util.h index c81e77874e..72fb0fd1a7 100644 --- a/tensorflow/contrib/lite/toco/tooling_util.h +++ b/tensorflow/contrib/lite/toco/tooling_util.h @@ -274,6 +274,11 @@ bool EstimateArithmeticOpsCount(const Model& model, int64* result); int AxesCount(AxesOrder axes_order); +// Returns the permutation of the dimensions based on the input axes order and +// output axes order. +void GetShuffleShape(AxesOrder input_axes_order, AxesOrder output_axes_order, + std::vector* shuffle); + void ShuffleDims(const Shape& input_shape, AxesOrder input_axes_order, AxesOrder output_axes_order, Shape* output_shape); void ShuffleArray(const Shape& input_shape, AxesOrder input_axes_order, -- GitLab From edc0be5f7ff5452c41cd0b968d751177ed8d8d13 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Wed, 24 Jan 2018 06:40:44 +0900 Subject: [PATCH 132/258] CMake: fix -fPIC control. (#15381) if / endif cannot be stated inside. Use tensorflow_ENABLE_POSITION_INDEPENDENT_CODE itself to express ON or OFF; it is already set as ON or OFF by tensorflow/contrib/cmake/CMakeLists.txt Fixes #15380 Signed-off-by: MyungJoo Ham --- tensorflow/contrib/cmake/external/snappy.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/cmake/external/snappy.cmake b/tensorflow/contrib/cmake/external/snappy.cmake index 013b3a862f..fd57734298 100644 --- a/tensorflow/contrib/cmake/external/snappy.cmake +++ b/tensorflow/contrib/cmake/external/snappy.cmake @@ -47,4 +47,4 @@ ExternalProject_Add(snappy ) # actually enables snappy in the source code -add_definitions(-DTF_USE_SNAPPY) \ No newline at end of file +add_definitions(-DTF_USE_SNAPPY) -- GitLab From dff64beac8570d910f83774087642bb6a3fda96a Mon Sep 17 00:00:00 2001 From: michaelkhan3 Date: Tue, 23 Jan 2018 21:46:25 +0000 Subject: [PATCH 133/258] Add property to get cell wrapped by DropoutWrapper (#16006) * add property to get cell wrapped by dropout * updating golden files --- .../contrib/rnn/python/kernel_tests/core_rnn_cell_test.py | 6 ++++++ tensorflow/python/ops/rnn_cell_impl.py | 4 ++++ .../golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py b/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py index b5d81b7caa..cafeb56ad8 100644 --- a/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py +++ b/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py @@ -663,6 +663,12 @@ class DropoutWrapperTest(test.TestCase): self.assertEqual(res[1].h.shape, (batch_size, 3)) return res + def testWrappedCellProperty(self): + cell = rnn_cell_impl.BasicRNNCell(10) + wrapper = rnn_cell_impl.DropoutWrapper(cell) + # Github issue 15810 + self.assertEqual(wrapper.wrapped_cell, cell) + def testDropoutWrapperKeepAllConstantInput(self): keep = array_ops.ones([]) res = self._testDropoutWrapper( diff --git a/tensorflow/python/ops/rnn_cell_impl.py b/tensorflow/python/ops/rnn_cell_impl.py index 1bf5551aff..f1ac3e9baf 100644 --- a/tensorflow/python/ops/rnn_cell_impl.py +++ b/tensorflow/python/ops/rnn_cell_impl.py @@ -987,6 +987,10 @@ class DropoutWrapper(RNNCell): string = (str(self._seed) + salt).encode("utf-8") return int(hashlib.md5(string).hexdigest()[:8], 16) & 0x7FFFFFFF + @property + def wrapped_cell(self): + return self._cell + @property def state_size(self): return self._cell.state_size diff --git a/tensorflow/tools/api/golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt b/tensorflow/tools/api/golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt index f61a5a28e3..97edf245f6 100644 --- a/tensorflow/tools/api/golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt @@ -88,6 +88,10 @@ tf_class { name: "weights" mtype: "" } + member { + name: "wrapped_cell" + mtype: "" + } member_method { name: "__init__" argspec: "args=[\'self\', \'cell\', \'input_keep_prob\', \'output_keep_prob\', \'state_keep_prob\', \'variational_recurrent\', \'input_size\', \'dtype\', \'seed\', \'dropout_state_filter_visitor\'], varargs=None, keywords=None, defaults=[\'1.0\', \'1.0\', \'1.0\', \'False\', \'None\', \'None\', \'None\', \'None\'], " -- GitLab From fa35e11bca893dde9177b6b9f8a335453ac97eee Mon Sep 17 00:00:00 2001 From: Yao Zhang Date: Tue, 23 Jan 2018 13:51:44 -0800 Subject: [PATCH 134/258] Fix StridedSlice. (1) Use input index instead of input name to make sure the naming is unique, because in rare cases, two inputs may connect to the same node. (2) Consecutive if statements each should have a return and should not fall through; this created un-wanted behavior. Use switch and break now. PiperOrigin-RevId: 182986609 --- .../grappler/optimizers/layout_optimizer.cc | 34 ++++++++-- .../optimizers/layout_optimizer_test.cc | 49 +++++++------ .../python/grappler/layout_optimizer_test.py | 68 ++++++++++++++----- 3 files changed, 101 insertions(+), 50 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/layout_optimizer.cc b/tensorflow/core/grappler/optimizers/layout_optimizer.cc index ea7b05d381..50e6ba4a64 100644 --- a/tensorflow/core/grappler/optimizers/layout_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/layout_optimizer.cc @@ -590,7 +590,7 @@ class NodeProcessor : public GraphProcessor { // to ensure added_node is in the same frame with node_. NodeDef* added_node = graph_->add_node(); *added_node = *input_node; - string base_name = strings::StrCat(node_->name(), "-", input_node->name()); + string base_name = strings::StrCat(node_->name(), "-", input_index); string node_name = LayoutOptimizerNode(base_name); added_node->set_name(node_name); *node_->mutable_input(input_index) = node_name; @@ -1647,12 +1647,32 @@ class StridedSliceProcessor : public SliceProcessor { return errors::InvalidArgument("invalid mask value: ", i); } if (i == 0 || i == 1 || i == 14 || i == 15) return Status::OK(); - if (i == 2 || i == 3) i += 2; - if (i == 4 || i == 5) i += 4; - if (i == 6 || i == 7) i += 6; - if (i == 8 || i == 9) i -= 6; - if (i == 10 || i == 11) i -= 4; - if (i == 12 || i == 13) i -= 2; + switch (i) { + case 2: + case 3: + i += 2; + break; + case 4: + case 5: + i += 4; + break; + case 6: + case 7: + i += 6; + break; + case 8: + case 9: + i -= 6; + break; + case 10: + case 11: + i -= 4; + break; + case 12: + case 13: + i -= 2; + break; + } node_->mutable_attr()->at(mask).set_i(i); return Status::OK(); } diff --git a/tensorflow/core/grappler/optimizers/layout_optimizer_test.cc b/tensorflow/core/grappler/optimizers/layout_optimizer_test.cc index 587642c96e..5cb366df2d 100644 --- a/tensorflow/core/grappler/optimizers/layout_optimizer_test.cc +++ b/tensorflow/core/grappler/optimizers/layout_optimizer_test.cc @@ -172,8 +172,7 @@ TEST_F(LayoutOptimizerTest, Conv2DBackpropInput) { Status status = optimizer.Optimize(virtual_cluster_.get(), item, &output); NodeMap node_map(&output); - string input_name = - strings::StrCat("Conv2DBackpropInput-InputSizes", "-", "LayoutOptimizer"); + string input_name = "Conv2DBackpropInput-0-LayoutOptimizer"; auto input_sizes_node = node_map.GetNode(input_name); CHECK(input_sizes_node); auto conv2d_backprop_node = node_map.GetNode("Conv2DBackpropInput"); @@ -288,7 +287,7 @@ TEST_F(LayoutOptimizerTest, Pad) { auto pad = node_map.GetNode("p"); EXPECT_EQ(pad->input(0), "Conv2D"); - auto pad_const = node_map.GetNode("p-c-LayoutOptimizer"); + auto pad_const = node_map.GetNode("p-1-LayoutOptimizer"); EXPECT_TRUE(pad_const); EXPECT_TRUE(pad_const->attr().find("value") != pad_const->attr().end()); Tensor tensor; @@ -476,9 +475,9 @@ TEST_F(LayoutOptimizerTest, SplitDimC) { Status status = optimizer.Optimize(virtual_cluster_.get(), item, &output); NodeMap node_map(&output); auto split_node = node_map.GetNode("split"); - EXPECT_EQ(split_node->input(0), "split-c-LayoutOptimizer"); + EXPECT_EQ(split_node->input(0), "split-0-LayoutOptimizer"); EXPECT_EQ(split_node->input(1), "Conv2D"); - auto split_const = node_map.GetNode("split-c-LayoutOptimizer"); + auto split_const = node_map.GetNode("split-0-LayoutOptimizer"); EXPECT_EQ(split_const->op(), "Const"); EXPECT_EQ(split_const->attr().at({"value"}).tensor().int_val(0), 1); } @@ -496,9 +495,9 @@ TEST_F(LayoutOptimizerTest, SplitDimH) { Status status = optimizer.Optimize(virtual_cluster_.get(), item, &output); NodeMap node_map(&output); auto split_node = node_map.GetNode("split"); - EXPECT_EQ(split_node->input(0), "split-c-LayoutOptimizer"); + EXPECT_EQ(split_node->input(0), "split-0-LayoutOptimizer"); EXPECT_EQ(split_node->input(1), "Conv2D"); - auto split_const = node_map.GetNode("split-c-LayoutOptimizer"); + auto split_const = node_map.GetNode("split-0-LayoutOptimizer"); EXPECT_EQ(split_const->op(), "Const"); EXPECT_EQ(split_const->attr().at({"value"}).tensor().int_val(0), 2); } @@ -516,9 +515,9 @@ TEST_F(LayoutOptimizerTest, SplitDimW) { Status status = optimizer.Optimize(virtual_cluster_.get(), item, &output); NodeMap node_map(&output); auto split_node = node_map.GetNode("split"); - EXPECT_EQ(split_node->input(0), "split-c-LayoutOptimizer"); + EXPECT_EQ(split_node->input(0), "split-0-LayoutOptimizer"); EXPECT_EQ(split_node->input(1), "Conv2D"); - auto split_const = node_map.GetNode("split-c-LayoutOptimizer"); + auto split_const = node_map.GetNode("split-0-LayoutOptimizer"); EXPECT_EQ(split_const->op(), "Const"); EXPECT_EQ(split_const->attr().at({"value"}).tensor().int_val(0), 3); } @@ -536,9 +535,9 @@ TEST_F(LayoutOptimizerTest, SplitDimN) { Status status = optimizer.Optimize(virtual_cluster_.get(), item, &output); NodeMap node_map(&output); auto split_node = node_map.GetNode("split"); - EXPECT_EQ(split_node->input(0), "split-c-LayoutOptimizer"); + EXPECT_EQ(split_node->input(0), "split-0-LayoutOptimizer"); EXPECT_EQ(split_node->input(1), "Conv2D"); - auto split_const = node_map.GetNode("split-c-LayoutOptimizer"); + auto split_const = node_map.GetNode("split-0-LayoutOptimizer"); EXPECT_EQ(split_const->op(), "Const"); EXPECT_EQ(split_const->attr().at({"value"}).tensor().int_val(0), 0); } @@ -582,8 +581,8 @@ TEST_F(LayoutOptimizerTest, SplitSamePortToMultipleInputsOfSameNode) { EXPECT_EQ(concat_node->input(0), "split:1"); EXPECT_EQ(concat_node->input(1), "split:1"); EXPECT_EQ(concat_node->input(2), "split:1"); - EXPECT_EQ(concat_node->input(3), "concat-axis-LayoutOptimizer"); - auto concat_dim = node_map.GetNode("concat-axis-LayoutOptimizer"); + EXPECT_EQ(concat_node->input(3), "concat-3-LayoutOptimizer"); + auto concat_dim = node_map.GetNode("concat-3-LayoutOptimizer"); EXPECT_EQ(concat_dim->attr().at({"value"}).tensor().int_val(0), 1); } @@ -603,8 +602,8 @@ TEST_F(LayoutOptimizerTest, ConcatDimH) { auto concat_node = node_map.GetNode("concat"); EXPECT_EQ(concat_node->input(0), "split"); EXPECT_EQ(concat_node->input(1), "split:1"); - EXPECT_EQ(concat_node->input(2), "concat-axis-LayoutOptimizer"); - auto concat_dim = node_map.GetNode("concat-axis-LayoutOptimizer"); + EXPECT_EQ(concat_node->input(2), "concat-2-LayoutOptimizer"); + auto concat_dim = node_map.GetNode("concat-2-LayoutOptimizer"); EXPECT_EQ(concat_dim->attr().at({"value"}).tensor().int_val(0), 2); } @@ -648,8 +647,8 @@ TEST_F(LayoutOptimizerTest, ConcatDimW) { auto concat_node = node_map.GetNode("concat"); EXPECT_EQ(concat_node->input(0), "split"); EXPECT_EQ(concat_node->input(1), "split:1"); - EXPECT_EQ(concat_node->input(2), "concat-axis-LayoutOptimizer"); - auto concat_dim = node_map.GetNode("concat-axis-LayoutOptimizer"); + EXPECT_EQ(concat_node->input(2), "concat-2-LayoutOptimizer"); + auto concat_dim = node_map.GetNode("concat-2-LayoutOptimizer"); EXPECT_EQ(concat_dim->attr().at({"value"}).tensor().int_val(0), 3); } @@ -669,8 +668,8 @@ TEST_F(LayoutOptimizerTest, ConcatDimN) { auto concat_node = node_map.GetNode("concat"); EXPECT_EQ(concat_node->input(0), "split"); EXPECT_EQ(concat_node->input(1), "split:1"); - EXPECT_EQ(concat_node->input(2), "concat-axis-LayoutOptimizer"); - auto concat_dim = node_map.GetNode("concat-axis-LayoutOptimizer"); + EXPECT_EQ(concat_node->input(2), "concat-2-LayoutOptimizer"); + auto concat_dim = node_map.GetNode("concat-2-LayoutOptimizer"); EXPECT_EQ(concat_dim->attr().at({"value"}).tensor().int_val(0), 0); } @@ -690,8 +689,8 @@ TEST_F(LayoutOptimizerTest, ConcatDimC) { auto concat_node = node_map.GetNode("concat"); EXPECT_EQ(concat_node->input(0), "split"); EXPECT_EQ(concat_node->input(1), "split:1"); - EXPECT_EQ(concat_node->input(2), "concat-axis-LayoutOptimizer"); - auto concat_dim = node_map.GetNode("concat-axis-LayoutOptimizer"); + EXPECT_EQ(concat_node->input(2), "concat-2-LayoutOptimizer"); + auto concat_dim = node_map.GetNode("concat-2-LayoutOptimizer"); EXPECT_EQ(concat_dim->attr().at({"value"}).tensor().int_val(0), 1); } @@ -861,10 +860,10 @@ TEST_F(LayoutOptimizerTest, SliceConst) { NodeMap node_map(&output); auto slice_node = node_map.GetNode("slice"); EXPECT_EQ(slice_node->input(0), "Conv2D"); - EXPECT_EQ(slice_node->input(1), "slice-begin-LayoutOptimizer"); - EXPECT_EQ(slice_node->input(2), "slice-size-LayoutOptimizer"); + EXPECT_EQ(slice_node->input(1), "slice-1-LayoutOptimizer"); + EXPECT_EQ(slice_node->input(2), "slice-2-LayoutOptimizer"); - auto begin_const = node_map.GetNode("slice-begin-LayoutOptimizer"); + auto begin_const = node_map.GetNode("slice-1-LayoutOptimizer"); Tensor begin_tensor; EXPECT_TRUE(begin_tensor.FromProto( begin_const->mutable_attr()->at({"value"}).tensor())); @@ -872,7 +871,7 @@ TEST_F(LayoutOptimizerTest, SliceConst) { test::FillValues(&begin_tensor_expected, {0, 1, 2, 3}); test::ExpectTensorEqual(begin_tensor_expected, begin_tensor); - auto size_const = node_map.GetNode("slice-size-LayoutOptimizer"); + auto size_const = node_map.GetNode("slice-2-LayoutOptimizer"); Tensor size_tensor; EXPECT_TRUE(size_tensor.FromProto( size_const->mutable_attr()->at({"value"}).tensor())); diff --git a/tensorflow/python/grappler/layout_optimizer_test.py b/tensorflow/python/grappler/layout_optimizer_test.py index 25c5ef6b68..578f86ca5a 100644 --- a/tensorflow/python/grappler/layout_optimizer_test.py +++ b/tensorflow/python/grappler/layout_optimizer_test.py @@ -376,7 +376,7 @@ class LayoutOptimizerTest(test.TestCase): self.assertEqual(expected_num_transposes, num_transposes) self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('Pad-0-0', nodes) - self.assertIn('Pad-PaddingsConst-LayoutOptimizer', nodes) + self.assertIn('Pad-1-LayoutOptimizer', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) def testReduceSum(self): @@ -587,7 +587,7 @@ class LayoutOptimizerTest(test.TestCase): self.assertEqual(expected_num_transposes, num_transposes) self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('concat-0-0', nodes) - self.assertIn('concat-Const_2-LayoutOptimizer', nodes) + self.assertIn('concat-2-LayoutOptimizer', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) def testFill(self): @@ -698,7 +698,7 @@ class LayoutOptimizerTest(test.TestCase): self.assertEqual(expected_num_transposes, num_transposes) self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('ReverseV2-0-0', nodes) - self.assertIn('ReverseV2-DimsConst-LayoutOptimizer', nodes) + self.assertIn('ReverseV2-1-LayoutOptimizer', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) def testReverseWithNonConstDims(self): @@ -867,7 +867,7 @@ class LayoutOptimizerTest(test.TestCase): self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('MaxPoolV2-0-0', nodes) self._assert_vec_nhwc_to_nchw('MaxPoolV2-2', nodes) - self.assertIn('MaxPoolV2-Const_2-LayoutOptimizer', nodes) + self.assertIn('MaxPoolV2-1-LayoutOptimizer', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) def testMaxPoolGradV2(self): @@ -904,7 +904,7 @@ class LayoutOptimizerTest(test.TestCase): self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('MaxPoolGradV2-0-0', nodes) self._assert_vec_nhwc_to_nchw('MaxPoolGradV2-4', nodes) - self.assertIn('MaxPoolGradV2-Const_2-LayoutOptimizer', nodes) + self.assertIn('MaxPoolGradV2-3-LayoutOptimizer', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) def testSliceWithNonConstAxis(self): @@ -977,16 +977,17 @@ class LayoutOptimizerTest(test.TestCase): self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('StridedSlice-0-0', nodes) self._assert_vec_nhwc_to_nchw('StridedSlice-2', nodes) - self.assertIn('StridedSlice-StridedSlice/begin-LayoutOptimizer', nodes) - self.assertIn('StridedSlice-StridedSlice/strides-LayoutOptimizer', nodes) + self.assertIn('StridedSlice-1-LayoutOptimizer', nodes) + self.assertIn('StridedSlice-3-LayoutOptimizer', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) - def testStridedSliceWithMask(self): + def testStridedSliceWithMask1011(self): if test.is_gpu_available(cuda_only=True): random_seed.set_random_seed(0) x = random_ops.truncated_normal([1, 784], seed=0) conv = _two_layer_model(x) - # This will generate a StridedSlice op with begin mask and end mask. + # This will generate a StridedSlice op with begin mask and + # end mask 11(1011). s = conv[:, :, 1:-1, :] output = array_ops.identity(s) @@ -1010,11 +1011,44 @@ class LayoutOptimizerTest(test.TestCase): self.assertEqual(expected_num_transposes, num_transposes) self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('strided_slice-0-0', nodes) - self.assertIn('strided_slice-strided_slice/stack-LayoutOptimizer', nodes) - self.assertIn('strided_slice-strided_slice/stack_1-LayoutOptimizer', - nodes) - self.assertIn('strided_slice-strided_slice/stack_2-LayoutOptimizer', - nodes) + self.assertIn('strided_slice-1-LayoutOptimizer', nodes) + self.assertIn('strided_slice-2-LayoutOptimizer', nodes) + self.assertIn('strided_slice-3-LayoutOptimizer', nodes) + self.assertAllClose(output_val_ref, output_val, atol=1e-3) + + def testStridedSliceWithMask0111(self): + if test.is_gpu_available(cuda_only=True): + random_seed.set_random_seed(0) + x = random_ops.truncated_normal([1, 784], seed=0) + conv = _two_layer_model(x) + # This will generate a StridedSlice op with begin mask and + # end mask 7(0111). + s = conv[:, :, :, 1:-1] + output = array_ops.identity(s) + + with session.Session() as sess: + output_val_ref = sess.run(output) + + with session.Session(config=_get_config()) as sess: + metadata = config_pb2.RunMetadata() + output_val = sess.run(output, run_metadata=metadata) + + nodes = [] + num_transposes = 0 + for node in metadata.cost_graph.node: + if _is_transpose(node.name): + num_transposes += 1 + nodes.append(node.name) + + # Four transposes were initially added in the Expand phase of + # LayoutOptimizer; two of them are cancelled out in the Collapse phase. + expected_num_transposes = 2 + self.assertEqual(expected_num_transposes, num_transposes) + self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) + self._assert_trans_nchw_to_nhwc('strided_slice-0-0', nodes) + self.assertIn('strided_slice-1-LayoutOptimizer', nodes) + self.assertIn('strided_slice-2-LayoutOptimizer', nodes) + self.assertIn('strided_slice-3-LayoutOptimizer', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) def testStridedSliceGradWithNonConstAxis(self): @@ -1055,10 +1089,8 @@ class LayoutOptimizerTest(test.TestCase): self._assert_trans_nhwc_to_nchw('Conv2D-0', nodes) self._assert_trans_nchw_to_nhwc('StridedSliceGrad-0-0', nodes) self._assert_vec_nhwc_to_nchw('StridedSliceGrad-2', nodes) - self.assertIn('StridedSlice-StridedSliceGrad/begin-LayoutOptimizer', - nodes) - self.assertIn('StridedSlice-StridedSliceGrad/strides-LayoutOptimizer', - nodes) + self.assertIn('StridedSlice-1-LayoutOptimizer', nodes) + self.assertIn('StridedSlice-2-LayoutOptimizer', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) def testShapeN(self): -- GitLab From d50f68df6d1e4e41f4486ee71626454f6bd3ffe4 Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Tue, 23 Jan 2018 14:06:13 -0800 Subject: [PATCH 135/258] C API: don't return source/sink control edges. PiperOrigin-RevId: 182989157 --- tensorflow/c/c_api.cc | 14 ++++++++++---- tensorflow/c/c_api_test.cc | 31 ++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/tensorflow/c/c_api.cc b/tensorflow/c/c_api.cc index 6fc75a98f1..92c9adbec7 100644 --- a/tensorflow/c/c_api.cc +++ b/tensorflow/c/c_api.cc @@ -1469,7 +1469,13 @@ int TF_OperationOutputConsumers(TF_Output oper_out, TF_Input* consumers, } int TF_OperationNumControlInputs(TF_Operation* oper) { - return oper->node.in_edges().size() - oper->node.num_inputs(); + int count = 0; + for (const auto* edge : oper->node.in_edges()) { + if (edge->IsControlEdge() && !edge->src()->IsSource()) { + ++count; + } + } + return count; } int TF_OperationGetControlInputs(TF_Operation* oper, @@ -1477,7 +1483,7 @@ int TF_OperationGetControlInputs(TF_Operation* oper, int max_control_inputs) { int count = 0; for (const auto* edge : oper->node.in_edges()) { - if (edge->IsControlEdge()) { + if (edge->IsControlEdge() && !edge->src()->IsSource()) { if (count < max_control_inputs) { control_inputs[count] = ToOperation(edge->src()); } @@ -1490,7 +1496,7 @@ int TF_OperationGetControlInputs(TF_Operation* oper, int TF_OperationNumControlOutputs(TF_Operation* oper) { int count = 0; for (const auto* edge : oper->node.out_edges()) { - if (edge->IsControlEdge()) { + if (edge->IsControlEdge() && !edge->dst()->IsSink()) { ++count; } } @@ -1502,7 +1508,7 @@ int TF_OperationGetControlOutputs(TF_Operation* oper, int max_control_outputs) { int count = 0; for (const auto* edge : oper->node.out_edges()) { - if (edge->IsControlEdge()) { + if (edge->IsControlEdge() && !edge->dst()->IsSink()) { if (count < max_control_outputs) { control_outputs[count] = ToOperation(edge->dst()); } diff --git a/tensorflow/c/c_api_test.cc b/tensorflow/c/c_api_test.cc index df697e16d3..01954eb235 100644 --- a/tensorflow/c/c_api_test.cc +++ b/tensorflow/c/c_api_test.cc @@ -575,7 +575,7 @@ TEST(CAPI, ImportGraphDef) { TF_Status* s = TF_NewStatus(); TF_Graph* graph = TF_NewGraph(); - // Create a graph with two nodes: x and 3 + // Create a simple graph. Placeholder(graph, s); ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s); ASSERT_TRUE(TF_GraphOperationByName(graph, "feed") != nullptr); @@ -586,7 +586,7 @@ TEST(CAPI, ImportGraphDef) { ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s); ASSERT_TRUE(TF_GraphOperationByName(graph, "neg") != nullptr); - // Export to a GraphDef + // Export to a GraphDef. TF_Buffer* graph_def = TF_NewBuffer(); TF_GraphToGraphDef(graph, graph_def, s); ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s); @@ -606,6 +606,31 @@ TEST(CAPI, ImportGraphDef) { ASSERT_TRUE(feed != nullptr); ASSERT_TRUE(neg != nullptr); + // Test basic structure of the imported graph. + EXPECT_EQ(0, TF_OperationNumInputs(scalar)); + EXPECT_EQ(0, TF_OperationNumInputs(feed)); + ASSERT_EQ(1, TF_OperationNumInputs(neg)); + TF_Output neg_input = TF_OperationInput({neg, 0}); + EXPECT_EQ(scalar, neg_input.oper); + EXPECT_EQ(0, neg_input.index); + + // Test that we can't see control edges involving the source and sink nodes. + TF_Operation* control_ops[100]; + EXPECT_EQ(0, TF_OperationNumControlInputs(scalar)); + EXPECT_EQ(0, TF_OperationGetControlInputs(scalar, control_ops, 100)); + EXPECT_EQ(0, TF_OperationNumControlOutputs(scalar)); + EXPECT_EQ(0, TF_OperationGetControlOutputs(scalar, control_ops, 100)); + + EXPECT_EQ(0, TF_OperationNumControlInputs(feed)); + EXPECT_EQ(0, TF_OperationGetControlInputs(feed, control_ops, 100)); + EXPECT_EQ(0, TF_OperationNumControlOutputs(feed)); + EXPECT_EQ(0, TF_OperationGetControlOutputs(feed, control_ops, 100)); + + EXPECT_EQ(0, TF_OperationNumControlInputs(neg)); + EXPECT_EQ(0, TF_OperationGetControlInputs(neg, control_ops, 100)); + EXPECT_EQ(0, TF_OperationNumControlOutputs(neg)); + EXPECT_EQ(0, TF_OperationGetControlOutputs(neg, control_ops, 100)); + // Import it again, with an input mapping, return outputs, and a return // operation, into the same graph. TF_DeleteImportGraphDefOptions(opts); @@ -629,7 +654,7 @@ TEST(CAPI, ImportGraphDef) { ASSERT_TRUE(neg2 != nullptr); // Check input mapping - TF_Output neg_input = TF_OperationInput({neg, 0}); + neg_input = TF_OperationInput({neg, 0}); EXPECT_EQ(scalar, neg_input.oper); EXPECT_EQ(0, neg_input.index); -- GitLab From 634959be3220bf9263b1fac33ce41a0869fdc010 Mon Sep 17 00:00:00 2001 From: Amit Patankar Date: Tue, 23 Jan 2018 14:24:53 -0800 Subject: [PATCH 136/258] Updating the update_version script to act appropriately for rc0 when it comes to the install sources tested configurations table along with a warning. Using perl rather than sed as it supports regex look behind. PiperOrigin-RevId: 182992467 --- tensorflow/tools/ci_build/update_version.py | 110 +++++++++++--------- 1 file changed, 61 insertions(+), 49 deletions(-) diff --git a/tensorflow/tools/ci_build/update_version.py b/tensorflow/tools/ci_build/update_version.py index d2a63e5d66..347d0769a9 100755 --- a/tensorflow/tools/ci_build/update_version.py +++ b/tensorflow/tools/ci_build/update_version.py @@ -25,19 +25,19 @@ # pylint: disable=superfluous-parens import argparse -import fileinput import os import re import subprocess import time -# File parameters +# File parameters. TF_SRC_DIR = "tensorflow" VERSION_H = "%s/core/public/version.h" % TF_SRC_DIR SETUP_PY = "%s/tools/pip_package/setup.py" % TF_SRC_DIR README_MD = "./README.md" DEVEL_DOCKERFILE = "%s/tools/docker/Dockerfile.devel" % TF_SRC_DIR GPU_DEVEL_DOCKERFILE = "%s/tools/docker/Dockerfile.devel-gpu" % TF_SRC_DIR +CPU_MKL_DEVEL_DOCKERFILE = "%s/tools/docker/Dockerfile.devel-cpu-mkl" % TF_SRC_DIR RELEVANT_FILES = [TF_SRC_DIR, VERSION_H, SETUP_PY, @@ -45,17 +45,11 @@ RELEVANT_FILES = [TF_SRC_DIR, DEVEL_DOCKERFILE, GPU_DEVEL_DOCKERFILE] -# Version type parameters +# Version type parameters. NIGHTLY_VERSION = 1 REGULAR_VERSION = 0 -def replace_line(old_line, new_line, filename): - """Replace a line in a file.""" - for line in fileinput.input(filename, inplace=True): - print(line.rstrip().replace(old_line, new_line)) - - def check_existence(filename): """Check the existence of file or dir.""" if not os.path.exists(filename): @@ -69,9 +63,12 @@ def check_all_files(): check_existence(file_name) -def replace_with_sed(query, filename): +def replace_string_in_line(search, replace, filename): """Replace with sed when regex is required.""" - subprocess.check_call(['sed', '-i', '-r', '-e', query, filename]) + with open(filename, "r") as source: + content = source.read() + with open(filename, "w") as source: + source.write(re.sub(search, replace, content)) class Version(object): @@ -125,13 +122,13 @@ class Version(object): Raises: RuntimeError: If the version string is not valid. """ - # Check validity of new version string + # Check validity of new version string. if not re.search(r"[0-9]+\.[0-9]+\.[a-zA-Z0-9]+", string): raise RuntimeError("Invalid version string: %s" % string) major, minor, extension = string.split(".", 2) - # Isolate patch and identifier string if identifier string exists + # Isolate patch and identifier string if identifier string exists. extension_split = extension.split("-", 1) patch = extension_split[0] if len(extension_split) == 2: @@ -154,7 +151,7 @@ def get_current_semver_version(): core/public/version.h """ - # Get current version information + # Get current version information. version_file = open(VERSION_H, "r") for line in version_file: major_match = re.search("^#define TF_MAJOR_VERSION ([0-9]+)", line) @@ -185,32 +182,33 @@ def get_current_semver_version(): def update_version_h(old_version, new_version): """Update tensorflow/core/public/version.h.""" - replace_line("#define TF_MAJOR_VERSION %s" % old_version.major, - "#define TF_MAJOR_VERSION %s" % new_version.major, VERSION_H) - replace_line("#define TF_MINOR_VERSION %s" % old_version.minor, - "#define TF_MINOR_VERSION %s" % new_version.minor, VERSION_H) - replace_line("#define TF_PATCH_VERSION %s" % old_version.patch, - "#define TF_PATCH_VERSION %s" % new_version.patch, VERSION_H) - replace_line("#define TF_VERSION_SUFFIX \"%s\"" % - old_version.identifier_string, - "#define TF_VERSION_SUFFIX \"%s\"" - % new_version.identifier_string, - VERSION_H) + replace_string_in_line("#define TF_MAJOR_VERSION %s" % old_version.major, + "#define TF_MAJOR_VERSION %s" % new_version.major, + VERSION_H) + replace_string_in_line("#define TF_MINOR_VERSION %s" % old_version.minor, + "#define TF_MINOR_VERSION %s" % new_version.minor, + VERSION_H) + replace_string_in_line("#define TF_PATCH_VERSION %s" % old_version.patch, + "#define TF_PATCH_VERSION %s" % new_version.patch, + VERSION_H) + replace_string_in_line( + "#define TF_VERSION_SUFFIX \"%s\"" % old_version.identifier_string, + "#define TF_VERSION_SUFFIX \"%s\"" % new_version.identifier_string, + VERSION_H) def update_setup_dot_py(old_version, new_version): """Update setup.py.""" - replace_line("_VERSION = '%s'" % old_version.string, - "_VERSION = '%s'" % new_version.string, SETUP_PY) + replace_string_in_line("_VERSION = '%s'" % old_version.string, + "_VERSION = '%s'" % new_version.string, SETUP_PY) def update_readme(old_version, new_version): """Update README.""" pep_440_str = new_version.pep_440_str - replace_with_sed(r"s/%s\.%s\.([[:alnum:]]+)-/%s-/g" % (old_version.major, - old_version.minor, - pep_440_str), - README_MD) + replace_string_in_line(r"%s\.%s\.([[:alnum:]]+)-" % (old_version.major, + old_version.minor), + "%s-" % pep_440_str, README_MD) def update_md_files(old_version, new_version): @@ -226,22 +224,29 @@ def update_md_files(old_version, new_version): for filename in ["linux", "mac", "windows", "sources"]: filepath = "%s/docs_src/install/install_%s.md" % (TF_SRC_DIR, filename) - replace_with_sed("s/tensorflow-%s/tensorflow-%s/g" - % (old_pep_version, new_pep_version), filepath) - replace_with_sed("s/tensorflow_gpu-%s/tensorflow_gpu-%s/g" - % (old_pep_version, new_pep_version), filepath) - replace_with_sed("s/TensorFlow %s/TensorFlow %s/g" - % (old_pep_version, new_pep_version), filepath) + + if filename == "sources" and "rc0" in new_pep_version: + replace_string_in_line("(?)tensorflow-%s" % old_pep_version, + "tensorflow-%s" % new_pep_version, filepath) + replace_string_in_line("(?)tensorflow_gpu-%s" % old_pep_version, + "tensorflow_gpu-%s" % new_pep_version, filepath) + else: + replace_string_in_line("tensorflow-%s" % old_pep_version, + "tensorflow-%s" % new_pep_version, filepath) + replace_string_in_line("tensorflow_gpu-%s" % old_pep_version, + "tensorflow_gpu-%s" % new_pep_version, filepath) + replace_string_in_line("TensorFlow %s" % old_pep_version, + "TensorFlow %s" % new_pep_version, filepath) for filename in ["java", "go", "c"]: filepath = "%s/docs_src/install/install_%s.md" % (TF_SRC_DIR, filename) - replace_with_sed(r"s/x86_64-%s/x86_64-%s/g" - % (old_version, new_version), filepath) - replace_with_sed(r"s/libtensorflow-%s.jar/libtensorflow-%s.jar/g" - % (old_version, new_version), filepath) - replace_with_sed(r"s/%s<\/version>/%s<\/version>/g" - % (old_version, new_version), filepath) + replace_string_in_line(r"x86_64-%s" % old_version, + "x86_64-%s" % new_version, filepath) + replace_string_in_line(r"libtensorflow-%s.jar" % old_version, + "libtensorflow-%s.jar" % new_version, filepath) + replace_string_in_line(r"%s<\/version>" % old_version, + "%s" % new_version, filepath) def major_minor_change(old_version, new_version): @@ -266,10 +271,11 @@ def update_dockerfiles(old_version, new_version): % (old_r_major_minor_string, r_major_minor_string)) # Update dockerfiles - replace_with_sed("s/%s/%s/g" - % (old_r_major_minor, r_major_minor), DEVEL_DOCKERFILE) - replace_with_sed("s/%s/%s/g" - % (old_r_major_minor, r_major_minor), GPU_DEVEL_DOCKERFILE) + replace_string_in_line(old_r_major_minor, r_major_minor, DEVEL_DOCKERFILE) + replace_string_in_line(old_r_major_minor, r_major_minor, + GPU_DEVEL_DOCKERFILE) + replace_string_in_line(old_r_major_minor, r_major_minor, + CPU_MKL_DEVEL_DOCKERFILE) def check_for_lingering_string(lingering_string): @@ -333,7 +339,7 @@ def main(): old_version = get_current_semver_version() if args.nightly: - # dev minor version is one ahead of official + # Dev minor version is one ahead of official. nightly_minor_ver = int(old_version.minor) + 1 new_version = Version(old_version.major, str(nightly_minor_ver), @@ -349,12 +355,18 @@ def main(): update_md_files(old_version, new_version) update_dockerfiles(old_version, new_version) - # Print transition details + # Print transition details. print("Major: %s -> %s" % (old_version.major, new_version.major)) print("Minor: %s -> %s" % (old_version.minor, new_version.minor)) print("Patch: %s -> %s\n" % (old_version.patch, new_version.patch)) check_for_old_version(old_version, new_version) + if "rc0" in str(new_version): + print("\n\n\033[93mNOTE: Please update the tensorflow/docs_src/install/" + "install_sources.md and add a line for tensorflow-%s and " + "tensorflow_gpu-%s in the tested source configurations " + "table.\033[0m\n" % (new_version.pep_440_str, + new_version.pep_440_str)) if __name__ == "__main__": -- GitLab From 6d6fe1f8e6e47755ca9d1899e4348d7fa466f132 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 14:25:36 -0800 Subject: [PATCH 137/258] Replace the use of ConsumeValueOrDie with TF_ASSERT_OK_AND_ASSIGN. PiperOrigin-RevId: 182992618 --- .../service/hlo_element_type_converter_test.cc | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_element_type_converter_test.cc b/tensorflow/compiler/xla/service/hlo_element_type_converter_test.cc index 2aed82409b..cb94d9f19b 100644 --- a/tensorflow/compiler/xla/service/hlo_element_type_converter_test.cc +++ b/tensorflow/compiler/xla/service/hlo_element_type_converter_test.cc @@ -43,8 +43,8 @@ TEST_F(HloElementTypeConverterTest, CustomCallsNotConverted) { )"; auto module = CreateModuleFromHloString(hlo_string); HloElementTypeConverter type_converter(BF16, F32); - auto converted = type_converter.Run(module.get()).ConsumeValueOrDie(); - EXPECT_TRUE(converted == false); + TF_ASSERT_OK_AND_ASSIGN(bool converted, type_converter.Run(module.get())); + EXPECT_FALSE(converted); } TEST_F(HloElementTypeConverterTest, InfeedsOutfeedsNotConverted) { @@ -57,8 +57,8 @@ TEST_F(HloElementTypeConverterTest, InfeedsOutfeedsNotConverted) { )"; auto module = CreateModuleFromHloString(hlo_string); HloElementTypeConverter type_converter(BF16, F32); - auto converted = type_converter.Run(module.get()).ConsumeValueOrDie(); - EXPECT_TRUE(converted == false); + TF_ASSERT_OK_AND_ASSIGN(bool converted, type_converter.Run(module.get())); + EXPECT_FALSE(converted); } TEST_F(HloElementTypeConverterTest, OperationsInNestedTuplesConverted) { @@ -77,9 +77,8 @@ TEST_F(HloElementTypeConverterTest, OperationsInNestedTuplesConverted) { auto module = CreateModuleFromHloString(hlo_string); HloElementTypeConverter type_converter(BF16, F32); - auto converted = type_converter.Run(module.get()).ConsumeValueOrDie(); - EXPECT_TRUE(converted == true); - + TF_ASSERT_OK_AND_ASSIGN(bool converted, type_converter.Run(module.get())); + EXPECT_TRUE(converted); const HloInstruction* bf16_op = module->entry_computation()->root_instruction()->operand(0)->operand(1); EXPECT_THAT(bf16_op, op::Convert(op::Add(op::Constant(), op::Convert()))); @@ -106,9 +105,8 @@ TEST_F(HloElementTypeConverterTest, BatchNormGradBF16Converted) { auto module = CreateModuleFromHloString(hlo_string); HloElementTypeConverter type_converter(BF16, F32); - auto converted = type_converter.Run(module.get()).ConsumeValueOrDie(); - EXPECT_TRUE(converted == true); - + TF_ASSERT_OK_AND_ASSIGN(bool converted, type_converter.Run(module.get())); + EXPECT_TRUE(converted); const HloInstruction* tuple_instr = module->entry_computation()->root_instruction(); ::testing::Matcher batch_norm = -- GitLab From 23e25320211c13b48f67db603a6829ab3908d71e Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Tue, 23 Jan 2018 14:31:15 -0800 Subject: [PATCH 138/258] Turn private Operation and Tensor fields into properties. Unfortunately there are many uses of these private fields. Turning them into properties that call public API methods will allow enabling the C API before fixing all such uses. PiperOrigin-RevId: 182993539 --- tensorflow/python/framework/ops.py | 134 ++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 40 deletions(-) diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index ce9ca07215..9d3806e8fe 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -287,7 +287,7 @@ class Tensor(_TensorLike): self._op = op self._value_index = value_index self._dtype = dtypes.as_dtype(dtype) - self._shape = tensor_shape.unknown_shape() + self._shape_val = tensor_shape.unknown_shape() # List of operations that use this Tensor as input. We maintain this list # to easily navigate a computation graph. self._consumers = [] @@ -381,7 +381,18 @@ class Tensor(_TensorLike): graph, self._as_tf_output(), num_dims, status) dim_list = [None if i == -1 else i for i in dim_list] return tensor_shape.TensorShape(dim_list) - return self._shape + return self._shape_val + + @property + def _shape(self): + logging.warning("Tensor._shape is private, use Tensor.shape " + "instead. Tensor._shape will eventually be removed.") + return self.shape + + @_shape.setter + def _shape(self, value): + raise ValueError( + "Tensor._shape cannot be assigned, use Tensor.set_shape instead.") def __iter__(self): if context.in_graph_mode(): @@ -456,7 +467,7 @@ class Tensor(_TensorLike): this tensor. """ if not _USE_C_API: - self._shape = self._shape.merge_with(shape) # pylint: disable=protected-access + self._shape_val = self._shape_val.merge_with(shape) return if not isinstance(shape, tensor_shape.TensorShape): shape = tensor_shape.TensorShape(shape) @@ -1572,7 +1583,7 @@ class Operation(object): "Cannot create a tensor proto whose content is larger than 2GB.") if not _VALID_OP_NAME_REGEX.match(node_def.name): raise ValueError("'%s' is not a valid node name" % node_def.name) - self._node_def = copy.deepcopy(node_def) + self._node_def_val = copy.deepcopy(node_def) c_op = None elif type(node_def).__name__ == "SwigPyObject": assert inputs is None @@ -1581,7 +1592,7 @@ class Operation(object): assert input_types is None assert original_op is None assert op_def is None - self._node_def = None + self._node_def_val = None c_op = node_def else: raise TypeError("node_def needs to be a NodeDef: %s" % node_def) @@ -1589,28 +1600,29 @@ class Operation(object): if not isinstance(g, Graph): raise TypeError("g needs to be a Graph: %s" % g) self._graph = g + if inputs is None: inputs = [] elif not isinstance(inputs, list): raise TypeError("inputs needs to be a list of Tensors: %s" % inputs) - self._inputs = list(inputs) # Defensive copy. - for a in self._inputs: + self._inputs_val = list(inputs) # Defensive copy. + for a in self._inputs_val: if not isinstance(a, Tensor): raise TypeError("input needs to be a Tensor: %s" % a) if input_types is None: - input_types = [i.dtype.base_dtype for i in self._inputs] + input_types = [i.dtype.base_dtype for i in self._inputs_val] else: if not all( x.is_compatible_with(i.dtype) - for i, x in zip(self._inputs, input_types)): + for i, x in zip(self._inputs_val, input_types)): raise TypeError("In op '%s', input types (%s) are not compatible " "with expected types (%s)" % - (self.node_def.name, [i.dtype for i in self._inputs], + (self.node_def.name, [i.dtype for i in self._inputs_val], input_types)) self._input_types_val = input_types # Build the list of control inputs. - self._control_inputs = [] + self._control_inputs_val = [] if control_inputs: for c in control_inputs: control_op = None @@ -1621,11 +1633,11 @@ class Operation(object): else: raise TypeError("Control input must be an Operation, " "a Tensor, or IndexedSlices: %s" % c) - self._control_inputs.append(control_op) + self._control_inputs_val.append(control_op) self._id_value = self._graph._next_id() # pylint: disable=protected-access self._original_op = original_op - self._op_def = op_def + self._op_def_val = op_def self._traceback = self._graph._extract_stack() # pylint: disable=protected-access self._control_flow_context = self.graph._get_control_flow_context() # pylint: disable=protected-access @@ -1641,15 +1653,15 @@ class Operation(object): # Refactor so we don't have to do this here. grouped_inputs = self._reconstruct_sequence_inputs( op_def, inputs, node_def.attr) - self._c_op = _create_c_op(self._graph, self._node_def, grouped_inputs, - self._control_inputs) + self._c_op = _create_c_op(self._graph, self._node_def_val, grouped_inputs, + self._control_inputs_val) else: self._c_op = None # Mark that we consume the inputs. This is unnecessary and unsupported with # the C API enabled, since the C API tracks the tensor consumers instead. if not self._c_op: - for input_tensor in self._inputs: + for input_tensor in self._inputs_val: input_tensor._add_consumer(self) # pylint: disable=protected-access # Initialize self._outputs. @@ -1764,7 +1776,7 @@ class Operation(object): if self._c_op: return c_api.TF_OperationName(self._c_op) else: - return self._node_def.name + return self._node_def_val.name @property def _id(self): @@ -1783,7 +1795,7 @@ class Operation(object): if self._c_op: return c_api.TF_OperationDevice(self._c_op) else: - return self._node_def.device + return self._node_def_val.device @property def _output_types(self): @@ -1843,7 +1855,7 @@ class Operation(object): self._c_op, # pylint: disable=protected-access compat.as_str(_device_string(device))) else: - self._node_def.device = _device_string(device) + self._node_def_val.device = _device_string(device) def _add_input(self, tensor, dtype=None): """Add a new input to this operation. @@ -1871,7 +1883,7 @@ class Operation(object): raise TypeError( "Cannot convert a tensor of type %s to an input of type %s" % (tensor.dtype.name, dtype.name)) - self._inputs.append(tensor) + self._inputs_val.append(tensor) self._input_types_val.append(dtype) tensor._add_consumer(self) # pylint: disable=protected-access self._recompute_node_def() @@ -1901,8 +1913,8 @@ class Operation(object): self._tf_input(index), status) else: - self._inputs[index].consumers().remove(self) - self._inputs[index] = tensor + self._inputs_val[index].consumers().remove(self) + self._inputs_val[index] = tensor self._input_types_val[index] = tensor.dtype tensor._add_consumer(self) # pylint: disable=protected-access self._recompute_node_def() @@ -1928,7 +1940,7 @@ class Operation(object): if not isinstance(op, Operation): raise TypeError("op must be an Operation: %s" % op) _assert_same_graph(self, op) - self._control_inputs.append(op) + self._control_inputs_val.append(op) self._recompute_node_def() def _add_control_input(self, op): @@ -1960,13 +1972,14 @@ class Operation(object): # TODO(skyewm): remove this function when we switch to C API if self._c_op: return - del self._node_def.input[:] + del self._node_def_val.input[:] # pylint: disable=protected-access - self._node_def.input.extend([t._as_node_def_input() for t in self._inputs]) + self._node_def_val.input.extend( + [t._as_node_def_input() for t in self._inputs_val]) # pylint: enable=protected-access - if self._control_inputs: - self._node_def.input.extend( - ["^%s" % op.name for op in self._control_inputs]) + if self._control_inputs_val: + self._node_def_val.input.extend( + ["^%s" % op.name for op in self._control_inputs_val]) def __str__(self): return str(self.node_def) @@ -2016,7 +2029,17 @@ class Operation(object): ] # pylint: enable=protected-access return Operation._InputList(retval) - return Operation._InputList(self._inputs) + return Operation._InputList(self._inputs_val) + + @property + def _inputs(self): + logging.warning("Operation._inputs is private, use Operation.inputs " + "instead. Operation._inputs will eventually be removed.") + return self.inputs + + @_inputs.setter + def _inputs(self, value): + raise ValueError("Cannot assign _inputs") @property def _input_types(self): @@ -2030,6 +2053,10 @@ class Operation(object): else: return self._input_types_val + @_input_types.setter + def _input_types(self, value): + raise ValueError("Cannot assign _input_types") + @property def control_inputs(self): """The `Operation` objects on which this op has a control dependency. @@ -2053,7 +2080,22 @@ class Operation(object): ] # pylint: enable=protected-access else: - return self._control_inputs + return self._control_inputs_val + + @property + def _control_inputs(self): + logging.warning("Operation._control_inputs is private, use " + "Operation.control_inputs instead. " + "Operation._control_inputs will eventually be removed.") + return self.control_inputs + + @_control_inputs.setter + def _control_inputs(self, value): + logging.warning("Operation._control_inputs is private, use " + "Operation.control_inputs instead. " + "Operation._control_inputs will eventually be removed.") + self._remove_all_control_inputs() + self._add_control_inputs(value) @property def type(self): @@ -2062,7 +2104,7 @@ class Operation(object): op_type = c_api.TF_OperationOpType(self._c_op) return op_type else: - return self._node_def.op + return self._node_def_val.op @property def graph(self): @@ -2089,7 +2131,13 @@ class Operation(object): node_def.ParseFromString(compat.as_bytes(data)) return node_def else: - return self._node_def + return self._node_def_val + + @property + def _node_def(self): + logging.warning("Operation._node_def is private, use Operation.node_def " + "instead. Operation._node_def will eventually be removed.") + return self.node_def @property def op_def(self): @@ -2114,7 +2162,13 @@ class Operation(object): op_def.ParseFromString(compat.as_bytes(data)) return op_def else: - return self._op_def + return self._op_def_val + + @property + def _op_def(self): + logging.warning("Operation._op_def is private, use Operation.op_def " + "instead. Operation._op_def will eventually be removed.") + return self.op_def @property def traceback(self): @@ -2146,7 +2200,7 @@ class Operation(object): finally: c_api.TF_DeleteBuffer(buf) else: - self._node_def.attr[attr_name].CopyFrom(attr_value) + self._node_def_val.attr[attr_name].CopyFrom(attr_value) def get_attr(self, name): """Returns the value of the attr of this op with the given `name`. @@ -2173,10 +2227,10 @@ class Operation(object): x = attr_value_pb2.AttrValue() x.ParseFromString(data) else: - if name not in self._node_def.attr: + if name not in self._node_def_val.attr: raise ValueError( - "No attr named '" + name + "' in " + str(self._node_def)) - x = self._node_def.attr[name] + "No attr named '" + name + "' in " + str(self._node_def_val)) + x = self._node_def_val.attr[name] # Treat an empty oneof value as an empty list. if not x.WhichOneof("value"): @@ -4196,10 +4250,10 @@ class Graph(object): """ self._graph = graph if control_inputs is None: - self._control_inputs = [] + self._control_inputs_val = [] self._new_stack = True else: - self._control_inputs = control_inputs + self._control_inputs_val = control_inputs self._new_stack = False self._seen_nodes = set() self._old_stack = None @@ -4227,7 +4281,7 @@ class Graph(object): @property def control_inputs(self): - return self._control_inputs + return self._control_inputs_val def add_op(self, op): self._seen_nodes.add(op) -- GitLab From 54adb32f8510fbd6120f8a022fc15d93b9a04c5c Mon Sep 17 00:00:00 2001 From: Qiumin Xu Date: Tue, 23 Jan 2018 14:42:41 -0800 Subject: [PATCH 139/258] Fix a bug that capture_tpu_profile only takes absolute logdir path. (#16337) Also removed package dependancy on tensorflow for better compatibility. --- .../tpu/profiler/pip_package/cloud_tpu_profiler/main.py | 3 ++- tensorflow/contrib/tpu/profiler/pip_package/setup.py | 9 ++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tensorflow/contrib/tpu/profiler/pip_package/cloud_tpu_profiler/main.py b/tensorflow/contrib/tpu/profiler/pip_package/cloud_tpu_profiler/main.py index 7970c20a26..846db13329 100644 --- a/tensorflow/contrib/tpu/profiler/pip_package/cloud_tpu_profiler/main.py +++ b/tensorflow/contrib/tpu/profiler/pip_package/cloud_tpu_profiler/main.py @@ -42,8 +42,9 @@ def main(unused_argv=None): if not FLAGS.service_addr or not FLAGS.logdir: sys.exit('service_addr and logdir must be provided.') executable_path = os.path.join(os.path.dirname(__file__), EXECUTABLE) + logdir = os.path.expandvars(os.path.expanduser(FLAGS.logdir)) cmd = [executable_path] - cmd.append('--logdir='+FLAGS.logdir) + cmd.append('--logdir='+logdir) cmd.append('--service_addr='+FLAGS.service_addr) cmd.append('--duration_ms='+str(FLAGS.duration_ms)) subprocess.call(cmd) diff --git a/tensorflow/contrib/tpu/profiler/pip_package/setup.py b/tensorflow/contrib/tpu/profiler/pip_package/setup.py index 179d29602b..9219663831 100644 --- a/tensorflow/contrib/tpu/profiler/pip_package/setup.py +++ b/tensorflow/contrib/tpu/profiler/pip_package/setup.py @@ -20,16 +20,12 @@ from __future__ import print_function from setuptools import setup -_VERSION = '1.3.0-a1' +_VERSION = '1.4.3-a2' CONSOLE_SCRIPTS = [ 'capture_tpu_profile=cloud_tpu_profiler.main:run_main', ] -REQUIRED_PACKAGES = [ - 'tensorflow >= 1.2.0', -] - setup( name='cloud_tpu_profiler', version=_VERSION.replace('-', ''), @@ -45,13 +41,12 @@ setup( entry_points={ 'console_scripts': CONSOLE_SCRIPTS, }, - install_requires=REQUIRED_PACKAGES, classifiers=[ # How mature is this project? Common values are # 3 - Alpha # 4 - Beta # 5 - Production/Stable - 'Development Status :: 3 - Alpha', + 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: Education', -- GitLab From 935d5d8550ad06bc77e41e9a3d987658d3731be9 Mon Sep 17 00:00:00 2001 From: Jesse Kinkead Date: Tue, 23 Jan 2018 14:53:51 -0800 Subject: [PATCH 140/258] Singleton S3Client (#16232) * Ensure that the DeleteFile test works without special setup. * Only create one S3Client for the lifetime of the filesystem. * Rename variables to match Google C++ style. Move private section to bottom of class definition. * Initialize S3 client lazily. Register a deleter to handle cleanup instead of always cleaning up in the filesystem destructor. --- tensorflow/core/platform/s3/s3_file_system.cc | 240 +++++++++--------- tensorflow/core/platform/s3/s3_file_system.h | 9 + .../core/platform/s3/s3_file_system_test.cc | 2 + 3 files changed, 135 insertions(+), 116 deletions(-) diff --git a/tensorflow/core/platform/s3/s3_file_system.cc b/tensorflow/core/platform/s3/s3_file_system.cc index ebda3a2065..9ad4bba5a7 100644 --- a/tensorflow/core/platform/s3/s3_file_system.cc +++ b/tensorflow/core/platform/s3/s3_file_system.cc @@ -43,91 +43,96 @@ static const char* kS3FileSystemAllocationTag = "S3FileSystemAllocation"; static const size_t kS3ReadAppendableFileBufferSize = 1024 * 1024; static const int kS3GetChildrenMaxKeys = 100; -Aws::Client::ClientConfiguration& GetDefaultClientConfig() { - static mutex cfg_lock(LINKER_INITIALIZED); - static bool init(false); - static Aws::Client::ClientConfiguration cfg; +Aws::Client::ClientConfiguration GetDefaultClientConfig() { + Aws::Client::ClientConfiguration cfg; - std::lock_guard lock(cfg_lock); - - if (!init) { - const char* endpoint = getenv("S3_ENDPOINT"); - if (endpoint) { - cfg.endpointOverride = Aws::String(endpoint); - } - const char* region = getenv("AWS_REGION"); - if (!region) { - // TODO (yongtang): `S3_REGION` should be deprecated after 2.0. - region = getenv("S3_REGION"); - } - if (region) { - cfg.region = Aws::String(region); - } else { - // Load config file (e.g., ~/.aws/config) only if AWS_SDK_LOAD_CONFIG - // is set with a truthy value. - const char* load_config_env = getenv("AWS_SDK_LOAD_CONFIG"); - string load_config = - load_config_env ? str_util::Lowercase(load_config_env) : ""; - if (load_config == "true" || load_config == "1") { - Aws::String config_file; - // If AWS_CONFIG_FILE is set then use it, otherwise use ~/.aws/config. - const char* config_file_env = getenv("AWS_CONFIG_FILE"); - if (config_file_env) { - config_file = config_file_env; - } else { - const char* home_env = getenv("HOME"); - if (home_env) { - config_file = home_env; - config_file += "/.aws/config"; - } - } - Aws::Config::AWSConfigFileProfileConfigLoader loader(config_file); - loader.Load(); - auto profiles = loader.GetProfiles(); - if (!profiles["default"].GetRegion().empty()) { - cfg.region = profiles["default"].GetRegion(); + const char* endpoint = getenv("S3_ENDPOINT"); + if (endpoint) { + cfg.endpointOverride = Aws::String(endpoint); + } + const char* region = getenv("AWS_REGION"); + if (!region) { + // TODO (yongtang): `S3_REGION` should be deprecated after 2.0. + region = getenv("S3_REGION"); + } + if (region) { + cfg.region = Aws::String(region); + } else { + // Load config file (e.g., ~/.aws/config) only if AWS_SDK_LOAD_CONFIG + // is set with a truthy value. + const char* load_config_env = getenv("AWS_SDK_LOAD_CONFIG"); + string load_config = + load_config_env ? str_util::Lowercase(load_config_env) : ""; + if (load_config == "true" || load_config == "1") { + Aws::String config_file; + // If AWS_CONFIG_FILE is set then use it, otherwise use ~/.aws/config. + const char* config_file_env = getenv("AWS_CONFIG_FILE"); + if (config_file_env) { + config_file = config_file_env; + } else { + const char* home_env = getenv("HOME"); + if (home_env) { + config_file = home_env; + config_file += "/.aws/config"; } } - } - const char* use_https = getenv("S3_USE_HTTPS"); - if (use_https) { - if (use_https[0] == '0') { - cfg.scheme = Aws::Http::Scheme::HTTP; - } else { - cfg.scheme = Aws::Http::Scheme::HTTPS; + Aws::Config::AWSConfigFileProfileConfigLoader loader(config_file); + loader.Load(); + auto profiles = loader.GetProfiles(); + if (!profiles["default"].GetRegion().empty()) { + cfg.region = profiles["default"].GetRegion(); } } - const char* verify_ssl = getenv("S3_VERIFY_SSL"); - if (verify_ssl) { - if (verify_ssl[0] == '0') { - cfg.verifySSL = false; - } else { - cfg.verifySSL = true; - } + } + const char* use_https = getenv("S3_USE_HTTPS"); + if (use_https) { + if (use_https[0] == '0') { + cfg.scheme = Aws::Http::Scheme::HTTP; + } else { + cfg.scheme = Aws::Http::Scheme::HTTPS; } - const char* connect_timeout = getenv("S3_CONNECT_TIMEOUT_MSEC"); - if (connect_timeout) { - int64 timeout; - - if (strings::safe_strto64(connect_timeout, &timeout)) { - cfg.connectTimeoutMs = timeout; - } + } + const char* verify_ssl = getenv("S3_VERIFY_SSL"); + if (verify_ssl) { + if (verify_ssl[0] == '0') { + cfg.verifySSL = false; + } else { + cfg.verifySSL = true; } - const char* request_timeout = getenv("S3_REQUEST_TIMEOUT_MSEC"); - if (request_timeout) { - int64 timeout; + } + const char* connect_timeout = getenv("S3_CONNECT_TIMEOUT_MSEC"); + if (connect_timeout) { + int64 timeout; - if (strings::safe_strto64(request_timeout, &timeout)) { - cfg.requestTimeoutMs = timeout; - } + if (strings::safe_strto64(connect_timeout, &timeout)) { + cfg.connectTimeoutMs = timeout; } + } + const char* request_timeout = getenv("S3_REQUEST_TIMEOUT_MSEC"); + if (request_timeout) { + int64 timeout; - init = true; + if (strings::safe_strto64(request_timeout, &timeout)) { + cfg.requestTimeoutMs = timeout; + } + } else { + // Use a request default for S3 I/O. This helps ensure large file transfers + // will succeed. + cfg.requestTimeoutMs = 600000; // 10 minutes. } return cfg; }; +void ShutdownClient(Aws::S3::S3Client *s3_client) { + if (s3_client != nullptr) { + delete s3_client; + Aws::SDKOptions options; + Aws::ShutdownAPI(options); + AWSLogSystem::ShutdownAWSLogging(); + } +} + Status ParseS3Path(const string& fname, bool empty_object_ok, string* bucket, string* object) { if (!bucket || !object) { @@ -155,12 +160,12 @@ Status ParseS3Path(const string& fname, bool empty_object_ok, string* bucket, class S3RandomAccessFile : public RandomAccessFile { public: - S3RandomAccessFile(const string& bucket, const string& object) - : bucket_(bucket), object_(object) {} + S3RandomAccessFile(const string& bucket, const string& object, + std::shared_ptr s3_client) + : bucket_(bucket), object_(object), s3_client_(s3_client) {} Status Read(uint64 offset, size_t n, StringPiece* result, char* scratch) const override { - Aws::S3::S3Client s3Client(GetDefaultClientConfig()); Aws::S3::Model::GetObjectRequest getObjectRequest; getObjectRequest.WithBucket(bucket_.c_str()).WithKey(object_.c_str()); string bytes = strings::StrCat("bytes=", offset, "-", offset + n - 1); @@ -168,7 +173,7 @@ class S3RandomAccessFile : public RandomAccessFile { getObjectRequest.SetResponseStreamFactory([]() { return Aws::New(kS3FileSystemAllocationTag); }); - auto getObjectOutcome = s3Client.GetObject(getObjectRequest); + auto getObjectOutcome = this->s3_client_->GetObject(getObjectRequest); if (!getObjectOutcome.IsSuccess()) { n = 0; *result = StringPiece(scratch, n); @@ -186,13 +191,16 @@ class S3RandomAccessFile : public RandomAccessFile { private: string bucket_; string object_; + std::shared_ptr s3_client_; }; class S3WritableFile : public WritableFile { public: - S3WritableFile(const string& bucket, const string& object) + S3WritableFile(const string& bucket, const string& object, + std::shared_ptr s3_client) : bucket_(bucket), object_(object), + s3_client_(s3_client), sync_needed_(true), outfile_(Aws::MakeShared( kS3FileSystemAllocationTag, "/tmp/s3_filesystem_XXXXXX", @@ -231,17 +239,13 @@ class S3WritableFile : public WritableFile { if (!sync_needed_) { return Status::OK(); } - Aws::Client::ClientConfiguration clientConfig = GetDefaultClientConfig(); - clientConfig.connectTimeoutMs = 300000; - clientConfig.requestTimeoutMs = 600000; - Aws::S3::S3Client s3Client(clientConfig); Aws::S3::Model::PutObjectRequest putObjectRequest; putObjectRequest.WithBucket(bucket_.c_str()).WithKey(object_.c_str()); long offset = outfile_->tellp(); outfile_->seekg(0); putObjectRequest.SetBody(outfile_); putObjectRequest.SetContentLength(offset); - auto putObjectOutcome = s3Client.PutObject(putObjectRequest); + auto putObjectOutcome = this->s3_client_->PutObject(putObjectRequest); outfile_->clear(); outfile_->seekp(offset); if (!putObjectOutcome.IsSuccess()) { @@ -256,6 +260,7 @@ class S3WritableFile : public WritableFile { private: string bucket_; string object_; + std::shared_ptr s3_client_; bool sync_needed_; std::shared_ptr outfile_; }; @@ -274,31 +279,39 @@ class S3ReadOnlyMemoryRegion : public ReadOnlyMemoryRegion { } // namespace -S3FileSystem::S3FileSystem() { - AWSLogSystem::InitializeAWSLogging(); - - Aws::SDKOptions options; - options.cryptoOptions.sha256Factory_create_fn = []() { - return Aws::MakeShared(S3CryptoAllocationTag); - }; - options.cryptoOptions.sha256HMACFactory_create_fn = []() { - return Aws::MakeShared(S3CryptoAllocationTag); - }; - Aws::InitAPI(options); -} +S3FileSystem::S3FileSystem() : + s3_client_(nullptr, ShutdownClient), client_lock_() {} + +S3FileSystem::~S3FileSystem() {} + +// Initializes s3_client_, if needed, and returns it. +std::shared_ptr S3FileSystem::GetS3Client() { + std::lock_guard lock(this->client_lock_); -S3FileSystem::~S3FileSystem() { - Aws::SDKOptions options; - Aws::ShutdownAPI(options); + if (this->s3_client_.get() == nullptr) { + AWSLogSystem::InitializeAWSLogging(); - AWSLogSystem::ShutdownAWSLogging(); + Aws::SDKOptions options; + options.cryptoOptions.sha256Factory_create_fn = []() { + return Aws::MakeShared(S3CryptoAllocationTag); + }; + options.cryptoOptions.sha256HMACFactory_create_fn = []() { + return Aws::MakeShared(S3CryptoAllocationTag); + }; + Aws::InitAPI(options); + + this->s3_client_ = std::shared_ptr( + new Aws::S3::S3Client(GetDefaultClientConfig())); + } + + return this->s3_client_; } Status S3FileSystem::NewRandomAccessFile( const string& fname, std::unique_ptr* result) { string bucket, object; TF_RETURN_IF_ERROR(ParseS3Path(fname, false, &bucket, &object)); - result->reset(new S3RandomAccessFile(bucket, object)); + result->reset(new S3RandomAccessFile(bucket, object, this->GetS3Client())); return Status::OK(); } @@ -306,7 +319,7 @@ Status S3FileSystem::NewWritableFile(const string& fname, std::unique_ptr* result) { string bucket, object; TF_RETURN_IF_ERROR(ParseS3Path(fname, false, &bucket, &object)); - result->reset(new S3WritableFile(bucket, object)); + result->reset(new S3WritableFile(bucket, object, this->GetS3Client())); return Status::OK(); } @@ -321,7 +334,7 @@ Status S3FileSystem::NewAppendableFile(const string& fname, string bucket, object; TF_RETURN_IF_ERROR(ParseS3Path(fname, false, &bucket, &object)); - result->reset(new S3WritableFile(bucket, object)); + result->reset(new S3WritableFile(bucket, object, this->GetS3Client())); while (true) { status = reader->Read(offset, kS3ReadAppendableFileBufferSize, &read_chunk, @@ -372,7 +385,6 @@ Status S3FileSystem::GetChildren(const string& dir, prefix.push_back('/'); } - Aws::S3::S3Client s3Client(GetDefaultClientConfig()); Aws::S3::Model::ListObjectsRequest listObjectsRequest; listObjectsRequest.WithBucket(bucket.c_str()) .WithPrefix(prefix.c_str()) @@ -383,7 +395,7 @@ Status S3FileSystem::GetChildren(const string& dir, Aws::S3::Model::ListObjectsResult listObjectsResult; do { - auto listObjectsOutcome = s3Client.ListObjects(listObjectsRequest); + auto listObjectsOutcome = this->GetS3Client()->ListObjects(listObjectsRequest); if (!listObjectsOutcome.IsSuccess()) { string error = strings::StrCat( listObjectsOutcome.GetError().GetExceptionName().c_str(), ": ", @@ -417,11 +429,10 @@ Status S3FileSystem::Stat(const string& fname, FileStatistics* stats) { string bucket, object; TF_RETURN_IF_ERROR(ParseS3Path(fname, true, &bucket, &object)); - Aws::S3::S3Client s3Client(GetDefaultClientConfig()); if (object.empty()) { Aws::S3::Model::HeadBucketRequest headBucketRequest; headBucketRequest.WithBucket(bucket.c_str()); - auto headBucketOutcome = s3Client.HeadBucket(headBucketRequest); + auto headBucketOutcome = this->GetS3Client()->HeadBucket(headBucketRequest); if (!headBucketOutcome.IsSuccess()) { string error = strings::StrCat( headBucketOutcome.GetError().GetExceptionName().c_str(), ": ", @@ -439,7 +450,7 @@ Status S3FileSystem::Stat(const string& fname, FileStatistics* stats) { headObjectRequest.WithBucket(bucket.c_str()).WithKey(object.c_str()); headObjectRequest.SetResponseStreamFactory( []() { return Aws::New(kS3FileSystemAllocationTag); }); - auto headObjectOutcome = s3Client.HeadObject(headObjectRequest); + auto headObjectOutcome = this->GetS3Client()->HeadObject(headObjectRequest); if (headObjectOutcome.IsSuccess()) { stats->length = headObjectOutcome.GetResult().GetContentLength(); stats->is_directory = 0; @@ -457,7 +468,7 @@ Status S3FileSystem::Stat(const string& fname, FileStatistics* stats) { .WithMaxKeys(1); listObjectsRequest.SetResponseStreamFactory( []() { return Aws::New(kS3FileSystemAllocationTag); }); - auto listObjectsOutcome = s3Client.ListObjects(listObjectsRequest); + auto listObjectsOutcome = this->GetS3Client()->ListObjects(listObjectsRequest); if (listObjectsOutcome.IsSuccess()) { if (listObjectsOutcome.GetResult().GetContents().size() > 0) { stats->length = 0; @@ -475,11 +486,11 @@ Status S3FileSystem::DeleteFile(const string& fname) { string bucket, object; TF_RETURN_IF_ERROR(ParseS3Path(fname, false, &bucket, &object)); - Aws::S3::S3Client s3Client(GetDefaultClientConfig()); Aws::S3::Model::DeleteObjectRequest deleteObjectRequest; deleteObjectRequest.WithBucket(bucket.c_str()).WithKey(object.c_str()); - auto deleteObjectOutcome = s3Client.DeleteObject(deleteObjectRequest); + auto deleteObjectOutcome = + this->GetS3Client()->DeleteObject(deleteObjectRequest); if (!deleteObjectOutcome.IsSuccess()) { string error = strings::StrCat( deleteObjectOutcome.GetError().GetExceptionName().c_str(), ": ", @@ -494,10 +505,9 @@ Status S3FileSystem::CreateDir(const string& dirname) { TF_RETURN_IF_ERROR(ParseS3Path(dirname, true, &bucket, &object)); if (object.empty()) { - Aws::S3::S3Client s3Client(GetDefaultClientConfig()); Aws::S3::Model::HeadBucketRequest headBucketRequest; headBucketRequest.WithBucket(bucket.c_str()); - auto headBucketOutcome = s3Client.HeadBucket(headBucketRequest); + auto headBucketOutcome = this->GetS3Client()->HeadBucket(headBucketRequest); if (!headBucketOutcome.IsSuccess()) { return errors::NotFound("The bucket ", bucket, " was not found."); } @@ -517,7 +527,6 @@ Status S3FileSystem::DeleteDir(const string& dirname) { string bucket, object; TF_RETURN_IF_ERROR(ParseS3Path(dirname, false, &bucket, &object)); - Aws::S3::S3Client s3Client(GetDefaultClientConfig()); string prefix = object; if (prefix.back() != '/') { prefix.push_back('/'); @@ -528,7 +537,7 @@ Status S3FileSystem::DeleteDir(const string& dirname) { .WithMaxKeys(2); listObjectsRequest.SetResponseStreamFactory( []() { return Aws::New(kS3FileSystemAllocationTag); }); - auto listObjectsOutcome = s3Client.ListObjects(listObjectsRequest); + auto listObjectsOutcome = this->GetS3Client()->ListObjects(listObjectsRequest); if (listObjectsOutcome.IsSuccess()) { auto contents = listObjectsOutcome.GetResult().GetContents(); if (contents.size() > 1 || @@ -568,8 +577,6 @@ Status S3FileSystem::RenameFile(const string& src, const string& target) { } } - Aws::S3::S3Client s3Client(GetDefaultClientConfig()); - Aws::S3::Model::CopyObjectRequest copyObjectRequest; Aws::S3::Model::DeleteObjectRequest deleteObjectRequest; @@ -582,7 +589,7 @@ Status S3FileSystem::RenameFile(const string& src, const string& target) { Aws::S3::Model::ListObjectsResult listObjectsResult; do { - auto listObjectsOutcome = s3Client.ListObjects(listObjectsRequest); + auto listObjectsOutcome = this->GetS3Client()->ListObjects(listObjectsRequest); if (!listObjectsOutcome.IsSuccess()) { string error = strings::StrCat( listObjectsOutcome.GetError().GetExceptionName().c_str(), ": ", @@ -601,7 +608,7 @@ Status S3FileSystem::RenameFile(const string& src, const string& target) { copyObjectRequest.SetKey(target_key); copyObjectRequest.SetCopySource(source); - auto copyObjectOutcome = s3Client.CopyObject(copyObjectRequest); + auto copyObjectOutcome = this->GetS3Client()->CopyObject(copyObjectRequest); if (!copyObjectOutcome.IsSuccess()) { string error = strings::StrCat( copyObjectOutcome.GetError().GetExceptionName().c_str(), ": ", @@ -612,7 +619,8 @@ Status S3FileSystem::RenameFile(const string& src, const string& target) { deleteObjectRequest.SetBucket(src_bucket.c_str()); deleteObjectRequest.SetKey(src_key.c_str()); - auto deleteObjectOutcome = s3Client.DeleteObject(deleteObjectRequest); + auto deleteObjectOutcome = + this->GetS3Client()->DeleteObject(deleteObjectRequest); if (!deleteObjectOutcome.IsSuccess()) { string error = strings::StrCat( deleteObjectOutcome.GetError().GetExceptionName().c_str(), ": ", diff --git a/tensorflow/core/platform/s3/s3_file_system.h b/tensorflow/core/platform/s3/s3_file_system.h index 31ba3cecc5..168b8007f3 100644 --- a/tensorflow/core/platform/s3/s3_file_system.h +++ b/tensorflow/core/platform/s3/s3_file_system.h @@ -16,7 +16,9 @@ limitations under the License. #ifndef TENSORFLOW_CONTRIB_S3_S3_FILE_SYSTEM_H_ #define TENSORFLOW_CONTRIB_S3_S3_FILE_SYSTEM_H_ +#include #include "tensorflow/core/platform/env.h" +#include "tensorflow/core/platform/mutex.h" namespace tensorflow { @@ -53,6 +55,13 @@ class S3FileSystem : public FileSystem { Status GetFileSize(const string& fname, uint64* size) override; Status RenameFile(const string& src, const string& target) override; + private: + // Returns the member S3 client, initializing as-needed. + std::shared_ptr GetS3Client(); + + std::shared_ptr s3_client_; + // Lock held when checking for s3_client_ initialization. + mutex client_lock_; }; } // namespace tensorflow diff --git a/tensorflow/core/platform/s3/s3_file_system_test.cc b/tensorflow/core/platform/s3/s3_file_system_test.cc index 0b42f5fcec..d4411d9865 100644 --- a/tensorflow/core/platform/s3/s3_file_system_test.cc +++ b/tensorflow/core/platform/s3/s3_file_system_test.cc @@ -130,6 +130,8 @@ TEST_F(S3FileSystemTest, NewReadOnlyMemoryRegionFromFile) { TEST_F(S3FileSystemTest, FileExists) { const string fname = TmpDir("FileExists"); + // Ensure the file doesn't yet exist. + TF_ASSERT_OK(s3fs.DeleteFile(fname)); EXPECT_EQ(error::Code::NOT_FOUND, s3fs.FileExists(fname).code()); TF_ASSERT_OK(WriteString(fname, "test")); TF_EXPECT_OK(s3fs.FileExists(fname)); -- GitLab From 392437c566f5363bc4ac25c4932fb0fbf48fb3ed Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Tue, 23 Jan 2018 14:54:22 -0800 Subject: [PATCH 141/258] Make bijectors/reshape_test.py work with C API enabled. Some of the error messages change with the C API enabled due to slight differences in shape inference (in this case, the C API catches shape errors sooner). This change refactors some of the tests to expect different error messages in different cases. PiperOrigin-RevId: 182997183 --- .../kernel_tests/bijectors/reshape_test.py | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/tensorflow/contrib/distributions/python/kernel_tests/bijectors/reshape_test.py b/tensorflow/contrib/distributions/python/kernel_tests/bijectors/reshape_test.py index 49451446b5..e216d88cb1 100644 --- a/tensorflow/contrib/distributions/python/kernel_tests/bijectors/reshape_test.py +++ b/tensorflow/contrib/distributions/python/kernel_tests/bijectors/reshape_test.py @@ -22,12 +22,15 @@ import numpy as np from tensorflow.contrib.distributions.python.ops.bijectors.reshape import Reshape from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops.distributions.bijector_test_util import assert_bijective_and_finite from tensorflow.python.platform import test +@test_util.with_c_api class _ReshapeBijectorTest(object): """Base class for testing the reshape transformation. @@ -136,7 +139,8 @@ class _ReshapeBijectorTest(object): sess.run(bijector.forward_event_shape_tensor(shape_in), feed_dict=feed_dict) - def testInvalidDimensionsOpError(self): + # pylint: disable=invalid-name + def _testInvalidDimensionsOpError(self, expected_error_message): with self.test_session() as sess: @@ -146,10 +150,10 @@ class _ReshapeBijectorTest(object): event_shape_in=shape_in, validate_args=True) - with self.assertRaisesError( - "elements must be either positive integers or `-1`."): + with self.assertRaisesError(expected_error_message): sess.run(bijector.forward_event_shape_tensor(shape_in), feed_dict=feed_dict) + # pylint: enable=invalid-name def testValidButNonMatchingInputOpError(self): x = np.random.randn(4, 3, 2) @@ -184,7 +188,8 @@ class _ReshapeBijectorTest(object): sess.run(bijector.forward(x), feed_dict=feed_dict) - def testInputOutputMismatchOpError(self): + # pylint: disable=invalid-name + def _testInputOutputMismatchOpError(self, expected_error_message): x1 = np.random.randn(4, 2, 3) x2 = np.random.randn(4, 1, 1, 5) @@ -196,13 +201,11 @@ class _ReshapeBijectorTest(object): event_shape_in=shape_in, validate_args=True) - # test that *all* methods check basic assertions - with self.assertRaisesError( - "Input to reshape is a tensor with"): + with self.assertRaisesError(expected_error_message): sess.run(bijector.forward(x1), feed_dict=fd_mismatched) - with self.assertRaisesError( - "Input to reshape is a tensor with"): + with self.assertRaisesError(expected_error_message): sess.run(bijector.inverse(x2), feed_dict=fd_mismatched) + # pylint: enable=invalid-name def testOneShapePartiallySpecified(self): expected_x = np.random.randn(4, 6) @@ -262,6 +265,7 @@ class _ReshapeBijectorTest(object): raise NotImplementedError("Subclass failed to implement `build_shapes`.") +@test_util.with_c_api class ReshapeBijectorTestStatic(test.TestCase, _ReshapeBijectorTest): def build_shapes(self, shape_in, shape_out): @@ -299,7 +303,22 @@ class ReshapeBijectorTestStatic(test.TestCase, _ReshapeBijectorTest): validate_args=True) assert_bijective_and_finite(bijector, x, y, rtol=1e-6, atol=0) + def testInvalidDimensionsOpError(self): + if ops._USE_C_API: + error_message = "Invalid value in tensor used for shape: -2" + else: + error_message = "elements must be either positive integers or `-1`." + self._testInvalidDimensionsOpError(error_message) + + def testInputOutputMismatchOpError(self): + if ops._USE_C_API: + error_message = "Cannot reshape a tensor with" + else: + error_message = "Input to reshape is a tensor with" + self._testInputOutputMismatchOpError(error_message) + +@test_util.with_c_api class ReshapeBijectorTestDynamic(test.TestCase, _ReshapeBijectorTest): def build_shapes(self, shape_in, shape_out): @@ -313,7 +332,15 @@ class ReshapeBijectorTestDynamic(test.TestCase, _ReshapeBijectorTest): def assertRaisesError(self, msg): return self.assertRaisesOpError(msg) + def testInvalidDimensionsOpError(self): + self._testInvalidDimensionsOpError( + "elements must be either positive integers or `-1`.") + + def testInputOutputMismatchOpError(self): + self._testInputOutputMismatchOpError("Input to reshape is a tensor with") + +@test_util.with_c_api class ReshapeBijectorTestDynamicNdims(test.TestCase, _ReshapeBijectorTest): def build_shapes(self, shape_in, shape_out): @@ -325,6 +352,13 @@ class ReshapeBijectorTestDynamicNdims(test.TestCase, _ReshapeBijectorTest): def assertRaisesError(self, msg): return self.assertRaisesOpError(msg) + def testInvalidDimensionsOpError(self): + self._testInvalidDimensionsOpError( + "elements must be either positive integers or `-1`.") + + def testInputOutputMismatchOpError(self): + self._testInputOutputMismatchOpError("Input to reshape is a tensor with") + if __name__ == "__main__": test.main() -- GitLab From 67ed32d35148f382de92c9383347400875eaba40 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Tue, 23 Jan 2018 15:01:14 -0800 Subject: [PATCH 142/258] Tweaks to PR 16101 which adds stream selection support for `tf.contrib.ffmpeg.decode_audio`. PiperOrigin-RevId: 182998275 --- tensorflow/contrib/ffmpeg/decode_audio_op.cc | 20 +++++++++++---- .../contrib/ffmpeg/decode_audio_op_test.py | 19 ++++++++++++-- .../contrib/ffmpeg/default/ffmpeg_lib.cc | 24 +++++++++++------- tensorflow/contrib/ffmpeg/ffmpeg_lib.h | 2 +- tensorflow/contrib/ffmpeg/ffmpeg_ops.py | 7 +++-- .../testdata/mono_16khz_mp3_32khz_aac.mp4 | Bin 0 -> 69357 bytes 6 files changed, 53 insertions(+), 19 deletions(-) create mode 100644 tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3_32khz_aac.mp4 diff --git a/tensorflow/contrib/ffmpeg/decode_audio_op.cc b/tensorflow/contrib/ffmpeg/decode_audio_op.cc index 92fad70b1f..5ab57ca4cd 100644 --- a/tensorflow/contrib/ffmpeg/decode_audio_op.cc +++ b/tensorflow/contrib/ffmpeg/decode_audio_op.cc @@ -44,7 +44,7 @@ const char* kValidFileFormats[] = {"mp3", "mp4", "ogg", "wav"}; void Decode(OpKernelContext* context, const tensorflow::StringPiece& file_contents, const string& file_format, const int32 samples_per_second, - const int32 channel_count) { + const int32 channel_count, const string& stream) { // Write the input data to a temp file. const string temp_filename = io::GetTempFilename(file_format); OP_REQUIRES_OK(context, WriteFile(temp_filename, file_contents)); @@ -54,7 +54,7 @@ void Decode(OpKernelContext* context, std::vector output_samples; Status result = ffmpeg::ReadAudioFile(temp_filename, file_format, samples_per_second, - channel_count, &output_samples); + channel_count, stream, &output_samples); if (result.code() == error::Code::NOT_FOUND) { OP_REQUIRES( context, result.ok(), @@ -99,7 +99,12 @@ void Decode(OpKernelContext* context, */ class DecodeAudioOpV2 : public OpKernel { public: - explicit DecodeAudioOpV2(OpKernelConstruction* context) : OpKernel(context) {} + explicit DecodeAudioOpV2(OpKernelConstruction* context) : OpKernel(context) { + string stream; + if (context->GetAttr("stream", &stream).ok()) { + stream_ = stream; + } + } void Compute(OpKernelContext* context) override { OP_REQUIRES( @@ -153,8 +158,12 @@ class DecodeAudioOpV2 : public OpKernel { errors::InvalidArgument("channel_count must be positive, but got: ", channel_count)); - Decode(context, contents, file_format, samples_per_second, channel_count); + Decode(context, contents, file_format, samples_per_second, channel_count, + stream_); } + + private: + string stream_; }; REGISTER_KERNEL_BUILDER(Name("DecodeAudioV2").Device(DEVICE_CPU), @@ -166,6 +175,7 @@ REGISTER_OP("DecodeAudioV2") .Input("samples_per_second: int32") .Input("channel_count: int32") .Output("sampled_audio: float") + .Attr("stream: string = ''") .SetShapeFn([](shape_inference::InferenceContext* c) { const Tensor* channels_tensor = c->input_tensor(3); if (channels_tensor == nullptr) { @@ -237,7 +247,7 @@ class DecodeAudioOp : public OpKernel { const tensorflow::StringPiece file_contents = contents.scalar()(); Decode(context, file_contents, file_format_, samples_per_second_, - channel_count_); + channel_count_, ""); } private: diff --git a/tensorflow/contrib/ffmpeg/decode_audio_op_test.py b/tensorflow/contrib/ffmpeg/decode_audio_op_test.py index 0d7c9cb99e..3dc663bb6f 100644 --- a/tensorflow/contrib/ffmpeg/decode_audio_op_test.py +++ b/tensorflow/contrib/ffmpeg/decode_audio_op_test.py @@ -33,7 +33,8 @@ class DecodeAudioOpTest(test.TestCase): def _loadFileAndTest(self, filename, file_format, duration_sec, samples_per_second, channel_count, - samples_per_second_tensor=None, feed_dict=None): + samples_per_second_tensor=None, feed_dict=None, + stream=None): """Loads an audio file and validates the output tensor. Args: @@ -49,6 +50,9 @@ class DecodeAudioOpTest(test.TestCase): feed_dict: Used when evaluating the `decode_audio` op. If not provided, will be empty. Useful when providing a placeholder for `samples_per_second_tensor`. + stream: A string specifying which stream from the content file + should be decoded. The default value is '' which leaves the + decision to ffmpeg. """ if samples_per_second_tensor is None: samples_per_second_tensor = samples_per_second @@ -62,7 +66,7 @@ class DecodeAudioOpTest(test.TestCase): contents, file_format=file_format, samples_per_second=samples_per_second_tensor, - channel_count=channel_count) + channel_count=channel_count, stream=stream) audio = audio_op.eval(feed_dict=feed_dict or {}) self.assertEqual(len(audio.shape), 2) self.assertNear( @@ -72,6 +76,17 @@ class DecodeAudioOpTest(test.TestCase): 0.1 * audio.shape[0]) self.assertEqual(audio.shape[1], channel_count) + def testStreamIdentifier(self): + # mono_16khz_mp3_32khz_aac.mp4 was generated from: + # ffmpeg -i tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3.mp4 \ + # -i tensorflow/contrib/ffmpeg/testdata/mono_32khz_aac.mp4 \ + # -strict -2 -map 0:a -map 1:a \ + # tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3_32khz_aac.mp4 + self._loadFileAndTest('mono_16khz_mp3_32khz_aac.mp4', 'mp4', 2.77, 20000, + 1, stream='0') + self._loadFileAndTest('mono_16khz_mp3_32khz_aac.mp4', 'mp4', 2.77, 20000, + 1, stream='1') + def testMonoMp3(self): self._loadFileAndTest('mono_16khz.mp3', 'mp3', 0.57, 20000, 1) self._loadFileAndTest('mono_16khz.mp3', 'mp3', 0.57, 20000, 2) diff --git a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc index 1e8af1458c..3c51deefbc 100644 --- a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc +++ b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc @@ -44,8 +44,10 @@ std::vector FfmpegAudioCommandLine(const string& input_filename, const string& output_filename, const string& input_format_id, int32 samples_per_second, - int32 channel_count) { - return {"-nostats", // No additional progress display. + int32 channel_count, + const string& stream) { + std::vector command({ + "-nostats", // No additional progress display. "-nostdin", // No interactive commands accepted. "-f", input_format_id, // eg: "mp3" "-probesize", StrCat(kDefaultProbeSize), "-i", input_filename, @@ -58,8 +60,15 @@ std::vector FfmpegAudioCommandLine(const string& input_filename, // Output set (in several ways) to signed 16-bit little-endian ints. "-codec:a:0", "pcm_s16le", "-sample_fmt", "s16", "-f", "s16le", "-sn", // No subtitle recording. - "-y", // Overwrite output file. - StrCat(output_filename)}; + "-y" // Overwrite output file. + }); + if (!stream.empty()) { + command.emplace_back("-map"); + command.emplace_back(StrCat("0:", stream)); + } + command.emplace_back(StrCat(output_filename)); + + return command; } std::vector FfmpegVideoCommandLine(const string& input_filename, @@ -123,7 +132,6 @@ bool IsBinaryInstalled(const string& binary_name) { std::transform(args.begin(), args.end(), std::back_inserter(args_chars), [](const string& s) { return const_cast(s.c_str()); }); args_chars.push_back(nullptr); - ::execvp(kFfmpegExecutable, args_chars.data()); // exec only returns on error. const int error = errno; @@ -308,13 +316,12 @@ Status WriteFile(const string& filename, StringPiece contents) { Status ReadAudioFile(const string& filename, const string& audio_format_id, int32 samples_per_second, int32 channel_count, - std::vector* output_samples) { + const string& stream, std::vector* output_samples) { // Create an argument list. string output_filename = io::GetTempFilename("raw"); const std::vector args = FfmpegAudioCommandLine(filename, output_filename, audio_format_id, - samples_per_second, channel_count); - + samples_per_second, channel_count, stream); // Unfortunately, it's impossible to differentiate an exec failure due to the // binary being missing and an error from the binary's execution. Therefore, // check to see if the binary *should* be available. If not, return an error @@ -368,7 +375,6 @@ Status ReadVideoFile(const string& filename, std::vector* output_data, // Create an argument list. const std::vector args = FfmpegVideoCommandLine(filename, output_filename); - // Execute ffmpeg and report errors. pid_t child_pid = ::fork(); if (child_pid < 0) { diff --git a/tensorflow/contrib/ffmpeg/ffmpeg_lib.h b/tensorflow/contrib/ffmpeg/ffmpeg_lib.h index c5ea1432bf..bc1733ead8 100644 --- a/tensorflow/contrib/ffmpeg/ffmpeg_lib.h +++ b/tensorflow/contrib/ffmpeg/ffmpeg_lib.h @@ -42,7 +42,7 @@ Status WriteFile(const string& filename, tensorflow::StringPiece contents); // contain a separate sample for each channel. Frames are ordered by time. Status ReadAudioFile(const string& filename, const string& audio_format_id, int32 samples_per_second, int32 channel_count, - std::vector* output_samples); + const string& stream, std::vector* output_samples); // Creates an audio file using ffmpeg in a specific format. The samples are in // [-1.0, 1.0]. If there are multiple channels in the audio then each frame will diff --git a/tensorflow/contrib/ffmpeg/ffmpeg_ops.py b/tensorflow/contrib/ffmpeg/ffmpeg_ops.py index 08b5a6ea48..020b5c99c6 100644 --- a/tensorflow/contrib/ffmpeg/ffmpeg_ops.py +++ b/tensorflow/contrib/ffmpeg/ffmpeg_ops.py @@ -31,7 +31,7 @@ _ffmpeg_so = loader.load_op_library( def decode_audio(contents, file_format=None, samples_per_second=None, - channel_count=None): + channel_count=None, stream=None): """Create an op that decodes the contents of an audio file. Note that ffmpeg is free to select the "best" audio track from an mp4. @@ -51,6 +51,9 @@ def decode_audio(contents, file_format=None, samples_per_second=None, `contents` have more than this number, then some channels will be merged or dropped. If `contents` has fewer than this, then additional channels will be created from the existing ones. + stream: A string specifying which stream from the content file + should be decoded, e.g., '0' means the 0-th stream. + The default value is '' which leaves the decision to ffmpeg. Returns: A rank-2 tensor that has time along dimension 0 and channels along @@ -61,7 +64,7 @@ def decode_audio(contents, file_format=None, samples_per_second=None, """ return gen_decode_audio_op_py.decode_audio_v2( contents, file_format=file_format, samples_per_second=samples_per_second, - channel_count=channel_count) + channel_count=channel_count, stream=stream) ops.NotDifferentiable('DecodeAudio') diff --git a/tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3_32khz_aac.mp4 b/tensorflow/contrib/ffmpeg/testdata/mono_16khz_mp3_32khz_aac.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..2485da86d60837800fbb0b390c440e674de25993 GIT binary patch literal 69357 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 ZQxd_NL5Y*WC$TKe)J)IBK+n*?5CER*t;qlY literal 0 HcmV?d00001 -- GitLab From 68a9ee1d4e041d7690a949718b2651b035a6bfad Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Tue, 23 Jan 2018 15:02:46 -0800 Subject: [PATCH 143/258] LabeledTensor: don't test Tensor.shape object, test value instead. With the C API enabled, a new TensorShape object may be generated every Tensor.get_shape call. PiperOrigin-RevId: 182998609 --- tensorflow/contrib/labeled_tensor/python/ops/core_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/labeled_tensor/python/ops/core_test.py b/tensorflow/contrib/labeled_tensor/python/ops/core_test.py index 1f4a3ef568..e70b492374 100644 --- a/tensorflow/contrib/labeled_tensor/python/ops/core_test.py +++ b/tensorflow/contrib/labeled_tensor/python/ops/core_test.py @@ -225,7 +225,7 @@ class LabeledTensorTest(test_util.Base): tensor = array_ops.placeholder(dtypes.string, [None]) actual = core.LabeledTensor(tensor, ['x']) self.assertIsNone(actual.axes['x'].size) - self.assertIs(actual.axes['x'].value, tensor.get_shape()[0]) + self.assertIsNone(actual.axes['x'].value.value) def test_eq(self): self.assertEqual(self.lt, self.lt) -- GitLab From 58d227d36aa17d038c70c94787f415b1cd64d982 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 15:08:26 -0800 Subject: [PATCH 144/258] Switch models/ to use new test-specification format PiperOrigin-RevId: 182999650 --- tensorflow/contrib/lite/models/speech_test.cc | 189 ++++++++++++++++ .../testdata/speech_asr_lm_model.test_spec | 202 ++++++++++++++++++ 2 files changed, 391 insertions(+) create mode 100644 tensorflow/contrib/lite/models/speech_test.cc create mode 100644 tensorflow/contrib/lite/models/testdata/speech_asr_lm_model.test_spec diff --git a/tensorflow/contrib/lite/models/speech_test.cc b/tensorflow/contrib/lite/models/speech_test.cc new file mode 100644 index 0000000000..daa8c3100b --- /dev/null +++ b/tensorflow/contrib/lite/models/speech_test.cc @@ -0,0 +1,189 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +// Unit test for speech models (Hotword, SpeakerId) using TFLite Ops. + +#include +#include + +#include + +#include "testing/base/public/googletest.h" +#include +#include "tensorflow/contrib/lite/testing/parse_testdata.h" +#include "tensorflow/contrib/lite/testing/split.h" +#include "tensorflow/contrib/lite/testing/tflite_driver.h" + +namespace tflite { +namespace { + +const char kDataPath[] = "third_party/tensorflow/contrib/lite/models/testdata/"; + +bool Init(const string& in_file_name, testing::TfLiteDriver* driver, + std::ifstream* in_file) { + driver->SetModelBaseDir(kDataPath); + in_file->open(string(kDataPath) + in_file_name, std::ifstream::in); + return in_file->is_open(); +} + +// Converts a set of test files provided by the speech team into a single +// test_spec. Input CSV files are supposed to contain a number of sequences per +// line. Each sequence maps to a single invocation of the interpreter and the +// output tensor after all sequences have run is compared to the corresponding +// line in the output CSV file. +bool ConvertCsvData(const string& model_name, const string& in_name, + const string& out_name, const string& input_tensor, + const string& output_tensor, + const string& persistent_tensors, int sequence_size, + std::ostream* out) { + auto data_path = [](const string& s) { return string(kDataPath) + s; }; + + *out << "load_model: \"" << data_path(model_name) << "\"" << std::endl; + + *out << "init_state: \"" << persistent_tensors << "\"" << std::endl; + + string in_file_name = data_path(in_name); + std::ifstream in_file(in_file_name); + if (!in_file.is_open()) { + std::cerr << "Failed to open " << in_file_name << std::endl; + return false; + } + string out_file_name = data_path(out_name); + std::ifstream out_file(out_file_name); + if (!out_file.is_open()) { + std::cerr << "Failed to open " << out_file_name << std::endl; + return false; + } + + int invocation_count = 0; + string in_values; + while (std::getline(in_file, in_values, '\n')) { + std::vector input = testing::Split(in_values, ","); + int num_sequences = input.size() / sequence_size; + + for (int j = 0; j < num_sequences; ++j) { + *out << "invoke {" << std::endl; + *out << " id: " << invocation_count << std::endl; + *out << " input: \""; + for (int k = 0; k < sequence_size; ++k) { + *out << input[k + j * sequence_size] << ","; + } + *out << "\"" << std::endl; + + if (j == num_sequences - 1) { + string out_values; + if (!std::getline(out_file, out_values, '\n')) { + std::cerr << "Not enough lines in " << out_file_name << std::endl; + return false; + } + *out << " output: \"" << out_values << "\"" << std::endl; + } + + *out << "}" << std::endl; + ++invocation_count; + } + } + return true; +} + +TEST(SpeechTest, HotwordOkGoogleRank1Test) { + std::stringstream os; + ASSERT_TRUE(ConvertCsvData( + "speech_hotword_model_rank1.tflite", "speech_hotword_model_in.csv", + "speech_hotword_model_out_rank1.csv", /*input_tensor=*/"0", + /*output_tensor=*/"18", /*persistent_tensors=*/"4", + /*sequence_size=*/40, &os)); + testing::TfLiteDriver test_driver(/*use_nnapi=*/false); + ASSERT_TRUE(testing::ParseAndRunTests(&os, &test_driver)) + << test_driver.GetErrorMessage(); +} + +TEST(SpeechTest, HotwordOkGoogleRank2Test) { + std::stringstream os; + ASSERT_TRUE(ConvertCsvData( + "speech_hotword_model_rank2.tflite", "speech_hotword_model_in.csv", + "speech_hotword_model_out_rank2.csv", /*input_tensor=*/"17", + /*output_tensor=*/"18", /*persistent_tensors=*/"1", + /*sequence_size=*/40, &os)); + testing::TfLiteDriver test_driver(/*use_nnapi=*/false); + ASSERT_TRUE(testing::ParseAndRunTests(&os, &test_driver)) + << test_driver.GetErrorMessage(); +} + +TEST(SpeechTest, SpeakerIdOkGoogleTest) { + std::stringstream os; + ASSERT_TRUE(ConvertCsvData( + "speech_speakerid_model.tflite", "speech_speakerid_model_in.csv", + "speech_speakerid_model_out.csv", /*input_tensor=*/"0", + /*output_tensor=*/"66", + /*persistent_tensors=*/"19,20,40,41,61,62", + /*sequence_size=*/80, &os)); + testing::TfLiteDriver test_driver(/*use_nnapi=*/false); + ASSERT_TRUE(testing::ParseAndRunTests(&os, &test_driver)) + << test_driver.GetErrorMessage(); +} + +TEST(SpeechTest, AsrAmTest) { + std::stringstream os; + ASSERT_TRUE( + ConvertCsvData("speech_asr_am_model.tflite", "speech_asr_am_model_in.csv", + "speech_asr_am_model_out.csv", /*input_tensor=*/"0", + /*output_tensor=*/"109", + /*persistent_tensors=*/"19,20,40,41,61,62,82,83,103,104", + /*sequence_size=*/320, &os)); + testing::TfLiteDriver test_driver(/*use_nnapi=*/false); + ASSERT_TRUE(testing::ParseAndRunTests(&os, &test_driver)) + << test_driver.GetErrorMessage(); +} + +// The original version of speech_asr_lm_model_test.cc ran a few sequences +// through the interpreter and stored the sum of all the output, which was them +// compared for correctness. In this test we are comparing all the intermediate +// results. +TEST(SpeechTest, AsrLmTest) { + std::ifstream in_file; + testing::TfLiteDriver test_driver(/*use_nnapi=*/false); + ASSERT_TRUE(Init("speech_asr_lm_model.test_spec", &test_driver, &in_file)); + ASSERT_TRUE(testing::ParseAndRunTests(&in_file, &test_driver)) + << test_driver.GetErrorMessage(); +} + +TEST(SpeechTest, EndpointerTest) { + std::stringstream os; + ASSERT_TRUE(ConvertCsvData( + "speech_endpointer_model.tflite", "speech_endpointer_model_in.csv", + "speech_endpointer_model_out.csv", /*input_tensor=*/"0", + /*output_tensor=*/"58", + /*persistent_tensors=*/"28,29,49,50", + /*sequence_size=*/320, &os)); + testing::TfLiteDriver test_driver(/*use_nnapi=*/false); + ASSERT_TRUE(testing::ParseAndRunTests(&os, &test_driver)) + << test_driver.GetErrorMessage(); +} + +TEST(SpeechTest, TtsTest) { + std::stringstream os; + ASSERT_TRUE(ConvertCsvData("speech_tts_model.tflite", + "speech_tts_model_in.csv", + "speech_tts_model_out.csv", /*input_tensor=*/"0", + /*output_tensor=*/"74", + /*persistent_tensors=*/"25,26,46,47,67,68,73", + /*sequence_size=*/334, &os)); + testing::TfLiteDriver test_driver(/*use_nnapi=*/false); + ASSERT_TRUE(testing::ParseAndRunTests(&os, &test_driver)) + << test_driver.GetErrorMessage(); +} + +} // namespace +} // namespace tflite diff --git a/tensorflow/contrib/lite/models/testdata/speech_asr_lm_model.test_spec b/tensorflow/contrib/lite/models/testdata/speech_asr_lm_model.test_spec new file mode 100644 index 0000000000..5812de4b30 --- /dev/null +++ b/tensorflow/contrib/lite/models/testdata/speech_asr_lm_model.test_spec @@ -0,0 +1,202 @@ +load_model: "speech_asr_lm_model.tflite" +init_state: "21,22,42,43,63,64" +invoke { + id: 3 + input: "63982" + input: "8409" + output: "-2.75389" +} +invoke { + id: 4 + input: "8409" + input: "1488" + output: "0.601841" +} +invoke { + id: 5 + input: "1488" + input: "63981" + output: "-0.314846" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 6 + input: "63982" + input: "8409" + output: "-2.75389" +} +invoke { + id: 7 + input: "8409" + input: "3082" + output: "-3.63721" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 8 + input: "63982" + input: "8409" + output: "-2.75389" +} +invoke { + id: 9 + input: "8409" + input: "18965" + output: "-6.93985" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 13 + input: "63982" + input: "12516" + output: "-6.20867" +} +invoke { + id: 14 + input: "12516" + input: "914" + output: "-0.407277" +} +invoke { + id: 15 + input: "914" + input: "63981" + output: "-3.82091" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 19 + input: "63982" + input: "12516" + output: "-6.20867" +} +invoke { + id: 20 + input: "12516" + input: "914" + output: "-0.407277" +} +invoke { + id: 21 + input: "914" + input: "48619" + output: "-4.02131" +} +invoke { + id: 22 + input: "48619" + input: "63981" + output: "-0.677399" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 26 + input: "63982" + input: "12516" + output: "-6.20867" +} +invoke { + id: 27 + input: "12516" + input: "914" + output: "-0.407277" +} +invoke { + id: 28 + input: "914" + input: "4700" + output: "-4.056" +} +invoke { + id: 29 + input: "4700" + input: "63981" + output: "0.415889" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 30 + input: "63982" + input: "12516" + output: "-6.20867" +} +invoke { + id: 31 + input: "12516" + input: "914" + output: "-0.407277" +invoke { + id: 32 + input: "914" + input: "51923" + output: "-14.1147" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 34 + input: "63982" + input: "5520" + output: "-4.56971" +} +invoke { + id: 35 + input: "5520" + input: "16318" + output: "-1.54815" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 36 + input: "63982" + input: "5520" + output: "-4.56971" +} +invoke { + id: 37 + input: "5520" + input: "28303" + output: "-14.0947" +} +init_state: "21,22,42,43,63,64" +invoke { + id: 38 + input: "63982" + input: "12451" + output: "-6.24243" +} +invoke { + id: 39 + input: "12451" + input: "752" + output: "0.0700736" +} +invoke { + id: 40 + input: "752" + input: "11" + output: "-1.72744" +} +invoke { + id: 41 + input: "11" + input: "19454" + output: "-3.19211" +} +invoke { + id: 42 + input: "19454" + input: "16989" + output: "-4.01684" +} +invoke { + id: 43 + input: "16989" + input: "40168" + output: "-8.91317" +} +invoke { + id: 44 + input: "40168" + input: "63981" + output: "-0.675377" +} -- GitLab From 9d84147b0a895ef970f60dde6b78a5bfcc8ba4d7 Mon Sep 17 00:00:00 2001 From: Sami Kama Date: Tue, 23 Jan 2018 15:13:14 -0800 Subject: [PATCH 145/258] Workaround 'too perfect forwarding' issue in variant_op_registry (#16309) * Workaround 'too perfect forwarding' issue in variant_op_registry * Fix comment issue created by clang-format * Fix friend declaration for clang --- .../core/framework/variant_op_registry.cc | 24 +++++----- .../core/framework/variant_op_registry.h | 44 +++++++++++++++---- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/tensorflow/core/framework/variant_op_registry.cc b/tensorflow/core/framework/variant_op_registry.cc index 395329da3b..ee07db1aee 100644 --- a/tensorflow/core/framework/variant_op_registry.cc +++ b/tensorflow/core/framework/variant_op_registry.cc @@ -182,7 +182,7 @@ Status VariantDeviceCopy( // Special casing UnaryOpFn per op and per device. UnaryVariantOpRegistry::VariantUnaryOpFn* UnaryVariantOpRegistry::GetUnaryOpFn( VariantUnaryOp op, StringPiece device, StringPiece type_name) { - auto found = unary_op_fns.find(std::make_tuple(op, device, type_name)); + auto found = unary_op_fns.find({op, device, type_name}); if (found == unary_op_fns.end()) return nullptr; return &found->second; } @@ -195,12 +195,10 @@ void UnaryVariantOpRegistry::RegisterUnaryOpFn( CHECK_EQ(existing, nullptr) << "Unary VariantUnaryOpFn for type_name: " << type_name << " already registered for device type: " << device; - unary_op_fns.insert( - std::pair, - VariantUnaryOpFn>( - std::make_tuple(op, GetPersistentStringPiece(device), - GetPersistentStringPiece(type_name)), - unary_op_fn)); + unary_op_fns.insert(std::pair, VariantUnaryOpFn>( + {op, GetPersistentStringPiece(device), + GetPersistentStringPiece(type_name)}, + unary_op_fn)); } namespace { @@ -229,7 +227,7 @@ REGISTER_VARIANT_ZEROS_LIKE_TYPE(bool); UnaryVariantOpRegistry::VariantBinaryOpFn* UnaryVariantOpRegistry::GetBinaryOpFn(VariantBinaryOp op, StringPiece device, StringPiece type_name) { - auto found = binary_op_fns.find(std::make_tuple(op, device, type_name)); + auto found = binary_op_fns.find({op, device, type_name}); if (found == binary_op_fns.end()) return nullptr; return &found->second; } @@ -242,12 +240,10 @@ void UnaryVariantOpRegistry::RegisterBinaryOpFn( CHECK_EQ(existing, nullptr) << "Unary VariantBinaryOpFn for type_name: " << type_name << " already registered for device type: " << device; - binary_op_fns.insert( - std::pair, - VariantBinaryOpFn>( - std::make_tuple(op, GetPersistentStringPiece(device), - GetPersistentStringPiece(type_name)), - add_fn)); + binary_op_fns.insert(std::pair, VariantBinaryOpFn>( + {op, GetPersistentStringPiece(device), + GetPersistentStringPiece(type_name)}, + add_fn)); } namespace { diff --git a/tensorflow/core/framework/variant_op_registry.h b/tensorflow/core/framework/variant_op_registry.h index 13f6908cae..0e2a410429 100644 --- a/tensorflow/core/framework/variant_op_registry.h +++ b/tensorflow/core/framework/variant_op_registry.h @@ -166,6 +166,21 @@ class UnaryVariantOpRegistry { device_copy_fns; // Map std::tuple to function. + + // this breaks by falling victim to "too perfect forwarding" + // see https://stackoverflow.com/questions/44475317/variadic-template-issue + // and references therein + template + struct FuncTuple { + FuncTuple(const Op& op, const StringPiece& dev, const StringPiece& tname) + : op_type_(op), device_(dev), typename_(tname){}; + Op op_type_; + StringPiece device_, typename_; + }; + //friend declaration for operator== + // needed for clang + template + friend bool operator==(const FuncTuple &l, const FuncTuple &r); struct TupleHash { template std::size_t operator()( @@ -176,18 +191,24 @@ class UnaryVariantOpRegistry { ret = Hash64Combine(ret, sp_hasher_(std::get<2>(x))); return ret; } + + template + std::size_t operator()(const FuncTuple& x) const { + // The hash of an enum is just its value as a std::size_t. + std::size_t ret = static_cast(x.op_type_); + ret = Hash64Combine(ret, sp_hasher_(x.device_)); + ret = Hash64Combine(ret, sp_hasher_(x.typename_)); + return ret; + } StringPieceHasher sp_hasher_; }; - std::unordered_map, - VariantUnaryOpFn, TupleHash> + std::unordered_map, VariantUnaryOpFn, TupleHash> unary_op_fns; - std::unordered_map, - VariantBinaryOpFn, TupleHash> + std::unordered_map, VariantBinaryOpFn, TupleHash> binary_op_fns; // Find or insert a string into a persistent string storage - // container; return the StringPiece pointing to the permanent - // string location. + // container; return the StringPiece pointing to the permanent string location. static StringPiece GetPersistentStringPiece(const string& str) { const auto string_storage = PersistentStringStorage(); auto found = string_storage->find(str); @@ -199,7 +220,12 @@ class UnaryVariantOpRegistry { } } }; - +template +inline bool operator==(const UnaryVariantOpRegistry::FuncTuple& lhs, + const UnaryVariantOpRegistry::FuncTuple& rhs) { + return (lhs.op_type_ == rhs.op_type_) && (lhs.device_ == rhs.device_) && + (lhs.typename_ == rhs.typename_); +} // Gets a TensorShape from a Tensor containing a scalar Variant. // Returns an Internal error if the Variant does not have a registered shape // function, or if it's a serialized Variant that cannot be decoded. @@ -283,8 +309,8 @@ Status BinaryOpVariants(OpKernelContext* ctx, VariantBinaryOp op, return errors::Internal( "No unary variant binary_op function found for binary variant op " "enum: ", - op, " Variant type_name: '", a.TypeName(), - "' for device type: ", device); + op, " Variant type_name: '", a.TypeName(), "' for device type: ", + device); } return (*binary_op_fn)(ctx, a, b, out); } -- GitLab From 3f3c9f73e269d1a24b7bb2841d17ad6be3353b7e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 15:11:22 -0800 Subject: [PATCH 146/258] Adds regularization_losses in remaining heads. PiperOrigin-RevId: 183000075 --- .../estimator/python/estimator/head.py | 71 +++++-- .../estimator/python/estimator/head_test.py | 80 +++++++- tensorflow/python/estimator/canned/head.py | 115 ++++++++--- .../python/estimator/canned/head_test.py | 186 +++++++++++++++++- 4 files changed, 410 insertions(+), 42 deletions(-) diff --git a/tensorflow/contrib/estimator/python/estimator/head.py b/tensorflow/contrib/estimator/python/estimator/head.py index d6ca33e189..fd0994490a 100644 --- a/tensorflow/contrib/estimator/python/estimator/head.py +++ b/tensorflow/contrib/estimator/python/estimator/head.py @@ -220,7 +220,7 @@ def multi_label_head(n_classes, `batch_size`. The head expects `logits` with shape `[D0, D1, ... DN, n_classes]`. In many - applications, the shape is `[batch_size, label_n_classes]`. + applications, the shape is `[batch_size, n_classes]`. Labels can be: * A multi-hot tensor of shape `[D0, D1, ... DN, n_classes]` @@ -392,8 +392,32 @@ class _MultiLabelHead(head_lib._Head): # pylint:disable=protected-access processed_labels=processed_labels) def create_estimator_spec( - self, features, mode, logits, labels=None, train_op_fn=None): - """See `Head`.""" + self, features, mode, logits, labels=None, train_op_fn=None, + regularization_losses=None): + """Returns an `EstimatorSpec`. + + Args: + features: Input `dict` of `Tensor` or `SparseTensor` objects. + mode: Estimator's `ModeKeys`. + logits: logits `Tensor` with shape `[D0, D1, ... DN, n_classes]`. + For many applications, the shape is `[batch_size, n_classes]`. + labels: Labels with shape matching `logits`. Can be multi-hot `Tensor` + with shape `[D0, D1, ... DN, n_classes]` or `SparseTensor` with + `dense_shape` `[D0, D1, ... DN, ?]`. `labels` is required argument when + `mode` equals `TRAIN` or `EVAL`. + train_op_fn: Function that takes a scalar loss `Tensor` and returns + `train_op`. Required in TRAIN mode. + regularization_losses: A list of additional scalar losses to be added to + the training loss, such as regularization losses. These losses are + usually expressed as a batch average, so for best results users need to + set `loss_reduction=SUM_OVER_BATCH_SIZE` or + `loss_reduction=SUM_OVER_NONZERO_WEIGHTS` when creating the head to + avoid scaling errors. + Returns: + `EstimatorSpec`. + Raises: + ValueError: If `train_op_fn` is `None` in TRAIN mode. + """ with ops.name_scope(self._name, 'head'): logits = head_lib._check_logits_final_dim(logits, self.logits_dimension) # pylint:disable=protected-access @@ -422,18 +446,26 @@ class _MultiLabelHead(head_lib._Head): # pylint:disable=protected-access (training_loss, unreduced_loss, weights, processed_labels) = self.create_loss( features=features, mode=mode, logits=logits, labels=labels) + if regularization_losses: + regularization_loss = math_ops.add_n(regularization_losses) + regularized_training_loss = math_ops.add_n( + [training_loss, regularization_loss]) + else: + regularization_loss = None + regularized_training_loss = training_loss # Eval. if mode == model_fn.ModeKeys.EVAL: return model_fn.EstimatorSpec( mode=model_fn.ModeKeys.EVAL, predictions=predictions, - loss=training_loss, + loss=regularized_training_loss, eval_metric_ops=self._eval_metric_ops( labels=processed_labels, probabilities=probabilities, weights=weights, - unreduced_loss=unreduced_loss)) + unreduced_loss=unreduced_loss, + regularization_loss=regularization_loss)) # Train. if train_op_fn is None: @@ -447,25 +479,31 @@ class _MultiLabelHead(head_lib._Head): # pylint:disable=protected-access else: mean_loss = None with ops.name_scope(''): + keys = metric_keys.MetricKeys summary.scalar( - head_lib._summary_key(self._name, metric_keys.MetricKeys.LOSS), # pylint:disable=protected-access - training_loss) + head_lib._summary_key(self._name, keys.LOSS), # pylint:disable=protected-access + regularized_training_loss) if mean_loss is not None: summary.scalar( - head_lib._summary_key( # pylint:disable=protected-access - self._name, metric_keys.MetricKeys.LOSS_MEAN), + head_lib._summary_key(self._name, keys.LOSS_MEAN), # pylint:disable=protected-access mean_loss) + if regularization_loss is not None: + summary.scalar( + head_lib._summary_key(self._name, keys.LOSS_REGULARIZATION), # pylint:disable=protected-access + regularization_loss) return model_fn.EstimatorSpec( mode=model_fn.ModeKeys.TRAIN, predictions=predictions, - loss=training_loss, - train_op=train_op_fn(training_loss)) + loss=regularized_training_loss, + train_op=train_op_fn(regularized_training_loss)) - def _eval_metric_ops(self, labels, probabilities, weights, unreduced_loss): + def _eval_metric_ops( + self, labels, probabilities, weights, unreduced_loss, + regularization_loss): """Returns a dict of metrics for eval_metric_ops.""" with ops.name_scope( None, 'metrics', - [labels, probabilities, weights, unreduced_loss]): + [labels, probabilities, weights, unreduced_loss, regularization_loss]): keys = metric_keys.MetricKeys metric_ops = { # Estimator already adds a metric for loss. @@ -482,6 +520,13 @@ class _MultiLabelHead(head_lib._Head): # pylint:disable=protected-access weights=weights, curve='PR', name=keys.AUC_PR), } + if regularization_loss is not None: + loss_regularization_key = head_lib._summary_key( # pylint:disable=protected-access + self._name, keys.LOSS_REGULARIZATION) + metric_ops[loss_regularization_key] = ( + metrics_lib.mean( + values=regularization_loss, + name=keys.LOSS_REGULARIZATION)) for threshold in self._thresholds: accuracy_key = keys.ACCURACY_AT_THRESHOLD % threshold metric_ops[head_lib._summary_key(self._name, accuracy_key)] = ( # pylint:disable=protected-access diff --git a/tensorflow/contrib/estimator/python/estimator/head_test.py b/tensorflow/contrib/estimator/python/estimator/head_test.py index e39e44541d..1adbd6f0fe 100644 --- a/tensorflow/contrib/estimator/python/estimator/head_test.py +++ b/tensorflow/contrib/estimator/python/estimator/head_test.py @@ -399,12 +399,13 @@ class MultiLabelHead(test.TestCase): def _test_eval( self, head, logits, labels, expected_loss, expected_metrics, - features=None): + features=None, regularization_losses=None): spec = head.create_estimator_spec( features=features or {}, mode=model_fn.ModeKeys.EVAL, logits=logits, - labels=labels) + labels=labels, + regularization_losses=regularization_losses) # Assert spec contains expected tensors. self.assertIsNotNone(spec.loss) @@ -486,6 +487,38 @@ class MultiLabelHead(test.TestCase): expected_loss=expected_loss, expected_metrics=expected_metrics) + def test_eval_with_regularization_losses(self): + n_classes = 2 + head = head_lib.multi_label_head( + n_classes, loss_reduction=losses.Reduction.SUM_OVER_BATCH_SIZE) + logits = np.array([[-1., 1.], [-1.5, 1.5]], dtype=np.float32) + labels = np.array([[1, 0], [1, 1]], dtype=np.int64) + regularization_losses = [1.5, 0.5] + expected_regularization_loss = 2. + # unregularized_loss = sum( + # labels * -log(sigmoid(logits)) + + # (1 - labels) * -log(1 - sigmoid(logits))) / batch_size + expected_unregularized_loss = np.sum( + _sigmoid_cross_entropy(labels=labels, logits=logits)) / 2. + expected_regularized_loss = ( + expected_unregularized_loss + expected_regularization_loss) + keys = metric_keys.MetricKeys + expected_metrics = { + keys.LOSS_MEAN: expected_unregularized_loss, + keys.LOSS_REGULARIZATION: expected_regularization_loss, + # auc and auc_pr cannot be reliably calculated for only 4 samples, but + # this assert tests that the algorithm remains consistent. + keys.AUC: 0.3333, + keys.AUC_PR: 0.7639, + } + self._test_eval( + head=head, + logits=logits, + labels=labels, + expected_loss=expected_regularized_loss, + expected_metrics=expected_metrics, + regularization_losses=regularization_losses) + def test_eval_with_label_vocabulary(self): n_classes = 2 head = head_lib.multi_label_head( @@ -829,6 +862,49 @@ class MultiLabelHead(test.TestCase): self._test_train( head=head, logits=logits, labels=labels, expected_loss=expected_loss) + def test_train_with_regularization_losses(self): + head = head_lib.multi_label_head( + n_classes=2, loss_reduction=losses.Reduction.SUM_OVER_BATCH_SIZE) + logits = np.array([[-10., 10.], [-15., 10.]], dtype=np.float32) + labels = np.array([[1, 0], [1, 1]], dtype=np.int64) + regularization_losses = [1.5, 0.5] + # For large logits, sigmoid cross entropy loss is approximated as: + # loss = labels * (logits < 0) * (-logits) + + # (1 - labels) * (logits > 0) * logits => + # expected_unweighted_loss = [[10., 10.], [15., 0.]] + # Average over classes and over batch and add regularization loss. + expected_loss = 35. / 4. + 2. + expected_summaries = { + metric_keys.MetricKeys.LOSS: expected_loss, + metric_keys.MetricKeys.LOSS_REGULARIZATION: 2., + } + expected_train_result = 'my_train_op' + def _train_op_fn(loss): + return string_ops.string_join( + [constant_op.constant(expected_train_result), + string_ops.as_string(loss, precision=3)]) + + spec = head.create_estimator_spec( + features={'x': np.array(((42,),), dtype=np.int32)}, + mode=model_fn.ModeKeys.TRAIN, + logits=logits, + labels=labels, + train_op_fn=_train_op_fn, + regularization_losses=regularization_losses) + + # Assert predictions, loss, train_op, and summaries. + tol = 1e-3 + with self.test_session() as sess: + _initialize_variables(self, spec.scaffold) + self.assertIsNotNone(spec.scaffold.summary_op) + loss, train_result, summary_str = sess.run((spec.loss, spec.train_op, + spec.scaffold.summary_op)) + self.assertAllClose(expected_loss, loss, rtol=tol, atol=tol) + self.assertEqual( + six.b('{0:s}{1:.3f}'.format(expected_train_result, expected_loss)), + train_result) + _assert_simple_summaries(self, expected_summaries, summary_str, tol) + def test_train_with_weights(self): n_classes = 2 head = head_lib.multi_label_head(n_classes, weight_column='example_weights') diff --git a/tensorflow/python/estimator/canned/head.py b/tensorflow/python/estimator/canned/head.py index 204e1119f2..94a5d3a342 100644 --- a/tensorflow/python/estimator/canned/head.py +++ b/tensorflow/python/estimator/canned/head.py @@ -627,15 +627,15 @@ class _MultiClassHeadWithSoftmaxCrossEntropyLoss(_Head): logits: logits `Tensor` with shape `[D0, D1, ... DN, logits_dimension]`. For many applications, the shape is `[batch_size, logits_dimension]`. labels: Labels integer or string `Tensor` with shape matching `logits`, - namely `[D0, D1, ... DN, 1]`. `labels` is required argument when `mode` - equals `TRAIN` or `EVAL`. + namely `[D0, D1, ... DN, 1]` or `[D0, D1, ... DN]`. `labels` is + required argument when `mode` equals `TRAIN` or `EVAL`. train_op_fn: Function that takes a scalar loss `Tensor` and returns `train_op`. Required in TRAIN mode. regularization_losses: A list of additional scalar losses to be added to the training loss, such as regularization losses. These losses are usually expressed as a batch average, so for best results users need to - set `loss_reduction=MEAN_PER_ELEMENT` or - `loss_reduction=SUM_BY_NONZERO_WEIGHTS` when creating the head to + set `loss_reduction=SUM_OVER_BATCH_SIZE` or + `loss_reduction=SUM_OVER_NONZERO_WEIGHTS` when creating the head to avoid scaling errors. Returns: `EstimatorSpec`. @@ -827,10 +827,10 @@ class _BinaryLogisticHeadWithSigmoidCrossEntropyLoss(_Head): return 1 def _eval_metric_ops(self, labels, logits, logistic, class_ids, weights, - unreduced_loss): + unreduced_loss, regularization_loss): with ops.name_scope(None, 'metrics', (labels, logits, logistic, class_ids, weights, - unreduced_loss)): + unreduced_loss, regularization_loss)): keys = metric_keys.MetricKeys labels_mean = _indicator_labels_mean( labels=labels, weights=weights, name=keys.LABEL_MEAN) @@ -870,6 +870,11 @@ class _BinaryLogisticHeadWithSigmoidCrossEntropyLoss(_Head): curve='PR', name=keys.AUC_PR) } + if regularization_loss is not None: + metric_ops[_summary_key(self._name, keys.LOSS_REGULARIZATION)] = ( + metrics_lib.mean( + values=regularization_loss, + name=keys.LOSS_REGULARIZATION)) for threshold in self._thresholds: accuracy_key = keys.ACCURACY_AT_THRESHOLD % threshold metric_ops[_summary_key(self._name, @@ -924,8 +929,31 @@ class _BinaryLogisticHeadWithSigmoidCrossEntropyLoss(_Head): processed_labels=labels) def create_estimator_spec( - self, features, mode, logits, labels=None, train_op_fn=None): - """See `Head`.""" + self, features, mode, logits, labels=None, train_op_fn=None, + regularization_losses=None): + """Returns an `EstimatorSpec`. + + Args: + features: Input `dict` of `Tensor` or `SparseTensor` objects. + mode: Estimator's `ModeKeys`. + logits: logits `Tensor` with shape `[D0, D1, ... DN, 1]`. For many + applications, the shape is `[batch_size, 1]`. + labels: Labels integer or string `Tensor` with shape matching `logits`, + namely `[D0, D1, ... DN, 1]` or `[D0, D1, ... DN]`. `labels` is required + argument when `mode` equals `TRAIN` or `EVAL`. + train_op_fn: Function that takes a scalar loss `Tensor` and returns + `train_op`. Required in TRAIN mode. + regularization_losses: A list of additional scalar losses to be added to + the training loss, such as regularization losses. These losses are + usually expressed as a batch average, so for best results users need to + set `loss_reduction=SUM_OVER_BATCH_SIZE` or + `loss_reduction=SUM_OVER_NONZERO_WEIGHTS` when creating the head to + avoid scaling errors. + Returns: + `EstimatorSpec`. + Raises: + ValueError: If `train_op_fn` is `None` in TRAIN mode. + """ # Predict. with ops.name_scope(self._name, 'head'): with ops.name_scope(None, 'predictions', (logits,)): @@ -972,20 +1000,28 @@ class _BinaryLogisticHeadWithSigmoidCrossEntropyLoss(_Head): (training_loss, unreduced_loss, weights, processed_labels) = ( self.create_loss( features=features, mode=mode, logits=logits, labels=labels)) + if regularization_losses: + regularization_loss = math_ops.add_n(regularization_losses) + regularized_training_loss = math_ops.add_n( + [training_loss, regularization_loss]) + else: + regularization_loss = None + regularized_training_loss = training_loss # Eval. if mode == model_fn.ModeKeys.EVAL: return model_fn.EstimatorSpec( mode=model_fn.ModeKeys.EVAL, predictions=predictions, - loss=training_loss, + loss=regularized_training_loss, eval_metric_ops=self._eval_metric_ops( labels=processed_labels, logits=logits, logistic=logistic, class_ids=class_ids, weights=weights, - unreduced_loss=unreduced_loss)) + unreduced_loss=unreduced_loss, + regularization_loss=regularization_loss)) # Train. if train_op_fn is None: @@ -999,18 +1035,22 @@ class _BinaryLogisticHeadWithSigmoidCrossEntropyLoss(_Head): else: mean_loss = None with ops.name_scope(''): + keys = metric_keys.MetricKeys summary.scalar( - _summary_key(self._name, metric_keys.MetricKeys.LOSS), - training_loss) + _summary_key(self._name, keys.LOSS), + regularized_training_loss) if mean_loss is not None: summary.scalar( - _summary_key(self._name, metric_keys.MetricKeys.LOSS_MEAN), - mean_loss) + _summary_key(self._name, keys.LOSS_MEAN), mean_loss) + if regularization_loss is not None: + summary.scalar( + _summary_key(self._name, keys.LOSS_REGULARIZATION), + regularization_loss) return model_fn.EstimatorSpec( mode=model_fn.ModeKeys.TRAIN, predictions=predictions, - loss=training_loss, - train_op=train_op_fn(training_loss)) + loss=regularized_training_loss, + train_op=train_op_fn(regularized_training_loss)) def _regression_head_with_mean_squared_error_loss( @@ -1111,7 +1151,8 @@ class _RegressionHeadWithMeanSquaredErrorLoss(_Head): processed_labels=labels) def create_estimator_spec( - self, features, mode, logits, labels=None, train_op_fn=None): + self, features, mode, logits, labels=None, train_op_fn=None, + regularization_losses=None): """Returns an `EstimatorSpec`. Args: @@ -1125,6 +1166,12 @@ class _RegressionHeadWithMeanSquaredErrorLoss(_Head): `mode` equals `TRAIN` or `EVAL`. train_op_fn: Function that takes a scalar loss `Tensor` and returns `train_op`. Required in TRAIN mode. + regularization_losses: A list of additional scalar losses to be added to + the training loss, such as regularization losses. These losses are + usually expressed as a batch average, so for best results users need to + set `loss_reduction=SUM_OVER_BATCH_SIZE` or + `loss_reduction=SUM_OVER_NONZERO_WEIGHTS` when creating the head to + avoid scaling errors. Returns: `EstimatorSpec`. Raises: @@ -1147,20 +1194,34 @@ class _RegressionHeadWithMeanSquaredErrorLoss(_Head): training_loss, unreduced_loss, weights, _ = self.create_loss( features=features, mode=mode, logits=logits, labels=labels) + if regularization_losses: + regularization_loss = math_ops.add_n(regularization_losses) + regularized_training_loss = math_ops.add_n( + [training_loss, regularization_loss]) + else: + regularization_loss = None + regularized_training_loss = training_loss # Eval. if mode == model_fn.ModeKeys.EVAL: + keys = metric_keys.MetricKeys # Estimator already adds a metric for loss. eval_metric_ops = { - _summary_key(self._name, metric_keys.MetricKeys.LOSS_MEAN): + _summary_key(self._name, keys.LOSS_MEAN): metrics_lib.mean( values=unreduced_loss, weights=weights) } + if regularization_loss is not None: + regularization_loss_key = _summary_key( + self._name, keys.LOSS_REGULARIZATION) + eval_metric_ops[regularization_loss_key] = metrics_lib.mean( + values=regularization_loss, + name=keys.LOSS_REGULARIZATION) return model_fn.EstimatorSpec( mode=model_fn.ModeKeys.EVAL, predictions=predictions, - loss=training_loss, + loss=regularized_training_loss, eval_metric_ops=eval_metric_ops) # Train. @@ -1175,18 +1236,22 @@ class _RegressionHeadWithMeanSquaredErrorLoss(_Head): else: mean_loss = None with ops.name_scope(''): + keys = metric_keys.MetricKeys summary.scalar( - _summary_key(self._name, metric_keys.MetricKeys.LOSS), - training_loss) + _summary_key(self._name, keys.LOSS), + regularized_training_loss) if mean_loss is not None: summary.scalar( - _summary_key(self._name, metric_keys.MetricKeys.LOSS_MEAN), - mean_loss) + _summary_key(self._name, keys.LOSS_MEAN), mean_loss) + if regularization_loss is not None: + summary.scalar( + _summary_key(self._name, keys.LOSS_REGULARIZATION), + regularization_loss) return model_fn.EstimatorSpec( mode=model_fn.ModeKeys.TRAIN, predictions=predictions, - loss=training_loss, - train_op=train_op_fn(training_loss)) + loss=regularized_training_loss, + train_op=train_op_fn(regularized_training_loss)) def _assert_range(labels, n_classes, message=None): diff --git a/tensorflow/python/estimator/canned/head_test.py b/tensorflow/python/estimator/canned/head_test.py index 28b8e635fb..4e871e8f37 100644 --- a/tensorflow/python/estimator/canned/head_test.py +++ b/tensorflow/python/estimator/canned/head_test.py @@ -487,7 +487,7 @@ class MultiClassHeadWithSoftmaxCrossEntropyLoss(test.TestCase): def test_eval_with_regularization_losses(self): n_classes = 3 head = head_lib._multi_class_head_with_softmax_cross_entropy_loss( - n_classes, loss_reduction=losses.Reduction.MEAN) + n_classes, loss_reduction=losses.Reduction.SUM_OVER_BATCH_SIZE) logits = np.array(((10, 0, 0), (0, 10, 0),), dtype=np.float32) labels = np.array(((1,), (1,)), dtype=np.int64) features = {'x': np.array(((42,),), dtype=np.int32)} @@ -790,7 +790,7 @@ class MultiClassHeadWithSoftmaxCrossEntropyLoss(test.TestCase): def test_train_with_regularization_losses(self): n_classes = 3 head = head_lib._multi_class_head_with_softmax_cross_entropy_loss( - n_classes, loss_reduction=losses.Reduction.MEAN) + n_classes, loss_reduction=losses.Reduction.SUM_OVER_BATCH_SIZE) logits = np.array(((10, 0, 0), (0, 10, 0),), dtype=np.float32) labels = np.array(((1,), (1,)), dtype=np.int64) @@ -1485,6 +1485,53 @@ class BinaryLogisticHeadWithSigmoidCrossEntropyLossTest(test.TestCase): ] self.assertItemsEqual(expected_metric_keys, spec.eval_metric_ops.keys()) + def test_eval_with_regularization_losses(self): + head = head_lib._binary_logistic_head_with_sigmoid_cross_entropy_loss( + loss_reduction=losses.Reduction.SUM_OVER_BATCH_SIZE) + logits = np.array(((45,), (-41,),), dtype=np.float32) + labels = np.array(((1,), (1,),), dtype=np.int32) + features = {'x': np.array(((42,),), dtype=np.int32)} + regularization_losses = [1.5, 0.5] + expected_regularization_loss = 2. + # unregularized_loss = sum(cross_entropy(labels, logits)) / batch_size + # = sum(0, 41) / 2 = 20.5 + expected_unregularized_loss = 20.5 + expected_regularized_loss = ( + expected_unregularized_loss + expected_regularization_loss) + + # Create estimator spec. + spec = head.create_estimator_spec( + features=features, + mode=model_fn.ModeKeys.EVAL, + logits=logits, + labels=labels, + regularization_losses=regularization_losses) + + keys = metric_keys.MetricKeys + expected_metrics = { + keys.LOSS_MEAN: expected_unregularized_loss, + keys.LOSS_REGULARIZATION: expected_regularization_loss, + keys.ACCURACY: 1./2, + keys.PREDICTION_MEAN: 1./2, + keys.LABEL_MEAN: 2./2, + keys.ACCURACY_BASELINE: 2./2, + keys.AUC: 0., + keys.AUC_PR: 1., + } + + # Assert predictions, loss, and metrics. + with self.test_session() as sess: + _initialize_variables(self, spec.scaffold) + self.assertIsNone(spec.scaffold.summary_op) + value_ops = {k: spec.eval_metric_ops[k][0] for k in spec.eval_metric_ops} + update_ops = {k: spec.eval_metric_ops[k][1] for k in spec.eval_metric_ops} + loss, metrics = sess.run((spec.loss, update_ops)) + self.assertAllClose(expected_regularized_loss, loss) + # Check results of both update (in `metrics`) and value ops. + self.assertAllClose(expected_metrics, metrics) + self.assertAllClose( + expected_metrics, {k: value_ops[k].eval() for k in value_ops}) + def test_eval_with_vocabulary_list_create_loss(self): head = head_lib._binary_logistic_head_with_sigmoid_cross_entropy_loss( label_vocabulary=['aang', 'iroh']) @@ -1749,6 +1796,49 @@ class BinaryLogisticHeadWithSigmoidCrossEntropyLossTest(test.TestCase): }, summary_str) + def test_train_with_regularization_losses(self): + head = head_lib._binary_logistic_head_with_sigmoid_cross_entropy_loss( + loss_reduction=losses.Reduction.SUM_OVER_BATCH_SIZE) + + logits = np.array(((45,), (-41,),), dtype=np.float32) + labels = np.array(((1,), (1,),), dtype=np.float64) + expected_train_result = b'my_train_op' + features = {'x': np.array(((42,),), dtype=np.float32)} + regularization_losses = [1.5, 0.5] + expected_regularization_loss = 2. + # unregularized_loss = sum(cross_entropy(labels, logits)) / batch_size + # = sum(0, 41) / 2 = 20.5 + # loss = unregularized_loss + regularization_loss = 7. + expected_loss = 22.5 + def _train_op_fn(loss): + with ops.control_dependencies((check_ops.assert_equal( + math_ops.to_float(expected_loss), math_ops.to_float(loss), + name='assert_loss'),)): + return constant_op.constant(expected_train_result) + + # Create estimator spec. + spec = head.create_estimator_spec( + features=features, + mode=model_fn.ModeKeys.TRAIN, + logits=logits, + labels=labels, + train_op_fn=_train_op_fn, + regularization_losses=regularization_losses) + + # Assert predictions, loss, train_op, and summaries. + with self.test_session() as sess: + _initialize_variables(self, spec.scaffold) + self.assertIsNotNone(spec.scaffold.summary_op) + loss, train_result, summary_str = sess.run((spec.loss, spec.train_op, + spec.scaffold.summary_op)) + self.assertAllClose(expected_loss, loss) + self.assertEqual(expected_train_result, train_result) + _assert_simple_summaries(self, { + metric_keys.MetricKeys.LOSS: expected_loss, + metric_keys.MetricKeys.LOSS_REGULARIZATION: ( + expected_regularization_loss), + }, summary_str) + def test_float_labels_train_create_loss(self): head = head_lib._binary_logistic_head_with_sigmoid_cross_entropy_loss() @@ -2512,6 +2602,51 @@ class RegressionHeadWithMeanSquaredErrorLossTest(test.TestCase): ] self.assertItemsEqual(expected_metric_keys, spec.eval_metric_ops.keys()) + def test_eval_with_regularization_losses(self): + head = head_lib._regression_head_with_mean_squared_error_loss( + loss_reduction=losses.Reduction.SUM_OVER_BATCH_SIZE) + self.assertEqual(1, head.logits_dimension) + + logits = np.array(((45,), (41,),), dtype=np.float32) + labels = np.array(((43,), (44,),), dtype=np.int32) + features = {'x': np.array(((42,),), dtype=np.float32)} + regularization_losses = [1.5, 0.5] + expected_regularization_loss = 2. + # unregularized_loss = ((43-45)^2 + (44-41)^2) / batch_size + # = (4 + 9) / 2 = 6.5 + expected_unregularized_loss = 6.5 + expected_regularized_loss = ( + expected_unregularized_loss + expected_regularization_loss) + # Create estimator spec. + spec = head.create_estimator_spec( + features=features, + mode=model_fn.ModeKeys.EVAL, + logits=logits, + labels=labels, + regularization_losses=regularization_losses) + + keys = metric_keys.MetricKeys + expected_metrics = { + keys.LOSS_MEAN: expected_unregularized_loss, + keys.LOSS_REGULARIZATION: expected_regularization_loss, + } + + # Assert predictions, loss, and metrics. + with self.test_session() as sess: + _initialize_variables(self, spec.scaffold) + self.assertIsNone(spec.scaffold.summary_op) + value_ops = {k: spec.eval_metric_ops[k][0] for k in spec.eval_metric_ops} + update_ops = {k: spec.eval_metric_ops[k][1] for k in spec.eval_metric_ops} + prediction_key = prediction_keys.PredictionKeys.PREDICTIONS + predictions, loss, metrics = sess.run(( + spec.predictions[prediction_key], spec.loss, update_ops)) + self.assertAllClose(logits, predictions) + self.assertAllClose(expected_regularized_loss, loss) + # Check results of both update (in `metrics`) and value ops. + self.assertAllClose(expected_metrics, metrics) + self.assertAllClose( + expected_metrics, {k: value_ops[k].eval() for k in value_ops}) + def test_train_create_loss(self): head = head_lib._regression_head_with_mean_squared_error_loss() logits = np.array(((45,), (41,),), dtype=np.float32) @@ -2666,6 +2801,53 @@ class RegressionHeadWithMeanSquaredErrorLossTest(test.TestCase): }, summary_str) + def test_train_with_regularization_losses(self): + head = head_lib._regression_head_with_mean_squared_error_loss( + loss_reduction=losses.Reduction.SUM_OVER_BATCH_SIZE) + self.assertEqual(1, head.logits_dimension) + + # Create estimator spec. + logits = np.array(((45,), (41,),), dtype=np.float32) + labels = np.array(((43.,), (44.,),), dtype=np.float64) + expected_train_result = b'my_train_op' + features = {'x': np.array(((42.,),), dtype=np.float32)} + regularization_losses = [1.5, 0.5] + expected_regularization_loss = 2. + # unregularized_loss = ((43-45)^2 + (44-41)^2) / batch_size + # = (4 + 9) / 2 = 6.5 + # loss = unregularized_loss + regularization_loss = 8.5 + expected_loss = 8.5 + def _train_op_fn(loss): + with ops.control_dependencies((check_ops.assert_equal( + math_ops.to_float(expected_loss), math_ops.to_float(loss), + name='assert_loss'),)): + return constant_op.constant(expected_train_result) + + spec = head.create_estimator_spec( + features=features, + mode=model_fn.ModeKeys.TRAIN, + logits=logits, + labels=labels, + train_op_fn=_train_op_fn, + regularization_losses=regularization_losses) + + # Assert predictions, loss, train_op, and summaries. + with self.test_session() as sess: + _initialize_variables(self, spec.scaffold) + self.assertIsNotNone(spec.scaffold.summary_op) + prediction_key = prediction_keys.PredictionKeys.PREDICTIONS + predictions, loss, train_result, summary_str = sess.run(( + spec.predictions[prediction_key], spec.loss, spec.train_op, + spec.scaffold.summary_op)) + self.assertAllClose(logits, predictions) + self.assertAllClose(expected_loss, loss) + self.assertEqual(expected_train_result, train_result) + _assert_simple_summaries(self, { + metric_keys.MetricKeys.LOSS: expected_loss, + metric_keys.MetricKeys.LOSS_REGULARIZATION: ( + expected_regularization_loss), + }, summary_str) + def test_weighted_multi_example_eval(self): """1d label, 3 examples, 1 batch.""" head = head_lib._regression_head_with_mean_squared_error_loss( -- GitLab From 75a5ae1d422c9e3efd8c3d4da2ef734c143c8aea Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 23 Jan 2018 15:20:43 -0800 Subject: [PATCH 147/258] [TF:XLA:CPU] Alias tensorflow::gtl to gtl for brevity PiperOrigin-RevId: 183001493 --- .../compiler/xla/service/cpu/ir_emitter.cc | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/tensorflow/compiler/xla/service/cpu/ir_emitter.cc b/tensorflow/compiler/xla/service/cpu/ir_emitter.cc index cfdf9f4ebc..ac8d5d33fa 100644 --- a/tensorflow/compiler/xla/service/cpu/ir_emitter.cc +++ b/tensorflow/compiler/xla/service/cpu/ir_emitter.cc @@ -72,6 +72,7 @@ namespace { using llvm_ir::AsStringRef; using llvm_ir::IrName; using llvm_ir::SetToFirstInsertPoint; +namespace gtl = tensorflow::gtl; } // namespace namespace cpu { @@ -491,7 +492,7 @@ Status IrEmitter::HandleTuple(HloInstruction* tuple) { } Status IrEmitter::HandleMap(HloInstruction* map) { - tensorflow::gtl::ArraySlice operands(map->operands()); + gtl::ArraySlice operands(map->operands()); HloComputation* function = map->to_apply(); // The called computation should have been emitted previously. llvm::Function* mapped_ir_function = FindOrDie(emitted_functions_, function); @@ -1632,7 +1633,7 @@ IrEmitter::EmitInnerLoopForVectorizedReduction( const ReductionGenerator& reduction_generator, const llvm_ir::IrArray::Index& output_index, const ShardedVectorType& accumulator_type, HloInstruction* init_value, - HloInstruction* arg, tensorflow::gtl::ArraySlice dimensions, + HloInstruction* arg, gtl::ArraySlice dimensions, unsigned element_alignment) { ShardedVector accumulator; accumulator.reserve(accumulator_type.size()); @@ -1736,7 +1737,7 @@ void IrEmitter::EmitShardedVectorStore( StatusOr IrEmitter::EmitVectorizedReduce( HloInstruction* reduce, HloInstruction* arg, HloInstruction* init_value, - tensorflow::gtl::ArraySlice dimensions, HloComputation* function, + gtl::ArraySlice dimensions, HloComputation* function, string* failure_reason) { ReductionGenerator reduction_generator = MatchReductionGenerator(function, failure_reason); @@ -1881,7 +1882,7 @@ StatusOr IrEmitter::EmitVectorizedReduce( Status IrEmitter::HandleReduce(HloInstruction* reduce) { auto arg = reduce->mutable_operand(0); auto init_value = reduce->mutable_operand(1); - tensorflow::gtl::ArraySlice dimensions(reduce->dimensions()); + gtl::ArraySlice dimensions(reduce->dimensions()); HloComputation* function = reduce->to_apply(); if (!options::VectorizedReduceDisabled(hlo_module_config_)) { string vectorization_failure_reason; @@ -2001,7 +2002,7 @@ Status IrEmitter::HandleSlice(HloInstruction* slice) { // // * Implement the memcpy within the innermost loop. - tensorflow::gtl::FlatSet inner_dims; + gtl::FlatSet inner_dims; for (int64 dim : LayoutUtil::MinorToMajor(layout)) { if (operand->shape().dimensions(dim) != slice->shape().dimensions(dim)) { break; @@ -2329,8 +2330,7 @@ Status IrEmitter::HandleCall(HloInstruction* call) { } Status IrEmitter::HandleCustomCall(HloInstruction* custom_call) { - tensorflow::gtl::ArraySlice operands( - custom_call->operands()); + gtl::ArraySlice operands(custom_call->operands()); tensorflow::StringPiece custom_call_target(custom_call->custom_call_target()); llvm::Type* i8_ptr_type = ir_builder_.getInt8PtrTy(); llvm::AllocaInst* operands_alloca = @@ -2461,8 +2461,7 @@ Status IrEmitter::HandleWhile(HloInstruction* xla_while) { } StatusOr IrEmitter::EmitFastConcatenate( - HloInstruction* concatenate, - tensorflow::gtl::ArraySlice operands, + HloInstruction* concatenate, gtl::ArraySlice operands, string* failure_reason) { if (ShouldEmitParallelLoopFor(*concatenate)) { *failure_reason = @@ -2601,8 +2600,7 @@ void IrEmitter::EmitTransferElements(llvm::Value* target, llvm::Value* source, } Status IrEmitter::HandleConcatenate(HloInstruction* concatenate) { - tensorflow::gtl::ArraySlice operands( - concatenate->operands()); + gtl::ArraySlice operands(concatenate->operands()); string failure_reason; TF_ASSIGN_OR_RETURN( bool successful, @@ -2915,7 +2913,7 @@ llvm::Value* IrEmitter::EmitTempBufferPointer( // for a single element_type value, and loads it after call. llvm::Value* IrEmitter::EmitElementFunctionCall( llvm::Function* function, const Shape& return_shape, - tensorflow::gtl::ArraySlice parameter_addresses, + gtl::ArraySlice parameter_addresses, tensorflow::StringPiece name) { llvm::Value* return_value_buffer = EmitArrayFunctionCall( function, return_shape, 1, parameter_addresses, name); @@ -2935,8 +2933,7 @@ llvm::Value* IrEmitter::EmitElementFunctionCall( // temps) // return return_value_buffer -- address of the return value. void IrEmitter::EmitArrayFunctionCallInto( - llvm::Function* function, - tensorflow::gtl::ArraySlice parameter_addresses, + llvm::Function* function, gtl::ArraySlice parameter_addresses, llvm::Value* return_value_buffer, tensorflow::StringPiece name) { ir_builder_.CreateCall( function, GetArrayFunctionCallArguments( @@ -2949,7 +2946,7 @@ void IrEmitter::EmitArrayFunctionCallInto( llvm::Value* IrEmitter::EmitArrayFunctionCall( llvm::Function* function, const Shape& return_shape, int64 element_count, - tensorflow::gtl::ArraySlice parameter_addresses, + gtl::ArraySlice parameter_addresses, tensorflow::StringPiece name) { llvm::Value* elements = llvm::ConstantInt::get(ir_builder_.getInt64Ty(), element_count); @@ -3059,8 +3056,8 @@ Status IrEmitter::EmitMemcpy(const HloInstruction& source, Status IrEmitter::ElementTypesSameAndSupported( const HloInstruction& instruction, - tensorflow::gtl::ArraySlice operands, - tensorflow::gtl::ArraySlice supported_types) { + gtl::ArraySlice operands, + gtl::ArraySlice supported_types) { for (auto operand : operands) { TF_RET_CHECK( ShapeUtil::SameElementType(operands[0]->shape(), operand->shape())); -- GitLab From f16cf555905d711c1877039e3b37240e9026c1f2 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 15:41:33 -0800 Subject: [PATCH 148/258] Add a base transformer class with useful utilities. Intercept errors in the base class and include additional context information. Use the base transformer class with type_info.py. PiperOrigin-RevId: 183004622 --- tensorflow/contrib/py2tf/conversion.py | 20 ++++--- .../py2tf/convert/builtin_functions_test.py | 2 +- .../contrib/py2tf/convert/call_trees_test.py | 2 +- .../py2tf/convert/control_flow_test.py | 2 +- .../py2tf/convert/print_functions_test.py | 2 +- .../py2tf/convert/side_effect_guards_test.py | 2 +- tensorflow/contrib/py2tf/pyct/BUILD | 1 + .../py2tf/pyct/static_analysis/type_info.py | 10 ++-- .../pyct/static_analysis/type_info_test.py | 25 ++++----- tensorflow/contrib/py2tf/pyct/transformer.py | 52 +++++++++++++++++++ 10 files changed, 90 insertions(+), 28 deletions(-) create mode 100644 tensorflow/contrib/py2tf/pyct/transformer.py diff --git a/tensorflow/contrib/py2tf/conversion.py b/tensorflow/contrib/py2tf/conversion.py index 3bdbc66a99..38f1c0a14a 100644 --- a/tensorflow/contrib/py2tf/conversion.py +++ b/tensorflow/contrib/py2tf/conversion.py @@ -181,7 +181,8 @@ def function_to_graph(f, conversion_map, param_value_hints, owner_type=None): node_globals[fn.__name__] = fn namer = conversion_map.new_namer(node_globals) - node = node_to_graph(node, namer, node_globals, param_value_hints, + node = node_to_graph(node, tf_inspect.getsource(f), tf_inspect.getfile(f), + namer, node_globals, param_value_hints, conversion_map.nocompile_decorators) # Simulate a rename to ensure the top level is in the name map. This is needed @@ -196,18 +197,23 @@ def function_to_graph(f, conversion_map, param_value_hints, owner_type=None): return node, conversion_map.name_map[f] -def _static_analysis_pass(node, namespace, value_hints): +def _static_analysis_pass(node, source, f, namespace, value_hints): node = access.resolve(node) node = live_values.resolve(node, namespace, config.PYTHON_LITERALS) - node = type_info.resolve(node, value_hints) + node = type_info.resolve(node, source, f, value_hints) return node -def node_to_graph(node, namer, namespace, value_hints, nocompile_decorators): +def node_to_graph(node, source, f, namer, namespace, value_hints, + nocompile_decorators): """Convert Python code to equivalent TF graph mode code. Args: node: A Python AST node representing the code to convert. + source: Optional string containing the source code of the node. Used in + error messages. + f: Optional string indicating the file where the node originated. None if + unknown. Used in error messages. namer: A naming.Namer object. namespace: Dict mapping symbol names to their corresponding live objects. value_hints: A dict containing value hints for symbols like function @@ -235,7 +241,7 @@ def node_to_graph(node, namer, namespace, value_hints, nocompile_decorators): # tree, which must be accounted. Although less efficient, it is most robust # to re-run the analysis. - node = _static_analysis_pass(node, namespace, value_hints) + node = _static_analysis_pass(node, source, f, namespace, value_hints) node = decorators.transform(node, nocompile_decorators) node = break_canonicalization.transform(node, namer) @@ -245,14 +251,14 @@ def node_to_graph(node, namer, namespace, value_hints, nocompile_decorators): node = continue_canonicalization.transform(node, namer) namespace['len'] = len - node = _static_analysis_pass(node, namespace, value_hints) + node = _static_analysis_pass(node, None, None, namespace, value_hints) node = for_canonicalization.transform(node, namer) # for_canonicalization may insert new global references. node = builtin_functions.transform(node) # builtin_functions may insert new global references. namespace['print'] = print - node = _static_analysis_pass(node, namespace, value_hints) + node = _static_analysis_pass(node, None, None, namespace, value_hints) node = print_functions.transform(node) node = call_trees.transform(node, namer, namespace, config.DEFAULT_UNCOMPILED_MODULES, diff --git a/tensorflow/contrib/py2tf/convert/builtin_functions_test.py b/tensorflow/contrib/py2tf/convert/builtin_functions_test.py index 633602f4d4..ab02b362aa 100644 --- a/tensorflow/contrib/py2tf/convert/builtin_functions_test.py +++ b/tensorflow/contrib/py2tf/convert/builtin_functions_test.py @@ -35,7 +35,7 @@ class BuiltinFunctionsTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, {}) + node = type_info.resolve(node, None, None, {}) return node def test_len(self): diff --git a/tensorflow/contrib/py2tf/convert/call_trees_test.py b/tensorflow/contrib/py2tf/convert/call_trees_test.py index 3367d41db3..78a6b53910 100644 --- a/tensorflow/contrib/py2tf/convert/call_trees_test.py +++ b/tensorflow/contrib/py2tf/convert/call_trees_test.py @@ -41,7 +41,7 @@ class CallTreesTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, {}) + node = type_info.resolve(node, None, None, {}) return node def test_basic(self): diff --git a/tensorflow/contrib/py2tf/convert/control_flow_test.py b/tensorflow/contrib/py2tf/convert/control_flow_test.py index 121af4ee94..64a317ee9c 100644 --- a/tensorflow/contrib/py2tf/convert/control_flow_test.py +++ b/tensorflow/contrib/py2tf/convert/control_flow_test.py @@ -46,7 +46,7 @@ class ControlFlowTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, {}) + node = type_info.resolve(node, None, None, {}) return node def test_simple_while(self): diff --git a/tensorflow/contrib/py2tf/convert/print_functions_test.py b/tensorflow/contrib/py2tf/convert/print_functions_test.py index 65e592b66e..8b6c238aa4 100644 --- a/tensorflow/contrib/py2tf/convert/print_functions_test.py +++ b/tensorflow/contrib/py2tf/convert/print_functions_test.py @@ -35,7 +35,7 @@ class PrintFunctionsTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, {}) + node = type_info.resolve(node, None, None, {}) return node def test_transform(self): diff --git a/tensorflow/contrib/py2tf/convert/side_effect_guards_test.py b/tensorflow/contrib/py2tf/convert/side_effect_guards_test.py index d932840186..1715e9eb95 100644 --- a/tensorflow/contrib/py2tf/convert/side_effect_guards_test.py +++ b/tensorflow/contrib/py2tf/convert/side_effect_guards_test.py @@ -43,7 +43,7 @@ class SideEffectGuardsTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, {}) + node = type_info.resolve(node, None, None, {}) return node def test_transform(self): diff --git a/tensorflow/contrib/py2tf/pyct/BUILD b/tensorflow/contrib/py2tf/pyct/BUILD index b60ed918f5..9dd564cb9f 100644 --- a/tensorflow/contrib/py2tf/pyct/BUILD +++ b/tensorflow/contrib/py2tf/pyct/BUILD @@ -23,6 +23,7 @@ py_library( "parser.py", "pretty_printer.py", "templates.py", + "transformer.py", ], srcs_version = "PY2AND3", visibility = ["//visibility:public"], diff --git a/tensorflow/contrib/py2tf/pyct/static_analysis/type_info.py b/tensorflow/contrib/py2tf/pyct/static_analysis/type_info.py index 3e54590326..b17af5d844 100644 --- a/tensorflow/contrib/py2tf/pyct/static_analysis/type_info.py +++ b/tensorflow/contrib/py2tf/pyct/static_analysis/type_info.py @@ -24,6 +24,7 @@ from __future__ import print_function import gast from tensorflow.contrib.py2tf.pyct import anno +from tensorflow.contrib.py2tf.pyct import transformer from tensorflow.python.util import tf_inspect @@ -69,7 +70,7 @@ class Scope(object): raise KeyError(name) -class TypeInfoResolver(gast.NodeTransformer): +class TypeInfoResolver(transformer.Base): """Annotates symbols with type information where possible. Nodes currently annotated: @@ -77,7 +78,8 @@ class TypeInfoResolver(gast.NodeTransformer): * Attribute (helps resolve object methods) """ - def __init__(self, value_hints): + def __init__(self, value_hints, source, f): + super(TypeInfoResolver, self).__init__(source, f) self.scope = Scope(None) self.value_hints = value_hints self.function_level = 0 @@ -206,6 +208,6 @@ class TypeInfoResolver(gast.NodeTransformer): return node -def resolve(node, value_hints): +def resolve(node, source, f, value_hints): assert value_hints is not None - return TypeInfoResolver(value_hints).visit(node) + return TypeInfoResolver(value_hints, source, f).visit(node) diff --git a/tensorflow/contrib/py2tf/pyct/static_analysis/type_info_test.py b/tensorflow/contrib/py2tf/pyct/static_analysis/type_info_test.py index 8526f42413..98dc7bf50f 100644 --- a/tensorflow/contrib/py2tf/pyct/static_analysis/type_info_test.py +++ b/tensorflow/contrib/py2tf/pyct/static_analysis/type_info_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.contrib.py2tf.pyct import anno from tensorflow.contrib.py2tf.pyct import parser +from tensorflow.contrib.py2tf.pyct import transformer from tensorflow.contrib.py2tf.pyct.static_analysis import access from tensorflow.contrib.py2tf.pyct.static_analysis import live_values from tensorflow.contrib.py2tf.pyct.static_analysis import type_info @@ -63,7 +64,7 @@ class TypeInfoResolverTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, {'training': training}, {}) - node = type_info.resolve(node, {}) + node = type_info.resolve(node, None, None, {}) call_node = node.body[0].body[0].value self.assertEquals(training.GradientDescentOptimizer, @@ -80,7 +81,7 @@ class TypeInfoResolverTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, {'training': training}, {}) - node = type_info.resolve(node, {}) + node = type_info.resolve(node, None, None, {}) attr_call_node = node.body[0].body[1].value.func self.assertEquals((training.__name__, 'GradientDescentOptimizer'), @@ -95,7 +96,7 @@ class TypeInfoResolverTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, {'session': session}, {}) - node = type_info.resolve(node, {}) + node = type_info.resolve(node, None, None, {}) constructor_call = node.body[0].body[0].items[0].context_expr self.assertEquals(session.Session, anno.getanno(constructor_call, 'type')) @@ -118,8 +119,8 @@ class TypeInfoResolverTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, {'training': training}, {}) - with self.assertRaises(ValueError): - node = type_info.resolve(node, {}) + with self.assertRaises(transformer.PyFlowParseError): + node = type_info.resolve(node, None, None, {}) def test_parameter_class_members(self): @@ -129,8 +130,8 @@ class TypeInfoResolverTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, {'training': training}, {}) - with self.assertRaises(ValueError): - node = type_info.resolve(node, {}) + with self.assertRaises(transformer.PyFlowParseError): + node = type_info.resolve(node, None, None, {}) def test_parameter_class_members_with_value_hints(self): @@ -141,7 +142,7 @@ class TypeInfoResolverTest(test.TestCase): node = access.resolve(node) node = live_values.resolve(node, {'training': training}, {}) node = type_info.resolve( - node, { + node, None, None, { 'opt': (('%s.GradientDescentOptimizer' % training.__name__), training.GradientDescentOptimizer(0.1)) }) @@ -163,8 +164,8 @@ class TypeInfoResolverTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, {'bar': bar}, {}) - with self.assertRaises(ValueError): - node = type_info.resolve(node, {}) + with self.assertRaises(transformer.PyFlowParseError): + node = type_info.resolve(node, None, None, {}) def test_nested_members(self): @@ -175,8 +176,8 @@ class TypeInfoResolverTest(test.TestCase): node = parser.parse_object(test_fn) node = access.resolve(node) node = live_values.resolve(node, {'training': training}, {}) - with self.assertRaises(ValueError): - node = type_info.resolve(node, {}) + with self.assertRaises(transformer.PyFlowParseError): + node = type_info.resolve(node, None, None, {}) if __name__ == '__main__': diff --git a/tensorflow/contrib/py2tf/pyct/transformer.py b/tensorflow/contrib/py2tf/pyct/transformer.py new file mode 100644 index 0000000000..1658a1b694 --- /dev/null +++ b/tensorflow/contrib/py2tf/pyct/transformer.py @@ -0,0 +1,52 @@ +# Copyright 2017 The TensorFlow Authors. 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 node transformer that includes utilities for SCT.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import gast + +from tensorflow.contrib.py2tf.pyct import pretty_printer + + +class PyFlowParseError(SyntaxError): + pass + + +class Base(gast.NodeTransformer): + """Base class for specialized transformers.""" + + def __init__(self, source, f): + self._lineno = 0 + self._col_offset = 0 + self._source = source + self._file = f + + def visit(self, node): + try: + if self._source and hasattr(node, 'lineno'): + self._lineno = node.lineno + self._col_offset = node.col_offset + return super(Base, self).visit(node) + except ValueError as e: + msg = '%s\nOccurred at node:\n%s' % (str(e), pretty_printer.fmt(node)) + if self._source: + line = self._source.splitlines()[self._lineno - 1] + else: + line = '' + raise PyFlowParseError( + msg, (self._file, self._lineno, self._col_offset + 1, line)) -- GitLab From 84a5c4bb26d6ce30d2243c4314320d0ff93fda47 Mon Sep 17 00:00:00 2001 From: Frank Perbet Date: Tue, 23 Jan 2018 15:59:09 -0800 Subject: [PATCH 149/258] Make namedtuples with identical name and field names to be considered as the same shallow structure. PiperOrigin-RevId: 183007218 --- tensorflow/python/util/nest.py | 87 +++++++++++++++++++++++++---- tensorflow/python/util/nest_test.py | 30 ++++++++++ 2 files changed, 107 insertions(+), 10 deletions(-) diff --git a/tensorflow/python/util/nest.py b/tensorflow/python/util/nest.py index 4ce871de72..874df3d108 100644 --- a/tensorflow/python/util/nest.py +++ b/tensorflow/python/util/nest.py @@ -47,10 +47,25 @@ def _sorted(dict_): raise TypeError("nest only supports dicts with sortable keys.") -def _is_namedtuple(instance): - """Returns True iff `instance` is a `namedtuple`.""" +def _is_namedtuple(instance, strict=False): + """Returns True iff `instance` is a `namedtuple`. + + Args: + instance: An instance of a Python object. + strict: If True, `instance` is considered to be a `namedtuple` only if + it is a "plain" namedtuple. For instance, a class inheriting + from a `namedtuple` will be considered to be a `namedtuple` + iff `strict=False`. + + Returns: + True if `instance` is a `namedtuple`. + """ + # Attemp to limit the test to plain namedtuple (not stuff inheriting from it). + if not isinstance(instance, tuple): + return False + if strict and instance.__class__.__base__ != tuple: + return False return ( - isinstance(instance, tuple) and hasattr(instance, "_fields") and isinstance(instance._fields, _collections.Sequence) and all(isinstance(f, _six.string_types) for f in instance._fields)) @@ -140,8 +155,37 @@ def flatten(nest): return _pywrap_tensorflow.Flatten(nest) +def _same_namedtuples(nest1, nest2): + """Returns True if the two namedtuples have the same name and fields.""" + if nest1._fields != nest2._fields: + return False + if nest1.__class__.__name__ != nest2.__class__.__name__: + return False + return True + + def _recursive_assert_same_structure(nest1, nest2, check_types): - """Helper function for `assert_same_structure`.""" + """Helper function for `assert_same_structure`. + + See `assert_same_structure` for further information about namedtuples. + + Args: + nest1: An arbitrarily nested structure. + nest2: An arbitrarily nested structure. + check_types: If `True` (default) types of sequences are checked as + well, including the keys of dictionaries. If set to `False`, for example + a list and a tuple of objects will look the same if they have the same + size. Note that namedtuples with identical name and fields are always + considered to have the same shallow structure. + + Returns: + True if `nest1` and `nest2` have the same structure. + + Raises: + ValueError: If the two structure don't have the same nested structre. + TypeError: If the two structure don't have the same sequence type. + ValueError: If the two dictionaries don't have the same set of keys. + """ is_sequence_nest1 = is_sequence(nest1) if is_sequence_nest1 != is_sequence(nest2): raise ValueError( @@ -154,11 +198,21 @@ def _recursive_assert_same_structure(nest1, nest2, check_types): if check_types: type_nest1 = type(nest1) type_nest2 = type(nest2) - if type_nest1 != type_nest2: - raise TypeError( - "The two structures don't have the same sequence type. First " - "structure has type %s, while second structure has type %s." - % (type_nest1, type_nest2)) + + # Duck-typing means that nest should be fine with two different namedtuples + # with identical name and fields. + if _is_namedtuple(nest1, True) and _is_namedtuple(nest2, True): + if not _same_namedtuples(nest1, nest2): + raise TypeError( + "The two namedtuples don't have the same sequence type. First " + "structure has type %s, while second structure has type %s." + % (type_nest1, type_nest2)) + else: + if type_nest1 != type_nest2: + raise TypeError( + "The two structures don't have the same sequence type. First " + "structure has type %s, while second structure has type %s." + % (type_nest1, type_nest2)) if isinstance(nest1, dict): keys1 = set(_six.iterkeys(nest1)) @@ -178,13 +232,24 @@ def _recursive_assert_same_structure(nest1, nest2, check_types): def assert_same_structure(nest1, nest2, check_types=True): """Asserts that two structures are nested in the same way. + Note that namedtuples with identical name and fields are always considered + to have the same shallow structure (even with `check_types=True`). + For intance, this code will print `True`: + + ```python + def nt(a, b): + return collections.namedtuple('foo', 'a b')(a, b) + print(assert_same_structure(nt(0, 1), nt(2, 3))) + ``` + Args: nest1: an arbitrarily nested structure. nest2: an arbitrarily nested structure. check_types: if `True` (default) types of sequences are checked as well, including the keys of dictionaries. If set to `False`, for example a list and a tuple of objects will look the same if they have the same - size. + size. Note that namedtuples with identical name and fields are always + considered to have the same shallow structure. Raises: ValueError: If the two structures do not have the same number of elements or @@ -354,6 +419,8 @@ def map_structure(func, *structure, **check_types_dict): `True` (default) the types of iterables within the structures have to be same (e.g. `map_structure(func, [1], (1,))` raises a `TypeError` exception). To allow this set this argument to `False`. + Note that namedtuples with identical name and fields are always + considered to have the same shallow structure. Returns: A new structure with the same arity as `structure`, whose values correspond diff --git a/tensorflow/python/util/nest_test.py b/tensorflow/python/util/nest_test.py index 4906649f01..6bec397db5 100644 --- a/tensorflow/python/util/nest_test.py +++ b/tensorflow/python/util/nest_test.py @@ -258,6 +258,36 @@ class NestTest(test.TestCase): "don't have the same set of keys"): nest.assert_same_structure({"a": 1}, {"b": 1}) + same_name_type_0 = collections.namedtuple("same_name", ("a", "b")) + same_name_type_1 = collections.namedtuple("same_name", ("a", "b")) + nest.assert_same_structure(same_name_type_0(0, 1), same_name_type_1(2, 3)) + + # This assertion is expected to pass: two namedtuples with the same + # name and field names are considered to be identical. + same_name_type_2 = collections.namedtuple("same_name_1", ("x", "y")) + same_name_type_3 = collections.namedtuple("same_name_1", ("x", "y")) + nest.assert_same_structure( + same_name_type_0(same_name_type_2(0, 1), 2), + same_name_type_1(same_name_type_3(2, 3), 4)) + + expected_message = "The two structures don't have the same.*" + with self.assertRaisesRegexp(ValueError, expected_message): + nest.assert_same_structure(same_name_type_0(0, same_name_type_1(1, 2)), + same_name_type_1(same_name_type_0(0, 1), 2)) + + same_name_type_1 = collections.namedtuple("not_same_name", ("a", "b")) + self.assertRaises(TypeError, nest.assert_same_structure, + same_name_type_0(0, 1), same_name_type_1(2, 3)) + + same_name_type_1 = collections.namedtuple("same_name", ("x", "y")) + self.assertRaises(TypeError, nest.assert_same_structure, + same_name_type_0(0, 1), same_name_type_1(2, 3)) + + class SameNamedType1(collections.namedtuple("same_name", ("a", "b"))): + pass + self.assertRaises(TypeError, nest.assert_same_structure, + same_name_type_0(0, 1), SameNamedType1(2, 3)) + def testMapStructure(self): structure1 = (((1, 2), 3), 4, (5, 6)) structure2 = (((7, 8), 9), 10, (11, 12)) -- GitLab From 3fd539dce556ba11cb5ee88cbdd75614be0590b7 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Tue, 23 Jan 2018 16:03:41 -0800 Subject: [PATCH 150/258] Make the toco python wrapper lazy loaded to avoid dep error. PiperOrigin-RevId: 183007943 --- tensorflow/contrib/lite/python/lite.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/lite/python/lite.py b/tensorflow/contrib/lite/python/lite.py index 4d87a5907b..3c369774be 100644 --- a/tensorflow/contrib/lite/python/lite.py +++ b/tensorflow/contrib/lite/python/lite.py @@ -31,10 +31,18 @@ import tempfile from tensorflow.contrib.lite.toco import model_flags_pb2 as _model_flags_pb2 from tensorflow.contrib.lite.toco import toco_flags_pb2 as _toco_flags_pb2 from tensorflow.contrib.lite.toco import types_pb2 as _types_pb2 -from tensorflow.contrib.lite.toco.python.tensorflow_wrap_toco import TocoConvert as _toco_convert_protos from tensorflow.python.framework import dtypes as _dtypes from tensorflow.python.platform import resource_loader as _resource_loader from tensorflow.python.util.all_util import remove_undocumented +from tensorflow.python.util.lazy_loader import LazyLoader + +# Lazy load since some of the performance benchmark skylark rules +# break dependencies. +_toco_python = LazyLoader( + "tensorflow_wrap_toco", globals(), + "tensorflow.contrib.lite.toco.python." + "tensorflow_wrap_toco") +del LazyLoader # Enum types from the protobuf promoted to the API FLOAT = _types_pb2.FLOAT @@ -86,7 +94,8 @@ def toco_convert_protos(model_flags_str, toco_flags_str, input_data_str): # TODO(aselle): When toco does not use fatal errors for failure, we can # switch this on. if not _toco_from_proto_bin: - return _toco_convert_protos(model_flags_str, toco_flags_str, input_data_str) + return _toco_python.TocoConvert( + model_flags_str, toco_flags_str, input_data_str) with tempfile.NamedTemporaryFile() as fp_toco, \ tempfile.NamedTemporaryFile() as fp_model, \ -- GitLab From f5c6d3f28f382d09c19f36ff99a8966231d85c15 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 16:22:43 -0800 Subject: [PATCH 151/258] Add unidirectional sequence LSTM to TFLite Ops. PiperOrigin-RevId: 183010993 --- tensorflow/contrib/lite/kernels/BUILD | 13 + tensorflow/contrib/lite/kernels/register.cc | 3 + .../kernels/unidirectional_sequence_lstm.cc | 527 ++++++++ .../unidirectional_sequence_lstm_test.cc | 1089 +++++++++++++++++ tensorflow/contrib/lite/model.cc | 1 + tensorflow/contrib/lite/nnapi_delegate.cc | 1 + tensorflow/contrib/lite/schema/schema.fbs | 1 + .../contrib/lite/schema/schema_generated.h | 9 +- 8 files changed, 1641 insertions(+), 3 deletions(-) create mode 100644 tensorflow/contrib/lite/kernels/unidirectional_sequence_lstm.cc create mode 100644 tensorflow/contrib/lite/kernels/unidirectional_sequence_lstm_test.cc diff --git a/tensorflow/contrib/lite/kernels/BUILD b/tensorflow/contrib/lite/kernels/BUILD index bd390d664d..2d51b8727f 100644 --- a/tensorflow/contrib/lite/kernels/BUILD +++ b/tensorflow/contrib/lite/kernels/BUILD @@ -106,6 +106,7 @@ cc_library( "sub.cc", "svdf.cc", "transpose.cc", + "unidirectional_sequence_lstm.cc", "unidirectional_sequence_rnn.cc", ], hdrs = [ @@ -249,6 +250,18 @@ tf_cc_test( ], ) +tf_cc_test( + name = "unidirectional_sequence_lstm_test", + size = "small", + srcs = ["unidirectional_sequence_lstm_test.cc"], + deps = [ + ":builtin_ops", + "//tensorflow/contrib/lite:framework", + "//tensorflow/contrib/lite/kernels:test_util", + "@com_google_googletest//:gtest", + ], +) + tf_cc_test( name = "unidirectional_sequence_rnn_test", size = "small", diff --git a/tensorflow/contrib/lite/kernels/register.cc b/tensorflow/contrib/lite/kernels/register.cc index 45ad5f1890..c9e74cb8d5 100644 --- a/tensorflow/contrib/lite/kernels/register.cc +++ b/tensorflow/contrib/lite/kernels/register.cc @@ -48,6 +48,7 @@ TfLiteRegistration* Register_MUL(); TfLiteRegistration* Register_L2_NORMALIZATION(); TfLiteRegistration* Register_LOCAL_RESPONSE_NORMALIZATION(); TfLiteRegistration* Register_LSTM(); +TfLiteRegistration* Register_UNIDIRECTIONAL_SEQUENCE_LSTM(); TfLiteRegistration* Register_PAD(); TfLiteRegistration* Register_RESHAPE(); TfLiteRegistration* Register_RESIZE_BILINEAR(); @@ -89,6 +90,8 @@ BuiltinOpResolver::BuiltinOpResolver() { AddBuiltin(BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION, Register_LOCAL_RESPONSE_NORMALIZATION()); AddBuiltin(BuiltinOperator_LSTM, Register_LSTM()); + AddBuiltin(BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, + Register_UNIDIRECTIONAL_SEQUENCE_LSTM()); AddBuiltin(BuiltinOperator_PAD, Register_PAD()); AddBuiltin(BuiltinOperator_RESHAPE, Register_RESHAPE()); AddBuiltin(BuiltinOperator_RESIZE_BILINEAR, Register_RESIZE_BILINEAR()); diff --git a/tensorflow/contrib/lite/kernels/unidirectional_sequence_lstm.cc b/tensorflow/contrib/lite/kernels/unidirectional_sequence_lstm.cc new file mode 100644 index 0000000000..9cdb58714e --- /dev/null +++ b/tensorflow/contrib/lite/kernels/unidirectional_sequence_lstm.cc @@ -0,0 +1,527 @@ +/* Copyright 2017 The TensorFlow Authors. 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 +#include +#include +#include +#include +#include +#include + +#include "tensorflow/contrib/lite/builtin_op_data.h" +#include "tensorflow/contrib/lite/context.h" +#include "tensorflow/contrib/lite/kernels/activation_functor.h" +#include "tensorflow/contrib/lite/kernels/internal/tensor_utils.h" +#include "tensorflow/contrib/lite/kernels/kernel_util.h" +#include "tensorflow/contrib/lite/kernels/op_macros.h" + +namespace tflite { +namespace ops { +namespace builtin { +namespace unidirectional_sequence_lstm { + +// Input Tensors of size {max_time, n_batch, n_input} +constexpr int kInputTensor = 0; + +// Input weight tensors of size: {n_cell, n_input} +constexpr int kInputToInputWeightsTensor = 1; // Optional +constexpr int kInputToForgetWeightsTensor = 2; +constexpr int kInputToCellWeightsTensor = 3; +constexpr int kInputToOutputWeightsTensor = 4; + +// Recurrent weight tensors of size {n_cell, n_output} +constexpr int kRecurrentToInputWeightsTensor = 5; // Optional +constexpr int kRecurrentToForgetWeightsTensor = 6; +constexpr int kRecurrentToCellWeightsTensor = 7; +constexpr int kRecurrentToOutputWeightsTensor = 8; + +// Peephole weights tensors of size {n_cell}, representing a diagonal matrix. +constexpr int kCellToInputWeightsTensor = 9; // Optional +constexpr int kCellToForgetWeightsTensor = 10; // Optional +constexpr int kCellToOutputWeightsTensor = 11; // Optional + +// Gates bias tensors of size {n_cell} +constexpr int kInputGateBiasTensor = 12; // Optional +constexpr int kForgetGateBiasTensor = 13; +constexpr int kCellGateBiasTensor = 14; +constexpr int kOutputGateBiasTensor = 15; + +// Projection weight tensor of size {n_output, n_cell} +constexpr int kProjectionWeightsTensor = 16; // Optional +// Projection bias tensor of size {n_output} +constexpr int kProjectionBiasTensor = 17; // Optional + +// Output tensors. +constexpr int kScratchBufferTensor = 0; +constexpr int kOutputStateTensor = 1; +constexpr int kCellStateTensor = 2; +constexpr int kOutputTensor = 3; + +// Check that input tensor dimensions matches with each other. +TfLiteStatus CheckInputTensorDimensions(TfLiteContext* context, + TfLiteNode* node, int n_input, + int n_output, int n_cell) { + auto* params = reinterpret_cast(node->builtin_data); + + // Making sure clipping parameters have valid values. + // == 0 means no clipping + // > 0 means clipping + TF_LITE_ENSURE(context, params->cell_clip >= 0); + TF_LITE_ENSURE(context, params->proj_clip >= 0); + + TfLiteTensor* input_to_input_weights = + GetOptionalInputTensor(context, node, kInputToInputWeightsTensor); + if (input_to_input_weights) { + TF_LITE_ENSURE_EQ(context, input_to_input_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, input_to_input_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_EQ(context, input_to_input_weights->dims->data[1], n_input); + } + + TfLiteTensor* input_to_forget_weights = + GetInput(context, node, kInputToForgetWeightsTensor); + TF_LITE_ENSURE_EQ(context, input_to_forget_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, input_to_forget_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_EQ(context, input_to_forget_weights->dims->data[1], n_input); + + TfLiteTensor* input_to_cell_weights = + GetInput(context, node, kInputToCellWeightsTensor); + TF_LITE_ENSURE_EQ(context, input_to_cell_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, input_to_cell_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_EQ(context, input_to_cell_weights->dims->data[1], n_input); + + TfLiteTensor* recurrent_to_input_weights = + GetOptionalInputTensor(context, node, kRecurrentToInputWeightsTensor); + if (recurrent_to_input_weights) { + TF_LITE_ENSURE_EQ(context, recurrent_to_input_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, recurrent_to_input_weights->dims->data[0], + n_cell); + TF_LITE_ENSURE_EQ(context, recurrent_to_input_weights->dims->data[1], + n_output); + } + + TfLiteTensor* recurrent_to_forget_weights = + GetInput(context, node, kRecurrentToForgetWeightsTensor); + TF_LITE_ENSURE_EQ(context, recurrent_to_forget_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, recurrent_to_forget_weights->dims->data[0], + n_cell); + TF_LITE_ENSURE_EQ(context, recurrent_to_forget_weights->dims->data[1], + n_output); + + TfLiteTensor* recurrent_to_cell_weights = + GetInput(context, node, kRecurrentToCellWeightsTensor); + TF_LITE_ENSURE_EQ(context, recurrent_to_cell_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, recurrent_to_cell_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_EQ(context, recurrent_to_cell_weights->dims->data[1], + n_output); + + // We make sure the input-gate's parameters are either both present (regular + // LSTM) or not at all (CIFG-LSTM). + const bool cifg_weights_all_or_none = + ((input_to_input_weights != nullptr) && + (recurrent_to_input_weights != nullptr)) || + ((input_to_input_weights == nullptr) && + (recurrent_to_input_weights == nullptr)); + TF_LITE_ENSURE(context, cifg_weights_all_or_none == true); + + TfLiteTensor* cell_to_input_weights = + GetOptionalInputTensor(context, node, kCellToInputWeightsTensor); + if (cell_to_input_weights) { + TF_LITE_ENSURE_EQ(context, cell_to_input_weights->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_to_input_weights->dims->data[0], n_cell); + } + + TfLiteTensor* cell_to_forget_weights = + GetOptionalInputTensor(context, node, kCellToForgetWeightsTensor); + if (cell_to_forget_weights) { + TF_LITE_ENSURE_EQ(context, cell_to_forget_weights->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_to_forget_weights->dims->data[0], n_cell); + } + + TfLiteTensor* cell_to_output_weights = + GetOptionalInputTensor(context, node, kCellToOutputWeightsTensor); + if (cell_to_output_weights) { + TF_LITE_ENSURE_EQ(context, cell_to_output_weights->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_to_output_weights->dims->data[0], n_cell); + } + + // Making sure the peephole weights are there all or none. + const bool use_cifg = (input_to_input_weights == nullptr); + const bool peephole_weights_all_or_none = + ((cell_to_input_weights != nullptr || use_cifg) && + (cell_to_forget_weights != nullptr) && + (cell_to_output_weights != nullptr)) || + ((cell_to_input_weights == nullptr) && + (cell_to_forget_weights == nullptr) && + (cell_to_output_weights == nullptr)); + TF_LITE_ENSURE(context, peephole_weights_all_or_none == true); + + // Make sure the input gate bias is present only when not a CIFG-LSTM. + TfLiteTensor* input_gate_bias = + GetOptionalInputTensor(context, node, kInputGateBiasTensor); + if (use_cifg) { + TF_LITE_ENSURE_EQ(context, input_gate_bias, nullptr); + } else { + TF_LITE_ENSURE_EQ(context, input_gate_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, input_gate_bias->dims->data[0], n_cell); + } + + TfLiteTensor* forget_gate_bias = + GetInput(context, node, kForgetGateBiasTensor); + TF_LITE_ENSURE_EQ(context, forget_gate_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, forget_gate_bias->dims->data[0], n_cell); + + TfLiteTensor* cell_bias = GetInput(context, node, kCellGateBiasTensor); + TF_LITE_ENSURE_EQ(context, cell_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_bias->dims->data[0], n_cell); + + TfLiteTensor* output_gate_bias = + GetInput(context, node, kOutputGateBiasTensor); + TF_LITE_ENSURE_EQ(context, output_gate_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, output_gate_bias->dims->data[0], n_cell); + + TfLiteTensor* projection_weights = + GetOptionalInputTensor(context, node, kProjectionWeightsTensor); + if (projection_weights) { + TF_LITE_ENSURE_EQ(context, projection_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, projection_weights->dims->data[0], n_output); + TF_LITE_ENSURE_EQ(context, projection_weights->dims->data[1], n_cell); + } + + TfLiteTensor* projection_bias = + GetOptionalInputTensor(context, node, kProjectionBiasTensor); + if (projection_bias) { + TF_LITE_ENSURE_EQ(context, projection_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, projection_bias->dims->data[0], n_output); + } + + // Making sure the projection tensors are consistent: + // 1) If projection weight is not present, then projection bias should not be + // present. + // 2) If projection weight is present, then projection bias is optional. + // TODO(ghodrat): make sure this is correct. + const bool projecton_tensors_consistent = + ((projection_weights != nullptr) || (projection_bias == nullptr)); + TF_LITE_ENSURE(context, projecton_tensors_consistent == true); + + return kTfLiteOk; +} + +// Resize the output, state and scratch tensors based on the sizes of the input +// tensors. Also check that the size of the input tensors match each other. +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + // Check we have all the inputs and outputs we need. + TF_LITE_ENSURE_EQ(context, node->inputs->size, 18); + TF_LITE_ENSURE_EQ(context, node->outputs->size, 4); + + // Inferring batch size, number of outputs and sequence length and + // number of cells from the input tensors. + TfLiteTensor* input = GetInput(context, node, kInputTensor); + TF_LITE_ENSURE(context, input->dims->size > 1); + const int max_time = input->dims->data[0]; + const int n_batch = input->dims->data[1]; + const int n_input = input->dims->data[2]; + + TfLiteTensor* input_to_output_weights = + GetInput(context, node, kInputToOutputWeightsTensor); + const int n_cell = input_to_output_weights->dims->data[0]; + TF_LITE_ENSURE_EQ(context, input_to_output_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, input_to_output_weights->dims->data[1], n_input); + + TfLiteTensor* recurrent_to_output_weights = + GetInput(context, node, kRecurrentToOutputWeightsTensor); + TF_LITE_ENSURE_EQ(context, recurrent_to_output_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, recurrent_to_output_weights->dims->data[0], + n_cell); + const int n_output = recurrent_to_output_weights->dims->data[1]; + + // Check that input tensor dimensions matches with each other. + CheckInputTensorDimensions(context, node, n_input, n_output, n_cell); + + // Get the pointer to output, state and scratch buffer tensors. + TfLiteTensor* output = GetOutput(context, node, kOutputTensor); + TfLiteTensor* output_state = GetOutput(context, node, kOutputStateTensor); + TfLiteTensor* cell_state = GetOutput(context, node, kCellStateTensor); + // TODO(ghodrat): Modify this as soon as we have a finalized method for + // scratch buffers. + TfLiteTensor* scratch_buffer = GetOutput(context, node, kScratchBufferTensor); + + // Resize the output and output_state tensors. + TfLiteIntArray* output_size = TfLiteIntArrayCreate(3); + output_size->data[0] = max_time; + output_size->data[1] = n_batch; + output_size->data[2] = n_output; + TF_LITE_ENSURE_OK(context, + context->ResizeTensor(context, output, output_size)); + + TfLiteIntArray* output_state_size = TfLiteIntArrayCreate(2); + output_state_size->data[0] = n_batch; + output_state_size->data[1] = n_output; + TF_LITE_ENSURE_OK( + context, context->ResizeTensor(context, output_state, output_state_size)); + + // Resize the scratch buffer tensor. + TfLiteIntArray* cell_size = TfLiteIntArrayCreate(2); + cell_size->data[0] = n_batch; + cell_size->data[1] = n_cell; + TF_LITE_ENSURE_OK(context, + context->ResizeTensor(context, cell_state, cell_size)); + + // Mark state tensors as persistent tensors. + output_state->allocation_type = kTfLiteArenaRwPersistent; + cell_state->allocation_type = kTfLiteArenaRwPersistent; + + TfLiteTensor* input_to_input_weights = + GetOptionalInputTensor(context, node, kInputToInputWeightsTensor); + const bool use_cifg = (input_to_input_weights == nullptr); + if (use_cifg) { + TfLiteIntArray* scratch_buffer_size = TfLiteIntArrayCreate(2); + scratch_buffer_size->data[0] = n_batch; + // Reserving space for Cell, Forget, Output gates + scratch_buffer_size->data[1] = n_cell * 3; + TF_LITE_ENSURE_OK(context, context->ResizeTensor(context, scratch_buffer, + scratch_buffer_size)); + } else { + TfLiteIntArray* scratch_buffer_size = TfLiteIntArrayCreate(2); + scratch_buffer_size->data[0] = n_batch; + // Reserving space for Input, Cell, Forget, Output gates + scratch_buffer_size->data[1] = n_cell * 4; + TF_LITE_ENSURE_OK(context, context->ResizeTensor(context, scratch_buffer, + scratch_buffer_size)); + } + return kTfLiteOk; +} + +// The LSTM Op engine. +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + auto* params = reinterpret_cast(node->builtin_data); + TfLiteTensor* input = GetInput(context, node, kInputTensor); + + TfLiteTensor* input_to_input_weights = + GetOptionalInputTensor(context, node, kInputToInputWeightsTensor); + TfLiteTensor* input_to_forget_weights = + GetInput(context, node, kInputToForgetWeightsTensor); + TfLiteTensor* input_to_cell_weights = + GetInput(context, node, kInputToCellWeightsTensor); + TfLiteTensor* input_to_output_weights = + GetInput(context, node, kInputToOutputWeightsTensor); + + TfLiteTensor* recurrent_to_input_weights = + GetOptionalInputTensor(context, node, kRecurrentToInputWeightsTensor); + TfLiteTensor* recurrent_to_forget_weights = + GetInput(context, node, kRecurrentToForgetWeightsTensor); + TfLiteTensor* recurrent_to_cell_weights = + GetInput(context, node, kRecurrentToCellWeightsTensor); + TfLiteTensor* recurrent_to_output_weights = + GetInput(context, node, kRecurrentToOutputWeightsTensor); + + TfLiteTensor* cell_to_input_weights = + GetOptionalInputTensor(context, node, kCellToInputWeightsTensor); + TfLiteTensor* cell_to_forget_weights = + GetOptionalInputTensor(context, node, kCellToForgetWeightsTensor); + TfLiteTensor* cell_to_output_weights = + GetOptionalInputTensor(context, node, kCellToOutputWeightsTensor); + + TfLiteTensor* input_gate_bias = + GetOptionalInputTensor(context, node, kInputGateBiasTensor); + TfLiteTensor* forget_gate_bias = + GetInput(context, node, kForgetGateBiasTensor); + TfLiteTensor* cell_bias = GetInput(context, node, kCellGateBiasTensor); + TfLiteTensor* output_gate_bias = + GetInput(context, node, kOutputGateBiasTensor); + + TfLiteTensor* projection_weights = + GetOptionalInputTensor(context, node, kProjectionWeightsTensor); + TfLiteTensor* projection_bias = + GetOptionalInputTensor(context, node, kProjectionBiasTensor); + + TfLiteTensor* output_state = GetOutput(context, node, kOutputStateTensor); + TfLiteTensor* cell_state = GetOutput(context, node, kCellStateTensor); + TfLiteTensor* output = GetOutput(context, node, kOutputTensor); + + const int max_time = input->dims->data[0]; + const int n_batch = input->dims->data[1]; + const int n_input = input->dims->data[2]; + // n_cell and n_output will be the same size when there is no projection. + const int n_cell = input_to_output_weights->dims->data[0]; + const int n_output = recurrent_to_output_weights->dims->data[1]; + + // Since we have already checked that weights are all there or none, we can + // check the existense of only one to the get the condition. + const bool use_cifg = (input_to_input_weights == nullptr); + const bool use_peephole = (cell_to_output_weights != nullptr); + + // Index the scratch buffers pointers to the global scratch buffer. + TfLiteTensor* scratch_buffer = GetOutput(context, node, kScratchBufferTensor); + float* input_gate_scratch = nullptr; + float* cell_scratch = nullptr; + float* forget_gate_scratch = nullptr; + float* output_gate_scratch = nullptr; + if (use_cifg) { + cell_scratch = scratch_buffer->data.f; + forget_gate_scratch = scratch_buffer->data.f + n_cell * n_batch; + output_gate_scratch = scratch_buffer->data.f + 2 * n_cell * n_batch; + } else { + input_gate_scratch = scratch_buffer->data.f; + cell_scratch = scratch_buffer->data.f + n_cell * n_batch; + forget_gate_scratch = scratch_buffer->data.f + 2 * n_cell * n_batch; + output_gate_scratch = scratch_buffer->data.f + 3 * n_cell * n_batch; + } + + for (int t = 0; t < max_time; t++) { + const float* input_ptr_time = input->data.f + t * n_batch * n_input; + // Initialize scratch buffers with bias. + if (!use_cifg) { + tensor_utils::VectorBatchVectorAssign(input_gate_bias->data.f, n_cell, + n_batch, input_gate_scratch); + } + tensor_utils::VectorBatchVectorAssign(forget_gate_bias->data.f, n_cell, + n_batch, forget_gate_scratch); + tensor_utils::VectorBatchVectorAssign(cell_bias->data.f, n_cell, n_batch, + cell_scratch); + tensor_utils::VectorBatchVectorAssign(output_gate_bias->data.f, n_cell, + n_batch, output_gate_scratch); + + // For each batch and cell: compute input_weight * input. + if (!use_cifg) { + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + input_to_input_weights->data.f, n_cell, n_input, input_ptr_time, + n_batch, input_gate_scratch, /*result_stride=*/1); + } + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + input_to_forget_weights->data.f, n_cell, n_input, input_ptr_time, + n_batch, forget_gate_scratch, /*result_stride=*/1); + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + input_to_cell_weights->data.f, n_cell, n_input, input_ptr_time, n_batch, + cell_scratch, /*result_stride=*/1); + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + input_to_output_weights->data.f, n_cell, n_input, input_ptr_time, + n_batch, output_gate_scratch, /*result_stride=*/1); + + // For each batch and cell: compute recurrent_weight * output_state. + if (!use_cifg) { + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + recurrent_to_input_weights->data.f, n_cell, n_output, + output_state->data.f, n_batch, input_gate_scratch, + /*result_stride=*/1); + } + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + recurrent_to_forget_weights->data.f, n_cell, n_output, + output_state->data.f, n_batch, forget_gate_scratch, + /*result_stride=*/1); + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + recurrent_to_cell_weights->data.f, n_cell, n_output, + output_state->data.f, n_batch, cell_scratch, /*result_stride=*/1); + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + recurrent_to_output_weights->data.f, n_cell, n_output, + output_state->data.f, n_batch, output_gate_scratch, + /*result_stride=*/1); + + // For each batch and cell: update input gate. + if (!use_cifg) { + if (use_peephole) { + tensor_utils::VectorBatchVectorCwiseProductAccumulate( + cell_to_input_weights->data.f, n_cell, cell_state->data.f, n_batch, + input_gate_scratch); + } + tensor_utils::ApplySigmoidToVector(input_gate_scratch, n_cell * n_batch, + input_gate_scratch); + } + + // For each batch and cell: update forget gate. + if (use_peephole) { + tensor_utils::VectorBatchVectorCwiseProductAccumulate( + cell_to_forget_weights->data.f, n_cell, cell_state->data.f, n_batch, + forget_gate_scratch); + } + tensor_utils::ApplySigmoidToVector(forget_gate_scratch, n_cell * n_batch, + forget_gate_scratch); + + // For each batch and cell: update the cell. + tensor_utils::VectorVectorCwiseProduct(forget_gate_scratch, + cell_state->data.f, n_batch * n_cell, + cell_state->data.f); + tensor_utils::ApplyActivationToVector(cell_scratch, n_batch * n_cell, + params->activation, cell_scratch); + if (use_cifg) { + tensor_utils::Sub1Vector(forget_gate_scratch, n_batch * n_cell, + forget_gate_scratch); + tensor_utils::VectorVectorCwiseProductAccumulate( + cell_scratch, forget_gate_scratch, n_batch * n_cell, + cell_state->data.f); + } else { + tensor_utils::VectorVectorCwiseProductAccumulate( + cell_scratch, input_gate_scratch, n_batch * n_cell, + cell_state->data.f); + } + if (params->cell_clip > 0.0) { + tensor_utils::ClipVector(cell_state->data.f, n_batch * n_cell, + params->cell_clip, cell_state->data.f); + } + + // For each batch and cell: update the output gate. + if (use_peephole) { + tensor_utils::VectorBatchVectorCwiseProductAccumulate( + cell_to_output_weights->data.f, n_cell, cell_state->data.f, n_batch, + output_gate_scratch); + } + tensor_utils::ApplySigmoidToVector(output_gate_scratch, n_batch * n_cell, + output_gate_scratch); + tensor_utils::ApplyActivationToVector(cell_state->data.f, n_batch * n_cell, + params->activation, cell_scratch); + tensor_utils::VectorVectorCwiseProduct(output_gate_scratch, cell_scratch, + n_batch * n_cell, + output_gate_scratch); + + // For each batch: update the projection and output_state. + const bool use_projection_weight = (projection_weights != nullptr); + const bool use_projection_bias = (projection_bias != nullptr); + float* output_ptr_time = output->data.f + t * n_batch * n_output; + if (use_projection_weight) { + if (use_projection_bias) { + tensor_utils::VectorBatchVectorAssign(projection_bias->data.f, n_output, + n_batch, output_ptr_time); + } else { + tensor_utils::ZeroVector(output_ptr_time, n_batch * n_output); + } + tensor_utils::MatrixBatchVectorMultiplyAccumulate( + projection_weights->data.f, n_output, n_cell, output_gate_scratch, + n_batch, output_ptr_time, /*result_stride=*/1); + if (params->proj_clip > 0.0) { + tensor_utils::ClipVector(output_ptr_time, n_batch * n_output, + params->proj_clip, output_ptr_time); + } + } else { + tensor_utils::CopyVector(output_gate_scratch, n_batch * n_output, + output_ptr_time); + } + tensor_utils::CopyVector(output_ptr_time, n_batch * n_output, + output_state->data.f); + } + return kTfLiteOk; +} + +} // namespace unidirectional_sequence_lstm + +TfLiteRegistration* Register_UNIDIRECTIONAL_SEQUENCE_LSTM() { + static TfLiteRegistration r = {/*init=*/nullptr, /*free=*/nullptr, + unidirectional_sequence_lstm::Prepare, + unidirectional_sequence_lstm::Eval}; + return &r; +} + +} // namespace builtin +} // namespace ops +} // namespace tflite diff --git a/tensorflow/contrib/lite/kernels/unidirectional_sequence_lstm_test.cc b/tensorflow/contrib/lite/kernels/unidirectional_sequence_lstm_test.cc new file mode 100644 index 0000000000..93b635ae57 --- /dev/null +++ b/tensorflow/contrib/lite/kernels/unidirectional_sequence_lstm_test.cc @@ -0,0 +1,1089 @@ +/* Copyright 2017 The TensorFlow Authors. 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. +==============================================================================*/ +// Unit test for TFLite Sequential LSTM op. + +#include +#include +#include + +#include +#include +#include "tensorflow/contrib/lite/interpreter.h" +#include "tensorflow/contrib/lite/kernels/register.h" +#include "tensorflow/contrib/lite/kernels/test_util.h" +#include "tensorflow/contrib/lite/model.h" + +namespace tflite { +namespace { + +using ::testing::ElementsAreArray; + +class UnidirectionalLSTMOpModel : public SingleOpModel { + public: + UnidirectionalLSTMOpModel(int n_batch, int n_input, int n_cell, int n_output, + int sequence_length, bool use_cifg, + bool use_peephole, bool use_projection_weights, + bool use_projection_bias, float cell_clip, + float proj_clip, + const std::vector>& input_shapes) + : n_batch_(n_batch), + n_input_(n_input), + n_cell_(n_cell), + n_output_(n_output), + sequence_length_(sequence_length) { + input_ = AddInput(TensorType_FLOAT32); + + if (use_cifg) { + input_to_input_weights_ = AddNullInput(); + } else { + input_to_input_weights_ = AddInput(TensorType_FLOAT32); + } + + input_to_forget_weights_ = AddInput(TensorType_FLOAT32); + input_to_cell_weights_ = AddInput(TensorType_FLOAT32); + input_to_output_weights_ = AddInput(TensorType_FLOAT32); + + if (use_cifg) { + recurrent_to_input_weights_ = AddNullInput(); + } else { + recurrent_to_input_weights_ = AddInput(TensorType_FLOAT32); + } + + recurrent_to_forget_weights_ = AddInput(TensorType_FLOAT32); + recurrent_to_cell_weights_ = AddInput(TensorType_FLOAT32); + recurrent_to_output_weights_ = AddInput(TensorType_FLOAT32); + + if (use_peephole) { + if (use_cifg) { + cell_to_input_weights_ = AddNullInput(); + } else { + cell_to_input_weights_ = AddInput(TensorType_FLOAT32); + } + cell_to_forget_weights_ = AddInput(TensorType_FLOAT32); + cell_to_output_weights_ = AddInput(TensorType_FLOAT32); + } else { + cell_to_input_weights_ = AddNullInput(); + cell_to_forget_weights_ = AddNullInput(); + cell_to_output_weights_ = AddNullInput(); + } + + if (use_cifg) { + input_gate_bias_ = AddNullInput(); + } else { + input_gate_bias_ = AddInput(TensorType_FLOAT32); + } + forget_gate_bias_ = AddInput(TensorType_FLOAT32); + cell_bias_ = AddInput(TensorType_FLOAT32); + output_gate_bias_ = AddInput(TensorType_FLOAT32); + + if (use_projection_weights) { + projection_weights_ = AddInput(TensorType_FLOAT32); + if (use_projection_bias) { + projection_bias_ = AddInput(TensorType_FLOAT32); + } else { + projection_bias_ = AddNullInput(); + } + } else { + projection_weights_ = AddNullInput(); + projection_bias_ = AddNullInput(); + } + + scratch_buffer_ = AddOutput(TensorType_FLOAT32); + // TODO(ghodrat): Modify these states when we have a permanent solution for + // persistent buffer. + output_state_ = AddOutput(TensorType_FLOAT32); + cell_state_ = AddOutput(TensorType_FLOAT32); + output_ = AddOutput(TensorType_FLOAT32); + + SetBuiltinOp(BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, + BuiltinOptions_LSTMOptions, + CreateLSTMOptions(builder_, ActivationFunctionType_TANH, + cell_clip, proj_clip) + .Union()); + BuildInterpreter(input_shapes); + } + + void SetInputToInputWeights(std::initializer_list f) { + PopulateTensor(input_to_input_weights_, f); + } + + void SetInputToForgetWeights(std::initializer_list f) { + PopulateTensor(input_to_forget_weights_, f); + } + + void SetInputToCellWeights(std::initializer_list f) { + PopulateTensor(input_to_cell_weights_, f); + } + + void SetInputToOutputWeights(std::initializer_list f) { + PopulateTensor(input_to_output_weights_, f); + } + + void SetRecurrentToInputWeights(std::initializer_list f) { + PopulateTensor(recurrent_to_input_weights_, f); + } + + void SetRecurrentToForgetWeights(std::initializer_list f) { + PopulateTensor(recurrent_to_forget_weights_, f); + } + + void SetRecurrentToCellWeights(std::initializer_list f) { + PopulateTensor(recurrent_to_cell_weights_, f); + } + + void SetRecurrentToOutputWeights(std::initializer_list f) { + PopulateTensor(recurrent_to_output_weights_, f); + } + + void SetCellToInputWeights(std::initializer_list f) { + PopulateTensor(cell_to_input_weights_, f); + } + + void SetCellToForgetWeights(std::initializer_list f) { + PopulateTensor(cell_to_forget_weights_, f); + } + + void SetCellToOutputWeights(std::initializer_list f) { + PopulateTensor(cell_to_output_weights_, f); + } + + void SetInputGateBias(std::initializer_list f) { + PopulateTensor(input_gate_bias_, f); + } + + void SetForgetGateBias(std::initializer_list f) { + PopulateTensor(forget_gate_bias_, f); + } + + void SetCellBias(std::initializer_list f) { + PopulateTensor(cell_bias_, f); + } + + void SetOutputGateBias(std::initializer_list f) { + PopulateTensor(output_gate_bias_, f); + } + + void SetProjectionWeights(std::initializer_list f) { + PopulateTensor(projection_weights_, f); + } + + void SetProjectionBias(std::initializer_list f) { + PopulateTensor(projection_bias_, f); + } + + void ResetOutputState() { + const int zero_buffer_size = n_cell_ * n_batch_; + std::unique_ptr zero_buffer(new float[zero_buffer_size]); + memset(zero_buffer.get(), 0, zero_buffer_size * sizeof(float)); + PopulateTensor(output_state_, 0, zero_buffer.get(), + zero_buffer.get() + zero_buffer_size); + } + + void ResetCellState() { + const int zero_buffer_size = n_cell_ * n_batch_; + std::unique_ptr zero_buffer(new float[zero_buffer_size]); + memset(zero_buffer.get(), 0, zero_buffer_size * sizeof(float)); + PopulateTensor(cell_state_, 0, zero_buffer.get(), + zero_buffer.get() + zero_buffer_size); + } + + void SetInput(int offset, float* begin, float* end) { + PopulateTensor(input_, offset, begin, end); + } + + std::vector GetOutput() { return ExtractVector(output_); } + + int num_inputs() { return n_input_; } + int num_outputs() { return n_output_; } + int num_cells() { return n_cell_; } + int num_batches() { return n_batch_; } + int sequence_length() { return sequence_length_; } + + private: + int input_; + int input_to_input_weights_; + int input_to_forget_weights_; + int input_to_cell_weights_; + int input_to_output_weights_; + + int recurrent_to_input_weights_; + int recurrent_to_forget_weights_; + int recurrent_to_cell_weights_; + int recurrent_to_output_weights_; + + int cell_to_input_weights_; + int cell_to_forget_weights_; + int cell_to_output_weights_; + + int input_gate_bias_; + int forget_gate_bias_; + int cell_bias_; + int output_gate_bias_; + + int projection_weights_; + int projection_bias_; + + int output_; + int output_state_; + int cell_state_; + int scratch_buffer_; + + int n_batch_; + int n_input_; + int n_cell_; + int n_output_; + int sequence_length_; +}; + +TEST(LSTMOpTest, BlackBoxTestNoCifgNoPeepholeNoProjectionNoClipping) { + const int n_batch = 1; + const int n_input = 2; + // n_cell and n_output have the same size when there is no projection. + const int n_cell = 4; + const int n_output = 4; + const int sequence_length = 3; + + UnidirectionalLSTMOpModel lstm( + n_batch, n_input, n_cell, n_output, sequence_length, /*use_cifg=*/false, + /*use_peephole=*/false, /*use_projection_weights=*/false, + /*use_projection_bias=*/false, /*cell_clip=*/0.0, /*proj_clip=*/0.0, + { + {sequence_length, n_batch, n_input}, // input tensor + + {n_cell, n_input}, // input_to_input_weight tensor + {n_cell, n_input}, // input_to_forget_weight tensor + {n_cell, n_input}, // input_to_cell_weight tensor + {n_cell, n_input}, // input_to_output_weight tensor + + {n_cell, n_output}, // recurrent_to_input_weight tensor + {n_cell, n_output}, // recurrent_to_forget_weight tensor + {n_cell, n_output}, // recurrent_to_cell_weight tensor + {n_cell, n_output}, // recurrent_to_output_weight tensor + + {0}, // cell_to_input_weight tensor + {0}, // cell_to_forget_weight tensor + {0}, // cell_to_output_weight tensor + + {n_cell}, // input_gate_bias tensor + {n_cell}, // forget_gate_bias tensor + {n_cell}, // cell_bias tensor + {n_cell}, // output_gate_bias tensor + + {0, 0}, // projection_weight tensor + {0}, // projection_bias tensor + }); + + lstm.SetInputToInputWeights({-0.45018822, -0.02338299, -0.0870589, + -0.34550029, 0.04266912, -0.15680569, + -0.34856534, 0.43890524}); + + lstm.SetInputToCellWeights({-0.50013041, 0.1370284, 0.11810488, 0.2013163, + -0.20583314, 0.44344562, 0.22077113, + -0.29909778}); + + lstm.SetInputToForgetWeights({0.09701663, 0.20334584, -0.50592935, + -0.31343272, -0.40032279, 0.44781327, + 0.01387155, -0.35593212}); + + lstm.SetInputToOutputWeights({-0.25065863, -0.28290087, 0.04613829, + 0.40525138, 0.44272184, 0.03897077, -0.1556896, + 0.19487578}); + + lstm.SetInputGateBias({0., 0., 0., 0.}); + + lstm.SetCellBias({0., 0., 0., 0.}); + + lstm.SetForgetGateBias({1., 1., 1., 1.}); + + lstm.SetOutputGateBias({0., 0., 0., 0.}); + + lstm.SetRecurrentToInputWeights( + {-0.0063535, -0.2042388, 0.31454784, -0.35746509, 0.28902304, 0.08183324, + -0.16555229, 0.02286911, -0.13566875, 0.03034258, 0.48091322, + -0.12528998, 0.24077177, -0.51332325, -0.33502164, 0.10629296}); + + lstm.SetRecurrentToCellWeights( + {-0.3407414, 0.24443203, -0.2078532, 0.26320225, 0.05695659, -0.00123841, + -0.4744786, -0.35869038, -0.06418842, -0.13502428, -0.501764, 0.22830659, + -0.46367589, 0.26016325, -0.03894562, -0.16368064}); + + lstm.SetRecurrentToForgetWeights( + {-0.48684245, -0.06655136, 0.42224967, 0.2112639, 0.27654213, 0.20864892, + -0.07646349, 0.45877004, 0.00141793, -0.14609534, 0.36447752, 0.09196436, + 0.28053468, 0.01560611, -0.20127171, -0.01140004}); + + lstm.SetRecurrentToOutputWeights( + {0.43385774, -0.17194885, 0.2718237, 0.09215671, 0.24107647, -0.39835793, + 0.18212086, 0.01301402, 0.48572797, -0.50656658, 0.20047462, -0.20607421, + -0.51818722, -0.15390486, 0.0468148, 0.39922136}); + + // Input should have n_input * sequence_length many values. + static float lstm_input[] = {2., 3., 3., 4., 1., 1.}; + static float lstm_golden_output[] = {-0.02973187, 0.1229473, 0.20885126, + -0.15358765, -0.03716109, 0.12507336, + 0.41193449, -0.20860538, -0.15053082, + 0.09120187, 0.24278517, -0.12222792}; + + // Resetting cell_state and output_state + lstm.ResetCellState(); + lstm.ResetOutputState(); + + float* batch0_start = lstm_input; + float* batch0_end = batch0_start + lstm.num_inputs() * lstm.sequence_length(); + + lstm.SetInput(0, batch0_start, batch0_end); + + lstm.Invoke(); + + float* golden_start = lstm_golden_output; + float* golden_end = + golden_start + lstm.num_outputs() * lstm.sequence_length(); + std::vector expected; + expected.insert(expected.end(), golden_start, golden_end); + EXPECT_THAT(lstm.GetOutput(), ElementsAreArray(ArrayFloatNear(expected))); +} + +TEST(LSTMOpTest, BlackBoxTestWithCifgWithPeepholeNoProjectionNoClipping) { + const int n_batch = 1; + const int n_input = 2; + // n_cell and n_output have the same size when there is no projection. + const int n_cell = 4; + const int n_output = 4; + const int sequence_length = 3; + + UnidirectionalLSTMOpModel lstm( + n_batch, n_input, n_cell, n_output, sequence_length, /*use_cifg=*/true, + /*use_peephole=*/true, /*use_projection_weights=*/false, + /*use_projection_bias=*/false, /*cell_clip=*/0.0, /*proj_clip=*/0.0, + { + {sequence_length, n_batch, n_input}, // input tensor + + {0, 0}, // input_to_input_weight tensor + {n_cell, n_input}, // input_to_forget_weight tensor + {n_cell, n_input}, // input_to_cell_weight tensor + {n_cell, n_input}, // input_to_output_weight tensor + + {0, 0}, // recurrent_to_input_weight tensor + {n_cell, n_output}, // recurrent_to_forget_weight tensor + {n_cell, n_output}, // recurrent_to_cell_weight tensor + {n_cell, n_output}, // recurrent_to_output_weight tensor + + {0}, // cell_to_input_weight tensor + {n_cell}, // cell_to_forget_weight tensor + {n_cell}, // cell_to_output_weight tensor + + {0}, // input_gate_bias tensor + {n_cell}, // forget_gate_bias tensor + {n_cell}, // cell_bias tensor + {n_cell}, // output_gate_bias tensor + + {0, 0}, // projection_weight tensor + {0}, // projection_bias tensor + }); + + lstm.SetInputToCellWeights({-0.49770179, -0.27711356, -0.09624726, 0.05100781, + 0.04717243, 0.48944736, -0.38535351, + -0.17212132}); + + lstm.SetInputToForgetWeights({-0.55291498, -0.42866567, 0.13056988, + -0.3633365, -0.22755712, 0.28253698, 0.24407166, + 0.33826375}); + + lstm.SetInputToOutputWeights({0.10725588, -0.02335852, -0.55932593, + -0.09426838, -0.44257352, 0.54939759, + 0.01533556, 0.42751634}); + + lstm.SetCellBias({0., 0., 0., 0.}); + + lstm.SetForgetGateBias({1., 1., 1., 1.}); + + lstm.SetOutputGateBias({0., 0., 0., 0.}); + + lstm.SetRecurrentToCellWeights( + {0.54066205, -0.32668582, -0.43562764, -0.56094903, 0.42957711, + 0.01841056, -0.32764608, -0.33027974, -0.10826075, 0.20675004, + 0.19069612, -0.03026325, -0.54532051, 0.33003211, 0.44901288, + 0.21193194}); + + lstm.SetRecurrentToForgetWeights( + {-0.13832897, -0.0515101, -0.2359007, -0.16661474, -0.14340827, + 0.36986142, 0.23414481, 0.55899, 0.10798943, -0.41174671, 0.17751795, + -0.34484994, -0.35874045, -0.11352962, 0.27268326, 0.54058349}); + + lstm.SetRecurrentToOutputWeights( + {0.41613156, 0.42610586, -0.16495961, -0.5663873, 0.30579174, -0.05115908, + -0.33941799, 0.23364776, 0.11178309, 0.09481031, -0.26424935, 0.46261835, + 0.50248802, 0.26114327, -0.43736315, 0.33149987}); + + lstm.SetCellToForgetWeights( + {0.47485286, -0.51955009, -0.24458408, 0.31544167}); + lstm.SetCellToOutputWeights( + {-0.17135078, 0.82760304, 0.85573703, -0.77109635}); + + static float lstm_input[] = {2., 3., 3., 4., 1., 1.}; + static float lstm_golden_output[] = {-0.36444446, -0.00352185, 0.12886585, + -0.05163646, -0.42312205, -0.01218222, + 0.24201041, -0.08124574, -0.358325, + -0.04621704, 0.21641694, -0.06471302}; + + // Resetting cell_state and output_state + lstm.ResetCellState(); + lstm.ResetOutputState(); + + float* batch0_start = lstm_input; + float* batch0_end = batch0_start + lstm.num_inputs() * lstm.sequence_length(); + + lstm.SetInput(0, batch0_start, batch0_end); + + lstm.Invoke(); + + float* golden_start = lstm_golden_output; + float* golden_end = + golden_start + lstm.num_outputs() * lstm.sequence_length(); + std::vector expected; + expected.insert(expected.end(), golden_start, golden_end); + EXPECT_THAT(lstm.GetOutput(), ElementsAreArray(ArrayFloatNear(expected))); +} + +TEST(LSTMOpTest, BlackBoxTestWithPeepholeWithProjectionNoClipping) { + const int n_batch = 2; + const int n_input = 5; + const int n_cell = 20; + const int n_output = 16; + const int sequence_length = 4; + + UnidirectionalLSTMOpModel lstm( + n_batch, n_input, n_cell, n_output, sequence_length, /*use_cifg=*/false, + /*use_peephole=*/true, /*use_projection_weights=*/true, + /*use_projection_bias=*/false, + /*cell_clip=*/0.0, /*proj_clip=*/0.0, + { + {sequence_length, n_batch, n_input}, // input tensor + + {n_cell, n_input}, // input_to_input_weight tensor + {n_cell, n_input}, // input_to_forget_weight tensor + {n_cell, n_input}, // input_to_cell_weight tensor + {n_cell, n_input}, // input_to_output_weight tensor + + {n_cell, n_output}, // recurrent_to_input_weight tensor + {n_cell, n_output}, // recurrent_to_forget_weight tensor + {n_cell, n_output}, // recurrent_to_cell_weight tensor + {n_cell, n_output}, // recurrent_to_output_weight tensor + + {n_cell}, // cell_to_input_weight tensor + {n_cell}, // cell_to_forget_weight tensor + {n_cell}, // cell_to_output_weight tensor + + {n_cell}, // input_gate_bias tensor + {n_cell}, // forget_gate_bias tensor + {n_cell}, // cell_bias tensor + {n_cell}, // output_gate_bias tensor + + {n_output, n_cell}, // projection_weight tensor + {0}, // projection_bias tensor + }); + + lstm.SetInputToInputWeights( + {0.021393683, 0.06124551, 0.046905167, -0.014657677, -0.03149463, + 0.09171803, 0.14647801, 0.10797193, -0.0057968358, 0.0019193048, + -0.2726754, 0.10154029, -0.018539885, 0.080349885, -0.10262385, + -0.022599787, -0.09121155, -0.008675967, -0.045206103, -0.0821282, + -0.008045952, 0.015478081, 0.055217247, 0.038719587, 0.044153627, + -0.06453243, 0.05031825, -0.046935108, -0.008164439, 0.014574226, + -0.1671009, -0.15519552, -0.16819797, -0.13971269, -0.11953059, + 0.25005487, -0.22790983, 0.009855087, -0.028140958, -0.11200698, + 0.11295408, -0.0035217577, 0.054485075, 0.05184695, 0.064711206, + 0.10989193, 0.11674786, 0.03490607, 0.07727357, 0.11390585, + -0.1863375, -0.1034451, -0.13945189, -0.049401227, -0.18767063, + 0.042483903, 0.14233552, 0.13832581, 0.18350165, 0.14545603, + -0.028545704, 0.024939531, 0.050929718, 0.0076203286, -0.0029723682, + -0.042484224, -0.11827596, -0.09171104, -0.10808628, -0.16327988, + -0.2273378, -0.0993647, -0.017155107, 0.0023917493, 0.049272764, + 0.0038534778, 0.054764505, 0.089753784, 0.06947234, 0.08014476, + -0.04544234, -0.0497073, -0.07135631, -0.048929106, -0.004042012, + -0.009284026, 0.018042054, 0.0036860977, -0.07427302, -0.11434604, + -0.018995456, 0.031487543, 0.012834908, 0.019977754, 0.044256654, + -0.39292613, -0.18519334, -0.11651281, -0.06809892, 0.011373677}); + + lstm.SetInputToForgetWeights( + {-0.0018401089, -0.004852237, 0.03698424, 0.014181704, 0.028273236, + -0.016726194, -0.05249759, -0.10204261, 0.00861066, -0.040979505, + -0.009899187, 0.01923892, -0.028177269, -0.08535103, -0.14585495, + 0.10662567, -0.01909731, -0.017883534, -0.0047269356, -0.045103323, + 0.0030784295, 0.076784775, 0.07463696, 0.094531395, 0.0814421, + -0.12257899, -0.033945758, -0.031303465, 0.045630626, 0.06843887, + -0.13492945, -0.012480007, -0.0811829, -0.07224499, -0.09628791, + 0.045100946, 0.0012300825, 0.013964662, 0.099372394, 0.02543059, + 0.06958324, 0.034257296, 0.0482646, 0.06267997, 0.052625068, + 0.12784666, 0.07077897, 0.025725935, 0.04165009, 0.07241905, + 0.018668644, -0.037377294, -0.06277783, -0.08833636, -0.040120605, + -0.011405586, -0.007808335, -0.010301386, -0.005102167, 0.027717464, + 0.05483423, 0.11449111, 0.11289652, 0.10939839, 0.13396506, + -0.08402166, -0.01901462, -0.044678304, -0.07720565, 0.014350063, + -0.11757958, -0.0652038, -0.08185733, -0.076754324, -0.092614375, + 0.10405491, 0.052960336, 0.035755895, 0.035839386, -0.012540553, + 0.036881298, 0.02913376, 0.03420159, 0.05448447, -0.054523353, + 0.02582715, 0.02327355, -0.011857179, -0.0011980024, -0.034641717, + -0.026125094, -0.17582615, -0.15923657, -0.27486774, -0.0006143371, + 0.0001771948, -8.470171e-05, 0.02651807, 0.045790765, 0.06956496}); + + lstm.SetInputToCellWeights( + {-0.04580283, -0.09549462, -0.032418985, -0.06454633, + -0.043528453, 0.043018587, -0.049152344, -0.12418144, + -0.078985475, -0.07596889, 0.019484362, -0.11434962, + -0.0074034138, -0.06314844, -0.092981495, 0.0062155537, + -0.025034338, -0.0028890965, 0.048929527, 0.06235075, + 0.10665918, -0.032036792, -0.08505916, -0.10843358, + -0.13002433, -0.036816437, -0.02130134, -0.016518239, + 0.0047691227, -0.0025825808, 0.066017866, 0.029991534, + -0.10652836, -0.1037554, -0.13056071, -0.03266643, + -0.033702414, -0.006473424, -0.04611692, 0.014419339, + -0.025174323, 0.0396852, 0.081777506, 0.06157468, + 0.10210095, -0.009658194, 0.046511717, 0.03603906, + 0.0069369148, 0.015960095, -0.06507666, 0.09551598, + 0.053568836, 0.06408714, 0.12835667, -0.008714329, + -0.20211966, -0.12093674, 0.029450472, 0.2849013, + -0.029227901, 0.1164364, -0.08560263, 0.09941786, + -0.036999565, -0.028842626, -0.0033637602, -0.017012902, + -0.09720865, -0.11193351, -0.029155117, -0.017936034, + -0.009768936, -0.04223324, -0.036159635, 0.06505112, + -0.021742892, -0.023377212, -0.07221364, -0.06430552, + 0.05453865, 0.091149814, 0.06387331, 0.007518393, + 0.055960953, 0.069779344, 0.046411168, 0.10509911, + 0.07463894, 0.0075130584, 0.012850982, 0.04555431, + 0.056955688, 0.06555285, 0.050801456, -0.009862683, + 0.00826772, -0.026555609, -0.0073611983, -0.0014897042}); + + lstm.SetInputToOutputWeights( + {-0.0998932, -0.07201956, -0.052803773, -0.15629593, -0.15001918, + -0.07650751, 0.02359855, -0.075155355, -0.08037709, -0.15093534, + 0.029517552, -0.04751393, 0.010350531, -0.02664851, -0.016839722, + -0.023121163, 0.0077019283, 0.012851257, -0.05040649, -0.0129761, + -0.021737747, -0.038305793, -0.06870586, -0.01481247, -0.001285394, + 0.10124236, 0.083122835, 0.053313006, -0.062235646, -0.075637154, + -0.027833903, 0.029774971, 0.1130802, 0.09218906, 0.09506135, + -0.086665764, -0.037162706, -0.038880914, -0.035832845, -0.014481564, + -0.09825003, -0.12048569, -0.097665586, -0.05287633, -0.0964047, + -0.11366429, 0.035777505, 0.13568819, 0.052451383, 0.050649304, + 0.05798951, -0.021852335, -0.099848844, 0.014740475, -0.078897946, + 0.04974699, 0.014160473, 0.06973932, 0.04964942, 0.033364646, + 0.08190124, 0.025535367, 0.050893165, 0.048514254, 0.06945813, + -0.078907564, -0.06707616, -0.11844508, -0.09986688, -0.07509403, + 0.06263226, 0.14925587, 0.20188436, 0.12098451, 0.14639415, + 0.0015017595, -0.014267382, -0.03417257, 0.012711468, 0.0028300495, + -0.024758482, -0.05098548, -0.0821182, 0.014225672, 0.021544158, + 0.08949725, 0.07505268, -0.0020780868, 0.04908258, 0.06476295, + -0.022907063, 0.027562456, 0.040185735, 0.019567577, -0.015598739, + -0.049097303, -0.017121866, -0.083368234, -0.02332002, -0.0840956}); + + lstm.SetInputGateBias( + {0.02234832, 0.14757581, 0.18176508, 0.10380666, 0.053110216, + -0.06928846, -0.13942584, -0.11816189, 0.19483899, 0.03652339, + -0.10250295, 0.036714908, -0.18426876, 0.036065217, 0.21810818, + 0.02383196, -0.043370757, 0.08690144, -0.04444982, 0.00030581196}); + + lstm.SetForgetGateBias({0.035185695, -0.042891346, -0.03032477, 0.23027696, + 0.11098921, 0.15378423, 0.09263801, 0.09790885, + 0.09508917, 0.061199076, 0.07665568, -0.015443159, + -0.03499149, 0.046190713, 0.08895977, 0.10899629, + 0.40694186, 0.06030037, 0.012413437, -0.06108739}); + + lstm.SetCellBias({-0.024379363, 0.0055531194, 0.23377132, 0.033463873, + -0.1483596, -0.10639995, -0.091433935, 0.058573797, + -0.06809782, -0.07889636, -0.043246906, -0.09829136, + -0.4279842, 0.034901652, 0.18797937, 0.0075234566, + 0.016178843, 0.1749513, 0.13975595, 0.92058027}); + + lstm.SetOutputGateBias( + {0.046159424, -0.0012809046, 0.03563469, 0.12648113, 0.027195795, + 0.35373217, -0.018957434, 0.008907322, -0.0762701, 0.12018895, + 0.04216877, 0.0022856654, 0.040952638, 0.3147856, 0.08225149, + -0.057416286, -0.14995944, -0.008040261, 0.13208859, 0.029760877}); + + lstm.SetRecurrentToInputWeights( + {-0.001374326, -0.078856036, 0.10672688, 0.029162422, + -0.11585556, 0.02557986, -0.13446963, -0.035785314, + -0.01244275, 0.025961924, -0.02337298, -0.044228926, + -0.055839065, -0.046598054, -0.010546039, -0.06900766, + 0.027239809, 0.022582639, -0.013296484, -0.05459212, + 0.08981, -0.045407712, 0.08682226, -0.06867011, + -0.14390695, -0.02916037, 0.000996957, 0.091420636, + 0.14283475, -0.07390571, -0.06402044, 0.062524505, + -0.093129106, 0.04860203, -0.08364217, -0.08119002, + 0.009352075, 0.22920375, 0.0016303885, 0.11583097, + -0.13732095, 0.012405723, -0.07551853, 0.06343048, + 0.12162708, -0.031923793, -0.014335606, 0.01790974, + -0.10650317, -0.0724401, 0.08554849, -0.05727212, + 0.06556731, -0.042729504, -0.043227166, 0.011683251, + -0.013082158, -0.029302018, -0.010899579, -0.062036745, + -0.022509435, -0.00964907, -0.01567329, 0.04260106, + -0.07787477, -0.11576462, 0.017356863, 0.048673786, + -0.017577527, -0.05527947, -0.082487635, -0.040137455, + -0.10820036, -0.04666372, 0.022746278, -0.07851417, + 0.01068115, 0.032956902, 0.022433773, 0.0026891115, + 0.08944216, -0.0685835, 0.010513544, 0.07228705, + 0.02032331, -0.059686817, -0.0005566496, -0.086984694, + 0.040414046, -0.1380399, 0.094208956, -0.05722982, + 0.012092817, -0.04989123, -0.086576, -0.003399834, + -0.04696032, -0.045747425, 0.10091314, 0.048676282, + -0.029037097, 0.031399418, -0.0040285117, 0.047237843, + 0.09504992, 0.041799378, -0.049185462, -0.031518843, + -0.10516937, 0.026374253, 0.10058866, -0.0033195973, + -0.041975245, 0.0073591834, 0.0033782164, -0.004325073, + -0.10167381, 0.042500053, -0.01447153, 0.06464186, + -0.017142897, 0.03312627, 0.009205989, 0.024138335, + -0.011337001, 0.035530265, -0.010912711, 0.0706555, + -0.005894094, 0.051841937, -0.1401738, -0.02351249, + 0.0365468, 0.07590991, 0.08838724, 0.021681072, + -0.10086113, 0.019608743, -0.06195883, 0.077335775, + 0.023646897, -0.095322326, 0.02233014, 0.09756986, + -0.048691444, -0.009579111, 0.07595467, 0.11480546, + -0.09801813, 0.019894179, 0.08502348, 0.004032281, + 0.037211012, 0.068537936, -0.048005626, -0.091520436, + -0.028379958, -0.01556313, 0.06554592, -0.045599163, + -0.01672207, -0.020169014, -0.011877351, -0.20212261, + 0.010889619, 0.0047078193, 0.038385306, 0.08540671, + -0.017140968, -0.0035865551, 0.016678626, 0.005633034, + 0.015963363, 0.00871737, 0.060130805, 0.028611384, + 0.10109069, -0.015060172, -0.07894427, 0.06401885, + 0.011584063, -0.024466386, 0.0047652307, -0.09041358, + 0.030737216, -0.0046374933, 0.14215417, -0.11823516, + 0.019899689, 0.006106124, -0.027092824, 0.0786356, + 0.05052217, -0.058925, -0.011402121, -0.024987547, + -0.0013661642, -0.06832946, -0.015667673, -0.1083353, + -0.00096863037, -0.06988685, -0.053350925, -0.027275559, + -0.033664223, -0.07978348, -0.025200296, -0.017207067, + -0.058403496, -0.055697463, 0.005798788, 0.12965427, + -0.062582195, 0.0013350133, -0.10482091, 0.0379771, + 0.072521195, -0.0029455067, -0.13797039, -0.03628521, + 0.013806405, -0.017858358, -0.01008298, -0.07700066, + -0.017081132, 0.019358726, 0.0027079724, 0.004635139, + 0.062634714, -0.02338735, -0.039547626, -0.02050681, + 0.03385117, -0.083611414, 0.002862572, -0.09421313, + 0.058618143, -0.08598433, 0.00972939, 0.023867095, + -0.053934585, -0.023203006, 0.07452513, -0.048767887, + -0.07314807, -0.056307215, -0.10433547, -0.06440842, + 0.04328182, 0.04389765, -0.020006588, -0.09076438, + -0.11652589, -0.021705797, 0.03345259, -0.010329105, + -0.025767034, 0.013057034, -0.07316461, -0.10145612, + 0.06358255, 0.18531723, 0.07759293, 0.12006465, + 0.1305557, 0.058638252, -0.03393652, 0.09622831, + -0.16253184, -2.4580743e-06, 0.079869635, -0.070196845, + -0.005644518, 0.06857898, -0.12598175, -0.035084512, + 0.03156317, -0.12794146, -0.031963028, 0.04692781, + 0.030070418, 0.0071660685, -0.095516115, -0.004643372, + 0.040170413, -0.062104587, -0.0037324072, 0.0554317, + 0.08184801, -0.019164372, 0.06791302, 0.034257166, + -0.10307039, 0.021943003, 0.046745934, 0.0790918, + -0.0265588, -0.007824208, 0.042546265, -0.00977924, + -0.0002440307, -0.017384544, -0.017990116, 0.12252321, + -0.014512694, -0.08251313, 0.08861942, 0.13589665, + 0.026351685, 0.012641483, 0.07466548, 0.044301085, + -0.045414884, -0.051112458, 0.03444247, -0.08502782, + -0.04106223, -0.028126027, 0.028473156, 0.10467447}); + + lstm.SetRecurrentToForgetWeights( + {-0.057784554, -0.026057621, -0.068447545, -0.022581743, + 0.14811787, 0.10826372, 0.09471067, 0.03987225, + -0.0039523416, 0.00030638507, 0.053185795, 0.10572994, + 0.08414449, -0.022036452, -0.00066928595, -0.09203576, + 0.032950465, -0.10985798, -0.023809856, 0.0021431844, + -0.02196096, -0.00326074, 0.00058621005, -0.074678116, + -0.06193199, 0.055729095, 0.03736828, 0.020123724, + 0.061878487, -0.04729229, 0.034919553, -0.07585433, + -0.04421272, -0.044019096, 0.085488975, 0.04058006, + -0.06890133, -0.030951202, -0.024628663, -0.07672815, + 0.034293607, 0.08556707, -0.05293577, -0.033561368, + -0.04899627, 0.0241671, 0.015736353, -0.095442444, + -0.029564252, 0.016493602, -0.035026584, 0.022337519, + -0.026871363, 0.004780428, 0.0077918363, -0.03601621, + 0.016435321, -0.03263031, -0.09543275, -0.047392778, + 0.013454138, 0.028934088, 0.01685226, -0.086110644, + -0.046250615, -0.01847454, 0.047608484, 0.07339695, + 0.034546845, -0.04881143, 0.009128804, -0.08802852, + 0.03761666, 0.008096139, -0.014454086, 0.014361001, + -0.023502491, -0.0011840804, -0.07607001, 0.001856849, + -0.06509276, -0.006021153, -0.08570962, -0.1451793, + 0.060212336, 0.055259194, 0.06974018, 0.049454916, + -0.027794661, -0.08077226, -0.016179763, 0.1169753, + 0.17213494, -0.0056326236, -0.053934924, -0.0124349, + -0.11520337, 0.05409887, 0.088759385, 0.0019655675, + 0.0042065294, 0.03881498, 0.019844765, 0.041858196, + -0.05695512, 0.047233116, 0.038937137, -0.06542224, + 0.014429736, -0.09719407, 0.13908425, -0.05379757, + 0.012321099, 0.082840554, -0.029899208, 0.044217527, + 0.059855383, 0.07711018, -0.045319796, 0.0948846, + -0.011724666, -0.0033288454, -0.033542685, -0.04764985, + -0.13873616, 0.040668588, 0.034832682, -0.015319203, + -0.018715994, 0.046002675, 0.0599172, -0.043107376, + 0.0294216, -0.002314414, -0.022424703, 0.0030315618, + 0.0014641669, 0.0029166266, -0.11878115, 0.013738511, + 0.12375372, -0.0006038222, 0.029104086, 0.087442465, + 0.052958444, 0.07558703, 0.04817258, 0.044462286, + -0.015213451, -0.08783778, -0.0561384, -0.003008196, + 0.047060397, -0.002058388, 0.03429439, -0.018839769, + 0.024734668, 0.024614193, -0.042046934, 0.09597743, + -0.0043254104, 0.04320769, 0.0064070094, -0.0019131786, + -0.02558259, -0.022822596, -0.023273505, -0.02464396, + -0.10991725, -0.006240552, 0.0074488563, 0.024044557, + 0.04383914, -0.046476185, 0.028658995, 0.060410924, + 0.050786525, 0.009452605, -0.0073054377, -0.024810238, + 0.0052906186, 0.0066939713, -0.0020913032, 0.014515517, + 0.015898481, 0.021362653, -0.030262267, 0.016587038, + -0.011442813, 0.041154444, -0.007631438, -0.03423484, + -0.010977775, 0.036152758, 0.0066366293, 0.11915515, + 0.02318443, -0.041350313, 0.021485701, -0.10906167, + -0.028218046, -0.00954771, 0.020531068, -0.11995105, + -0.03672871, 0.024019798, 0.014255957, -0.05221243, + -0.00661567, -0.04630967, 0.033188973, 0.10107534, + -0.014027541, 0.030796422, -0.10270911, -0.035999842, + 0.15443139, 0.07684145, 0.036571592, -0.035900835, + -0.0034699554, 0.06209149, 0.015920248, -0.031122351, + -0.03858649, 0.01849943, 0.13872518, 0.01503974, + 0.069941424, -0.06948533, -0.0088794185, 0.061282158, + -0.047401894, 0.03100163, -0.041533746, -0.10430945, + 0.044574402, -0.01425562, -0.024290353, 0.034563623, + 0.05866852, 0.023947537, -0.09445152, 0.035450947, + 0.02247216, -0.0042998926, 0.061146557, -0.10250651, + 0.020881841, -0.06747029, 0.10062043, -0.0023941975, + 0.03532124, -0.016341697, 0.09685456, -0.016764693, + 0.051808182, 0.05875331, -0.04536488, 0.001626336, + -0.028892258, -0.01048663, -0.009793449, -0.017093895, + 0.010987891, 0.02357273, -0.00010856845, 0.0099760275, + -0.001845119, -0.03551521, 0.0018358806, 0.05763657, + -0.01769146, 0.040995963, 0.02235177, -0.060430344, + 0.11475477, -0.023854522, 0.10071741, 0.0686208, + -0.014250481, 0.034261297, 0.047418304, 0.08562733, + -0.030519066, 0.0060542435, 0.014653856, -0.038836084, + 0.04096551, 0.032249358, -0.08355519, -0.026823482, + 0.056386515, -0.010401743, -0.028396193, 0.08507674, + 0.014410365, 0.020995233, 0.17040324, 0.11511526, + 0.02459721, 0.0066619175, 0.025853224, -0.023133837, + -0.081302024, 0.017264642, -0.009585969, 0.09491168, + -0.051313367, 0.054532815, -0.014298593, 0.10657464, + 0.007076659, 0.10964551, 0.0409152, 0.008275321, + -0.07283536, 0.07937492, 0.04192024, -0.1075027}); + + lstm.SetRecurrentToCellWeights( + {-0.037322544, 0.018592842, 0.0056175636, -0.06253426, + 0.055647098, -0.05713207, -0.05626563, 0.005559383, + 0.03375411, -0.025757805, -0.088049285, 0.06017052, + -0.06570978, 0.007384076, 0.035123326, -0.07920549, + 0.053676967, 0.044480428, -0.07663568, 0.0071805613, + 0.08089997, 0.05143358, 0.038261272, 0.03339287, + -0.027673481, 0.044746667, 0.028349208, 0.020090483, + -0.019443132, -0.030755889, -0.0040000007, 0.04465846, + -0.021585021, 0.0031670958, 0.0053199246, -0.056117613, + -0.10893326, 0.076739706, -0.08509834, -0.027997585, + 0.037871376, 0.01449768, -0.09002357, -0.06111149, + -0.046195522, 0.0422062, -0.005683705, -0.1253618, + -0.012925729, -0.04890792, 0.06985068, 0.037654128, + 0.03398274, -0.004781977, 0.007032333, -0.031787455, + 0.010868644, -0.031489216, 0.09525667, 0.013939797, + 0.0058680447, 0.0167067, 0.02668468, -0.04797466, + -0.048885044, -0.12722108, 0.035304096, 0.06554885, + 0.00972396, -0.039238118, -0.05159735, -0.11329045, + 0.1613692, -0.03750952, 0.06529313, -0.071974665, + -0.11769596, 0.015524369, -0.0013754242, -0.12446318, + 0.02786344, -0.014179351, 0.005264273, 0.14376344, + 0.015983658, 0.03406988, -0.06939408, 0.040699873, + 0.02111075, 0.09669095, 0.041345075, -0.08316494, + -0.07684199, -0.045768797, 0.032298047, -0.041805092, + 0.0119405, 0.0061010392, 0.12652606, 0.0064572375, + -0.024950314, 0.11574242, 0.04508852, -0.04335324, + 0.06760663, -0.027437469, 0.07216407, 0.06977076, + -0.05438599, 0.034033038, -0.028602652, 0.05346137, + 0.043184172, -0.037189785, 0.10420091, 0.00882477, + -0.054019816, -0.074273005, -0.030617684, -0.0028467078, + 0.024302477, -0.0038869337, 0.005332455, 0.0013399826, + 0.04361412, -0.007001822, 0.09631092, -0.06702025, + -0.042049985, -0.035070654, -0.04103342, -0.10273396, + 0.0544271, 0.037184782, -0.13150354, -0.0058036847, + -0.008264958, 0.042035464, 0.05891794, 0.029673764, + 0.0063542654, 0.044788733, 0.054816857, 0.062257513, + -0.00093483756, 0.048938446, -0.004952862, -0.007730018, + -0.04043371, -0.017094059, 0.07229206, -0.023670016, + -0.052195564, -0.025616996, -0.01520939, 0.045104615, + -0.007376126, 0.003533447, 0.006570588, 0.056037236, + 0.12436656, 0.051817212, 0.028532185, -0.08686856, + 0.11868599, 0.07663395, -0.07323171, 0.03463402, + -0.050708205, -0.04458982, -0.11590894, 0.021273347, + 0.1251325, -0.15313013, -0.12224372, 0.17228661, + 0.023029093, 0.086124025, 0.006445803, -0.03496501, + 0.028332196, 0.04449512, -0.042436164, -0.026587414, + -0.006041347, -0.09292539, -0.05678812, 0.03897832, + 0.09465633, 0.008115513, -0.02171956, 0.08304309, + 0.071401566, 0.019622514, 0.032163795, -0.004167056, + 0.02295182, 0.030739572, 0.056506045, 0.004612461, + 0.06524936, 0.059999723, 0.046395954, -0.0045512207, + -0.1335546, -0.030136576, 0.11584653, -0.014678886, + 0.0020118146, -0.09688814, -0.0790206, 0.039770417, + -0.0329582, 0.07922767, 0.029322514, 0.026405897, + 0.04207835, -0.07073373, 0.063781224, 0.0859677, + -0.10925287, -0.07011058, 0.048005477, 0.03438226, + -0.09606514, -0.006669445, -0.043381985, 0.04240257, + -0.06955775, -0.06769346, 0.043903265, -0.026784198, + -0.017840602, 0.024307009, -0.040079936, -0.019946516, + 0.045318738, -0.12233574, 0.026170589, 0.0074471775, + 0.15978073, 0.10185836, 0.10298046, -0.015476589, + -0.039390966, -0.072174534, 0.0739445, -0.1211869, + -0.0347889, -0.07943156, 0.014809798, -0.12412325, + -0.0030663363, 0.039695457, 0.0647603, -0.08291318, + -0.018529687, -0.004423833, 0.0037507233, 0.084633216, + -0.01514876, -0.056505352, -0.012800942, -0.06994386, + 0.012962922, -0.031234352, 0.07029052, 0.016418684, + 0.03618972, 0.055686004, -0.08663945, -0.017404709, + -0.054761406, 0.029065743, 0.052404847, 0.020238016, + 0.0048197987, -0.0214882, 0.07078733, 0.013016777, + 0.06262858, 0.009184685, 0.020785125, -0.043904778, + -0.0270329, -0.03299152, -0.060088247, -0.015162964, + -0.001828936, 0.12642565, -0.056757294, 0.013586685, + 0.09232601, -0.035886683, 0.06000002, 0.05229691, + -0.052580316, -0.082029596, -0.010794592, 0.012947712, + -0.036429964, -0.085508935, -0.13127148, -0.017744139, + 0.031502828, 0.036232427, -0.031581745, 0.023051167, + -0.05325106, -0.03421577, 0.028793324, -0.034633752, + -0.009881397, -0.043551125, -0.018609839, 0.0019097115, + -0.008799762, 0.056595087, 0.0022273948, 0.055752404}); + + lstm.SetRecurrentToOutputWeights({ + 0.025825322, -0.05813119, 0.09495884, -0.045984812, -0.01255415, + -0.0026479573, -0.08196161, -0.054914974, -0.0046604523, -0.029587349, + -0.044576716, -0.07480124, -0.082868785, 0.023254942, 0.027502948, + -0.0039728214, -0.08683098, -0.08116779, -0.014675607, -0.037924774, + -0.023314456, -0.007401714, -0.09255757, 0.029460307, -0.08829125, + -0.005139627, -0.08989442, -0.0555066, 0.13596267, -0.025062224, + -0.048351806, -0.03850004, 0.07266485, -0.022414139, 0.05940088, + 0.075114764, 0.09597592, -0.010211725, -0.0049794707, -0.011523867, + -0.025980417, 0.072999895, 0.11091378, -0.081685916, 0.014416728, + 0.043229222, 0.034178585, -0.07530371, 0.035837382, -0.085607, + -0.007721233, -0.03287832, -0.043848954, -0.06404588, -0.06632928, + -0.073643476, 0.008214239, -0.045984086, 0.039764922, 0.03474462, + 0.060612556, -0.080590084, 0.049127717, 0.04151091, -0.030063879, + 0.008801774, -0.023021035, -0.019558564, 0.05158114, -0.010947698, + -0.011825728, 0.0075720972, 0.0699727, -0.0039981045, 0.069350146, + 0.08799282, 0.016156472, 0.035502106, 0.11695009, 0.006217345, + 0.13392477, -0.037875112, 0.025745004, 0.08940699, -0.00924166, + 0.0046702605, -0.036598757, -0.08811812, 0.10522024, -0.032441203, + 0.008176899, -0.04454919, 0.07058152, 0.0067963637, 0.039206743, + 0.03259838, 0.03725492, -0.09515802, 0.013326398, -0.052055415, + -0.025676316, 0.03198509, -0.015951829, -0.058556724, 0.036879618, + 0.043357447, 0.028362012, -0.05908629, 0.0059240665, -0.04995891, + -0.019187413, 0.0276265, -0.01628143, 0.0025863599, 0.08800015, + 0.035250366, -0.022165963, -0.07328642, -0.009415526, -0.07455109, + 0.11690406, 0.0363299, 0.07411125, 0.042103454, -0.009660886, + 0.019076364, 0.018299393, -0.046004917, 0.08891175, 0.0431396, + -0.026327137, -0.051502608, 0.08979574, -0.051670972, 0.04940282, + -0.07491107, -0.021240504, 0.022596184, -0.034280192, 0.060163025, + -0.058211457, -0.051837247, -0.01349775, -0.04639988, -0.035936575, + -0.011681591, 0.064818054, 0.0073146066, -0.021745546, -0.043124277, + -0.06471268, -0.07053354, -0.029321948, -0.05330136, 0.016933719, + -0.053782392, 0.13747959, -0.1361751, -0.11569455, 0.0033329215, + 0.05693899, -0.053219706, 0.063698, 0.07977434, -0.07924483, + 0.06936997, 0.0034815092, -0.007305279, -0.037325785, -0.07251102, + -0.033633437, -0.08677009, 0.091591336, -0.14165086, 0.021752775, + 0.019683983, 0.0011612234, -0.058154266, 0.049996935, 0.0288841, + -0.0024567875, -0.14345716, 0.010955264, -0.10234828, 0.1183656, + -0.0010731248, -0.023590032, -0.072285876, -0.0724771, -0.026382286, + -0.0014920527, 0.042667855, 0.0018776858, 0.02986552, 0.009814309, + 0.0733756, 0.12289186, 0.018043943, -0.0458958, 0.049412545, + 0.033632483, 0.05495232, 0.036686596, -0.013781798, -0.010036754, + 0.02576849, -0.08307328, 0.010112348, 0.042521734, -0.05869831, + -0.071689695, 0.03876447, -0.13275425, -0.0352966, -0.023077697, + 0.10285965, 0.084736146, 0.15568255, -0.00040734606, 0.027835453, + -0.10292561, -0.032401145, 0.10053256, -0.026142767, -0.08271222, + -0.0030240538, -0.016368777, 0.1070414, 0.042672627, 0.013456989, + -0.0437609, -0.022309763, 0.11576483, 0.04108048, 0.061026827, + -0.0190714, -0.0869359, 0.037901703, 0.0610107, 0.07202949, + 0.01675338, 0.086139716, -0.08795751, -0.014898893, -0.023771819, + -0.01965048, 0.007955471, -0.043740474, 0.03346837, -0.10549954, + 0.090567775, 0.042013682, -0.03176985, 0.12569028, -0.02421228, + -0.029526481, 0.023851605, 0.031539805, 0.05292009, -0.02344001, + -0.07811758, -0.08834428, 0.10094801, 0.16594367, -0.06861939, + -0.021256343, -0.041093912, -0.06669611, 0.035498552, 0.021757556, + -0.09302526, -0.015403468, -0.06614931, -0.051798206, -0.013874718, + 0.03630673, 0.010412845, -0.08077351, 0.046185967, 0.0035662893, + 0.03541868, -0.094149634, -0.034814864, 0.003128424, -0.020674974, + -0.03944324, -0.008110165, -0.11113267, 0.08484226, 0.043586485, + 0.040582247, 0.0968012, -0.065249965, -0.028036479, 0.0050708856, + 0.0017462453, 0.0326779, 0.041296225, 0.09164146, -0.047743853, + -0.015952192, -0.034451712, 0.084197424, -0.05347844, -0.11768019, + 0.085926116, -0.08251791, -0.045081906, 0.0948852, 0.068401024, + 0.024856757, 0.06978981, -0.057309967, -0.012775832, -0.0032452994, + 0.01977615, -0.041040014, -0.024264973, 0.063464895, 0.05431621, + }); + + lstm.SetCellToInputWeights( + {0.040369894, 0.030746894, 0.24704495, 0.018586371, -0.037586458, + -0.15312155, -0.11812848, -0.11465643, 0.20259799, 0.11418174, + -0.10116027, -0.011334949, 0.12411352, -0.076769054, -0.052169047, + 0.21198851, -0.38871562, -0.09061183, -0.09683246, -0.21929175}); + + lstm.SetCellToForgetWeights( + {-0.01998659, -0.15568835, -0.24248174, -0.012770197, 0.041331276, + -0.072311886, -0.052123554, -0.0066330447, -0.043891653, 0.036225766, + -0.047248036, 0.021479502, 0.033189066, 0.11952997, -0.020432774, + 0.64658105, -0.06650122, -0.03467612, 0.095340036, 0.23647355}); + + lstm.SetCellToOutputWeights( + {0.08286371, -0.08261836, -0.51210177, 0.002913762, 0.17764764, + -0.5495371, -0.08460716, -0.24552552, 0.030037103, 0.04123544, + -0.11940523, 0.007358328, 0.1890978, 0.4833202, -0.34441817, + 0.36312827, -0.26375428, 0.1457655, -0.19724406, 0.15548733}); + + lstm.SetProjectionWeights( + {-0.009802181, 0.09401916, 0.0717386, -0.13895074, 0.09641832, + 0.060420845, 0.08539281, 0.054285463, 0.061395317, 0.034448683, + -0.042991187, 0.019801661, -0.16840284, -0.015726732, -0.23041931, + -0.024478018, -0.10959692, -0.013875541, 0.18600968, -0.061274476, + 0.0138165, -0.08160894, -0.07661644, 0.032372914, 0.16169067, + 0.22465782, -0.03993472, -0.004017731, 0.08633481, -0.28869787, + 0.08682067, 0.17240396, 0.014975425, 0.056431185, 0.031037588, + 0.16702051, 0.0077946745, 0.15140012, 0.29405436, 0.120285, + -0.188994, -0.027265169, 0.043389652, -0.022061434, 0.014777949, + -0.20203483, 0.094781205, 0.19100232, 0.13987629, -0.036132768, + -0.06426278, -0.05108664, 0.13221376, 0.009441198, -0.16715929, + 0.15859416, -0.040437475, 0.050779544, -0.022187516, 0.012166504, + 0.027685808, -0.07675938, -0.0055694645, -0.09444123, 0.0046453946, + 0.050794356, 0.10770313, -0.20790008, -0.07149004, -0.11425117, + 0.008225835, -0.035802525, 0.14374903, 0.15262283, 0.048710253, + 0.1847461, -0.007487823, 0.11000021, -0.09542012, 0.22619456, + -0.029149994, 0.08527916, 0.009043713, 0.0042746216, 0.016261552, + 0.022461696, 0.12689082, -0.043589946, -0.12035478, -0.08361797, + -0.050666027, -0.1248618, -0.1275799, -0.071875185, 0.07377272, + 0.09944291, -0.18897448, -0.1593054, -0.06526116, -0.040107165, + -0.004618631, -0.067624845, -0.007576253, 0.10727444, 0.041546922, + -0.20424393, 0.06907816, 0.050412357, 0.00724631, 0.039827548, + 0.12449835, 0.10747581, 0.13708383, 0.09134148, -0.12617786, + -0.06428341, 0.09956831, 0.1208086, -0.14676677, -0.0727722, + 0.1126304, 0.010139365, 0.015571211, -0.038128063, 0.022913318, + -0.042050496, 0.16842307, -0.060597885, 0.10531834, -0.06411776, + -0.07451711, -0.03410368, -0.13393489, 0.06534304, 0.003620307, + 0.04490757, 0.05970546, 0.05197996, 0.02839995, 0.10434969, + -0.013699693, -0.028353551, -0.07260381, 0.047201227, -0.024575593, + -0.036445823, 0.07155557, 0.009672501, -0.02328883, 0.009533515, + -0.03606021, -0.07421458, -0.028082801, -0.2678904, -0.13221288, + 0.18419984, -0.13012612, -0.014588381, -0.035059117, -0.04824723, + 0.07830115, -0.056184657, 0.03277091, 0.025466874, 0.14494097, + -0.12522776, -0.098633975, -0.10766018, -0.08317623, 0.08594209, + 0.07749552, 0.039474737, 0.1776665, -0.07409566, -0.0477268, + 0.29323658, 0.10801441, 0.1154011, 0.013952499, 0.10739139, + 0.10708251, -0.051456142, 0.0074137426, -0.10430189, 0.10034707, + 0.045594677, 0.0635285, -0.0715442, -0.089667566, -0.10811871, + 0.00026344223, 0.08298446, -0.009525053, 0.006585689, -0.24567553, + -0.09450807, 0.09648481, 0.026996298, -0.06419476, -0.04752702, + -0.11063944, -0.23441927, -0.17608605, -0.052156363, 0.067035615, + 0.19271925, -0.0032889997, -0.043264326, 0.09663576, -0.057112187, + -0.10100678, 0.0628376, 0.04447668, 0.017961001, -0.10094388, + -0.10190601, 0.18335468, 0.10494553, -0.052095775, -0.0026118709, + 0.10539724, -0.04383912, -0.042349473, 0.08438151, -0.1947263, + 0.02251204, 0.11216432, -0.10307853, 0.17351969, -0.039091777, + 0.08066188, -0.00561982, 0.12633002, 0.11335965, -0.0088127935, + -0.019777594, 0.06864014, -0.059751723, 0.016233567, -0.06894641, + -0.28651384, -0.004228674, 0.019708522, -0.16305895, -0.07468996, + -0.0855457, 0.099339016, -0.07580735, -0.13775392, 0.08434318, + 0.08330512, -0.12131499, 0.031935584, 0.09180414, -0.08876437, + -0.08049874, 0.008753825, 0.03498998, 0.030215185, 0.03907079, + 0.089751154, 0.029194152, -0.03337423, -0.019092513, 0.04331237, + 0.04299654, -0.036394123, -0.12915532, 0.09793732, 0.07512415, + -0.11319543, -0.032502122, 0.15661901, 0.07671967, -0.005491124, + -0.19379048, -0.218606, 0.21448623, 0.017840758, 0.1416943, + -0.07051762, 0.19488361, 0.02664691, -0.18104725, -0.09334311, + 0.15026465, -0.15493552, -0.057762887, -0.11604192, -0.262013, + -0.01391798, 0.012185008, 0.11156489, -0.07483202, 0.06693364, + -0.26151478, 0.046425626, 0.036540434, -0.16435726, 0.17338543, + -0.21401681, -0.11385144, -0.08283257, -0.069031075, 0.030635102, + 0.010969227, 0.11109743, 0.010919218, 0.027526086, 0.13519906, + 0.01891392, -0.046839405, -0.040167913, 0.017953383, -0.09700955, + 0.0061885654, -0.07000971, 0.026893595, -0.038844477, 0.14543656}); + + static float lstm_input[][20] = { + {// Batch0: 4 (input_sequence_size) * 5 (n_input) + 0.787926, 0.151646, 0.071352, 0.118426, 0.458058, 0.596268, 0.998386, + 0.568695, 0.864524, 0.571277, 0.073204, 0.296072, 0.743333, 0.069199, + 0.045348, 0.867394, 0.291279, 0.013714, 0.482521, 0.626339}, + + {// Batch1: 4 (input_sequence_size) * 5 (n_input) + 0.295743, 0.544053, 0.690064, 0.858138, 0.497181, 0.642421, 0.524260, + 0.134799, 0.003639, 0.162482, 0.640394, 0.930399, 0.050782, 0.432485, + 0.988078, 0.082922, 0.563329, 0.865614, 0.333232, 0.259916}}; + + static float lstm_golden_output[][64] = { + {// Batch0: 4 (input_sequence_size) * 16 (n_output) + -0.00396806, 0.029352, -0.00279226, 0.0159977, -0.00835576, + -0.0211779, 0.0283512, -0.0114597, 0.00907307, -0.0244004, + -0.0152191, -0.0259063, 0.00914318, 0.00415118, 0.017147, + 0.0134203, -0.0166936, 0.0381209, 0.000889694, 0.0143363, + -0.0328911, -0.0234288, 0.0333051, -0.012229, 0.0110322, + -0.0457725, -0.000832209, -0.0202817, 0.0327257, 0.0121308, + 0.0155969, 0.0312091, -0.0213783, 0.0350169, 0.000324794, + 0.0276012, -0.0263374, -0.0371449, 0.0446149, -0.0205474, + 0.0103729, -0.0576349, -0.0150052, -0.0292043, 0.0376827, + 0.0136115, 0.0243435, 0.0354492, -0.0189322, 0.0464512, + -0.00251373, 0.0225745, -0.0308346, -0.0317124, 0.0460407, + -0.0189395, 0.0149363, -0.0530162, -0.0150767, -0.0340193, + 0.0286833, 0.00824207, 0.0264887, 0.0305169}, + {// Batch1: 4 (input_sequence_size) * 16 (n_output) + -0.013869, 0.0287268, -0.00334693, 0.00733398, -0.0287926, + -0.0186926, 0.0193662, -0.0115437, 0.00422612, -0.0345232, + 0.00223253, -0.00957321, 0.0210624, 0.013331, 0.0150954, + 0.02168, -0.0141913, 0.0322082, 0.00227024, 0.0260507, + -0.0188721, -0.0296489, 0.0399134, -0.0160509, 0.0116039, + -0.0447318, -0.0150515, -0.0277406, 0.0316596, 0.0118233, + 0.0214762, 0.0293641, -0.0204549, 0.0450315, -0.00117378, + 0.0167673, -0.0375007, -0.0238314, 0.038784, -0.0174034, + 0.0131743, -0.0506589, -0.0048447, -0.0240239, 0.0325789, + 0.00790065, 0.0220157, 0.0333314, -0.0264787, 0.0387855, + -0.000764675, 0.0217599, -0.037537, -0.0335206, 0.0431679, + -0.0211424, 0.010203, -0.062785, -0.00832363, -0.025181, + 0.0412031, 0.0118723, 0.0239643, 0.0394009}}; + + // Resetting cell_state and output_state + lstm.ResetCellState(); + lstm.ResetOutputState(); + + for (int i = 0; i < lstm.sequence_length(); i++) { + float* batch0_start = lstm_input[0] + i * lstm.num_inputs(); + float* batch0_end = batch0_start + lstm.num_inputs(); + + lstm.SetInput(2 * i * lstm.num_inputs(), batch0_start, batch0_end); + + float* batch1_start = lstm_input[1] + i * lstm.num_inputs(); + float* batch1_end = batch1_start + lstm.num_inputs(); + lstm.SetInput((2 * i + 1) * lstm.num_inputs(), batch1_start, batch1_end); + } + + lstm.Invoke(); + + std::vector expected; + for (int i = 0; i < lstm.sequence_length(); i++) { + float* golden_start_batch0 = lstm_golden_output[0] + i * lstm.num_outputs(); + float* golden_end_batch0 = golden_start_batch0 + lstm.num_outputs(); + float* golden_start_batch1 = lstm_golden_output[1] + i * lstm.num_outputs(); + float* golden_end_batch1 = golden_start_batch1 + lstm.num_outputs(); + expected.insert(expected.end(), golden_start_batch0, golden_end_batch0); + expected.insert(expected.end(), golden_start_batch1, golden_end_batch1); + } + EXPECT_THAT(lstm.GetOutput(), ElementsAreArray(ArrayFloatNear(expected))); +} + +} // namespace +} // namespace tflite + +int main(int argc, char** argv) { + ::tflite::LogToStderr(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tensorflow/contrib/lite/model.cc b/tensorflow/contrib/lite/model.cc index 4b0c853f77..4d8a6d10c8 100644 --- a/tensorflow/contrib/lite/model.cc +++ b/tensorflow/contrib/lite/model.cc @@ -463,6 +463,7 @@ void* ParseOpData(const Operator* op, BuiltinOperator op_type, builtin_data = reinterpret_cast(params); break; } + case BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM: case BuiltinOperator_LSTM: { TfLiteLSTMParams* params = MallocPOD(); if (auto* lstm_params = op->builtin_options_as_LSTMOptions()) { diff --git a/tensorflow/contrib/lite/nnapi_delegate.cc b/tensorflow/contrib/lite/nnapi_delegate.cc index b3602f799e..998a7b7614 100644 --- a/tensorflow/contrib/lite/nnapi_delegate.cc +++ b/tensorflow/contrib/lite/nnapi_delegate.cc @@ -322,6 +322,7 @@ void AddOpsAndParams(tflite::Interpreter* interpreter, case tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN: case tflite::BuiltinOperator_EMBEDDING_LOOKUP: case tflite::BuiltinOperator_EMBEDDING_LOOKUP_SPARSE: + case tflite::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM: case tflite::BuiltinOperator_L2_NORMALIZATION: case tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION: case tflite::BuiltinOperator_MUL: diff --git a/tensorflow/contrib/lite/schema/schema.fbs b/tensorflow/contrib/lite/schema/schema.fbs index 260a87c93b..6fcd3e51a4 100644 --- a/tensorflow/contrib/lite/schema/schema.fbs +++ b/tensorflow/contrib/lite/schema/schema.fbs @@ -117,6 +117,7 @@ enum BuiltinOperator : byte { SUB = 41, DIV = 42, SQUEEZE = 43, + UNIDIRECTIONAL_SEQUENCE_LSTM = 44, } // Options for the builtin operators. diff --git a/tensorflow/contrib/lite/schema/schema_generated.h b/tensorflow/contrib/lite/schema/schema_generated.h index fd98be8f70..6eb9ae2926 100755 --- a/tensorflow/contrib/lite/schema/schema_generated.h +++ b/tensorflow/contrib/lite/schema/schema_generated.h @@ -206,11 +206,12 @@ enum BuiltinOperator { BuiltinOperator_SUB = 41, BuiltinOperator_DIV = 42, BuiltinOperator_SQUEEZE = 43, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44, BuiltinOperator_MIN = BuiltinOperator_ADD, - BuiltinOperator_MAX = BuiltinOperator_SQUEEZE + BuiltinOperator_MAX = BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM }; -inline BuiltinOperator (&EnumValuesBuiltinOperator())[41] { +inline BuiltinOperator (&EnumValuesBuiltinOperator())[42] { static BuiltinOperator values[] = { BuiltinOperator_ADD, BuiltinOperator_AVERAGE_POOL_2D, @@ -252,7 +253,8 @@ inline BuiltinOperator (&EnumValuesBuiltinOperator())[41] { BuiltinOperator_MEAN, BuiltinOperator_SUB, BuiltinOperator_DIV, - BuiltinOperator_SQUEEZE}; + BuiltinOperator_SQUEEZE, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM}; return values; } @@ -301,6 +303,7 @@ inline const char **EnumNamesBuiltinOperator() { "SUB", "DIV", "SQUEEZE", + "UNIDIRECTIONAL_SEQUENCE_LSTM", nullptr}; return names; } -- GitLab From 4af0e15de653c148608a61ae2575acd493160795 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Wed, 24 Jan 2018 09:30:10 +0900 Subject: [PATCH 152/258] fix typo --- tensorflow/python/estimator/canned/dnn_testing_utils.py | 2 +- tensorflow/python/estimator/canned/linear_testing_utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/estimator/canned/dnn_testing_utils.py b/tensorflow/python/estimator/canned/dnn_testing_utils.py index 2bdec69303..706575985f 100644 --- a/tensorflow/python/estimator/canned/dnn_testing_utils.py +++ b/tensorflow/python/estimator/canned/dnn_testing_utils.py @@ -877,7 +877,7 @@ class BaseDNNWarmStartingTest(object): # Create a second DNNClassifier, warm-started from the first. Use a # learning_rate = 0.0 optimizer to check values (use SGD so we don't have - # accumulator values that change). Use a a new FeatureColumn with a + # accumulator values that change). Use a new FeatureColumn with a # different vocabulary for occupation. new_vocab_list = ['doctor', 'consultant', 'engineer'] new_vocab_file = os.path.join(self._ckpt_and_vocab_dir, diff --git a/tensorflow/python/estimator/canned/linear_testing_utils.py b/tensorflow/python/estimator/canned/linear_testing_utils.py index cccb9af4b2..3e9183cf1b 100644 --- a/tensorflow/python/estimator/canned/linear_testing_utils.py +++ b/tensorflow/python/estimator/canned/linear_testing_utils.py @@ -2003,7 +2003,7 @@ class BaseLinearWarmStartingTest(object): # Create a second LinearClassifier, warm-started from the first. Use a # learning_rate = 0.0 optimizer to check values (use SGD so we don't have - # accumulator values that change). Use a a new FeatureColumn with a + # accumulator values that change). Use a new FeatureColumn with a # different vocabulary for occupation. new_vocab_list = ['doctor', 'consultant', 'engineer'] new_vocab_file = os.path.join(self._ckpt_and_vocab_dir, -- GitLab From 5dfcb10d324873ccd7d5f6cca7bc503cea9cd9cc Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 16:38:55 -0800 Subject: [PATCH 153/258] Enable and fix some bfloat16 tests. PiperOrigin-RevId: 183013346 --- tensorflow/compiler/tests/binary_ops_test.py | 14 ++++++++++---- tensorflow/compiler/tests/image_ops_test.py | 15 ++++++++++----- tensorflow/compiler/tests/unary_ops_test.py | 6 ++++-- tensorflow/core/kernels/pack_op.cc | 1 - tensorflow/core/ops/image_ops.cc | 6 ++++-- tensorflow/python/framework/test_util.py | 6 +++++- tensorflow/python/lib/core/bfloat16_test.py | 19 +++++++++++++++++++ 7 files changed, 52 insertions(+), 15 deletions(-) diff --git a/tensorflow/compiler/tests/binary_ops_test.py b/tensorflow/compiler/tests/binary_ops_test.py index 65706b35d6..16856bd736 100644 --- a/tensorflow/compiler/tests/binary_ops_test.py +++ b/tensorflow/compiler/tests/binary_ops_test.py @@ -43,7 +43,7 @@ class BinaryOpsTest(XLATestCase): output = op(pa, pb) result = session.run(output, {pa: a, pb: b}) if equality_test is None: - equality_test = self.assertAllClose + equality_test = self.assertAllCloseAccordingToType equality_test(result, expected, rtol=1e-3) def _testSymmetricBinary(self, op, a, b, expected, equality_test=None): @@ -54,14 +54,20 @@ class BinaryOpsTest(XLATestCase): """Tests closeness of two lists of floats.""" self.assertEqual(len(result), len(expected)) for i in range(len(result)): - self.assertAllClose(result[i], expected[i], rtol) + self.assertAllCloseAccordingToType(result[i], expected[i], rtol) def testFloatOps(self): for dtype in self.float_types: + if dtype == dtypes.bfloat16.as_numpy_dtype: + a = -1.01 + b = 4.1 + else: + a = -1.001 + b = 4.01 self._testBinary( lambda x, y: math_ops.approximate_equal(x, y, tolerance=0.0001), - np.array([[[[-1, 2.00009999], [-3, 4.01]]]], dtype=dtype), - np.array([[[[-1.001, 2], [-3.00009, 4]]]], dtype=dtype), + np.array([[[[-1, 2.00009999], [-3, b]]]], dtype=dtype), + np.array([[[[a, 2], [-3.00009, 4]]]], dtype=dtype), expected=np.array([[[[False, True], [True, False]]]], dtype=dtype)) self._testBinary( diff --git a/tensorflow/compiler/tests/image_ops_test.py b/tensorflow/compiler/tests/image_ops_test.py index e84b790037..538fa8e8e5 100644 --- a/tensorflow/compiler/tests/image_ops_test.py +++ b/tensorflow/compiler/tests/image_ops_test.py @@ -65,7 +65,7 @@ class RGBToHSVTest(XLATestCase): # Verify that processing batch elements together is the same as separate self.assertAllClose(batch1, join1) self.assertAllClose(batch2, join2) - self.assertAllClose(batch2, inp) + self.assertAllCloseAccordingToType(batch2, inp, bfloat16_atol=0.03) def testRGBToHSVRoundTrip(self): data = [0, 5, 13, 54, 135, 226, 37, 8, 234, 90, 255, 1] @@ -77,21 +77,25 @@ class RGBToHSVTest(XLATestCase): hsv = image_ops.rgb_to_hsv(placeholder) rgb = image_ops.hsv_to_rgb(hsv) rgb_tf = rgb.eval(feed_dict={placeholder: rgb_np}) - self.assertAllClose(rgb_tf, rgb_np) + self.assertAllCloseAccordingToType(rgb_tf, rgb_np, bfloat16_atol=0.03) def testRGBToHSVNumpy(self): """Tests the RGB to HSV conversion matches a reference implementation.""" for nptype in self.float_types: rgb_flat = np.random.random(64 * 3).reshape((64, 3)).astype(nptype) rgb_np = rgb_flat.reshape(4, 4, 4, 3) - hsv_np = np.array([colorsys.rgb_to_hsv(r, g, b) for r, g, b in rgb_flat]) + hsv_np = np.array([ + colorsys.rgb_to_hsv( + r.astype(np.float64), g.astype(np.float64), b.astype(np.float64)) + for r, g, b in rgb_flat + ]) hsv_np = hsv_np.reshape(4, 4, 4, 3) with self.test_session(): placeholder = array_ops.placeholder(nptype) with self.test_scope(): hsv_op = image_ops.rgb_to_hsv(placeholder) hsv_tf = hsv_op.eval(feed_dict={placeholder: rgb_np}) - self.assertAllClose(hsv_tf, hsv_np) + self.assertAllCloseAccordingToType(hsv_tf, hsv_np) class AdjustContrastTest(XLATestCase): @@ -427,7 +431,8 @@ class ResizeBilinearTest(XLATestCase): np.zeros([1, input_shape[0], input_shape[1], 1], dtype=dtype), align_corners=True) out = sess.run(resized, {grads: grads_np[np.newaxis, :, :, np.newaxis]}) - self.assertAllClose(expected[np.newaxis, :, :, np.newaxis], out) + self.assertAllCloseAccordingToType(expected[np.newaxis, :, :, np.newaxis], + out) def testAlignCorners1x2To3x2(self): for dtype in self.float_types: diff --git a/tensorflow/compiler/tests/unary_ops_test.py b/tensorflow/compiler/tests/unary_ops_test.py index 0a6fe04d3c..8e4b8a3833 100644 --- a/tensorflow/compiler/tests/unary_ops_test.py +++ b/tensorflow/compiler/tests/unary_ops_test.py @@ -67,8 +67,10 @@ class UnaryOpsTest(XLATestCase): output = op(pinp) result = session.run(output, {pinp: inp}) if equality_test is None: - equality_test = self.assertAllCloseAccordingToType - equality_test(result, expected, rtol=rtol, atol=atol) + self.assertAllCloseAccordingToType( + result, expected, rtol=rtol, atol=atol, bfloat16_rtol=0.03) + else: + equality_test(result, expected, rtol=rtol, atol=atol) def ListsAreClose(self, result, expected, rtol, atol): """Tests closeness of two lists of floats.""" diff --git a/tensorflow/core/kernels/pack_op.cc b/tensorflow/core/kernels/pack_op.cc index 2923c38662..2033fbf5dc 100644 --- a/tensorflow/core/kernels/pack_op.cc +++ b/tensorflow/core/kernels/pack_op.cc @@ -139,7 +139,6 @@ class PackOp : public OpKernel { TF_CALL_ALL_TYPES(REGISTER_PACK); TF_CALL_QUANTIZED_TYPES(REGISTER_PACK); -TF_CALL_bfloat16(REGISTER_PACK); TF_CALL_variant(REGISTER_PACK); #if defined(IS_MOBILE_PLATFORM) && !defined(SUPPORT_SELECTIVE_REGISTRATION) diff --git a/tensorflow/core/ops/image_ops.cc b/tensorflow/core/ops/image_ops.cc index 31cc662d21..7484ebb078 100644 --- a/tensorflow/core/ops/image_ops.cc +++ b/tensorflow/core/ops/image_ops.cc @@ -181,7 +181,9 @@ REGISTER_OP("ResizeBilinear") .Input("images: T") .Input("size: int32") .Output("resized_images: float") - .Attr("T: {int8, uint8, int16, uint16, int32, int64, half, float, double}") + .Attr( + "T: {int8, uint8, int16, uint16, int32, int64, bfloat16, half, " + "float, double}") .Attr("align_corners: bool = false") .SetShapeFn(ResizeShapeFn); @@ -212,7 +214,7 @@ REGISTER_OP("ResizeBilinearGrad") .Input("grads: float") .Input("original_image: T") .Output("output: T") - .Attr("T: {float, half, double}") + .Attr("T: {float, bfloat16, half, double}") .Attr("align_corners: bool = false") .SetShapeFn([](InferenceContext* c) { c->set_output(0, c->input(1)); diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py index 8124472a83..7b09891fc1 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py @@ -1130,7 +1130,11 @@ class TensorFlowTestCase(googletest.TestCase): print("not close dif = ", np.abs(x - y)) print("not close tol = ", atol + rtol * np.abs(y)) print("dtype = %s, shape = %s" % (a.dtype, a.shape)) - np.testing.assert_allclose(a, b, rtol=rtol, atol=atol, err_msg=msg) + # TODO(xpan): There seems to be a bug: + # tensorflow/compiler/tests:binary_ops_test pass with float32 + # nan even though the equal_nan is False by default internally. + np.testing.assert_allclose( + a, b, rtol=rtol, atol=atol, err_msg=msg, equal_nan=True) def assertAllClose(self, a, b, rtol=1e-6, atol=1e-6): """Asserts that two numpy arrays, or dicts of same, have near values. diff --git a/tensorflow/python/lib/core/bfloat16_test.py b/tensorflow/python/lib/core/bfloat16_test.py index 985a11272c..09d4b01fa4 100644 --- a/tensorflow/python/lib/core/bfloat16_test.py +++ b/tensorflow/python/lib/core/bfloat16_test.py @@ -25,6 +25,7 @@ import numpy as np # pylint: disable=unused-import,g-bad-import-order from tensorflow.python import pywrap_tensorflow +from tensorflow.python.framework import dtypes from tensorflow.python.platform import test @@ -160,6 +161,24 @@ class Bfloat16Test(test.TestCase): for w in self.float_values(): self.assertEqual(v != w, bfloat16(v) != bfloat16(w)) + def testNan(self): + a = np.isnan(bfloat16(float("nan"))) + self.assertTrue(a) + np.testing.assert_allclose(np.array([1.0, a]), np.array([1.0, a])) + + a = np.array( + [bfloat16(1.34375), + bfloat16(1.4375), + bfloat16(float("nan"))], + dtype=dtypes.bfloat16.as_numpy_dtype) + b = np.array( + [bfloat16(1.3359375), + bfloat16(1.4375), + bfloat16(float("nan"))], + dtype=dtypes.bfloat16.as_numpy_dtype) + np.testing.assert_allclose( + a, b, rtol=0.1, atol=0.1, equal_nan=True, err_msg="", verbose=True) + class Bfloat16NumPyTest(test.TestCase): -- GitLab From d725e36efc65ba614690b28c864a08b5e669c32e Mon Sep 17 00:00:00 2001 From: Saurabh Saxena Date: Tue, 23 Jan 2018 16:50:47 -0800 Subject: [PATCH 154/258] Adds a mechanism for whitelisting ops for use in map_fns using a WHITELIST_OP_FOR_DATASET_FUNCTIONS macro. Changes criteria for whitelisting stateful dataset ops. We used to check for the presence of the output_shapes attr. Now we just match the name and the output type. PiperOrigin-RevId: 183014929 --- tensorflow/core/BUILD | 1 + tensorflow/core/framework/dataset.h | 75 ++++++++++++++++++++++++++ tensorflow/core/kernels/data/dataset.h | 14 ++++- 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 tensorflow/core/framework/dataset.h diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index d73f003a1d..fc49825748 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -432,6 +432,7 @@ tf_cuda_library( "framework/cancellation.h", "framework/common_shape_fns.h", "framework/control_flow.h", # TODO(josh11b): Make internal? + "framework/dataset.h", "framework/device_base.h", "framework/function.h", "framework/graph_def_util.h", diff --git a/tensorflow/core/framework/dataset.h b/tensorflow/core/framework/dataset.h new file mode 100644 index 0000000000..2c2c7e7c58 --- /dev/null +++ b/tensorflow/core/framework/dataset.h @@ -0,0 +1,75 @@ +/* Copyright 2018 The TensorFlow Authors. 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_FRAMEWORK_DATASET_H_ +#define TENSORFLOW_FRAMEWORK_DATASET_H_ + +namespace tensorflow { +namespace dataset { +// Registry for stateful ops that need to be used in dataset functions. +// See below macro for usage details. +class WhitelistedStatefulOpRegistry { + public: + Status Add(StringPiece op_name) { + op_names_.insert(op_name); + return Status::OK(); + } + + bool Contains(StringPiece op_name) { + return op_names_.find(op_name) != op_names_.end(); + } + + static WhitelistedStatefulOpRegistry* Global() { + static WhitelistedStatefulOpRegistry* reg = + new WhitelistedStatefulOpRegistry; + return reg; + } + + private: + WhitelistedStatefulOpRegistry() {} + WhitelistedStatefulOpRegistry(WhitelistedStatefulOpRegistry const& copy); + WhitelistedStatefulOpRegistry operator=( + WhitelistedStatefulOpRegistry const& copy); + std::set op_names_; +}; + +} // namespace dataset + +// Use this macro to whitelist an op that is marked stateful but needs to be +// used inside a map_fn in an input pipeline. This is only needed if you wish +// to be able to checkpoint the state of the input pipeline. We currently +// do not allow stateful ops to be defined inside of map_fns since it is not +// possible to save their state. +// Note that the state of the whitelisted ops inside functions will not be +// saved during checkpointing, hence this should only be used if the op is +// marked stateful for reasons like to avoid constant folding during graph +// optimiztion but is not stateful. +// If possible, try to remove the stateful flag on the op first. +// Example usage: +// +// WHITELIST_STATEFUL_OP_FOR_DATASET_FUNCTIONS("LegacyStatefulReader"); +// +#define WHITELIST_STATEFUL_OP_FOR_DATASET_FUNCTIONS(name) \ + WHITELIST_STATEFUL_OP_FOR_DATASET_FUNCTIONS_UNIQ_HELPER(__COUNTER__, name) +#define WHITELIST_STATEFUL_OP_FOR_DATASET_FUNCTIONS_UNIQ_HELPER(ctr, name) \ + WHITELIST_STATEFUL_OP_FOR_DATASET_FUNCTIONS_UNIQ(ctr, name) +#define WHITELIST_STATEFUL_OP_FOR_DATASET_FUNCTIONS_UNIQ(ctr, name) \ + static ::tensorflow::Status whitelist_op##ctr TF_ATTRIBUTE_UNUSED = \ + ::tensorflow::dataset::WhitelistedStatefulOpRegistry::Global()->Add( \ + name) + +} // namespace tensorflow + +#endif // TENSORFLOW_FRAMEWORK_DATASET_H_ diff --git a/tensorflow/core/kernels/data/dataset.h b/tensorflow/core/kernels/data/dataset.h index 3cb3c08a32..fbaaf22527 100644 --- a/tensorflow/core/kernels/data/dataset.h +++ b/tensorflow/core/kernels/data/dataset.h @@ -19,11 +19,13 @@ limitations under the License. #include "tensorflow/core/framework/attr_value.pb.h" #include "tensorflow/core/framework/attr_value_util.h" +#include "tensorflow/core/framework/dataset.h" #include "tensorflow/core/framework/function.h" #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/framework/node_def.pb.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/framework/types.pb.h" #include "tensorflow/core/framework/variant_encode_decode.h" #include "tensorflow/core/framework/variant_tensor_data.h" #include "tensorflow/core/lib/strings/str_util.h" @@ -193,9 +195,17 @@ class GraphDefBuilderWrapper { return Status::OK(); } + // Returns whether an op has been whitelisted for use inside map_fns. + // Uses a heuristic to whitelist source dataset ops which have been + // marked stateful due to b/65524810. + // Also looks up the `op_def->name` in the global + // `WhitelistedStatefulOpRegistry`. bool IsOpWhitelisted(const OpDef* op_def) const { - return StringPiece(op_def->name()).ends_with("Dataset") && - HasAttr(op_def, "output_shapes"); + return (StringPiece(op_def->name()).ends_with("Dataset") && + op_def->output_arg_size() == 1 && + op_def->output_arg(0).type() == DT_VARIANT) || + dataset::WhitelistedStatefulOpRegistry::Global()->Contains( + op_def->name()); } bool HasAttr(const string& op_type_name, const string& attr_name) const; -- GitLab From 8c30d9a635b9d6456239fe9ec5526a8bba998e34 Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Tue, 23 Jan 2018 17:11:30 -0800 Subject: [PATCH 155/258] [XLA:python] Pull static method off of ComputationBuilder class. PiperOrigin-RevId: 183017700 --- tensorflow/compiler/xla/python/xla_client.py | 23 ++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tensorflow/compiler/xla/python/xla_client.py b/tensorflow/compiler/xla/python/xla_client.py index 5455adafcd..9cfe1249f5 100644 --- a/tensorflow/compiler/xla/python/xla_client.py +++ b/tensorflow/compiler/xla/python/xla_client.py @@ -555,22 +555,12 @@ class ComputationBuilder(object): A ComputationDataHandle representing the added pad op. """ if not isinstance(padding_config, xla_data_pb2.PaddingConfig): - padding_config = self._GetPaddingConfigFromTriples(padding_config) + padding_config = GetPaddingConfigFromTriples(padding_config) return _wrap_data_handle( self._client.Pad(_unwrap_data_handle(operand), _unwrap_data_handle(padding_value), padding_config)) - def _GetPaddingConfigFromTriples(self, triples): - """Create PaddingConfig proto from list of triples of integers.""" - padding_config = xla_data_pb2.PaddingConfig() - for lo, hi, interior in triples: - dimension = padding_config.dimensions.add() - dimension.edge_padding_low = lo - dimension.edge_padding_high = hi - dimension.interior_padding = interior - return padding_config - def Reshape(self, operand, dimensions, new_sizes): """Reshape op.""" return _wrap_data_handle( @@ -997,3 +987,14 @@ def get_replica_count(): yet or not. """ return c_api.GetReplicaCount() + + +def GetPaddingConfigFromTriples(triples): + """Create PaddingConfig proto from list of triples of integers.""" + padding_config = xla_data_pb2.PaddingConfig() + for lo, hi, interior in triples: + dimension = padding_config.dimensions.add() + dimension.edge_padding_low = lo + dimension.edge_padding_high = hi + dimension.interior_padding = interior + return padding_config -- GitLab From 678560c3fc5be1a1a2b8632136cbce0390d2c240 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Tue, 23 Jan 2018 17:26:50 -0800 Subject: [PATCH 156/258] Mark TensorArrayV2 ops and deprecated io_ops deprecated. PiperOrigin-RevId: 183019408 --- tensorflow/core/ops/data_flow_ops.cc | 36 ++++++++++++++-------------- tensorflow/core/ops/io_ops.cc | 16 ++++++------- tensorflow/core/public/version.h | 4 +++- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/tensorflow/core/ops/data_flow_ops.cc b/tensorflow/core/ops/data_flow_ops.cc index cf949ed647..12c27c7984 100644 --- a/tensorflow/core/ops/data_flow_ops.cc +++ b/tensorflow/core/ops/data_flow_ops.cc @@ -787,7 +787,6 @@ REGISTER_OP("TensorArray") .SetIsStateful() .SetShapeFn(shape_inference::UnknownShape) .Deprecated(16, "Use TensorArrayV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArrayV2") .Input("size: int32") .Attr("dtype: type") @@ -802,7 +801,8 @@ REGISTER_OP("TensorArrayV2") TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); c->set_output(0, c->Vector(2)); return Status::OK(); - }); + }) + .Deprecated(26, "Use TensorArrayV3"); REGISTER_OP("TensorArrayGrad") .Input("handle: string") .Input("flow_in: float") @@ -811,7 +811,6 @@ REGISTER_OP("TensorArrayGrad") .SetIsStateful() .SetShapeFn(shape_inference::UnknownShape) .Deprecated(16, "Use TensorArrayGradV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArrayGradV2") .Input("handle: string") .Input("flow_in: float") @@ -825,7 +824,8 @@ REGISTER_OP("TensorArrayGradV2") TF_RETURN_IF_ERROR(c->WithValue(c->Dim(handle, 0), 2, &unused_dim)); c->set_output(0, c->Vector(2)); return Status::OK(); - }); + }) + .Deprecated(26, "Use TensorArrayGradV3"); REGISTER_OP("TensorArrayWrite") .Input("handle: Ref(string)") .Input("index: int32") @@ -835,7 +835,6 @@ REGISTER_OP("TensorArrayWrite") .Attr("T: type") .SetShapeFn(shape_inference::UnknownShape) .Deprecated(16, "Use TensorArrayWriteV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArrayWriteV2") .Input("handle: string") .Input("index: int32") @@ -853,7 +852,8 @@ REGISTER_OP("TensorArrayWriteV2") TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); return shape_inference::ScalarShape(c); - }); + }) + .Deprecated(26, "Use TensorArrayWriteV3"); REGISTER_OP("TensorArrayRead") .Input("handle: Ref(string)") .Input("index: int32") @@ -862,7 +862,6 @@ REGISTER_OP("TensorArrayRead") .Attr("dtype: type") .SetShapeFn(shape_inference::UnknownShape) .Deprecated(16, "Use TensorArrayReadV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArrayReadV2") .Input("handle: string") .Input("index: int32") @@ -878,7 +877,8 @@ REGISTER_OP("TensorArrayReadV2") TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); return shape_inference::UnknownShape(c); - }); + }) + .Deprecated(26, "Use TensorArrayReadV3"); REGISTER_OP("TensorArrayPack") .Input("handle: Ref(string)") .Input("flow_in: float") @@ -904,7 +904,6 @@ REGISTER_OP("TensorArrayGather") .Attr("element_shape: shape = { unknown_rank: true }") .SetShapeFn(shape_inference::UnknownShape) .Deprecated(16, "Use TensorArrayGatherV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArrayGatherV2") .Input("handle: string") .Input("indices: int32") @@ -920,7 +919,8 @@ REGISTER_OP("TensorArrayGatherV2") TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); return shape_inference::UnknownShape(c); - }); + }) + .Deprecated(26, "Use TensorArrayGatherV3"); REGISTER_OP("TensorArrayScatter") .Input("handle: Ref(string)") .Input("indices: int32") @@ -930,7 +930,6 @@ REGISTER_OP("TensorArrayScatter") .Attr("T: type") .SetShapeFn(shape_inference::UnknownShape) .Deprecated(19, "Use TensorArrayGradV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArrayScatterV2") .Input("handle: string") .Input("indices: int32") @@ -946,7 +945,8 @@ REGISTER_OP("TensorArrayScatterV2") TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); return shape_inference::ScalarShape(c); - }); + }) + .Deprecated(26, "Use TensorArrayScatterV3"); REGISTER_OP("TensorArrayConcat") .Input("handle: Ref(string)") .Input("flow_in: float") @@ -983,7 +983,6 @@ REGISTER_OP("TensorArraySplit") .Attr("T: type") .SetShapeFn(shape_inference::UnknownShape) .Deprecated(16, "Use TensorArraySplitV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArraySplitV2") .Input("handle: string") .Input("value: T") @@ -1000,14 +999,14 @@ REGISTER_OP("TensorArraySplitV2") TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); return shape_inference::ScalarShape(c); - }); + }) + .Deprecated(26, "Use TensorArraySplitV3"); REGISTER_OP("TensorArraySize") .Input("handle: Ref(string)") .Input("flow_in: float") .Output("size: int32") .SetShapeFn(shape_inference::UnknownShape) .Deprecated(16, "Use TensorArraySizeV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArraySizeV2") .Input("handle: string") .Input("flow_in: float") @@ -1018,12 +1017,12 @@ REGISTER_OP("TensorArraySizeV2") TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &handle)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(handle, 0), 2, &unused_dim)); return shape_inference::ScalarShape(c); - }); + }) + .Deprecated(26, "Use TensorArraySizeV3"); REGISTER_OP("TensorArrayClose") .Input("handle: Ref(string)") .SetShapeFn([](InferenceContext* c) { return Status::OK(); }) .Deprecated(16, "Use TensorArrayCloseV3"); -// TODO(cwhipkey): mark this deprecated in favor of V3. REGISTER_OP("TensorArrayCloseV2") .Input("handle: string") .SetShapeFn([](InferenceContext* c) { @@ -1032,7 +1031,8 @@ REGISTER_OP("TensorArrayCloseV2") TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &handle)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(handle, 0), 2, &unused_dim)); return Status::OK(); - }); + }) + .Deprecated(26, "Use TensorArrayCloseV3"); // -------------------------------------------------------------------------- diff --git a/tensorflow/core/ops/io_ops.cc b/tensorflow/core/ops/io_ops.cc index 21f0d02ff2..7db4d0c4b6 100644 --- a/tensorflow/core/ops/io_ops.cc +++ b/tensorflow/core/ops/io_ops.cc @@ -272,14 +272,14 @@ REGISTER_OP("WholeFileReaderV2") .SetIsStateful() .SetShapeFn(shape_inference::ScalarShape); -// TODO(cwhipkey): mark this deprecated in favor of V2. REGISTER_OP("TextLineReader") .Output("reader_handle: Ref(string)") .Attr("skip_header_lines: int = 0") .Attr("container: string = ''") .Attr("shared_name: string = ''") .SetIsStateful() - .SetShapeFn(TwoElementOutput); + .SetShapeFn(TwoElementOutput) + .Deprecated(26, "Use TextLineReaderV2"); REGISTER_OP("TextLineReaderV2") .Output("reader_handle: resource") @@ -289,7 +289,6 @@ REGISTER_OP("TextLineReaderV2") .SetIsStateful() .SetShapeFn(shape_inference::ScalarShape); -// TODO(cwhipkey): mark this deprecated in favor of V2. REGISTER_OP("FixedLengthRecordReader") .Output("reader_handle: Ref(string)") .Attr("header_bytes: int = 0") @@ -299,7 +298,8 @@ REGISTER_OP("FixedLengthRecordReader") .Attr("container: string = ''") .Attr("shared_name: string = ''") .SetIsStateful() - .SetShapeFn(TwoElementOutput); + .SetShapeFn(TwoElementOutput) + .Deprecated(26, "Use FixedLengthRecordReaderV2"); REGISTER_OP("FixedLengthRecordReaderV2") .Output("reader_handle: resource") @@ -313,14 +313,14 @@ REGISTER_OP("FixedLengthRecordReaderV2") .SetIsStateful() .SetShapeFn(shape_inference::ScalarShape); -// TODO(cwhipkey): mark this deprecated in favor of V2. REGISTER_OP("TFRecordReader") .Output("reader_handle: Ref(string)") .Attr("container: string = ''") .Attr("shared_name: string = ''") .Attr("compression_type: string = ''") .SetIsStateful() - .SetShapeFn(TwoElementOutput); + .SetShapeFn(TwoElementOutput) + .Deprecated(26, "Use TFRecordReaderV2"); REGISTER_OP("TFRecordReaderV2") .Output("reader_handle: resource") @@ -337,13 +337,13 @@ REGISTER_OP("LMDBReader") .SetIsStateful() .SetShapeFn(TwoElementOutput); -// TODO(cwhipkey): mark this deprecated in favor of V2. REGISTER_OP("IdentityReader") .Output("reader_handle: Ref(string)") .Attr("container: string = ''") .Attr("shared_name: string = ''") .SetIsStateful() - .SetShapeFn(TwoElementOutput); + .SetShapeFn(TwoElementOutput) + .Deprecated(26, "Use IdentityReaderV2"); REGISTER_OP("IdentityReaderV2") .Output("reader_handle: resource") diff --git a/tensorflow/core/public/version.h b/tensorflow/core/public/version.h index 3baab75e27..836efc079f 100644 --- a/tensorflow/core/public/version.h +++ b/tensorflow/core/public/version.h @@ -94,10 +94,12 @@ limitations under the License. // 26. Add a bool 'stripped_default_attrs' to MetaInfoDef indicating // whether default-valued attrs have been stripped from the nodes in the // GraphDef. (7dec2017) +// 27. Deprecate TensorArray ops v2 in favor of v3 and deprecated io_ops +// deprecated in favor of V2 ops. (2018/01/23) #define TF_GRAPH_DEF_VERSION_MIN_PRODUCER 0 #define TF_GRAPH_DEF_VERSION_MIN_CONSUMER 0 -#define TF_GRAPH_DEF_VERSION 25 +#define TF_GRAPH_DEF_VERSION 26 // Checkpoint compatibility versions (the versions field in SavedSliceMeta). // -- GitLab From a3e81ec2892126056ad6c1feb9161bc16c2c2975 Mon Sep 17 00:00:00 2001 From: Peter Hawkins Date: Tue, 23 Jan 2018 17:32:39 -0800 Subject: [PATCH 157/258] [TPU] Add extra type checking in Python around the infeed operation, since it is a common mistake to make. PiperOrigin-RevId: 183020077 --- tensorflow/contrib/tpu/python/ops/tpu_ops.py | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/tensorflow/contrib/tpu/python/ops/tpu_ops.py b/tensorflow/contrib/tpu/python/ops/tpu_ops.py index 33e47f674d..a49a3dcf29 100644 --- a/tensorflow/contrib/tpu/python/ops/tpu_ops.py +++ b/tensorflow/contrib/tpu/python/ops/tpu_ops.py @@ -21,6 +21,7 @@ from __future__ import print_function import platform +from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops if platform.system() != "Windows": @@ -40,6 +41,63 @@ if platform.system() != "Windows": del op # Unused # The gradient of a cross replica sum is also a cross-replica sum. return gen_tpu_ops.cross_replica_sum(grad) + + # This extra type checking exists to give a more helpful error message in + # the common case that uint8 and int64 values are infed. Remove when both + # types are supported. + + _SUPPORTED_INFEED_DTYPES = set([ + dtypes.int32, dtypes.bfloat16, dtypes.float32 + ]) + + def infeed_dequeue(dtype, shape, name=None): + """A placeholder op for a value that will be fed into the computation. + + Args: + dtype: A `tf.DType`. The type of elements in the tensor. + shape: A `tf.TensorShape` or list of `ints`. The shape of the tensor. + name: A name for the operation (optional). + + Returns: + A `Tensor` of type `dtype`. + A tensor that will be provided using the infeed mechanism. + + Raises: + TypeError: If 'dtype` is not a supported infeed type. + """ + if dtype not in _SUPPORTED_INFEED_DTYPES: + raise TypeError( + "{} is not a supported TPU infeed type. Supported types are: " + "{}".format(dtype, list(_SUPPORTED_INFEED_DTYPES))) + + return gen_tpu_ops.infeed_dequeue(dtype, shape, name=name) + + # pylint: disable=redefined-outer-name + def infeed_dequeue_tuple(dtypes, shapes, name=None): + """A placeholder op for values fed into the TPU simultaneously as a tuple. + + Args: + dtypes: A list of `tf.DType`s that has length `>= 1`. + The element types of each element in `outputs`. + shapes: A list of shapes (each a `tf.TensorShape` or list of `ints`). + The shapes of each tensor in `outputs`. + name: A name for the operation (optional). + + Returns: + A list of `Tensor` objects of type `dtypes`. + A list of tensors that will be provided using the infeed mechanism. + + Raises: + TypeError: If a type in 'dtypes` is not a supported infeed type. + """ + for dtype in dtypes: + if dtype not in _SUPPORTED_INFEED_DTYPES: + raise TypeError( + "{} is not a supported TPU infeed type. Supported types are: " + "{}".format(dtype, list(_SUPPORTED_INFEED_DTYPES))) + return gen_tpu_ops.infeed_dequeue_tuple(dtypes, shapes, name=name) + # pylint: enable=redefined-outer-name + else: # We have already built the appropriate libraries into the binary via CMake # if we have built contrib, so we don't need this -- GitLab From 6dfe00ca4114371ed47c93810219736e3deda2d2 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 17:35:53 -0800 Subject: [PATCH 158/258] Support StridedSlice in TFLite for 1D-4D tensors. PiperOrigin-RevId: 183020501 --- tensorflow/contrib/lite/builtin_op_data.h | 20 +- tensorflow/contrib/lite/kernels/BUILD | 13 + .../internal/reference/reference_ops.h | 51 ++- tensorflow/contrib/lite/kernels/register.cc | 2 + .../contrib/lite/kernels/strided_slice.cc | 256 ++++++++++++ .../lite/kernels/strided_slice_test.cc | 375 ++++++++++++++++++ tensorflow/contrib/lite/model.cc | 12 + tensorflow/contrib/lite/nnapi_delegate.cc | 1 + tensorflow/contrib/lite/schema/schema.fbs | 10 + .../contrib/lite/schema/schema_generated.h | 239 ++++++++++- tensorflow/contrib/lite/testing/BUILD | 1 + .../contrib/lite/testing/generate_examples.py | 92 +++++ .../testing/generated_examples_zip_test.cc | 1 + .../resolve_strided_slice_attributes.cc | 4 + .../contrib/lite/toco/import_tensorflow.cc | 2 + tensorflow/contrib/lite/toco/model.h | 3 + .../contrib/lite/toco/tflite/operator.cc | 26 ++ .../contrib/lite/toco/tflite/operator_test.cc | 22 + 18 files changed, 1107 insertions(+), 23 deletions(-) create mode 100644 tensorflow/contrib/lite/kernels/strided_slice.cc create mode 100644 tensorflow/contrib/lite/kernels/strided_slice_test.cc mode change 100755 => 100644 tensorflow/contrib/lite/schema/schema_generated.h diff --git a/tensorflow/contrib/lite/builtin_op_data.h b/tensorflow/contrib/lite/builtin_op_data.h index 3b43a1fd5d..ab07c58c92 100644 --- a/tensorflow/contrib/lite/builtin_op_data.h +++ b/tensorflow/contrib/lite/builtin_op_data.h @@ -88,7 +88,9 @@ typedef struct { TfLiteFusedActivation activation; } TfLiteSequenceRNNParams; -typedef struct { TfLiteFusedActivation activation; } TfLiteFullyConnectedParams; +typedef struct { + TfLiteFusedActivation activation; +} TfLiteFullyConnectedParams; typedef enum { kTfLiteLshProjectionUnknown = 0, @@ -96,9 +98,13 @@ typedef enum { kTfLiteLshProjectionDense = 2, } TfLiteLSHProjectionType; -typedef struct { TfLiteLSHProjectionType type; } TfLiteLSHProjectionParams; +typedef struct { + TfLiteLSHProjectionType type; +} TfLiteLSHProjectionParams; -typedef struct { float beta; } TfLiteSoftmaxParams; +typedef struct { + float beta; +} TfLiteSoftmaxParams; typedef struct { int axis; @@ -226,6 +232,14 @@ typedef struct { int num_squeeze_dims; } TfLiteSqueezeParams; +typedef struct { + int begin_mask; + int end_mask; + int ellipsis_mask; + int new_axis_mask; + int shrink_axis_mask; +} TfLiteStridedSliceParams; + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tensorflow/contrib/lite/kernels/BUILD b/tensorflow/contrib/lite/kernels/BUILD index 2d51b8727f..4195e7553c 100644 --- a/tensorflow/contrib/lite/kernels/BUILD +++ b/tensorflow/contrib/lite/kernels/BUILD @@ -103,6 +103,7 @@ cc_library( "space_to_batch_nd.cc", "space_to_depth.cc", "squeeze.cc", + "strided_slice.cc", "sub.cc", "svdf.cc", "transpose.cc", @@ -518,6 +519,18 @@ tf_cc_test( ], ) +tf_cc_test( + name = "strided_slice_test", + size = "small", + srcs = ["strided_slice_test.cc"], + deps = [ + ":builtin_ops", + "//tensorflow/contrib/lite:framework", + "//tensorflow/contrib/lite/kernels:test_util", + "@com_google_googletest//:gtest", + ], +) + filegroup( name = "all_files", srcs = glob( diff --git a/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h b/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h index 1d86183d94..03708eb32b 100644 --- a/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h @@ -2330,6 +2330,18 @@ inline void Pad(const T* input_data, const Dims<4>& input_dims, } } +inline bool LoopCondition(int index, int stop, int stride) { + return stride > 0 ? index < stop : index > stop; +} + +inline int StartIndex(int start, int stride, int dim, bool masked) { + return masked ? (stride > 0 ? 0 : dim - 1) : start; +} + +inline int StopIndex(int stop, int stride, int dim, bool masked) { + return masked ? (stride > 0 ? dim : -1) : stop; +} + template inline void StridedSlice(const T* input_data, const Dims<4>& input_dims, int begin_mask, int end_mask, @@ -2337,20 +2349,35 @@ inline void StridedSlice(const T* input_data, const Dims<4>& input_dims, const std::vector& stops, const std::vector& strides, T* output_data, const Dims<4>& output_dims) { - const int start_b = (begin_mask & 8) ? 0 : starts[3]; - const int stop_b = (end_mask & 8) ? input_dims.sizes[3] : stops[3]; - const int start_h = (begin_mask & 4) ? 0 : starts[2]; - const int stop_h = (end_mask & 4) ? input_dims.sizes[2] : stops[2]; - const int start_w = (begin_mask & 2) ? 0 : starts[1]; - const int stop_w = (end_mask & 2) ? input_dims.sizes[1] : stops[1]; - const int start_d = (begin_mask & 1) ? 0 : starts[0]; - const int stop_d = (end_mask & 1) ? input_dims.sizes[0] : stops[0]; + TFLITE_DCHECK_EQ(starts.size(), 4); + TFLITE_DCHECK_EQ(stops.size(), 4); + TFLITE_DCHECK_EQ(strides.size(), 4); + const int start_b = + StartIndex(starts[3], strides[3], input_dims.sizes[3], begin_mask & 8); + const int stop_b = + StopIndex(stops[3], strides[3], input_dims.sizes[3], end_mask & 8); + const int start_h = + StartIndex(starts[2], strides[2], input_dims.sizes[2], begin_mask & 4); + const int stop_h = + StopIndex(stops[2], strides[2], input_dims.sizes[2], end_mask & 4); + const int start_w = + StartIndex(starts[1], strides[1], input_dims.sizes[1], begin_mask & 2); + const int stop_w = + StopIndex(stops[1], strides[1], input_dims.sizes[1], end_mask & 2); + const int start_d = + StartIndex(starts[0], strides[0], input_dims.sizes[0], begin_mask & 1); + const int stop_d = + StopIndex(stops[0], strides[0], input_dims.sizes[0], end_mask & 1); T* out_ptr = output_data; - for (int in_b = start_b; in_b < stop_b; in_b += strides[3]) { - for (int in_h = start_h; in_h < stop_h; in_h += strides[2]) { - for (int in_w = start_w; in_w < stop_w; in_w += strides[1]) { - for (int in_d = start_d; in_d < stop_d; in_d += strides[0]) { + for (int in_b = start_b; LoopCondition(in_b, stop_b, strides[3]); + in_b += strides[3]) { + for (int in_h = start_h; LoopCondition(in_h, stop_h, strides[2]); + in_h += strides[2]) { + for (int in_w = start_w; LoopCondition(in_w, stop_w, strides[1]); + in_w += strides[1]) { + for (int in_d = start_d; LoopCondition(in_d, stop_d, strides[0]); + in_d += strides[0]) { *out_ptr++ = input_data[Offset(input_dims, in_d, in_w, in_h, in_b)]; } } diff --git a/tensorflow/contrib/lite/kernels/register.cc b/tensorflow/contrib/lite/kernels/register.cc index c9e74cb8d5..f605deaa5b 100644 --- a/tensorflow/contrib/lite/kernels/register.cc +++ b/tensorflow/contrib/lite/kernels/register.cc @@ -58,6 +58,7 @@ TfLiteRegistration* Register_GATHER(); TfLiteRegistration* Register_TRANSPOSE(); TfLiteRegistration* Register_MEAN(); TfLiteRegistration* Register_SQUEEZE(); +TfLiteRegistration* Register_STRIDED_SLICE(); BuiltinOpResolver::BuiltinOpResolver() { AddBuiltin(BuiltinOperator_RELU, Register_RELU()); @@ -103,6 +104,7 @@ BuiltinOpResolver::BuiltinOpResolver() { AddBuiltin(BuiltinOperator_DIV, Register_DIV()); AddBuiltin(BuiltinOperator_SUB, Register_SUB()); AddBuiltin(BuiltinOperator_SQUEEZE, Register_SQUEEZE()); + AddBuiltin(BuiltinOperator_STRIDED_SLICE, Register_STRIDED_SLICE()); } TfLiteRegistration* BuiltinOpResolver::FindOp( diff --git a/tensorflow/contrib/lite/kernels/strided_slice.cc b/tensorflow/contrib/lite/kernels/strided_slice.cc new file mode 100644 index 0000000000..91ba4a9b78 --- /dev/null +++ b/tensorflow/contrib/lite/kernels/strided_slice.cc @@ -0,0 +1,256 @@ +/* Copyright 2018 The TensorFlow Authors. 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 +#include +#include +#include "tensorflow/contrib/lite/builtin_op_data.h" +#include "tensorflow/contrib/lite/context.h" +#include "tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h" +#include "tensorflow/contrib/lite/kernels/internal/tensor.h" +#include "tensorflow/contrib/lite/kernels/kernel_util.h" +#include "tensorflow/contrib/lite/kernels/op_macros.h" + +namespace tflite { +namespace ops { +namespace builtin { +namespace strided_slice { + +enum KernelType { + kReference, + // TODO(soroosh): add kGenericOptimized +}; + +constexpr int kInputTensor = 0; +constexpr int kBeginTensor = 1; +constexpr int kEndTensor = 2; +constexpr int kStridesTensor = 3; +constexpr int kOutputTensor = 0; + +struct StridedSliceContext { + StridedSliceContext(TfLiteContext* context, TfLiteNode* node) { + params = reinterpret_cast(node->builtin_data); + input = GetInput(context, node, kInputTensor); + begin = GetInput(context, node, kBeginTensor); + end = GetInput(context, node, kEndTensor); + strides = GetInput(context, node, kStridesTensor); + output = GetOutput(context, node, kOutputTensor); + dims = NumDimensions(input); + } + TfLiteStridedSliceParams* params; + TfLiteTensor* input; + TfLiteTensor* begin; + TfLiteTensor* end; + TfLiteTensor* strides; + TfLiteTensor* output; + int dims; +}; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 4); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + StridedSliceContext op_context(context, node); + + // Ensure validity of input tensor and its dimension + TF_LITE_ENSURE_EQ(context, NumDimensions(op_context.begin), 1); + TF_LITE_ENSURE_EQ(context, NumDimensions(op_context.end), 1); + TF_LITE_ENSURE_EQ(context, NumDimensions(op_context.strides), 1); + TF_LITE_ENSURE_EQ(context, op_context.input->type, op_context.output->type); + // Only INT32 begin/end/strides are supported + // TODO(soroosh) add support for INT64 + TF_LITE_ENSURE_EQ(context, op_context.begin->type, kTfLiteInt32); + TF_LITE_ENSURE_EQ(context, op_context.end->type, kTfLiteInt32); + TF_LITE_ENSURE_EQ(context, op_context.strides->type, kTfLiteInt32); + TF_LITE_ENSURE_MSG(context, op_context.dims <= 4, + "StridedSlice op only supports 1D-4D input arrays."); + + // TODO(soroosh): add the following missing functionalities + TF_LITE_ENSURE_MSG(context, op_context.params->ellipsis_mask == 0, + "ellipsis_mask is not implemented yet."); + TF_LITE_ENSURE_MSG(context, op_context.params->new_axis_mask == 0, + "new_axis_mask is not implemented yet."); + TF_LITE_ENSURE_MSG(context, op_context.params->shrink_axis_mask == 0, + "shrink_axis_mask is not implemented yet."); + + // TODO(soroosh): optimize for constant tensors to do allocation in Prepare + op_context.output->allocation_type = kTfLiteDynamic; + return kTfLiteOk; +} // namespace strided_slice + +// TODO(soroosh): consolidate with BytesRequired in interpreter.h +TfLiteStatus BytesRequired(TfLiteContext* context, TfLiteType type, + const int* dims, int dims_size, size_t* bytes) { + // TODO(aselle): Check for overflow here using overflow.h in TensorFlow + // MultiplyWithoutOverflow. + TF_LITE_ENSURE(context, bytes != nullptr); + size_t count = 1; + for (int k = 0; k < dims_size; k++) count *= dims[k]; + switch (type) { + case kTfLiteFloat32: + *bytes = sizeof(float) * count; + break; + case kTfLiteInt32: + *bytes = sizeof(int32_t) * count; + break; + case kTfLiteUInt8: + *bytes = sizeof(uint8_t) * count; + break; + case kTfLiteInt64: + *bytes = sizeof(int64_t) * count; + break; + default: + return kTfLiteError; + } + return kTfLiteOk; +} + +// Reverse order of bits in the mask to match the expected order in kernel +inline int ReverseMaskBits(int mask, int num_dimensions) { + int out = 0; + for (int dim = 0; dim < num_dimensions; dim++) { + out <<= 1; + out += (mask & 1); + mask >>= 1; + } + return out; +} + +// This Op only supports 1-4D cases and since we use the reference 4D +// implementation, the 1-3D tensors are mapped to 4D. +const int kMaxDim = 4; + +inline int32_t PositiveRemainder(int32_t dividend, int32_t divisor) { + return (divisor + (dividend % divisor)) % divisor; +} + +inline int32_t ClampedIndex(int32_t index, int dim, bool pos_stride) { + return pos_stride + ? (index >= dim ? dim + : PositiveRemainder( + std::min(std::max(index, -dim), dim), dim)) + : (index < -dim + ? -1 + : PositiveRemainder( + std::min(std::max(index, -dim), dim - 1), dim)); +} + +template +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + StridedSliceContext op_context(context, node); + + std::vector starts; + std::vector stops; + std::vector strides; + + // Determine size of output tensor and map indices + TfLiteIntArray* output_shape = TfLiteIntArrayCreate(op_context.dims); + for (int idx = op_context.dims - 1; idx >= 0; --idx) { + int dim = op_context.input->dims->data[idx]; + int32_t stride = GetTensorData(op_context.strides)[idx]; + TF_LITE_ENSURE_MSG(context, stride != 0, "stride value has to be non-zero"); + bool pos_stride = stride > 0; + + int32_t begin = + op_context.params->begin_mask & (1 << idx) + ? pos_stride ? 0 : dim - 1 + : ClampedIndex(GetTensorData(op_context.begin)[idx], dim, + pos_stride); + int32_t end = + op_context.params->end_mask & (1 << idx) + ? pos_stride ? dim : -1 + : ClampedIndex(GetTensorData(op_context.end)[idx], dim, + pos_stride); + + // This is valid for both positive and negative strides + output_shape->data[idx] = ceil((end - begin) / static_cast(stride)); + output_shape->data[idx] = + output_shape->data[idx] < 0 ? 0 : output_shape->data[idx]; + starts.emplace_back(begin); + stops.emplace_back(end); + strides.emplace_back(stride); + } + + for (int i = op_context.dims; i < kMaxDim; i++) { + starts.emplace_back(0); + stops.emplace_back(1); + strides.emplace_back(1); + } + + TF_LITE_ENSURE_STATUS( + context->ResizeTensor(context, op_context.output, output_shape)); + + size_t required_bytes; + TF_LITE_ENSURE_OK( + context, + BytesRequired(context, op_context.output->type, output_shape->data, + output_shape->size, &required_bytes)); + TfLiteTensorRealloc(required_bytes, op_context.output); + + op_context.params->begin_mask = + ReverseMaskBits(op_context.params->begin_mask, op_context.dims); + op_context.params->end_mask = + ReverseMaskBits(op_context.params->end_mask, op_context.dims); + +#define TF_LITE_STRIDED_SLICE(kernel_type, data_type) \ + kernel_type::StridedSlice( \ + GetTensorData(op_context.input), \ + GetTensorDims(op_context.input), op_context.params->begin_mask, \ + op_context.params->end_mask, starts, stops, strides, \ + GetTensorData(op_context.output), \ + GetTensorDims(op_context.output)) + + switch (op_context.input->type) { + case kTfLiteFloat32: + if (kernel_type == kReference) { + TF_LITE_STRIDED_SLICE(reference_ops, float); + } + break; + case kTfLiteInt32: + if (kernel_type == kReference) { + TF_LITE_STRIDED_SLICE(reference_ops, int32_t); + } + break; + case kTfLiteInt64: + if (kernel_type == kReference) { + TF_LITE_STRIDED_SLICE(reference_ops, int64_t); + } + break; + default: + context->ReportError(context, + "Type is currently not supported " + "by StridedSlice."); + return kTfLiteError; + } +#undef TF_LITE_STRIDED_SLICE + return kTfLiteOk; +} + +} // namespace strided_slice + +TfLiteRegistration* Register_STRIDED_SLICE_REF() { + static TfLiteRegistration r = { + nullptr, nullptr, strided_slice::Prepare, + strided_slice::Eval}; + return &r; +} + +// TODO(soroosh): add optimized +TfLiteRegistration* Register_STRIDED_SLICE() { + return Register_STRIDED_SLICE_REF(); +} + +} // namespace builtin +} // namespace ops +} // namespace tflite diff --git a/tensorflow/contrib/lite/kernels/strided_slice_test.cc b/tensorflow/contrib/lite/kernels/strided_slice_test.cc new file mode 100644 index 0000000000..cd4a364682 --- /dev/null +++ b/tensorflow/contrib/lite/kernels/strided_slice_test.cc @@ -0,0 +1,375 @@ +/* Copyright 2018 The TensorFlow Authors. 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 +#include "tensorflow/contrib/lite/interpreter.h" +#include "tensorflow/contrib/lite/kernels/register.h" +#include "tensorflow/contrib/lite/kernels/test_util.h" +#include "tensorflow/contrib/lite/model.h" + +namespace tflite { +namespace { + +using ::testing::ElementsAreArray; + +class StridedSliceOpModel : public SingleOpModel { + public: + StridedSliceOpModel(std::initializer_list input_shape, + std::initializer_list begin_shape, + std::initializer_list end_shape, + std::initializer_list strides_shape, int begin_mask, + int end_mask, int ellipsis_mask, int new_axis_mask, + int shrink_axis_mask) { + input_ = AddInput(TensorType_FLOAT32); + begin_ = AddInput(TensorType_INT32); + end_ = AddInput(TensorType_INT32); + strides_ = AddInput(TensorType_INT32); + output_ = AddOutput(TensorType_FLOAT32); + SetBuiltinOp( + BuiltinOperator_STRIDED_SLICE, BuiltinOptions_StridedSliceOptions, + CreateStridedSliceOptions(builder_, begin_mask, end_mask, ellipsis_mask, + new_axis_mask, shrink_axis_mask) + .Union()); + BuildInterpreter({input_shape, begin_shape, end_shape, strides_shape}); + } + + void SetInput(std::initializer_list data) { + PopulateTensor(input_, data); + } + void SetBegin(std::initializer_list data) { + PopulateTensor(begin_, data); + } + void SetEnd(std::initializer_list data) { + PopulateTensor(end_, data); + } + void SetStrides(std::initializer_list data) { + PopulateTensor(strides_, data); + } + + std::vector GetOutput() { return ExtractVector(output_); } + std::vector GetOutputShape() { return GetTensorShape(output_); } + + private: + int input_; + int begin_; + int end_; + int strides_; + int output_; +}; + +TEST(StridedSliceOpTest, UnsupportedInputSize) { + EXPECT_DEATH( + StridedSliceOpModel({2, 2, 2, 2, 2}, {5}, {5}, {5}, 0, 0, 0, 0, 0), + "StridedSlice op only supports 1D-4D input arrays."); +} + +TEST(StridedSliceOpTest, UnssupportedArgs) { + EXPECT_DEATH(StridedSliceOpModel({3, 2}, {2}, {2}, {2}, 0, 0, 1, 0, 0), + "ellipsis_mask is not implemented yet."); + EXPECT_DEATH(StridedSliceOpModel({3, 2}, {2}, {2}, {2}, 0, 0, 0, 1, 0), + "new_axis_mask is not implemented yet."); + EXPECT_DEATH(StridedSliceOpModel({3, 2}, {2}, {2}, {2}, 0, 0, 0, 0, 1), + "shrink_axis_mask is not implemented yet."); +} + +TEST(StridedSliceOpTest, In1D) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({1}); + m.SetEnd({3}); + m.SetStrides({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({2, 3})); +} + +TEST(StridedSliceOpTest, In1D_EmptyOutput) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({10}); + m.SetEnd({3}); + m.SetStrides({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({0})); +} + +TEST(StridedSliceOpTest, In1D_NegativeBegin) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({-3}); + m.SetEnd({3}); + m.SetStrides({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({2, 3})); +} + +TEST(StridedSliceOpTest, In1D_OutOfRangeBegin) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({-5}); + m.SetEnd({3}); + m.SetStrides({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 2, 3})); +} + +TEST(StridedSliceOpTest, In1D_NegativeEnd) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({1}); + m.SetEnd({-2}); + m.SetStrides({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({2})); +} + +TEST(StridedSliceOpTest, In1D_OutOfRangeEnd) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({-3}); + m.SetEnd({5}); + m.SetStrides({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({2, 3, 4})); +} + +TEST(StridedSliceOpTest, In1D_BeginMask) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 1, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({1}); + m.SetEnd({3}); + m.SetStrides({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 2, 3})); +} + +TEST(StridedSliceOpTest, In1D_NegativeBeginNegativeStride) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({-2}); + m.SetEnd({-3}); + m.SetStrides({-1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({3})); +} + +TEST(StridedSliceOpTest, In1D_OutOfRangeBeginNegativeStride) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({5}); + m.SetEnd({2}); + m.SetStrides({-1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({4})); +} + +TEST(StridedSliceOpTest, In1D_NegativeEndNegativeStride) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({2}); + m.SetEnd({-4}); + m.SetStrides({-1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({3, 2})); +} + +TEST(StridedSliceOpTest, In1D_OutOfRangeEndNegativeStride) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({-3}); + m.SetEnd({-5}); + m.SetStrides({-1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({2, 1})); +} + +TEST(StridedSliceOpTest, In1D_EndMask) { + StridedSliceOpModel m({4}, {1}, {1}, {1}, 0, 1, 0, 0, 0); + m.SetInput({1, 2, 3, 4}); + m.SetBegin({1}); + m.SetEnd({3}); + m.SetStrides({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({2, 3, 4})); +} +TEST(StridedSliceOpTest, In1D_NegStride) { + StridedSliceOpModel m({3}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3}); + m.SetBegin({-1}); + m.SetEnd({-4}); + m.SetStrides({-1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({3, 2, 1})); +} + +TEST(StridedSliceOpTest, In1D_EvenLenStride2) { + StridedSliceOpModel m({2}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2}); + m.SetBegin({0}); + m.SetEnd({2}); + m.SetStrides({2}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({1})); +} +TEST(StridedSliceOpTest, In1D_OddLenStride2) { + StridedSliceOpModel m({3}, {1}, {1}, {1}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3}); + m.SetBegin({0}); + m.SetEnd({3}); + m.SetStrides({2}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 3})); +} + +TEST(StridedSliceOpTest, In2D_Identity) { + StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetBegin({0, 0}); + m.SetEnd({2, 3}); + m.SetStrides({1, 1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 2, 3, 4, 5, 6})); +} +TEST(StridedSliceOpTest, In2D) { + StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetBegin({1, 0}); + m.SetEnd({2, 2}); + m.SetStrides({1, 1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({4, 5})); +} + +TEST(StridedSliceOpTest, In2D_Stride2) { + StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetBegin({0, 0}); + m.SetEnd({2, 3}); + m.SetStrides({2, 2}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 3})); +} + +TEST(StridedSliceOpTest, In2D_NegStride) { + StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetBegin({1, -1}); + m.SetEnd({2, -4}); + m.SetStrides({2, -1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({6, 5, 4})); +} + +TEST(StridedSliceOpTest, In2D_BeginMask) { + StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, 1, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetBegin({1, 0}); + m.SetEnd({2, 2}); + m.SetStrides({1, 1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 2, 4, 5})); +} + +TEST(StridedSliceOpTest, In2D_EndMask) { + StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, 0, 2, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetBegin({1, 0}); + m.SetEnd({2, 2}); + m.SetStrides({1, 1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({4, 5, 6})); +} + +TEST(StridedSliceOpTest, In2D_NegStrideBeginMask) { + StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, 2, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetBegin({1, -2}); + m.SetEnd({2, -4}); + m.SetStrides({1, -1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({6, 5, 4})); +} +TEST(StridedSliceOpTest, In2D_NegStrideEndMask) { + StridedSliceOpModel m({2, 3}, {2}, {2}, {2}, 0, 2, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetBegin({1, -2}); + m.SetEnd({2, -3}); + m.SetStrides({1, -1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 4})); +} + +TEST(StridedSliceOpTest, In3D_Identity) { + StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + m.SetBegin({0, 0, 0}); + m.SetEnd({2, 3, 2}); + m.SetStrides({1, 1, 1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3, 2})); + EXPECT_THAT(m.GetOutput(), + ElementsAreArray({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})); +} + +TEST(StridedSliceOpTest, In3D_NegStride) { + StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + m.SetBegin({-1, -1, -1}); + m.SetEnd({-3, -4, -3}); + m.SetStrides({-1, -1, -1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3, 2})); + EXPECT_THAT(m.GetOutput(), + ElementsAreArray({12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})); +} +TEST(StridedSliceOpTest, In3D_Strided2) { + StridedSliceOpModel m({2, 3, 2}, {3}, {3}, {3}, 0, 0, 0, 0, 0); + m.SetInput({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + m.SetBegin({0, 0, 0}); + m.SetEnd({2, 3, 2}); + m.SetStrides({2, 2, 2}); + m.Invoke(); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 1})); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({1, 5})); +} + +} // namespace +} // namespace tflite + +int main(int argc, char** argv) { + ::tflite::LogToStderr(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tensorflow/contrib/lite/model.cc b/tensorflow/contrib/lite/model.cc index 4d8a6d10c8..a01b74f9da 100644 --- a/tensorflow/contrib/lite/model.cc +++ b/tensorflow/contrib/lite/model.cc @@ -618,6 +618,18 @@ void* ParseOpData(const Operator* op, BuiltinOperator op_type, builtin_data = reinterpret_cast(params); break; } + case BuiltinOperator_STRIDED_SLICE: { + auto* params = MallocPOD(); + if (auto* schema_params = op->builtin_options_as_StridedSliceOptions()) { + params->begin_mask = schema_params->begin_mask(); + params->end_mask = schema_params->end_mask(); + params->ellipsis_mask = schema_params->ellipsis_mask(); + params->new_axis_mask = schema_params->new_axis_mask(); + params->shrink_axis_mask = schema_params->shrink_axis_mask(); + } + builtin_data = reinterpret_cast(params); + break; + } } return builtin_data; } diff --git a/tensorflow/contrib/lite/nnapi_delegate.cc b/tensorflow/contrib/lite/nnapi_delegate.cc index 998a7b7614..d5b9319407 100644 --- a/tensorflow/contrib/lite/nnapi_delegate.cc +++ b/tensorflow/contrib/lite/nnapi_delegate.cc @@ -339,6 +339,7 @@ void AddOpsAndParams(tflite::Interpreter* interpreter, case tflite::BuiltinOperator_DIV: case tflite::BuiltinOperator_SUB: case tflite::BuiltinOperator_SQUEEZE: + case tflite::BuiltinOperator_STRIDED_SLICE: FATAL("Op code %d is currently not delegated to NNAPI", builtin); nn_op_type = -1; // set to invalid break; diff --git a/tensorflow/contrib/lite/schema/schema.fbs b/tensorflow/contrib/lite/schema/schema.fbs index 6fcd3e51a4..8ddad4d251 100644 --- a/tensorflow/contrib/lite/schema/schema.fbs +++ b/tensorflow/contrib/lite/schema/schema.fbs @@ -118,6 +118,7 @@ enum BuiltinOperator : byte { DIV = 42, SQUEEZE = 43, UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + STRIDED_SLICE = 45, } // Options for the builtin operators. @@ -153,6 +154,7 @@ union BuiltinOptions { DivOptions, SqueezeOptions, SequenceRNNOptions, + StridedSliceOptions, } enum Padding : byte { SAME, VALID } @@ -340,6 +342,14 @@ table SqueezeOptions { squeeze_dims:[int]; } +table StridedSliceOptions { + begin_mask: int; + end_mask: int; + ellipsis_mask: int; + new_axis_mask: int; + shrink_axis_mask: int; +} + // An OperatorCode can be an enum value (BuiltinOperator) if the operator is a // builtin, or a string if the operator is custom. table OperatorCode { diff --git a/tensorflow/contrib/lite/schema/schema_generated.h b/tensorflow/contrib/lite/schema/schema_generated.h old mode 100755 new mode 100644 index 6eb9ae2926..b756891f66 --- a/tensorflow/contrib/lite/schema/schema_generated.h +++ b/tensorflow/contrib/lite/schema/schema_generated.h @@ -120,6 +120,9 @@ struct MeanOptionsT; struct SqueezeOptions; struct SqueezeOptionsT; +struct StridedSliceOptions; +struct StridedSliceOptionsT; + struct OperatorCode; struct OperatorCodeT; @@ -207,11 +210,12 @@ enum BuiltinOperator { BuiltinOperator_DIV = 42, BuiltinOperator_SQUEEZE = 43, BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + BuiltinOperator_STRIDED_SLICE = 45, BuiltinOperator_MIN = BuiltinOperator_ADD, - BuiltinOperator_MAX = BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM + BuiltinOperator_MAX = BuiltinOperator_STRIDED_SLICE }; -inline BuiltinOperator (&EnumValuesBuiltinOperator())[42] { +inline BuiltinOperator (&EnumValuesBuiltinOperator())[43] { static BuiltinOperator values[] = { BuiltinOperator_ADD, BuiltinOperator_AVERAGE_POOL_2D, @@ -254,7 +258,8 @@ inline BuiltinOperator (&EnumValuesBuiltinOperator())[42] { BuiltinOperator_SUB, BuiltinOperator_DIV, BuiltinOperator_SQUEEZE, - BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM}; + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, + BuiltinOperator_STRIDED_SLICE}; return values; } @@ -304,6 +309,7 @@ inline const char **EnumNamesBuiltinOperator() { "DIV", "SQUEEZE", "UNIDIRECTIONAL_SEQUENCE_LSTM", + "STRIDED_SLICE", nullptr}; return names; } @@ -346,11 +352,12 @@ enum BuiltinOptions { BuiltinOptions_DivOptions = 29, BuiltinOptions_SqueezeOptions = 30, BuiltinOptions_SequenceRNNOptions = 31, + BuiltinOptions_StridedSliceOptions = 32, BuiltinOptions_MIN = BuiltinOptions_NONE, - BuiltinOptions_MAX = BuiltinOptions_SequenceRNNOptions + BuiltinOptions_MAX = BuiltinOptions_StridedSliceOptions }; -inline BuiltinOptions (&EnumValuesBuiltinOptions())[32] { +inline BuiltinOptions (&EnumValuesBuiltinOptions())[33] { static BuiltinOptions values[] = { BuiltinOptions_NONE, BuiltinOptions_Conv2DOptions, @@ -383,7 +390,8 @@ inline BuiltinOptions (&EnumValuesBuiltinOptions())[32] { BuiltinOptions_SubOptions, BuiltinOptions_DivOptions, BuiltinOptions_SqueezeOptions, - BuiltinOptions_SequenceRNNOptions}; + BuiltinOptions_SequenceRNNOptions, + BuiltinOptions_StridedSliceOptions}; return values; } @@ -420,6 +428,7 @@ inline const char **EnumNamesBuiltinOptions() { "DivOptions", "SqueezeOptions", "SequenceRNNOptions", + "StridedSliceOptions", nullptr}; return names; } @@ -593,6 +602,11 @@ struct BuiltinOptionsTraits { static const BuiltinOptions enum_value = BuiltinOptions_SequenceRNNOptions; }; +template <> +struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_StridedSliceOptions; +}; + struct BuiltinOptionsUnion { BuiltinOptions type; void *value; @@ -950,6 +964,16 @@ struct BuiltinOptionsUnion { ? reinterpret_cast(value) : nullptr; } + StridedSliceOptionsT *AsStridedSliceOptions() { + return type == BuiltinOptions_StridedSliceOptions + ? reinterpret_cast(value) + : nullptr; + } + const StridedSliceOptionsT *AsStridedSliceOptions() const { + return type == BuiltinOptions_StridedSliceOptions + ? reinterpret_cast(value) + : nullptr; + } }; bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, @@ -3532,6 +3556,111 @@ flatbuffers::Offset CreateSqueezeOptions( flatbuffers::FlatBufferBuilder &_fbb, const SqueezeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +struct StridedSliceOptionsT : public flatbuffers::NativeTable { + typedef StridedSliceOptions TableType; + int32_t begin_mask; + int32_t end_mask; + int32_t ellipsis_mask; + int32_t new_axis_mask; + int32_t shrink_axis_mask; + StridedSliceOptionsT() + : begin_mask(0), + end_mask(0), + ellipsis_mask(0), + new_axis_mask(0), + shrink_axis_mask(0) {} +}; + +struct StridedSliceOptions FLATBUFFERS_FINAL_CLASS + : private flatbuffers::Table { + typedef StridedSliceOptionsT NativeTableType; + enum { + VT_BEGIN_MASK = 4, + VT_END_MASK = 6, + VT_ELLIPSIS_MASK = 8, + VT_NEW_AXIS_MASK = 10, + VT_SHRINK_AXIS_MASK = 12 + }; + int32_t begin_mask() const { return GetField(VT_BEGIN_MASK, 0); } + int32_t end_mask() const { return GetField(VT_END_MASK, 0); } + int32_t ellipsis_mask() const { + return GetField(VT_ELLIPSIS_MASK, 0); + } + int32_t new_axis_mask() const { + return GetField(VT_NEW_AXIS_MASK, 0); + } + int32_t shrink_axis_mask() const { + return GetField(VT_SHRINK_AXIS_MASK, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_BEGIN_MASK) && + VerifyField(verifier, VT_END_MASK) && + VerifyField(verifier, VT_ELLIPSIS_MASK) && + VerifyField(verifier, VT_NEW_AXIS_MASK) && + VerifyField(verifier, VT_SHRINK_AXIS_MASK) && + verifier.EndTable(); + } + StridedSliceOptionsT *UnPack( + const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo( + StridedSliceOptionsT *_o, + const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack( + flatbuffers::FlatBufferBuilder &_fbb, const StridedSliceOptionsT *_o, + const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct StridedSliceOptionsBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_begin_mask(int32_t begin_mask) { + fbb_.AddElement(StridedSliceOptions::VT_BEGIN_MASK, begin_mask, 0); + } + void add_end_mask(int32_t end_mask) { + fbb_.AddElement(StridedSliceOptions::VT_END_MASK, end_mask, 0); + } + void add_ellipsis_mask(int32_t ellipsis_mask) { + fbb_.AddElement(StridedSliceOptions::VT_ELLIPSIS_MASK, + ellipsis_mask, 0); + } + void add_new_axis_mask(int32_t new_axis_mask) { + fbb_.AddElement(StridedSliceOptions::VT_NEW_AXIS_MASK, + new_axis_mask, 0); + } + void add_shrink_axis_mask(int32_t shrink_axis_mask) { + fbb_.AddElement(StridedSliceOptions::VT_SHRINK_AXIS_MASK, + shrink_axis_mask, 0); + } + explicit StridedSliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + StridedSliceOptionsBuilder &operator=(const StridedSliceOptionsBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateStridedSliceOptions( + flatbuffers::FlatBufferBuilder &_fbb, int32_t begin_mask = 0, + int32_t end_mask = 0, int32_t ellipsis_mask = 0, int32_t new_axis_mask = 0, + int32_t shrink_axis_mask = 0) { + StridedSliceOptionsBuilder builder_(_fbb); + builder_.add_shrink_axis_mask(shrink_axis_mask); + builder_.add_new_axis_mask(new_axis_mask); + builder_.add_ellipsis_mask(ellipsis_mask); + builder_.add_end_mask(end_mask); + builder_.add_begin_mask(begin_mask); + return builder_.Finish(); +} + +flatbuffers::Offset CreateStridedSliceOptions( + flatbuffers::FlatBufferBuilder &_fbb, const StridedSliceOptionsT *_o, + const flatbuffers::rehasher_function_t *_rehasher = nullptr); + struct OperatorCodeT : public flatbuffers::NativeTable { typedef OperatorCode TableType; BuiltinOperator builtin_code; @@ -3816,6 +3945,11 @@ struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { ? static_cast(builtin_options()) : nullptr; } + const StridedSliceOptions *builtin_options_as_StridedSliceOptions() const { + return builtin_options_type() == BuiltinOptions_StridedSliceOptions + ? static_cast(builtin_options()) + : nullptr; + } const flatbuffers::Vector *custom_options() const { return GetPointer *>(VT_CUSTOM_OPTIONS); } @@ -4023,6 +4157,12 @@ Operator::builtin_options_as() const { return builtin_options_as_SequenceRNNOptions(); } +template <> +inline const StridedSliceOptions * +Operator::builtin_options_as() const { + return builtin_options_as_StridedSliceOptions(); +} + struct OperatorBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; @@ -4962,11 +5102,11 @@ inline void SequenceRNNOptions::UnPackTo( { auto _e = time_major(); _o->time_major = _e; - } + }; { auto _e = fused_activation_function(); _o->fused_activation_function = _e; - } + }; } inline flatbuffers::Offset SequenceRNNOptions::Pack( @@ -6040,6 +6180,67 @@ inline flatbuffers::Offset CreateSqueezeOptions( return tflite::CreateSqueezeOptions(_fbb, _squeeze_dims); } +inline StridedSliceOptionsT *StridedSliceOptions::UnPack( + const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new StridedSliceOptionsT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void StridedSliceOptions::UnPackTo( + StridedSliceOptionsT *_o, + const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { + auto _e = begin_mask(); + _o->begin_mask = _e; + }; + { + auto _e = end_mask(); + _o->end_mask = _e; + }; + { + auto _e = ellipsis_mask(); + _o->ellipsis_mask = _e; + }; + { + auto _e = new_axis_mask(); + _o->new_axis_mask = _e; + }; + { + auto _e = shrink_axis_mask(); + _o->shrink_axis_mask = _e; + }; +} + +inline flatbuffers::Offset StridedSliceOptions::Pack( + flatbuffers::FlatBufferBuilder &_fbb, const StridedSliceOptionsT *_o, + const flatbuffers::rehasher_function_t *_rehasher) { + return CreateStridedSliceOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateStridedSliceOptions( + flatbuffers::FlatBufferBuilder &_fbb, const StridedSliceOptionsT *_o, + const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { + flatbuffers::FlatBufferBuilder *__fbb; + const StridedSliceOptionsT *__o; + const flatbuffers::rehasher_function_t *__rehasher; + } _va = {&_fbb, _o, _rehasher}; + (void)_va; + auto _begin_mask = _o->begin_mask; + auto _end_mask = _o->end_mask; + auto _ellipsis_mask = _o->ellipsis_mask; + auto _new_axis_mask = _o->new_axis_mask; + auto _shrink_axis_mask = _o->shrink_axis_mask; + return tflite::CreateStridedSliceOptions(_fbb, _begin_mask, _end_mask, + _ellipsis_mask, _new_axis_mask, + _shrink_axis_mask); +} + inline OperatorCodeT *OperatorCode::UnPack( const flatbuffers::resolver_function_t *_resolver) const { auto _o = new OperatorCodeT(); @@ -6552,6 +6753,10 @@ inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, auto ptr = reinterpret_cast(obj); return verifier.VerifyTable(ptr); } + case BuiltinOptions_StridedSliceOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } default: return false; } @@ -6700,6 +6905,10 @@ inline void *BuiltinOptionsUnion::UnPack( auto ptr = reinterpret_cast(obj); return ptr->UnPack(resolver); } + case BuiltinOptions_StridedSliceOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } default: return nullptr; } @@ -6835,6 +7044,10 @@ inline flatbuffers::Offset BuiltinOptionsUnion::Pack( auto ptr = reinterpret_cast(value); return CreateSequenceRNNOptions(_fbb, ptr, _rehasher).Union(); } + case BuiltinOptions_StridedSliceOptions: { + auto ptr = reinterpret_cast(value); + return CreateStridedSliceOptions(_fbb, ptr, _rehasher).Union(); + } default: return 0; } @@ -6985,6 +7198,11 @@ inline BuiltinOptionsUnion::BuiltinOptionsUnion(const BuiltinOptionsUnion &u) *reinterpret_cast(u.value)); break; } + case BuiltinOptions_StridedSliceOptions: { + value = new StridedSliceOptionsT( + *reinterpret_cast(u.value)); + break; + } default: break; } @@ -7147,6 +7365,11 @@ inline void BuiltinOptionsUnion::Reset() { delete ptr; break; } + case BuiltinOptions_StridedSliceOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } default: break; } diff --git a/tensorflow/contrib/lite/testing/BUILD b/tensorflow/contrib/lite/testing/BUILD index 933da11353..50e8ca75f8 100644 --- a/tensorflow/contrib/lite/testing/BUILD +++ b/tensorflow/contrib/lite/testing/BUILD @@ -46,6 +46,7 @@ gen_zipped_test_files( "space_to_batch_nd.zip", "space_to_depth.zip", "squeeze.zip", + "strided_slice.zip", "sub.zip", "transpose.zip", ], diff --git a/tensorflow/contrib/lite/testing/generate_examples.py b/tensorflow/contrib/lite/testing/generate_examples.py index 56e4dfc7a2..6204471e52 100644 --- a/tensorflow/contrib/lite/testing/generate_examples.py +++ b/tensorflow/contrib/lite/testing/generate_examples.py @@ -1447,6 +1447,97 @@ def make_squeeze_tests(zip_path): make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) +def make_strided_slice_tests(zip_path): + """Make a set of tests to do strided_slice.""" + + # TODO(soroosh): add test/support for uint8. + test_parameters = [ + # 4-D + { + "dtype": [tf.float32, tf.int32, tf.int64], + "index_type": [tf.int32], + "input_shape": [[12, 2, 2, 5]], + "begin": [[0, 0, 0, 0], [1, 0, 1, 0]], + "end": [[8, 2, 2, 3], [12, 2, 2, 5]], + "strides": [None, [1, 1, 1, 1], [2, 1, 3, 1]], + "begin_mask": [None, 0, 1, 2, 8], + "end_mask": [None, 0, 1, 2, 8], + }, + # 2-D + { + "dtype": [tf.float32, tf.int32, tf.int64], + "index_type": [tf.int32], + "input_shape": [[2, 3]], + "begin": [[0, 0], [1, 0]], + "end": [[2, 3], [2, 2]], + "strides": [None, [1, 1], [2, 2]], + "begin_mask": [None, 0, 1, 2], + "end_mask": [None, 0, 1, 2], + }, + # Negative strides + { + "dtype": [tf.float32, tf.int32, tf.int64], + "index_type": [tf.int32], + "input_shape": [[2, 3]], + "begin": [[0, -1]], + "end": [[2, -3]], + "strides": [[1, -1]], + "begin_mask": [None, 0, 1, 2], + "end_mask": [None, 0, 1, 2], + }, + ] + + def build_graph(parameters): + """Build graph for stride_slice test.""" + input_tensor = tf.placeholder( + dtype=parameters["dtype"], + name="input", + shape=parameters["input_shape"]) + begin = tf.placeholder( + dtype=parameters["index_type"], + name="begin", + shape=[len(parameters["input_shape"])]) + end = tf.placeholder( + dtype=parameters["index_type"], + name="end", + shape=[len(parameters["input_shape"])]) + strides = ( + tf.placeholder( + dtype=parameters["index_type"], + name="strides", + shape=[len(parameters["input_shape"])]) + if parameters["strides"] is not None else None) + tensors = [input_tensor, begin, end] + if strides is not None: + tensors.append(strides) + out = tf.strided_slice( + input_tensor, + begin, + end, + strides, + begin_mask=parameters["begin_mask"], + end_mask=parameters["end_mask"]) + return tensors, [out] + + def build_inputs(parameters, sess, inputs, outputs): + """Build inputs for stride_slice test.""" + input_values = create_tensor_data(parameters["dtype"], + parameters["input_shape"]) + index_type = _TF_TYPE_INFO[parameters["index_type"]][0] + begin_values = np.array(parameters["begin"]).astype(index_type) + end_values = np.array(parameters["end"]).astype(index_type) + stride_values = ( + np.array(parameters["strides"]).astype(index_type) + if parameters["strides"] is not None else None) + values = [input_values, begin_values, end_values] + if stride_values is not None: + values.append(stride_values) + + return values, sess.run(outputs, feed_dict=dict(zip(inputs, values))) + + make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) + + def make_l2_pool(input_tensor, ksize, strides, padding, data_format): """Given an input perform a sequence of TensorFlow ops to produce l2pool.""" return tf.sqrt(tf.nn.avg_pool( @@ -1505,6 +1596,7 @@ def main(unused_args): "transpose.zip": make_transpose_tests, "mean.zip": make_mean_tests, "squeeze.zip": make_squeeze_tests, + "strided_slice.zip": make_strided_slice_tests, } out = FLAGS.zip_to_output bin_path = FLAGS.toco diff --git a/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc b/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc index c8a6e07abd..c29cd85c4d 100644 --- a/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc +++ b/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc @@ -263,6 +263,7 @@ INSTANTIATE_TESTS(div) INSTANTIATE_TESTS(transpose) INSTANTIATE_TESTS(mean) INSTANTIATE_TESTS(squeeze) +INSTANTIATE_TESTS(strided_slice) } // namespace testing } // namespace tflite diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_strided_slice_attributes.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_strided_slice_attributes.cc index de4d06be2a..7e8b249b07 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_strided_slice_attributes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_strided_slice_attributes.cc @@ -33,6 +33,10 @@ bool ResolveStridedSliceAttributes::Run(Model* model, std::size_t op_index) { CHECK_EQ(op->inputs.size(), 4); const auto& start_array = model->GetArray(op->inputs[1]); if (!start_array.has_shape()) return false; + if (toco::RequiredBufferSizeForShape(start_array.shape()) > 4) { + // Only 1-4D arrays are supported for now. + return false; + } const auto& stop_array = model->GetArray(op->inputs[2]); if (!stop_array.has_shape()) return false; diff --git a/tensorflow/contrib/lite/toco/import_tensorflow.cc b/tensorflow/contrib/lite/toco/import_tensorflow.cc index 1947271f55..e8f318cd43 100644 --- a/tensorflow/contrib/lite/toco/import_tensorflow.cc +++ b/tensorflow/contrib/lite/toco/import_tensorflow.cc @@ -1179,6 +1179,8 @@ void ConvertStridedSliceOperator(const NodeDef& node, const TensorFlowImportFlags& tf_import_flags, Model* model) { CHECK_EQ(node.op(), "StridedSlice"); + // TODO(soroosh): The 4th input (strides) should be e optional, to be + // consistent with TF. CheckInputsCount(node, tf_import_flags, 4); auto* op = new StridedSliceOperator; diff --git a/tensorflow/contrib/lite/toco/model.h b/tensorflow/contrib/lite/toco/model.h index 54fbba7381..3cda63a8ce 100644 --- a/tensorflow/contrib/lite/toco/model.h +++ b/tensorflow/contrib/lite/toco/model.h @@ -738,6 +738,9 @@ struct PadOperator : Operator { // // Inputs: // inputs[0]: required: the input array +// inputs[1]: required: the begin array +// inputs[2]: required: the end array +// inputs[3]: optional: the strides array // // TensorFlow equivalent: StridedSlice struct StridedSliceOperator : Operator { diff --git a/tensorflow/contrib/lite/toco/tflite/operator.cc b/tensorflow/contrib/lite/toco/tflite/operator.cc index 0111e1ed92..0c2b570aad 100644 --- a/tensorflow/contrib/lite/toco/tflite/operator.cc +++ b/tensorflow/contrib/lite/toco/tflite/operator.cc @@ -617,6 +617,30 @@ class Split : public CustomOperator { } }; +class StridedSlice + : public BuiltinOperator { + public: + using BuiltinOperator::BuiltinOperator; + flatbuffers::Offset WriteOptions( + const TocoOperator& op, + flatbuffers::FlatBufferBuilder* builder) const override { + return ::tflite::CreateStridedSliceOptions( + *builder, op.begin_mask, op.end_mask, op.ellipsis_mask, + op.new_axis_mask, op.shrink_axis_mask); + } + + void ReadOptions(const TfLiteOptions& options, + TocoOperator* op) const override { + op->begin_mask = options.begin_mask(); + op->end_mask = options.end_mask(); + op->ellipsis_mask = options.ellipsis_mask(); + op->new_axis_mask = options.new_axis_mask(); + op->shrink_axis_mask = options.shrink_axis_mask(); + } +}; + class TensorFlowUnsupported : public BaseOperator { public: using BaseOperator::BaseOperator; @@ -777,6 +801,8 @@ std::vector> BuildOperatorList() { new Mean(::tflite::BuiltinOperator_MEAN, OperatorType::kMean)); ops.emplace_back( new Squeeze(::tflite::BuiltinOperator_SQUEEZE, OperatorType::kSqueeze)); + ops.emplace_back(new StridedSlice(::tflite::BuiltinOperator_STRIDED_SLICE, + OperatorType::kStridedSlice)); // Custom Operators. ops.emplace_back(new Cast("CAST", OperatorType::kCast)); diff --git a/tensorflow/contrib/lite/toco/tflite/operator_test.cc b/tensorflow/contrib/lite/toco/tflite/operator_test.cc index 77c70847d1..de79c70e1b 100644 --- a/tensorflow/contrib/lite/toco/tflite/operator_test.cc +++ b/tensorflow/contrib/lite/toco/tflite/operator_test.cc @@ -398,6 +398,28 @@ TEST_F(OperatorTest, Squeeze) { EXPECT_EQ(op.squeeze_dims, output_toco_op->squeeze_dims); } +TEST_F(OperatorTest, StridedSlice) { + StridedSliceOperator op; + + op.begin_mask = 1; + op.end_mask = 2; + op.ellipsis_mask = 1; + op.new_axis_mask = 1; + op.shrink_axis_mask = 2; + + auto output_toco_op = SerializeAndDeserialize( + GetOperator("STRIDED_SLICE", OperatorType::kStridedSlice), op); + EXPECT_EQ(op.start_indices, output_toco_op->start_indices); + EXPECT_EQ(op.stop_indices, output_toco_op->stop_indices); + EXPECT_EQ(op.strides, output_toco_op->strides); + EXPECT_EQ(op.begin_mask, output_toco_op->begin_mask); + EXPECT_EQ(op.end_mask, output_toco_op->end_mask); + EXPECT_EQ(op.end_mask, output_toco_op->end_mask); + EXPECT_EQ(op.ellipsis_mask, output_toco_op->ellipsis_mask); + EXPECT_EQ(op.new_axis_mask, output_toco_op->new_axis_mask); + EXPECT_EQ(op.shrink_axis_mask, output_toco_op->shrink_axis_mask); +} + TEST_F(OperatorTest, TensorFlowUnsupported) { TensorFlowUnsupportedOperator op; op.tensorflow_op = "MyCustomUnsupportedOp"; -- GitLab From f073d5f56dd07b42d381a5a8ce6868b3ea6ac8f2 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 18:18:15 -0800 Subject: [PATCH 159/258] Update ops-related pbtxt files. PiperOrigin-RevId: 183024949 --- .../core/ops/compat/ops_history.v1.pbtxt | 468 ++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 54 ++ 2 files changed, 522 insertions(+) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index c2e2793760..47de3d398e 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -18822,6 +18822,57 @@ op { } is_stateful: true } +op { + name: "FixedLengthRecordReader" + output_arg { + name: "reader_handle" + type: DT_STRING + is_ref: true + } + attr { + name: "header_bytes" + type: "int" + default_value { + i: 0 + } + } + attr { + name: "record_bytes" + type: "int" + } + attr { + name: "footer_bytes" + type: "int" + default_value { + i: 0 + } + } + attr { + name: "hop_bytes" + type: "int" + default_value { + i: 0 + } + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + deprecation { + version: 26 + } + is_stateful: true +} op { name: "FixedLengthRecordReaderV2" output_arg { @@ -21384,6 +21435,32 @@ op { } is_stateful: true } +op { + name: "IdentityReader" + output_arg { + name: "reader_handle" + type: DT_STRING + is_ref: true + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + deprecation { + version: 26 + } + is_stateful: true +} op { name: "IdentityReaderV2" output_arg { @@ -38544,6 +38621,46 @@ op { } } } +op { + name: "ResizeBilinear" + input_arg { + name: "images" + type_attr: "T" + } + input_arg { + name: "size" + type: DT_INT32 + } + output_arg { + name: "resized_images" + type: DT_FLOAT + } + attr { + name: "T" + type: "type" + allowed_values { + list { + type: DT_INT8 + type: DT_UINT8 + type: DT_INT16 + type: DT_UINT16 + type: DT_INT32 + type: DT_INT64 + type: DT_BFLOAT16 + type: DT_HALF + type: DT_FLOAT + type: DT_DOUBLE + } + } + } + attr { + name: "align_corners" + type: "bool" + default_value { + b: false + } + } +} op { name: "ResizeBilinearGrad" input_arg { @@ -38577,6 +38694,40 @@ op { } } } +op { + name: "ResizeBilinearGrad" + input_arg { + name: "grads" + type: DT_FLOAT + } + input_arg { + name: "original_image" + type_attr: "T" + } + output_arg { + name: "output" + type_attr: "T" + } + attr { + name: "T" + type: "type" + allowed_values { + list { + type: DT_FLOAT + type: DT_BFLOAT16 + type: DT_HALF + type: DT_DOUBLE + } + } + } + attr { + name: "align_corners" + type: "bool" + default_value { + b: false + } + } +} op { name: "ResizeNearestNeighbor" input_arg { @@ -61858,6 +62009,39 @@ op { } is_stateful: true } +op { + name: "TFRecordReader" + output_arg { + name: "reader_handle" + type: DT_STRING + is_ref: true + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "compression_type" + type: "string" + default_value { + s: "" + } + } + deprecation { + version: 26 + } + is_stateful: true +} op { name: "TFRecordReaderV2" output_arg { @@ -62259,6 +62443,16 @@ op { type: DT_STRING } } +op { + name: "TensorArrayCloseV2" + input_arg { + name: "handle" + type: DT_STRING + } + deprecation { + version: 26 + } +} op { name: "TensorArrayCloseV3" input_arg { @@ -62436,6 +62630,41 @@ op { } } } +op { + name: "TensorArrayGatherV2" + input_arg { + name: "handle" + type: DT_STRING + } + input_arg { + name: "indices" + type: DT_INT32 + } + input_arg { + name: "flow_in" + type: DT_FLOAT + } + output_arg { + name: "value" + type_attr: "dtype" + } + attr { + name: "dtype" + type: "type" + } + attr { + name: "element_shape" + type: "shape" + default_value { + shape { + unknown_rank: true + } + } + } + deprecation { + version: 26 + } +} op { name: "TensorArrayGatherV3" input_arg { @@ -62513,6 +62742,29 @@ op { } is_stateful: true } +op { + name: "TensorArrayGradV2" + input_arg { + name: "handle" + type: DT_STRING + } + input_arg { + name: "flow_in" + type: DT_FLOAT + } + output_arg { + name: "grad_handle" + type: DT_STRING + } + attr { + name: "source" + type: "string" + } + deprecation { + version: 26 + } + is_stateful: true +} op { name: "TensorArrayGradV3" input_arg { @@ -62619,6 +62871,32 @@ op { type: "type" } } +op { + name: "TensorArrayReadV2" + input_arg { + name: "handle" + type: DT_STRING + } + input_arg { + name: "index" + type: DT_INT32 + } + input_arg { + name: "flow_in" + type: DT_FLOAT + } + output_arg { + name: "value" + type_attr: "dtype" + } + attr { + name: "dtype" + type: "type" + } + deprecation { + version: 26 + } +} op { name: "TensorArrayReadV3" input_arg { @@ -62701,6 +62979,36 @@ op { type: "type" } } +op { + name: "TensorArrayScatterV2" + input_arg { + name: "handle" + type: DT_STRING + } + input_arg { + name: "indices" + type: DT_INT32 + } + input_arg { + name: "value" + type_attr: "T" + } + input_arg { + name: "flow_in" + type: DT_FLOAT + } + output_arg { + name: "flow_out" + type: DT_FLOAT + } + attr { + name: "T" + type: "type" + } + deprecation { + version: 26 + } +} op { name: "TensorArrayScatterV3" input_arg { @@ -62763,6 +63071,24 @@ op { type: DT_INT32 } } +op { + name: "TensorArraySizeV2" + input_arg { + name: "handle" + type: DT_STRING + } + input_arg { + name: "flow_in" + type: DT_FLOAT + } + output_arg { + name: "size" + type: DT_INT32 + } + deprecation { + version: 26 + } +} op { name: "TensorArraySizeV3" input_arg { @@ -62837,6 +63163,36 @@ op { type: "type" } } +op { + name: "TensorArraySplitV2" + input_arg { + name: "handle" + type: DT_STRING + } + input_arg { + name: "value" + type_attr: "T" + } + input_arg { + name: "lengths" + type: DT_INT64 + } + input_arg { + name: "flow_in" + type: DT_FLOAT + } + output_arg { + name: "flow_out" + type: DT_FLOAT + } + attr { + name: "T" + type: "type" + } + deprecation { + version: 26 + } +} op { name: "TensorArraySplitV3" input_arg { @@ -62938,6 +63294,55 @@ op { } is_stateful: true } +op { + name: "TensorArrayV2" + input_arg { + name: "size" + type: DT_INT32 + } + output_arg { + name: "handle" + type: DT_STRING + } + attr { + name: "dtype" + type: "type" + } + attr { + name: "element_shape" + type: "shape" + default_value { + shape { + unknown_rank: true + } + } + } + attr { + name: "dynamic_size" + type: "bool" + default_value { + b: false + } + } + attr { + name: "clear_after_read" + type: "bool" + default_value { + b: true + } + } + attr { + name: "tensor_array_name" + type: "string" + default_value { + s: "" + } + } + deprecation { + version: 26 + } + is_stateful: true +} op { name: "TensorArrayV3" input_arg { @@ -63103,6 +63508,36 @@ op { type: "type" } } +op { + name: "TensorArrayWriteV2" + input_arg { + name: "handle" + type: DT_STRING + } + input_arg { + name: "index" + type: DT_INT32 + } + input_arg { + name: "value" + type_attr: "T" + } + input_arg { + name: "flow_in" + type: DT_FLOAT + } + output_arg { + name: "flow_out" + type: DT_FLOAT + } + attr { + name: "T" + type: "type" + } + deprecation { + version: 26 + } +} op { name: "TensorArrayWriteV3" input_arg { @@ -63481,6 +63916,39 @@ op { } is_stateful: true } +op { + name: "TextLineReader" + output_arg { + name: "reader_handle" + type: DT_STRING + is_ref: true + } + attr { + name: "skip_header_lines" + type: "int" + default_value { + i: 0 + } + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + deprecation { + version: 26 + } + is_stateful: true +} op { name: "TextLineReaderV2" output_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index 60da36a939..fe0b362d8f 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -8540,6 +8540,10 @@ op { s: "" } } + deprecation { + version: 26 + explanation: "Use FixedLengthRecordReaderV2" + } is_stateful: true } op { @@ -10137,6 +10141,10 @@ op { s: "" } } + deprecation { + version: 26 + explanation: "Use IdentityReaderV2" + } is_stateful: true } op { @@ -19699,6 +19707,7 @@ op { type: DT_UINT16 type: DT_INT32 type: DT_INT64 + type: DT_BFLOAT16 type: DT_HALF type: DT_FLOAT type: DT_DOUBLE @@ -19733,6 +19742,7 @@ op { allowed_values { list { type: DT_FLOAT + type: DT_BFLOAT16 type: DT_HALF type: DT_DOUBLE } @@ -28618,6 +28628,10 @@ op { s: "" } } + deprecation { + version: 26 + explanation: "Use TFRecordReaderV2" + } is_stateful: true } op { @@ -28888,6 +28902,10 @@ op { name: "handle" type: DT_STRING } + deprecation { + version: 26 + explanation: "Use TensorArrayCloseV3" + } } op { name: "TensorArrayCloseV3" @@ -29067,6 +29085,10 @@ op { } } } + deprecation { + version: 26 + explanation: "Use TensorArrayGatherV3" + } } op { name: "TensorArrayGatherV3" @@ -29144,6 +29166,10 @@ op { name: "source" type: "string" } + deprecation { + version: 26 + explanation: "Use TensorArrayGradV3" + } is_stateful: true } op { @@ -29253,6 +29279,10 @@ op { name: "dtype" type: "type" } + deprecation { + version: 26 + explanation: "Use TensorArrayReadV3" + } } op { name: "TensorArrayReadV3" @@ -29336,6 +29366,10 @@ op { name: "T" type: "type" } + deprecation { + version: 26 + explanation: "Use TensorArrayScatterV3" + } } op { name: "TensorArrayScatterV3" @@ -29399,6 +29433,10 @@ op { name: "size" type: DT_INT32 } + deprecation { + version: 26 + explanation: "Use TensorArraySizeV3" + } } op { name: "TensorArraySizeV3" @@ -29474,6 +29512,10 @@ op { name: "T" type: "type" } + deprecation { + version: 26 + explanation: "Use TensorArraySplitV3" + } } op { name: "TensorArraySplitV3" @@ -29575,6 +29617,10 @@ op { s: "" } } + deprecation { + version: 26 + explanation: "Use TensorArrayV3" + } is_stateful: true } op { @@ -29692,6 +29738,10 @@ op { name: "T" type: "type" } + deprecation { + version: 26 + explanation: "Use TensorArrayWriteV3" + } } op { name: "TensorArrayWriteV3" @@ -30069,6 +30119,10 @@ op { s: "" } } + deprecation { + version: 26 + explanation: "Use TextLineReaderV2" + } is_stateful: true } op { -- GitLab From 93307b6ea9d94a6d69783a9afad51dbe11788d41 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 18:46:01 -0800 Subject: [PATCH 160/258] Go: Update generated wrapper functions for TensorFlow ops. PiperOrigin-RevId: 183027491 --- tensorflow/go/op/wrappers.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tensorflow/go/op/wrappers.go b/tensorflow/go/op/wrappers.go index 2f1f3b0be4..7873201f3e 100644 --- a/tensorflow/go/op/wrappers.go +++ b/tensorflow/go/op/wrappers.go @@ -2461,6 +2461,8 @@ func TensorArrayV2TensorArrayName(value string) TensorArrayV2Attr { } // Deprecated. Use TensorArrayV3 +// +// DEPRECATED at GraphDef version 26: Use TensorArrayV3 func TensorArrayV2(scope *Scope, size tf.Output, dtype tf.DataType, optional ...TensorArrayV2Attr) (handle tf.Output) { if scope.Err() != nil { return @@ -10400,6 +10402,8 @@ func SparseReshape(scope *Scope, input_indices tf.Output, input_shape tf.Output, } // Deprecated. Use TensorArraySplitV3 +// +// DEPRECATED at GraphDef version 26: Use TensorArraySplitV3 func TensorArraySplitV2(scope *Scope, handle tf.Output, value tf.Output, lengths tf.Output, flow_in tf.Output) (flow_out tf.Output) { if scope.Err() != nil { return @@ -11813,6 +11817,8 @@ func MaxPoolV2(scope *Scope, input tf.Output, ksize tf.Output, strides tf.Output } // Deprecated. Use TensorArrayReadV3 +// +// DEPRECATED at GraphDef version 26: Use TensorArrayReadV3 func TensorArrayReadV2(scope *Scope, handle tf.Output, index tf.Output, flow_in tf.Output, dtype tf.DataType) (value tf.Output) { if scope.Err() != nil { return @@ -20211,6 +20217,8 @@ func DenseToSparseBatchDataset(scope *Scope, input_dataset tf.Output, batch_size } // Deprecated. Use TensorArrayGradV3 +// +// DEPRECATED at GraphDef version 26: Use TensorArrayGradV3 func TensorArrayGradV2(scope *Scope, handle tf.Output, flow_in tf.Output, source string) (grad_handle tf.Output) { if scope.Err() != nil { return @@ -21504,6 +21512,8 @@ func TensorArrayGatherV2ElementShape(value tf.Shape) TensorArrayGatherV2Attr { } // Deprecated. Use TensorArrayGatherV3 +// +// DEPRECATED at GraphDef version 26: Use TensorArrayGatherV3 func TensorArrayGatherV2(scope *Scope, handle tf.Output, indices tf.Output, flow_in tf.Output, dtype tf.DataType, optional ...TensorArrayGatherV2Attr) (value tf.Output) { if scope.Err() != nil { return @@ -22228,6 +22238,8 @@ func EncodeBase64(scope *Scope, input tf.Output, optional ...EncodeBase64Attr) ( // Deprecated. Use TensorArrayCloseV3 // +// DEPRECATED at GraphDef version 26: Use TensorArrayCloseV3 +// // Returns the created operation. func TensorArrayCloseV2(scope *Scope, handle tf.Output) (o *tf.Operation) { if scope.Err() != nil { @@ -23247,6 +23259,8 @@ func TensorArraySizeV3(scope *Scope, handle tf.Output, flow_in tf.Output) (size } // Deprecated. Use TensorArrayGradV3 +// +// DEPRECATED at GraphDef version 26: Use TensorArrayWriteV3 func TensorArrayWriteV2(scope *Scope, handle tf.Output, index tf.Output, value tf.Output, flow_in tf.Output) (flow_out tf.Output) { if scope.Err() != nil { return @@ -23397,6 +23411,8 @@ func AsString(scope *Scope, input tf.Output, optional ...AsStringAttr) (output t } // Deprecated. Use TensorArrayScatterV3 +// +// DEPRECATED at GraphDef version 26: Use TensorArrayScatterV3 func TensorArrayScatterV2(scope *Scope, handle tf.Output, indices tf.Output, value tf.Output, flow_in tf.Output) (flow_out tf.Output) { if scope.Err() != nil { return @@ -23601,6 +23617,8 @@ func FractionalMaxPool(scope *Scope, value tf.Output, pooling_ratio []float32, o } // Deprecated. Use TensorArraySizeV3 +// +// DEPRECATED at GraphDef version 26: Use TensorArraySizeV3 func TensorArraySizeV2(scope *Scope, handle tf.Output, flow_in tf.Output) (size tf.Output) { if scope.Err() != nil { return -- GitLab From 31301635e25a3e7bbac32c8527ceb60060c2264f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 18:49:09 -0800 Subject: [PATCH 161/258] Add nested support for `assertAllClose()` so `a` and `b` can be arbitrarily nested of a numpy array, tuple, list, namedtuple or anything can be converted to a numpy array. PiperOrigin-RevId: 183027752 --- tensorflow/python/framework/test_util.py | 93 ++++++++++++++----- tensorflow/python/framework/test_util_test.py | 34 +++++-- 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py index 7b09891fc1..0133318456 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py @@ -1136,41 +1136,84 @@ class TensorFlowTestCase(googletest.TestCase): np.testing.assert_allclose( a, b, rtol=rtol, atol=atol, err_msg=msg, equal_nan=True) - def assertAllClose(self, a, b, rtol=1e-6, atol=1e-6): - """Asserts that two numpy arrays, or dicts of same, have near values. - - This does not support nested dicts. `a` and `b` can be namedtuples too, - which are converted to dicts. - - Args: - a: The expected numpy ndarray (or anything can be converted to one), or - dict of same. Must be a dict iff `b` is a dict. - b: The actual numpy ndarray (or anything can be converted to one), or - dict of same. Must be a dict iff `a` is a dict. - rtol: relative tolerance. - atol: absolute tolerance. + def _assertAllCloseRecursive(self, a, b, rtol=1e-6, atol=1e-6, path=None): + path = path or [] + path_str = (("[" + "][".join([str(p) for p in path]) + "]") if path else "") - Raises: - ValueError: if only one of `a` and `b` is a dict. - """ # Check if a and/or b are namedtuples. if hasattr(a, "_asdict"): a = a._asdict() if hasattr(b, "_asdict"): b = b._asdict() - is_a_dict = isinstance(a, dict) - if is_a_dict != isinstance(b, dict): - raise ValueError("Can't compare dict to non-dict, %s vs %s." % (a, b)) - if is_a_dict: + a_is_dict = isinstance(a, dict) + if a_is_dict != isinstance(b, dict): + raise ValueError("Can't compare dict to non-dict, a%s vs b%s." % + (path_str, path_str)) + if a_is_dict: self.assertItemsEqual( - a.keys(), b.keys(), - msg="mismatched keys, expected %s, got %s" % (a.keys(), b.keys())) + a.keys(), + b.keys(), + msg="mismatched keys: a%s has keys %s, but b%s has keys %s" % + (path_str, a.keys(), path_str, b.keys())) for k in a: + path.append(k) + self._assertAllCloseRecursive( + a[k], b[k], rtol=rtol, atol=atol, path=path) + del path[-1] + elif isinstance(a, (list, tuple)): + # Try to directly compare a, b as ndarrays; if not work, then traverse + # through the sequence, which is more expensive. + try: + a_as_ndarray = np.array(a) + b_as_ndarray = np.array(b) self._assertArrayLikeAllClose( - a[k], b[k], rtol=rtol, atol=atol, - msg="%s: expected %s, got %s." % (k, a, b)) + a_as_ndarray, + b_as_ndarray, + rtol=rtol, + atol=atol, + msg="Mismatched value: a%s is different from b%s." % (path_str, + path_str)) + except (ValueError, TypeError) as e: + if len(a) != len(b): + raise ValueError( + "Mismatched length: a%s has %d items, but b%s has %d items" % + (path_str, len(a), path_str, len(b))) + for idx, (a_ele, b_ele) in enumerate(zip(a, b)): + path.append(str(idx)) + self._assertAllCloseRecursive( + a_ele, b_ele, rtol=rtol, atol=atol, path=path) + del path[-1] + # a and b are ndarray like objects else: - self._assertArrayLikeAllClose(a, b, rtol=rtol, atol=atol) + self._assertArrayLikeAllClose( + a, + b, + rtol=rtol, + atol=atol, + msg="Mismatched value: a%s is different from b%s." % (path_str, + path_str)) + + def assertAllClose(self, a, b, rtol=1e-6, atol=1e-6): + """Asserts that two structures of numpy arrays, have near values. + + `a` and `b` can be arbitrarily nested structures. A layer of a nested + structure can be a `dict`, `namedtuple`, `tuple` or `list`. + + Args: + a: The expected numpy `ndarray`, or anything that can be converted into a + numpy `ndarray`, or any arbitrarily nested of structure of these. + b: The actual numpy `ndarray`, or anything that can be converted into a + numpy `ndarray`, or any arbitrarily nested of structure of these. + rtol: relative tolerance. + atol: absolute tolerance. + + Raises: + ValueError: if only one of `a[p]` and `b[p]` is a dict or + `a[p]` and `b[p]` have different length, where `[p]` denotes a path + to the nested structure, e.g. given `a = [(1, 1), {'d': (6, 7)}]` and + `[p] = [1]['d']`, then `a[p] = (6, 7)`. + """ + self._assertAllCloseRecursive(a, b, rtol=rtol, atol=atol) def assertAllCloseAccordingToType(self, a, diff --git a/tensorflow/python/framework/test_util_test.py b/tensorflow/python/framework/test_util_test.py index 6ddb3533e5..3594d125bf 100644 --- a/tensorflow/python/framework/test_util_test.py +++ b/tensorflow/python/framework/test_util_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function import collections +import copy import random import threading @@ -252,12 +253,30 @@ class TestUtilTest(test_util.TensorFlowTestCase): with self.assertRaisesRegexp(AssertionError, r"Not equal to tolerance"): self.assertAllClose(expected, {"a": a, "b": b, "c": c_copy}) - def testAllCloseNestedDicts(self): - a = {"a": 1, "b": 2, "nested": {"d": 3, "e": 4}} - with self.assertRaisesRegexp( - TypeError, - r"inputs could not be safely coerced to any supported types"): - self.assertAllClose(a, a) + def testAllCloseListOfNamedtuples(self): + my_named_tuple = collections.namedtuple("MyNamedTuple", ["x", "y"]) + l1 = [ + my_named_tuple(x=np.array([[2.3, 2.5]]), y=np.array([[0.97, 0.96]])), + my_named_tuple(x=np.array([[3.3, 3.5]]), y=np.array([[0.98, 0.99]])) + ] + l2 = [ + ([[2.3, 2.5]], [[0.97, 0.96]]), + ([[3.3, 3.5]], [[0.98, 0.99]]), + ] + self.assertAllClose(l1, l2) + + def testAllCloseNestedStructure(self): + a = {"x": np.ones((3, 2, 4)) * 7, "y": (2, [{"nested": {"m": 3, "n": 4}}])} + self.assertAllClose(a, a) + + b = copy.deepcopy(a) + self.assertAllClose(a, b) + + # Test mismatched values + b["y"][1][0]["nested"]["n"] = 4.2 + with self.assertRaisesRegexp(AssertionError, + r"\[y\]\[1\]\[0\]\[nested\]\[n\]"): + self.assertAllClose(a, b) def testArrayNear(self): a = [1, 2] @@ -282,6 +301,9 @@ class TestUtilTest(test_util.TensorFlowTestCase): control_flow_ops.Assert(x, y).run() def testAssertAllCloseAccordingToType(self): + # test plain int + self.assertAllCloseAccordingToType(1, 1, rtol=1e-8, atol=1e-8) + # test float64 self.assertAllCloseAccordingToType( np.asarray([1e-8], dtype=np.float64), -- GitLab From 11429a5e25cf7bf9b45a564283a35e1495de6741 Mon Sep 17 00:00:00 2001 From: Shivani Agrawal Date: Tue, 23 Jan 2018 20:09:58 -0800 Subject: [PATCH 162/258] [tf.data] Fixes flaky timeouts of stats_dataset_ops_test. PiperOrigin-RevId: 183033139 --- tensorflow/contrib/data/python/kernel_tests/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/data/python/kernel_tests/BUILD b/tensorflow/contrib/data/python/kernel_tests/BUILD index 1fbf18f30a..1cf0202fd8 100644 --- a/tensorflow/contrib/data/python/kernel_tests/BUILD +++ b/tensorflow/contrib/data/python/kernel_tests/BUILD @@ -475,7 +475,7 @@ py_test( py_test( name = "stats_dataset_ops_test", - size = "small", + size = "medium", srcs = ["stats_dataset_ops_test.py"], srcs_version = "PY2AND3", tags = ["no_pip"], -- GitLab From 2a9866020dbcb53de32bcd984150545a623e34b7 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 21:51:06 -0800 Subject: [PATCH 163/258] Make an API for non-slot variables. This new API is safer than the existing AdamOptimizer code when switching between multiple graphs or multiple threads. PiperOrigin-RevId: 183039296 --- .../eager/python/checkpointable_test.py | 48 +++++++------- .../python/training/lazy_adam_optimizer.py | 5 +- .../opt/python/training/nadam_optimizer.py | 15 +++-- tensorflow/python/training/adam.py | 62 ++++++++----------- tensorflow/python/training/adam_test.py | 7 ++- tensorflow/python/training/optimizer.py | 27 ++++++-- .../training/sync_replicas_optimizer_test.py | 5 +- 7 files changed, 90 insertions(+), 79 deletions(-) diff --git a/tensorflow/contrib/eager/python/checkpointable_test.py b/tensorflow/contrib/eager/python/checkpointable_test.py index f820990bbe..ff419614f5 100644 --- a/tensorflow/contrib/eager/python/checkpointable_test.py +++ b/tensorflow/contrib/eager/python/checkpointable_test.py @@ -70,42 +70,36 @@ class CheckpointableAdam(adam.AdamOptimizer, checkpointable.Checkpointable): checkpointable.Checkpointable.__init__(self) adam.AdamOptimizer.__init__(self, *args, **kwargs) - # NOTE: Copied from AdamOptimizer with modifications to use add_variable + # NOTE: Copied from Optimizer with modifications to use add_variable # for non-slot variables. These contortions are necessary to maintain # checkpoint compatibility with variable.name based saving. - def _create_slots(self, var_list): - # Create the beta1 and beta2 accumulators on the same device as the first - # variable. Sort the var_list to make sure this device is consistent across - # workers (these need to go on the same PS, otherwise some updates are - # silently ignored). - first_var = min(var_list, key=lambda x: x.name) - - create_new = self._beta1_power is None - if not create_new and context.in_graph_mode(): - create_new = (self._beta1_power.graph is not first_var.graph) - - if create_new: - with ops.colocate_with(first_var): + # TODO(allenl): Make this cleaner. + def _create_non_slot_variable(self, initial_value, name, colocate_with): + """Add an extra variable, not associated with a slot.""" + if context.in_graph_mode(): + graph = colocate_with.graph + else: + graph = None + key = (name, graph) + v = self._non_slot_dict.get(key, None) + if v is None: + with ops.colocate_with(colocate_with): def _variable_getter(name, shape, dtype, initializer): del shape, dtype # not used, but there for compatibility return variable_scope.variable( name=name, initial_value=initializer, trainable=False) - self._beta1_power = self.add_variable( - name="beta1_power", - shape=[], - initializer=self._beta1, + initial_value = ops.convert_to_tensor(initial_value) + v = self.add_variable( + name=name, + shape=initial_value.get_shape(), + initializer=initial_value, getter=_variable_getter) - self._beta2_power = self.add_variable( - name="beta2_power", - shape=[], - initializer=self._beta2, - getter=_variable_getter) - # Create slots for the first and second moments. - for v in var_list: - self._zeros_slot(v, "m", self._name) - self._zeros_slot(v, "v", self._name) + + self._non_slot_dict[key] = v + + return v # TODO(allenl): Override slot variable creation (_get_or_make_slot, # _get_or_make_slot_with_initializer, _zeros_slot) to allow deferred diff --git a/tensorflow/contrib/opt/python/training/lazy_adam_optimizer.py b/tensorflow/contrib/opt/python/training/lazy_adam_optimizer.py index 4c3fec0672..aeca900bc8 100644 --- a/tensorflow/contrib/opt/python/training/lazy_adam_optimizer.py +++ b/tensorflow/contrib/opt/python/training/lazy_adam_optimizer.py @@ -47,8 +47,9 @@ class LazyAdamOptimizer(adam.AdamOptimizer): """ def _apply_sparse(self, grad, var): - beta1_power = math_ops.cast(self._beta1_power, var.dtype.base_dtype) - beta2_power = math_ops.cast(self._beta2_power, var.dtype.base_dtype) + beta1_power, beta2_power = self._get_beta_accumulators() + beta1_power = math_ops.cast(beta1_power, var.dtype.base_dtype) + beta2_power = math_ops.cast(beta2_power, var.dtype.base_dtype) lr_t = math_ops.cast(self._lr_t, var.dtype.base_dtype) beta1_t = math_ops.cast(self._beta1_t, var.dtype.base_dtype) beta2_t = math_ops.cast(self._beta2_t, var.dtype.base_dtype) diff --git a/tensorflow/contrib/opt/python/training/nadam_optimizer.py b/tensorflow/contrib/opt/python/training/nadam_optimizer.py index a4421ecfe6..44a8890cb1 100644 --- a/tensorflow/contrib/opt/python/training/nadam_optimizer.py +++ b/tensorflow/contrib/opt/python/training/nadam_optimizer.py @@ -34,12 +34,13 @@ class NadamOptimizer(adam.AdamOptimizer): def _apply_dense(self, grad, var): m = self.get_slot(var, "m") v = self.get_slot(var, "v") + beta1_power, beta2_power = self._get_beta_accumulators() return training_ops.apply_adam( var, m, v, - math_ops.cast(self._beta1_power, var.dtype.base_dtype), - math_ops.cast(self._beta2_power, var.dtype.base_dtype), + math_ops.cast(beta1_power, var.dtype.base_dtype), + math_ops.cast(beta2_power, var.dtype.base_dtype), math_ops.cast(self._lr_t, var.dtype.base_dtype), math_ops.cast(self._beta1_t, var.dtype.base_dtype), math_ops.cast(self._beta2_t, var.dtype.base_dtype), @@ -51,12 +52,13 @@ class NadamOptimizer(adam.AdamOptimizer): def _resource_apply_dense(self, grad, var): m = self.get_slot(var, "m") v = self.get_slot(var, "v") + beta1_power, beta2_power = self._get_beta_accumulators() return training_ops.resource_apply_adam( var.handle, m.handle, v.handle, - math_ops.cast(self._beta1_power, grad.dtype.base_dtype), - math_ops.cast(self._beta2_power, grad.dtype.base_dtype), + math_ops.cast(beta1_power, grad.dtype.base_dtype), + math_ops.cast(beta2_power, grad.dtype.base_dtype), math_ops.cast(self._lr_t, grad.dtype.base_dtype), math_ops.cast(self._beta1_t, grad.dtype.base_dtype), math_ops.cast(self._beta2_t, grad.dtype.base_dtype), @@ -66,8 +68,9 @@ class NadamOptimizer(adam.AdamOptimizer): use_nesterov=True) def _apply_sparse_shared(self, grad, var, indices, scatter_add): - beta1_power = math_ops.cast(self._beta1_power, var.dtype.base_dtype) - beta2_power = math_ops.cast(self._beta2_power, var.dtype.base_dtype) + beta1_power, beta2_power = self._get_beta_accumulators() + beta1_power = math_ops.cast(beta1_power, var.dtype.base_dtype) + beta2_power = math_ops.cast(beta2_power, var.dtype.base_dtype) lr_t = math_ops.cast(self._lr_t, var.dtype.base_dtype) beta1_t = math_ops.cast(self._beta1_t, var.dtype.base_dtype) beta2_t = math_ops.cast(self._beta2_t, var.dtype.base_dtype) diff --git a/tensorflow/python/training/adam.py b/tensorflow/python/training/adam.py index 266f5563e0..0c69f8bf39 100644 --- a/tensorflow/python/training/adam.py +++ b/tensorflow/python/training/adam.py @@ -24,7 +24,6 @@ from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import state_ops -from tensorflow.python.ops import variable_scope from tensorflow.python.training import optimizer from tensorflow.python.training import training_ops @@ -101,19 +100,16 @@ class AdamOptimizer(optimizer.Optimizer): self._beta2_t = None self._epsilon_t = None - # Variables to accumulate the powers of the beta parameters. - # Created in _create_slots when we know the variables to optimize. - self._beta1_power = None - self._beta2_power = None - # Created in SparseApply if needed. self._updated_lr = None def _get_beta_accumulators(self): - return self._beta1_power, self._beta2_power - - def _non_slot_variables(self): - return self._get_beta_accumulators() + if context.in_graph_mode(): + graph = ops.get_default_graph() + else: + graph = None + return (self._get_non_slot_variable("beta1_power", graph=graph), + self._get_non_slot_variable("beta2_power", graph=graph)) def _create_slots(self, var_list): # Create the beta1 and beta2 accumulators on the same device as the first @@ -121,19 +117,13 @@ class AdamOptimizer(optimizer.Optimizer): # workers (these need to go on the same PS, otherwise some updates are # silently ignored). first_var = min(var_list, key=lambda x: x.name) + self._create_non_slot_variable(initial_value=self._beta1, + name="beta1_power", + colocate_with=first_var) + self._create_non_slot_variable(initial_value=self._beta2, + name="beta2_power", + colocate_with=first_var) - create_new = self._beta1_power is None - if not create_new and context.in_graph_mode(): - create_new = (self._beta1_power.graph is not first_var.graph) - - if create_new: - with ops.colocate_with(first_var): - self._beta1_power = variable_scope.variable(self._beta1, - name="beta1_power", - trainable=False) - self._beta2_power = variable_scope.variable(self._beta2, - name="beta2_power", - trainable=False) # Create slots for the first and second moments. for v in var_list: self._zeros_slot(v, "m", self._name) @@ -148,10 +138,11 @@ class AdamOptimizer(optimizer.Optimizer): def _apply_dense(self, grad, var): m = self.get_slot(var, "m") v = self.get_slot(var, "v") + beta1_power, beta2_power = self._get_beta_accumulators() return training_ops.apply_adam( var, m, v, - math_ops.cast(self._beta1_power, var.dtype.base_dtype), - math_ops.cast(self._beta2_power, var.dtype.base_dtype), + math_ops.cast(beta1_power, var.dtype.base_dtype), + math_ops.cast(beta2_power, var.dtype.base_dtype), math_ops.cast(self._lr_t, var.dtype.base_dtype), math_ops.cast(self._beta1_t, var.dtype.base_dtype), math_ops.cast(self._beta2_t, var.dtype.base_dtype), @@ -161,10 +152,11 @@ class AdamOptimizer(optimizer.Optimizer): def _resource_apply_dense(self, grad, var): m = self.get_slot(var, "m") v = self.get_slot(var, "v") + beta1_power, beta2_power = self._get_beta_accumulators() return training_ops.resource_apply_adam( var.handle, m.handle, v.handle, - math_ops.cast(self._beta1_power, grad.dtype.base_dtype), - math_ops.cast(self._beta2_power, grad.dtype.base_dtype), + math_ops.cast(beta1_power, grad.dtype.base_dtype), + math_ops.cast(beta2_power, grad.dtype.base_dtype), math_ops.cast(self._lr_t, grad.dtype.base_dtype), math_ops.cast(self._beta1_t, grad.dtype.base_dtype), math_ops.cast(self._beta2_t, grad.dtype.base_dtype), @@ -172,8 +164,9 @@ class AdamOptimizer(optimizer.Optimizer): grad, use_locking=self._use_locking) def _apply_sparse_shared(self, grad, var, indices, scatter_add): - beta1_power = math_ops.cast(self._beta1_power, var.dtype.base_dtype) - beta2_power = math_ops.cast(self._beta2_power, var.dtype.base_dtype) + beta1_power, beta2_power = self._get_beta_accumulators() + beta1_power = math_ops.cast(beta1_power, var.dtype.base_dtype) + beta2_power = math_ops.cast(beta2_power, var.dtype.base_dtype) lr_t = math_ops.cast(self._lr_t, var.dtype.base_dtype) beta1_t = math_ops.cast(self._beta1_t, var.dtype.base_dtype) beta2_t = math_ops.cast(self._beta2_t, var.dtype.base_dtype) @@ -217,12 +210,11 @@ class AdamOptimizer(optimizer.Optimizer): def _finish(self, update_ops, name_scope): # Update the power accumulators. with ops.control_dependencies(update_ops): - with ops.colocate_with(self._beta1_power): - update_beta1 = self._beta1_power.assign( - self._beta1_power * self._beta1_t, - use_locking=self._use_locking) - update_beta2 = self._beta2_power.assign( - self._beta2_power * self._beta2_t, - use_locking=self._use_locking) + beta1_power, beta2_power = self._get_beta_accumulators() + with ops.colocate_with(beta1_power): + update_beta1 = beta1_power.assign( + beta1_power * self._beta1_t, use_locking=self._use_locking) + update_beta2 = beta2_power.assign( + beta2_power * self._beta2_t, use_locking=self._use_locking) return control_flow_ops.group(*update_ops + [update_beta1, update_beta2], name=name_scope) diff --git a/tensorflow/python/training/adam_test.py b/tensorflow/python/training/adam_test.py index ffb66abc4c..a521f1299e 100644 --- a/tensorflow/python/training/adam_test.py +++ b/tensorflow/python/training/adam_test.py @@ -174,8 +174,11 @@ class AdamOptimizerTest(test.TestCase): opt = adam.AdamOptimizer() update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) opt_variables = opt.variables() - self.assertIn(opt._beta1_power, opt_variables) - self.assertIn(opt._beta2_power, opt_variables) + beta1_power, beta2_power = opt._get_beta_accumulators() + self.assertTrue(beta1_power is not None) + self.assertTrue(beta2_power is not None) + self.assertIn(beta1_power, opt_variables) + self.assertIn(beta2_power, opt_variables) with ops.Graph().as_default(): # Shouldn't return non-slot variables from other graphs. diff --git a/tensorflow/python/training/optimizer.py b/tensorflow/python/training/optimizer.py index 56cf4d42ee..038469b1ba 100644 --- a/tensorflow/python/training/optimizer.py +++ b/tensorflow/python/training/optimizer.py @@ -32,6 +32,7 @@ from tensorflow.python.ops import gradients from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import state_ops +from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables from tensorflow.python.training import slot_creator from tensorflow.python.util import nest @@ -299,6 +300,7 @@ class Optimizer(object): # Dictionary of slots. # {slot_name : { variable_to_train: slot_for_the_variable, ...}, ... } self._slots = {} + self._non_slot_dict = {} def get_name(self): return self._name @@ -603,17 +605,32 @@ class Optimizer(object): # Sort variables by name so that the return is deterministic. return sorted(optimizer_variables, key=lambda v: v.name) + def _create_non_slot_variable(self, initial_value, name, colocate_with): + """Add an extra variable, not associated with a slot.""" + if context.in_graph_mode(): + graph = colocate_with.graph + else: + graph = None + + key = (name, graph) + v = self._non_slot_dict.get(key, None) + if v is None: + with ops.colocate_with(colocate_with): + v = variable_scope.variable(initial_value, name=name, trainable=False) + self._non_slot_dict[key] = v + + return v + + def _get_non_slot_variable(self, name, graph=None): + return self._non_slot_dict.get((name, graph), None) + def _non_slot_variables(self): """Additional variables created by the `Optimizer`. - This method should be overridden by child classes which create extra - variables, so that `variables()` includes the `Optimizer`'s non-slot - variables. - Returns: A list or tuple of variables. """ - return [] + return self._non_slot_dict.values() def _assert_valid_dtypes(self, tensors): """Asserts tensors are all valid types (see `_valid_dtypes`). diff --git a/tensorflow/python/training/sync_replicas_optimizer_test.py b/tensorflow/python/training/sync_replicas_optimizer_test.py index 297284f80c..fff17402e2 100644 --- a/tensorflow/python/training/sync_replicas_optimizer_test.py +++ b/tensorflow/python/training/sync_replicas_optimizer_test.py @@ -286,8 +286,9 @@ class SyncReplicasOptimizerHookTest(test.TestCase): global_step = variables.Variable(0, name="global_step", trainable=False) opt.minimize(v, global_step=global_step) opt_variables = opt.variables() - self.assertIn(opt._opt._beta1_power, opt_variables) - self.assertIn(opt._opt._beta2_power, opt_variables) + beta1_power, beta2_power = opt._opt._get_beta_accumulators() + self.assertIn(beta1_power, opt_variables) + self.assertIn(beta2_power, opt_variables) if __name__ == "__main__": -- GitLab From 95158cb83907d76e8df258fec23816c15ef4477e Mon Sep 17 00:00:00 2001 From: lspvic Date: Tue, 23 Jan 2018 03:19:57 +0800 Subject: [PATCH 164/258] Check axes value ranges --- tensorflow/python/ops/math_ops.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index 88260e2687..f4f18733f8 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -2765,9 +2765,12 @@ def tensordot(a, b, axes, name=None): """Generates two sets of contraction axes for the two tensor arguments.""" a_shape = a.get_shape() if isinstance(axes, compat.integral_types): - if axes < 1: - raise ValueError("'axes' must be at least 1.") + if axes < 0: + raise ValueError("'axes' must be at least 0.") if a_shape.ndims is not None: + if axes > a_shape.ndims: + raise ValueError("'axes' must not be larger than the number of " + "dimensions of tensor %s." % a) return (list(xrange(a_shape.ndims - axes, a_shape.ndims)), list(xrange(axes))) else: -- GitLab From 15d2baefdba2371761a93d7ff38c837ea433403f Mon Sep 17 00:00:00 2001 From: lspvic Date: Wed, 24 Jan 2018 13:43:03 +0800 Subject: [PATCH 165/258] Add tests for tensordot scalar axes --- .../python/kernel_tests/tensordot_op_test.py | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/tensorflow/python/kernel_tests/tensordot_op_test.py b/tensorflow/python/kernel_tests/tensordot_op_test.py index f375157287..38205518b5 100644 --- a/tensorflow/python/kernel_tests/tensordot_op_test.py +++ b/tensorflow/python/kernel_tests/tensordot_op_test.py @@ -64,7 +64,7 @@ class TensordotTest(test_lib.TestCase): a = [[1, 2], [3, 4]] b = [[1, 2], [3, 4]] # Invalid static axes. - for axes_value in -1, 0, [1], [[1]], [[1], [0, 1]]: + for axes_value in -1, 3, [1], [[1]], [[1], [0, 1]]: with self.assertRaises(ValueError): math_ops.tensordot(a, b, axes_value) @@ -87,7 +87,7 @@ class TensordotTest(test_lib.TestCase): # Test case for 11950 def test_valid_axis(self): - for axes_value in [1, 2], [[1], [2]]: + for axes_value in [1, 2], [[1], [2]], [[], []], 0: with self.test_session() as sess: np_a = np.ones((3,3)) np_b = np.array([2, 3, 1])[None, None] @@ -102,29 +102,29 @@ class TensordotTest(test_lib.TestCase): def test_partial_shape_inference(self): - a = array_ops.placeholder(dtypes.float32) - b = array_ops.placeholder(dtypes.float32) - axes = ([1], [0]) - output = math_ops.tensordot(a, b, axes) - self.assertEqual(output.get_shape().ndims, None) - a.set_shape([None, 2]) - b.set_shape([2, 3]) - output = math_ops.tensordot(a, b, axes) - output_shape = output.get_shape() - self.assertEqual(output_shape.ndims, 2) - output_shape = output_shape.as_list() - self.assertEqual(output_shape[0], None) - self.assertEqual(output_shape[1], 3) - a = array_ops.placeholder(dtypes.float32) - b = array_ops.placeholder(dtypes.float32) - a.set_shape([2, 2]) - b.set_shape([2, None]) - output = math_ops.tensordot(a, b, axes) - output_shape = output.get_shape() - self.assertEqual(output_shape.ndims, 2) - output_shape = output_shape.as_list() - self.assertEqual(output_shape[0], 2) - self.assertEqual(output_shape[1], None) + for axes in ([1],[0]), 1: + a = array_ops.placeholder(dtypes.float32) + b = array_ops.placeholder(dtypes.float32) + output = math_ops.tensordot(a, b, axes) + self.assertEqual(output.get_shape().ndims, None) + a.set_shape([None, 2]) + b.set_shape([2, 3]) + output = math_ops.tensordot(a, b, axes) + output_shape = output.get_shape() + self.assertEqual(output_shape.ndims, 2) + output_shape = output_shape.as_list() + self.assertEqual(output_shape[0], None) + self.assertEqual(output_shape[1], 3) + a = array_ops.placeholder(dtypes.float32) + b = array_ops.placeholder(dtypes.float32) + a.set_shape([2, 2]) + b.set_shape([2, None]) + output = math_ops.tensordot(a, b, axes) + output_shape = output.get_shape() + self.assertEqual(output_shape.ndims, 2) + output_shape = output_shape.as_list() + self.assertEqual(output_shape[0], 2) + self.assertEqual(output_shape[1], None) def _get_tensordot_tests(dtype_, rank_a_, rank_b_, num_dims_, dynamic_shape_): @@ -191,8 +191,8 @@ def _get_tensordot_tests(dtype_, rank_a_, rank_b_, num_dims_, dynamic_shape_): low=-1.0, high=1.0, size=np.prod(shape)).reshape(shape).astype(dtype_) b_np = np.random.uniform( low=-1.0, high=1.0, size=np.prod(shape)).reshape(shape).astype(dtype_) - all_axes = [1] - if a_np.ndim > 1: + all_axes = [0, 1] + if a_np.ndim > 2: all_axes.append(a_np.ndim - 1) for axes in all_axes: np_ans = np.tensordot(a_np, b_np, axes=axes) -- GitLab From abce81d8203d2f111a8cb7d54aeb18bd464465c6 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 23 Jan 2018 23:17:06 -0800 Subject: [PATCH 166/258] Add Real NVP and NICE bijectors and tests. PiperOrigin-RevId: 183044638 --- tensorflow/contrib/distributions/BUILD | 16 + .../kernel_tests/bijectors/real_nvp_test.py | 144 +++++++++ .../python/ops/bijectors/__init__.py | 3 + .../python/ops/bijectors/real_nvp.py | 282 ++++++++++++++++++ 4 files changed, 445 insertions(+) create mode 100644 tensorflow/contrib/distributions/python/kernel_tests/bijectors/real_nvp_test.py create mode 100644 tensorflow/contrib/distributions/python/ops/bijectors/real_nvp.py diff --git a/tensorflow/contrib/distributions/BUILD b/tensorflow/contrib/distributions/BUILD index 7d785c3636..7f510c4221 100644 --- a/tensorflow/contrib/distributions/BUILD +++ b/tensorflow/contrib/distributions/BUILD @@ -931,6 +931,22 @@ cuda_py_test( ], ) +cuda_py_test( + name = "real_nvp_test", + size = "small", + srcs = ["python/kernel_tests/bijectors/real_nvp_test.py"], + additional_deps = [ + ":bijectors_py", + ":distributions_py", + "//third_party/py/numpy", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + ], +) + cuda_py_test( name = "permute_test", size = "small", diff --git a/tensorflow/contrib/distributions/python/kernel_tests/bijectors/real_nvp_test.py b/tensorflow/contrib/distributions/python/kernel_tests/bijectors/real_nvp_test.py new file mode 100644 index 0000000000..46fe779741 --- /dev/null +++ b/tensorflow/contrib/distributions/python/kernel_tests/bijectors/real_nvp_test.py @@ -0,0 +1,144 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for MaskedAutoregressiveFlow.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np +from tensorflow.contrib.distributions.python.ops import test_util +from tensorflow.contrib.distributions.python.ops.bijectors.invert import Invert +from tensorflow.contrib.distributions.python.ops.bijectors.real_nvp import real_nvp_default_template +from tensorflow.contrib.distributions.python.ops.bijectors.real_nvp import RealNVP +from tensorflow.python.framework import constant_op +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import variables +from tensorflow.python.ops.distributions import normal as normal_lib +from tensorflow.python.ops.distributions import transformed_distribution as transformed_distribution_lib +from tensorflow.python.platform import test + + +class RealNVPTest(test_util.VectorDistributionTestHelpers, test.TestCase): + + @property + def _real_nvp_kwargs(self): + return { + "shift_and_log_scale_fn": real_nvp_default_template( + hidden_layers=[3], shift_only=False), + "is_constant_jacobian": False, + } + + def testBijector(self): + x_ = np.arange(3 * 4 * 2).astype(np.float32).reshape(3, 4 * 2) + with self.test_session() as sess: + nvp = RealNVP( + num_masked=4, + validate_args=True, + **self._real_nvp_kwargs) + x = constant_op.constant(x_) + forward_x = nvp.forward(x) + # Use identity to invalidate cache. + inverse_y = nvp.inverse(array_ops.identity(forward_x)) + fldj = nvp.forward_log_det_jacobian(x) + # Use identity to invalidate cache. + ildj = nvp.inverse_log_det_jacobian(array_ops.identity(forward_x)) + variables.global_variables_initializer().run() + [ + forward_x_, + inverse_y_, + ildj_, + fldj_, + ] = sess.run([ + forward_x, + inverse_y, + ildj, + fldj, + ]) + self.assertEqual("real_nvp", nvp.name) + self.assertAllClose(forward_x_, forward_x_, rtol=1e-6, atol=0.) + self.assertAllClose(x_, inverse_y_, rtol=1e-5, atol=0.) + self.assertAllClose(ildj_, -fldj_, rtol=1e-6, atol=0.) + + def testMutuallyConsistent(self): + dims = 4 + with self.test_session() as sess: + nvp = RealNVP( + num_masked=3, + validate_args=True, + **self._real_nvp_kwargs) + dist = transformed_distribution_lib.TransformedDistribution( + distribution=normal_lib.Normal(loc=0., scale=1.), + bijector=nvp, + event_shape=[dims], + validate_args=True) + self.run_test_sample_consistent_log_prob( + sess_run_fn=sess.run, + dist=dist, + num_samples=int(1e5), + radius=1., + center=0., + rtol=0.02) + + def testInvertMutuallyConsistent(self): + dims = 4 + with self.test_session() as sess: + nvp = Invert(RealNVP( + num_masked=3, + validate_args=True, + **self._real_nvp_kwargs)) + dist = transformed_distribution_lib.TransformedDistribution( + distribution=normal_lib.Normal(loc=0., scale=1.), + bijector=nvp, + event_shape=[dims], + validate_args=True) + self.run_test_sample_consistent_log_prob( + sess_run_fn=sess.run, + dist=dist, + num_samples=int(1e5), + radius=1., + center=0., + rtol=0.02) + + +class NICETest(RealNVPTest): + + @property + def _real_nvp_kwargs(self): + return { + "shift_and_log_scale_fn": real_nvp_default_template( + hidden_layers=[2], shift_only=True), + "is_constant_jacobian": True, + } + + +class RealNVPConstantShiftScaleTest(RealNVPTest): + + @property + def _real_nvp_kwargs(self): + + def constant_shift_log_scale_fn(x0, output_units): + del x0, output_units + shift = constant_op.constant([0.1]) + log_scale = constant_op.constant([0.5]) + return shift, log_scale + + return { + "shift_and_log_scale_fn": constant_shift_log_scale_fn, + "is_constant_jacobian": True, + } + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/contrib/distributions/python/ops/bijectors/__init__.py b/tensorflow/contrib/distributions/python/ops/bijectors/__init__.py index bc0ec7f195..93923c3f08 100644 --- a/tensorflow/contrib/distributions/python/ops/bijectors/__init__.py +++ b/tensorflow/contrib/distributions/python/ops/bijectors/__init__.py @@ -29,6 +29,7 @@ @@MaskedAutoregressiveFlow @@Permute @@PowerTransform +@@RealNVP @@Reshape @@Sigmoid @@SigmoidCentered @@ -39,6 +40,7 @@ @@masked_autoregressive_default_template @@masked_dense +@@real_nvp_default_template """ from __future__ import absolute_import @@ -60,6 +62,7 @@ from tensorflow.contrib.distributions.python.ops.bijectors.invert import * from tensorflow.contrib.distributions.python.ops.bijectors.masked_autoregressive import * from tensorflow.contrib.distributions.python.ops.bijectors.permute import * from tensorflow.contrib.distributions.python.ops.bijectors.power_transform import * +from tensorflow.contrib.distributions.python.ops.bijectors.real_nvp import * from tensorflow.contrib.distributions.python.ops.bijectors.reshape import * from tensorflow.contrib.distributions.python.ops.bijectors.sigmoid import * from tensorflow.contrib.distributions.python.ops.bijectors.sigmoid_centered import * diff --git a/tensorflow/contrib/distributions/python/ops/bijectors/real_nvp.py b/tensorflow/contrib/distributions/python/ops/bijectors/real_nvp.py new file mode 100644 index 0000000000..2840f52e74 --- /dev/null +++ b/tensorflow/contrib/distributions/python/ops/bijectors/real_nvp.py @@ -0,0 +1,282 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Real NVP bijector.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import ops +from tensorflow.python.layers import core as layers +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import nn_ops +from tensorflow.python.ops import template as template_ops +from tensorflow.python.ops.distributions import bijector as bijector_lib + + +__all__ = [ + "RealNVP", + "real_nvp_default_template" +] + + +class RealNVP(bijector_lib.Bijector): + """RealNVP "affine coupling layer" for vector-valued events. + + Real NVP models a normalizing flow on a `D`-dimensional distribution via a + single `D-d`-dimensional conditional distribution [1]: + + `y[d:D] = y[d:D] * math_ops.exp(log_scale_fn(y[d:D])) + shift_fn(y[d:D])` + `y[0:d] = x[0:d]` + + The last `D-d` units are scaled and shifted based on the first `d` units only, + while the first `d` units are 'masked' and left unchanged. Real NVP's + `shift_and_log_scale_fn` computes vector-valued quantities. For + scale-and-shift transforms that do not depend on any masked units, i.e. + `d=0`, use the `tfb.Affine` bijector with learned parameters instead. + + Masking is currently only supported for base distributions with + `event_ndims=1`. For more sophisticated masking schemes like checkerboard or + channel-wise masking [2], use the `tfb.Permute` bijector to re-order desired + masked units into the first `d` units. For base distributions with + `event_ndims > 1`, use the `tfb.Reshape` bijector to flatten the event shape. + + Recall that the MAF bijector [2] implements a normalizing flow via an + autoregressive transformation. MAF and IAF have opposite computational + tradeoffs - MAF can train all units in parallel but must sample units + sequentially, while IAF must train units sequentially but can sample in + parallel. In contrast, Real NVP can compute both forward and inverse + computations in parallel. However, the lack of an autoregressive + transformations makes it less expressive on a per-bijector basis. + + A "valid" `shift_and_log_scale_fn` must compute each `shift` (aka `loc` or + "mu" [2]) and `log(scale)` (aka "alpha" [2]) such that each are broadcastable + with the arguments to `forward` and `inverse`, i.e., such that the + calculations in `forward`, `inverse` [below] are possible. For convenience, + `real_nvp_default_nvp` is offered as a possible `shift_and_log_scale_fn` + function. + + NICE [3] is a special case of the Real NVP bijector which discards the scale + transformation, resulting in a constant-time inverse-log-determinant-Jacobian. + To use a NICE bijector instead of Real NVP, `shift_and_log_scale_fn` should + return `(shift, None)`, and `is_constant_jacobian` should be set to `True` in + the `RealNVP` constructor. Calling `real_nvp_default_template` with + `shift_only=True` returns one such NICE-compatible `shift_and_log_scale_fn`. + + Caching: the scalar input depth `D` of the base distribution is not known at + construction time. The first call to any of `forward(x)`, `inverse(x)`, + `inverse_log_det_jacobian(x)`, or `forward_log_det_jacobian(x)` memoizes + `D`, which is re-used in subsequent calls. This shape must be known prior to + graph execution (which is the case if using tf.layers). + + #### Example Use + + ```python + tfd = tf.contrib.distributions + tfb = tfd.bijectors + + # A common choice for a normalizing flow is to use a Gaussian for the base + # distribution. (However, any continuous distribution would work.) E.g., + nvp = tfd.TransformedDistribution( + distribution=tfd.MultivariateNormalDiag(loc=[0., 0., 0.])), + bijector=tfb.RealNVP( + num_masked=2, + shift_and_log_scale_fn=tfb.real_nvp_default_template( + hidden_layers=[512, 512]))) + + x = nvp.sample() + nvp.log_prob(x) + nvp.log_prob(0.) + ``` + + For more examples, see [4]. + + [1]: "Density Estimation using Real NVP." + Laurent Dinh, Jascha Sohl-Dickstein, Samy Bengio. ICLR. 2017. + https://arxiv.org/abs/1605.08803 + + [2]: "Masked Autoregressive Flow for Density Estimation." + George Papamakarios, Theo Pavlakou, Iain Murray. Arxiv. 2017. + https://arxiv.org/abs/1705.07057 + + [3]: "NICE: Non-linear Independent Components Estimation." + Laurent Dinh, David Krueger, Yoshua Bengio. ICLR. 2015. + https://arxiv.org/abs/1410.8516 + + [4]: "Normalizing Flows Tutorial, Part 2: Modern Normalizing Flows." + Eric Jang. Blog post. January 2018. + http://blog.evjang.com/2018/01/nf2.html + """ + + def __init__(self, + num_masked, + shift_and_log_scale_fn, + is_constant_jacobian=False, + validate_args=False, + name=None): + """Creates the Real NVP or NICE bijector. + + Args: + num_masked: Python `int` indicating that the first `d` units of the event + should be masked. Must be in the closed interval `[1, D-1]`, where `D` + is the event size of the base distribution. + shift_and_log_scale_fn: Python `callable` which computes `shift` and + `log_scale` from both the forward domain (`x`) and the inverse domain + (`y`). Calculation must respect the "autoregressive property" (see class + docstring). Suggested default + `masked_autoregressive_default_template(hidden_layers=...)`. + Typically the function contains `tf.Variables` and is wrapped using + `tf.make_template`. Returning `None` for either (both) `shift`, + `log_scale` is equivalent to (but more efficient than) returning zero. + is_constant_jacobian: Python `bool`. Default: `False`. When `True` the + implementation assumes `log_scale` does not depend on the forward domain + (`x`) or inverse domain (`y`) values. (No validation is made; + `is_constant_jacobian=False` is always safe but possibly computationally + inefficient.) + validate_args: Python `bool` indicating whether arguments should be + checked for correctness. + name: Python `str`, name given to ops managed by this object. + + Raises: + ValueError: If num_masked < 1. + """ + name = name or "real_nvp" + if num_masked <= 0: + raise ValueError("num_masked must be a positive integer.") + self._num_masked = num_masked + # At construction time, we don't know input_depth. + self._input_depth = None + self._shift_and_log_scale_fn = shift_and_log_scale_fn + super(RealNVP, self).__init__( + event_ndims=1, + is_constant_jacobian=is_constant_jacobian, + validate_args=validate_args, + name=name) + + def _cache_input_depth(self, x): + if self._input_depth is None: + self._input_depth = x.shape.with_rank_at_least(1)[-1].value + if self._input_depth is None: + raise NotImplementedError( + "Rightmost dimension must be known prior to graph execution.") + if self._num_masked >= self._input_depth: + raise ValueError( + "Number of masked units must be smaller than the event size.") + + def _forward(self, x): + self._cache_input_depth(x) + # Performs scale and shift. + x0, x1 = x[:, :self._num_masked], x[:, self._num_masked:] + shift, log_scale = self._shift_and_log_scale_fn( + x0, self._input_depth - self._num_masked) + y1 = x1 + if log_scale is not None: + y1 *= math_ops.exp(log_scale) + if shift is not None: + y1 += shift + y = array_ops.concat([x0, y1], axis=-1) + return y + + def _inverse(self, y): + self._cache_input_depth(y) + # Performs un-shift and un-scale. + y0, y1 = y[:, :self._num_masked], y[:, self._num_masked:] + shift, log_scale = self._shift_and_log_scale_fn( + y0, self._input_depth - self._num_masked) + x1 = y1 + if shift is not None: + x1 -= shift + if log_scale is not None: + x1 *= math_ops.exp(-log_scale) + x = array_ops.concat([y0, x1], axis=-1) + return x + + def _inverse_log_det_jacobian(self, y): + self._cache_input_depth(y) + y0 = y[:, :self._num_masked] + _, log_scale = self._shift_and_log_scale_fn( + y0, self._input_depth - self._num_masked) + if log_scale is None: + return constant_op.constant(0., dtype=y.dtype, name="ildj") + return -math_ops.reduce_sum(log_scale, axis=-1) + + def _forward_log_det_jacobian(self, x): + self._cache_input_depth(x) + x0 = x[:, :self._num_masked] + _, log_scale = self._shift_and_log_scale_fn( + x0, self._input_depth - self._num_masked) + if log_scale is None: + return constant_op.constant(0., dtype=x.dtype, name="ildj") + return math_ops.reduce_sum(log_scale, axis=-1) + + +def real_nvp_default_template( + hidden_layers, + shift_only=False, + activation=nn_ops.relu, + name=None, + *args, + **kwargs): + """Build a scale-and-shift function using a multi-layer neural network. + + This will be wrapped in a make_template to ensure the variables are only + created once. It takes the `d`-dimensional input x[0:d] and returns the `D-d` + dimensional outputs `loc` ("mu") and `log_scale` ("alpha"). + + Arguments: + hidden_layers: Python `list`-like of non-negative integer, scalars + indicating the number of units in each hidden layer. Default: `[512, 512]. + shift_only: Python `bool` indicating if only the `shift` term shall be + computed (i.e. NICE bijector). Default: `False`. + activation: Activation function (callable). Explicitly setting to `None` + implies a linear activation. + name: A name for ops managed by this function. Default: + "real_nvp_default_template". + *args: `tf.layers.dense` arguments. + **kwargs: `tf.layers.dense` keyword arguments. + + Returns: + shift: `Float`-like `Tensor` of shift terms (the "mu" in [2]). + log_scale: `Float`-like `Tensor` of log(scale) terms (the "alpha" in [2]). + + Raises: + NotImplementedError: if rightmost dimension of `inputs` is unknown prior to + graph execution. + """ + + with ops.name_scope(name, "real_nvp_default_template"): + def _fn(x, output_units): + """Fully connected MLP parameterized via `real_nvp_template`.""" + for units in hidden_layers: + x = layers.dense( + inputs=x, + units=units, + activation=activation, + *args, + **kwargs) + x = layers.dense( + inputs=x, + units=(1 if shift_only else 2) * output_units, + activation=None, + *args, + **kwargs) + if shift_only: + return x, None + shift, log_scale = array_ops.split(x, 2, axis=-1) + return shift, log_scale + return template_ops.make_template( + "real_nvp_default_template", _fn) -- GitLab From 03975654063aa72bb2aa93b28aff544b22c677f9 Mon Sep 17 00:00:00 2001 From: Yifei Feng Date: Tue, 23 Jan 2018 23:43:35 -0800 Subject: [PATCH 167/258] Make graph transform tool accessible via command line for pip install. (#15967) * Make graph transform tool accessible via command line for pip install. RELNOTE: Make graph transform tool available from command line as `transform_graph` for pip package. Fix #13287. * Fix buildifier format error. * Make wrapper work with bazel. * Update bazel path to data dir. --- tensorflow/tools/graph_transforms/BUILD | 12 ++++++ .../graph_transforms_wrapper.py | 39 +++++++++++++++++++ tensorflow/tools/pip_package/BUILD | 2 + .../tools/pip_package/build_pip_package.sh | 4 +- tensorflow/tools/pip_package/setup.py | 1 + 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tensorflow/tools/graph_transforms/graph_transforms_wrapper.py diff --git a/tensorflow/tools/graph_transforms/BUILD b/tensorflow/tools/graph_transforms/BUILD index b5465b7fb3..31c4349431 100644 --- a/tensorflow/tools/graph_transforms/BUILD +++ b/tensorflow/tools/graph_transforms/BUILD @@ -317,6 +317,18 @@ tf_py_test( main = "python/transform_graph_test.py", ) +py_binary( + name = "graph_transforms_wrapper", + srcs = ["graph_transforms_wrapper.py"], + srcs_version = "PY2AND3", + data = [ + ":transform_graph", + ], + deps = [ + "//tensorflow:tensorflow_py", + ], +) + filegroup( name = "all_files", srcs = glob( diff --git a/tensorflow/tools/graph_transforms/graph_transforms_wrapper.py b/tensorflow/tools/graph_transforms/graph_transforms_wrapper.py new file mode 100644 index 0000000000..e12feddba2 --- /dev/null +++ b/tensorflow/tools/graph_transforms/graph_transforms_wrapper.py @@ -0,0 +1,39 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Wrapper for runninmg graph_transform binary embedded in pip site-package. +NOTE: this mainly exists since PIP setup.py cannot install binaries to bin/. +It can only install Python "console-scripts." This will work as a console +script. See tools/pip_package/setup.py (search for CONSOLE_SCRIPTS). +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import sys +import tensorflow as tf + + +def main(): + # Pip installs the binary in aux-bin off of main site-package install. + # Just find it and exec, passing all arguments in the process. + pip_binary = os.path.join(tf.__path__[0], 'aux-bin/transform_graph') + bazel_binary = ('bazel-bin/tensorflow/tools/graph_transforms/' + 'graph_transforms_wrapper.runfiles/org_tensorflow/' + 'tensorflow/tools/graph_transforms/transform_graph') + binary = bazel_binary if os.path.isfile(bazel_binary) else pip_binary + os.execvp(binary, sys.argv) + +main() diff --git a/tensorflow/tools/pip_package/BUILD b/tensorflow/tools/pip_package/BUILD index c789e2ba0c..d61ddb889c 100644 --- a/tensorflow/tools/pip_package/BUILD +++ b/tensorflow/tools/pip_package/BUILD @@ -179,6 +179,8 @@ sh_binary( "//tensorflow/python/tools:tools_pip", "//tensorflow/python:test_ops", "//tensorflow/tools/dist_test/server:grpc_tensorflow_server", + "//tensorflow/tools/graph_transforms:graph_transforms_wrapper", + "//tensorflow/tools/graph_transforms:transform_graph", ], }) + if_mkl(["//third_party/mkl:intel_binary_blob"]), ) diff --git a/tensorflow/tools/pip_package/build_pip_package.sh b/tensorflow/tools/pip_package/build_pip_package.sh index ca8c272a08..32b8c54a56 100755 --- a/tensorflow/tools/pip_package/build_pip_package.sh +++ b/tensorflow/tools/pip_package/build_pip_package.sh @@ -137,9 +137,11 @@ function main() { fi fi fi - # Install toco as a binary in aux-bin. mkdir "${TMPDIR}/tensorflow/aux-bin" + # Install toco as a binary in aux-bin. cp bazel-bin/tensorflow/contrib/lite/toco/toco ${TMPDIR}/tensorflow/aux-bin/ + # Install graph transform tool as a bianry in aux-bin + cp bazel-bin/tensorflow/tools/graph_transforms/transform_graph ${TMPDIR}/tensorflow/aux-bin/ fi # protobuf pip package doesn't ship with header files. Copy the headers diff --git a/tensorflow/tools/pip_package/setup.py b/tensorflow/tools/pip_package/setup.py index 62df6453fb..0034fe447c 100644 --- a/tensorflow/tools/pip_package/setup.py +++ b/tensorflow/tools/pip_package/setup.py @@ -74,6 +74,7 @@ CONSOLE_SCRIPTS = [ 'freeze_graph = tensorflow.python.tools.freeze_graph:main', 'toco_from_protos = tensorflow.contrib.lite.toco.python.toco_from_protos:main', 'toco = tensorflow.contrib.lite.toco.python.toco_wrapper:main', + 'transform_graph = tensorflow.tools.graph_transforms.graph_transforms_wrapper:main', 'saved_model_cli = tensorflow.python.tools.saved_model_cli:main', # We need to keep the TensorBoard command, even though the console script # is now declared by the tensorboard pip package. If we remove the -- GitLab From 7c687707ee6e5aecc045be4c80a732585c7b045b Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Wed, 24 Jan 2018 16:45:59 +0900 Subject: [PATCH 168/258] Fix typo (#16340) * fix typo * fix typo --- tensorflow/python/estimator/canned/dnn_testing_utils.py | 2 +- tensorflow/python/estimator/canned/linear_testing_utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/estimator/canned/dnn_testing_utils.py b/tensorflow/python/estimator/canned/dnn_testing_utils.py index 2bdec69303..706575985f 100644 --- a/tensorflow/python/estimator/canned/dnn_testing_utils.py +++ b/tensorflow/python/estimator/canned/dnn_testing_utils.py @@ -877,7 +877,7 @@ class BaseDNNWarmStartingTest(object): # Create a second DNNClassifier, warm-started from the first. Use a # learning_rate = 0.0 optimizer to check values (use SGD so we don't have - # accumulator values that change). Use a a new FeatureColumn with a + # accumulator values that change). Use a new FeatureColumn with a # different vocabulary for occupation. new_vocab_list = ['doctor', 'consultant', 'engineer'] new_vocab_file = os.path.join(self._ckpt_and_vocab_dir, diff --git a/tensorflow/python/estimator/canned/linear_testing_utils.py b/tensorflow/python/estimator/canned/linear_testing_utils.py index cccb9af4b2..3e9183cf1b 100644 --- a/tensorflow/python/estimator/canned/linear_testing_utils.py +++ b/tensorflow/python/estimator/canned/linear_testing_utils.py @@ -2003,7 +2003,7 @@ class BaseLinearWarmStartingTest(object): # Create a second LinearClassifier, warm-started from the first. Use a # learning_rate = 0.0 optimizer to check values (use SGD so we don't have - # accumulator values that change). Use a a new FeatureColumn with a + # accumulator values that change). Use a new FeatureColumn with a # different vocabulary for occupation. new_vocab_list = ['doctor', 'consultant', 'engineer'] new_vocab_file = os.path.join(self._ckpt_and_vocab_dir, -- GitLab From 2e5ff39e56fcc63475dd4ecae18e3724695bf0a3 Mon Sep 17 00:00:00 2001 From: Taehoon Lee Date: Wed, 24 Jan 2018 16:48:23 +0900 Subject: [PATCH 169/258] Fix typos (#16349) --- tensorflow/cc/tools/freeze_saved_model_test.cc | 2 +- tensorflow/compiler/xla/tests/test_utils.cc | 2 +- .../contrib/opt/python/training/model_average_optimizer_test.py | 2 +- tensorflow/contrib/py2tf/api.py | 2 +- .../contrib/receptive_field/python/util/graph_compute_order.py | 2 +- tensorflow/contrib/verbs/README.md | 2 +- tensorflow/contrib/verbs/rdma.h | 2 +- tensorflow/core/kernels/mkl_softmax_op.cc | 2 +- tensorflow/python/layers/convolutional.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tensorflow/cc/tools/freeze_saved_model_test.cc b/tensorflow/cc/tools/freeze_saved_model_test.cc index 57244a4f0a..52a81a5028 100644 --- a/tensorflow/cc/tools/freeze_saved_model_test.cc +++ b/tensorflow/cc/tools/freeze_saved_model_test.cc @@ -71,7 +71,7 @@ class FreezeTest : public ::testing::Test { return Status::OK(); } - // Adds `graph_def` to `saved_model_bundle` and intializes a session with + // Adds `graph_def` to `saved_model_bundle` and initializes a session with // `init_node`. Status AddGraphDefToSavedModelBundle(const GraphDef& graph_def, const string& init_node, diff --git a/tensorflow/compiler/xla/tests/test_utils.cc b/tensorflow/compiler/xla/tests/test_utils.cc index 8b10aef5b8..0e90a32358 100644 --- a/tensorflow/compiler/xla/tests/test_utils.cc +++ b/tensorflow/compiler/xla/tests/test_utils.cc @@ -34,7 +34,7 @@ void PopulateWithRandomFloatingPointData(Literal* literal) { TF_CHECK_OK(literal->Populate( [&](tensorflow::gtl::ArraySlice indices) { // Generate a random uniforma number from -0.0625 and 0.0625 and bias it - // with a position dependent nubmer with mean 0.037109375. These number + // with a position dependent number with mean 0.037109375. These number // should allow for long chains of accumulation without being too close // to zero or to large to accumulate all numbers accurately. return (generator(engine) - 1.0625) + diff --git a/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py b/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py index a73aa772bb..a264946057 100644 --- a/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py +++ b/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py @@ -148,7 +148,7 @@ class ModelAverageOptimizerTest(test.TestCase): self.assertAllEqual(1.0, sessions[0].run(global_var_1)) self.assertAllEqual(0, sessions[0].run(global_step)) - # iteration 2, global varibale update + # iteration 2, global variable update thread_0 = self.checkedThread( target=self._run, args=(train_ops[0], sessions[0])) thread_1 = self.checkedThread( diff --git a/tensorflow/contrib/py2tf/api.py b/tensorflow/contrib/py2tf/api.py index 9a2b70c53c..0fd833e29c 100644 --- a/tensorflow/contrib/py2tf/api.py +++ b/tensorflow/contrib/py2tf/api.py @@ -86,7 +86,7 @@ def convert_inline(f, *args, **kwargs): def convert(recursive=False, arg_value_hints=None): """Decorator that compiles a function to graph mode. - The decorator is dynamic - invoking compilation whenever the decorated fuction + The decorator is dynamic - invoking compilation whenever the decorated function is called. This means the parameter values are known at compilation. Args: diff --git a/tensorflow/contrib/receptive_field/python/util/graph_compute_order.py b/tensorflow/contrib/receptive_field/python/util/graph_compute_order.py index b2360fec6c..0388079f20 100644 --- a/tensorflow/contrib/receptive_field/python/util/graph_compute_order.py +++ b/tensorflow/contrib/receptive_field/python/util/graph_compute_order.py @@ -61,7 +61,7 @@ def _compute_output_resolution(input_spatial_resolution, kernel_size, stride, stride: Stride (int). total_padding: Total padding to be applied (int). Returns: - output_resolution: Ouput dimension (int) or None. + output_resolution: Output dimension (int) or None. """ if (input_spatial_resolution is None) or (kernel_size is None) or ( stride is None) or (total_padding is None): diff --git a/tensorflow/contrib/verbs/README.md b/tensorflow/contrib/verbs/README.md index 1b99f4ce4f..647e68c695 100644 --- a/tensorflow/contrib/verbs/README.md +++ b/tensorflow/contrib/verbs/README.md @@ -115,7 +115,7 @@ When the receiver receives the RDMA write, it will locate the relevant **RdmaTen * Reallocate the result tensor (and proxy tensor if required). * Re-send the request to the remote side. * **RecvTensorContent()** - Receive tensor content from the remote side (RDMA write was completed). - * Decode proto if required and/or move to GPU if the content was not written to it directly (GPU direct is not avaliable). + * Decode proto if required and/or move to GPU if the content was not written to it directly (GPU direct is not available). * Invoke the done callback. * **class RdmaTensorResponse** - Holds and manages information for a single tensor response throughout the entire send cycle. API: * **Start()** - Start the response sequence. diff --git a/tensorflow/contrib/verbs/rdma.h b/tensorflow/contrib/verbs/rdma.h index 68b3d59f56..d57c5138b1 100644 --- a/tensorflow/contrib/verbs/rdma.h +++ b/tensorflow/contrib/verbs/rdma.h @@ -269,7 +269,7 @@ class RdmaTensorRequest { // Receive tensor content (RDMA write was completed). // // Decode proto if required and/or move to GPU if the content was not - // written to it directly (GPU direct is not avaliable). Afterwards, + // written to it directly (GPU direct is not available). Afterwards, // invoke Done(). void RecvTensorContent(); diff --git a/tensorflow/core/kernels/mkl_softmax_op.cc b/tensorflow/core/kernels/mkl_softmax_op.cc index 896d562933..e976632514 100644 --- a/tensorflow/core/kernels/mkl_softmax_op.cc +++ b/tensorflow/core/kernels/mkl_softmax_op.cc @@ -105,7 +105,7 @@ class MklSoftmaxOp : public OpKernel { // Softmax MklDnn output layout is same as input layout. auto dst_pd = src.GetUsrMemPrimDesc(); - // if input is MKL shape, ouput is also MKL shape. + // if input is MKL shape, output is also MKL shape. // if input is TF shape, output is also TF shape if (src_mkl_shape.IsMklTensor()) { output_mkl_shape.SetMklTensor(true); diff --git a/tensorflow/python/layers/convolutional.py b/tensorflow/python/layers/convolutional.py index 79c421f4c9..d5147b237b 100644 --- a/tensorflow/python/layers/convolutional.py +++ b/tensorflow/python/layers/convolutional.py @@ -1094,7 +1094,7 @@ class SeparableConv1D(_SeparableConv): strides = (1, 1, 1) + self.strides spatial_start_dim = 2 - # Explictly broadcast inputs and kernels to 4D. + # Explicitly broadcast inputs and kernels to 4D. # TODO(fchollet): refactor when a native separable_conv1d op is available. inputs = array_ops.expand_dims(inputs, spatial_start_dim) depthwise_kernel = array_ops.expand_dims(self.depthwise_kernel, 0) -- GitLab From 41a3bfe1e970b420ac2454020487cafa5a7cd0b6 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 01:17:31 -0800 Subject: [PATCH 170/258] Use RunConfig.master to set up the Session for running prediction in Estimator.predict() PiperOrigin-RevId: 183053484 --- tensorflow/python/estimator/estimator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/python/estimator/estimator.py b/tensorflow/python/estimator/estimator.py index 90eecc1fda..b4c6b2747e 100644 --- a/tensorflow/python/estimator/estimator.py +++ b/tensorflow/python/estimator/estimator.py @@ -453,6 +453,7 @@ class Estimator(object): with training.MonitoredSession( session_creator=training.ChiefSessionCreator( checkpoint_filename_with_path=checkpoint_path, + master=self._config.master, scaffold=estimator_spec.scaffold, config=self._session_config), hooks=input_hooks + hooks) as mon_sess: -- GitLab From 6ce118c193561e500fa5ed3e4b3683c4d447ff76 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Wed, 24 Jan 2018 21:24:54 +0900 Subject: [PATCH 171/258] fix typo --- tensorflow/core/profiler/internal/tfprof_stats.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/core/profiler/internal/tfprof_stats.h b/tensorflow/core/profiler/internal/tfprof_stats.h index d78abda588..01b17e2679 100644 --- a/tensorflow/core/profiler/internal/tfprof_stats.h +++ b/tensorflow/core/profiler/internal/tfprof_stats.h @@ -83,7 +83,7 @@ class TFStats { const MultiGraphNodeProto& ShowMultiGraphNode(const string& cmd, const Options& opts) const; - // A a (partial) graph to existing graph. + // Add a (partial) graph to existing graph. void AddGraph(std::unique_ptr graph); // Add a step of run time meta data. @@ -118,7 +118,7 @@ class TFStats { MultiGraphNodeProto empty_multi_graph_node_; std::map id_to_string_; - // Graph nodes covered by RunMetdata, that is traced with run time stats. + // Graph nodes covered by RunMetadata, that is traced with run time stats. std::set covered_nodes_; }; -- GitLab From 61d12729f7607caad8ddae30f4727042a353fb6e Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Wed, 24 Jan 2018 06:21:09 -0800 Subject: [PATCH 172/258] [TPU] Raise error for unimplemented TPU op. Raise an error as soon as detected that an unsupported TPU op is added. Update the list of unimplemented ops. PiperOrigin-RevId: 183076718 --- tensorflow/compiler/tf2xla/xla_op_registry.cc | 2 + tensorflow/contrib/tpu/python/tpu/tpu.py | 511 +++++++++++++++++- 2 files changed, 491 insertions(+), 22 deletions(-) diff --git a/tensorflow/compiler/tf2xla/xla_op_registry.cc b/tensorflow/compiler/tf2xla/xla_op_registry.cc index 0dde6a986c..bbe808595d 100644 --- a/tensorflow/compiler/tf2xla/xla_op_registry.cc +++ b/tensorflow/compiler/tf2xla/xla_op_registry.cc @@ -255,6 +255,8 @@ void XlaOpRegistry::RegisterCompilationKernels() { std::vector XlaOpRegistry::DeviceKernels( const string& compilation_device_name, bool include_compilation_only_kernels) { + // Ensure compilation kernels registered. + RegisterCompilationKernels(); std::vector kernels; XlaOpRegistry& registry = Instance(); mutex_lock lock(registry.mutex_); diff --git a/tensorflow/contrib/tpu/python/tpu/tpu.py b/tensorflow/contrib/tpu/python/tpu/tpu.py index 8fec379aad..d552f77f50 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu.py @@ -37,21 +37,479 @@ from tensorflow.python.util import compat # that's introduced outside of the infeed. _BLACKLISTED_OPS = set([ "Placeholder", + "PlaceholderV2", + "PlaceholderWithDefault", + "ScalarSummary", +]) + +# Operations that are deprecated and won't be implemented. +_DEPRECATED_OPS = set([ + "AdjustContrast", + "AudioSummary", + "BatchCholesky", + "BatchCholeskyGrad", + "BatchFFT", + "BatchFFT2D", + "BatchFFT3D", + "BatchIFFT", + "BatchIFFT2D", + "BatchIFFT3D", + "BatchMatrixBandPart", + "BatchMatrixDeterminant", + "BatchMatrixDiag", + "BatchMatrixDiagPart", + "BatchMatrixInverse", + "BatchMatrixSetDiag", + "BatchMatrixSolve", + "BatchMatrixSolveLs", + "BatchMatrixTriangularSolve", + "BatchNormWithGlobalNormalization", + "BatchNormWithGlobalNormalizationGrad", + "BatchSelfAdjointEig", + "BatchSelfAdjointEigV2", + "BatchSvd", + "Conv3DBackpropFilter", + "Conv3DBackpropInput", + "FixedLengthRecordReader", + "IdentityReader", + "NegTrain", + "PlaceholderV2", + "QuantizeAndDequantize", + "RandomCrop", + "RandomPoisson", + "SelfAdjointEig", + "Skipgram", + "TFRecordReader", + "TensorArray", + "TensorArrayClose", + "TensorArrayCloseV2", + "TensorArrayConcat", + "TensorArrayConcatV2", + "TensorArrayGather", + "TensorArrayGatherV2", + "TensorArrayGrad", + "TensorArrayGradV2", + "TensorArrayPack", + "TensorArrayRead", + "TensorArrayReadV2", + "TensorArrayScatter", + "TensorArrayScatterV2", + "TensorArraySize", + "TensorArraySizeV2", + "TensorArraySplit", + "TensorArraySplitV2", + "TensorArrayUnpack", + "TensorArrayV2", + "TensorArrayWrite", + "TensorArrayWriteV2", + "TextLineReader", + "TileGrad", + "TopK", +]) + +# Operations that don't make it to the TPU but are added to the graph. +_TRANSFORMED_OPS = set([ + "Enter", + "Exit", + "LoopCond", + "Merge", + "NextIteration", + "Switch", + "TPUReplicateMetadata", ]) # These operations will currently fail to compile, but we should be able to # support them eventually via CPU offload or extending our operation set. _NOT_IMPLEMENTED_OPS = set([ - "AudioSummary", + "Abort", + "AccumulateNV2", + "Acos", + "AddManySparseToTensorsMap", + "AddSparseToTensorsMap", + "AddV2", + "AllCandidateSampler", + "Asin", + "AsString", + "Atan", + "AudioSpectrogram", "AudioSummaryV2", + "BatchDataset", + "Betainc", + "Bincount", + "Bitcast", + "BitwiseXor", + "Bucketize", + "BytesProducedStatsDataset", + "CacheDataset", + "CholeskyGrad", + "CompareAndBitpack", + "ComputeAccidentalHits", + "ConcatenateDataset", + "ConjugateTranspose", + "Copy", + "CopyHost", + "CriticalSectionOp", + "CropAndResize", + "CropAndResizeGradBoxes", + "CropAndResizeGradImage", + "CTCBeamSearchDecoder", + "CTCGreedyDecoder", + "CTCLoss", + "Cumprod", + "DataFormatDimMap", + "DataFormatVecPermute", + "DatasetToSingleElement", + "DebugGradientIdentity", + "DebugIdentity", + "DebugNanCount", + "DebugNumericSummary", + "DecodeAndCropJpeg", + "DecodeBase64", + "DecodeBmp", + "DecodeCompressed", + "DecodeCSV", + "DecodeGif", + "DecodeJpeg", + "DecodeJSONExample", + "DecodePng", + "DecodeRaw", + "DecodeWav", + "DeleteSessionTensor", + "DenseToDenseSetOperation", + "DenseToSparseBatchDataset", + "DenseToSparseSetOperation", + "Dequantize", + "DeserializeIterator", + "DeserializeManySparse", + "DeserializeSparse", + "DestroyResourceOp", + "Digamma", + "Dilation2D", + "Dilation2DBackpropFilter", + "Dilation2DBackpropInput", + "DrawBoundingBoxes", + "DynamicPartition", + "EagerPyFunc", + "EditDistance", + "EmptyTensorList", + "EncodeBase64", + "EncodeJpeg", + "EncodePng", + "EncodeWav", + "Erf", + "Erfc", + "ExecuteInCriticalSection", + "ExtractGlimpse", + "ExtractImagePatches", + "ExtractJpegShape", + "Fact", + "FakeQuantWithMinMaxArgs", + "FakeQuantWithMinMaxArgsGradient", + "FakeQuantWithMinMaxVars", + "FakeQuantWithMinMaxVarsGradient", + "FakeQuantWithMinMaxVarsPerChannel", + "FakeQuantWithMinMaxVarsPerChannelGradient", + "FIFOQueueV2", + "FilterDataset", + "FixedLengthRecordDataset", + "FixedLengthRecordReaderV2", + "FixedUnigramCandidateSampler", + "FlatMapDataset", + "FractionalAvgPool", + "FractionalAvgPoolGrad", + "FractionalMaxPool", + "FractionalMaxPoolGrad", + "FusedPadConv2D", + "FusedResizeAndPadConv2D", + "GatherNd", + "GenerateVocabRemapping", + "GetSessionHandle", + "GetSessionHandleV2", + "GetSessionTensor", + "GroupByWindowDataset", + "GuaranteeConst", + "HashTableV2", + "HistogramFixedWidth", "HistogramSummary", + "IdentityReaderV2", + "Igamma", + "Igammac", + "IgnoreErrorsDataset", "ImageSummary", + "ImmutableConst", + "InitializeTableFromTextFileV2", + "InitializeTableV2", + "InterleaveDataset", + "InTopK", + "InTopKV2", + "InvGrad", + "Iterator", + "IteratorFromStringHandle", + "IteratorGetNext", + "IteratorSetStatsAggregator", + "IteratorToStringHandle", + "LatencyStatsDataset", + "LearnedUnigramCandidateSampler", + "Lgamma", + "ListDiff", + "LoadAndRemapMatrix", + "LogMatrixDeterminant", + "LogUniformCandidateSampler", + "LookupTableExportV2", + "LookupTableFindV2", + "LookupTableImportV2", + "LookupTableInsertV2", + "LookupTableSizeV2", + "MakeIterator", + "MapAndBatchDataset", + "MapClear", + "MapDataset", + "MapIncompleteSize", + "MapPeek", + "MapSize", + "MapStage", + "MapUnstage", + "MapUnstageNoKey", + "MatchingFiles", + "MatrixBandPart", + "MatrixDeterminant", + "MatrixExponential", + "MatrixInverse", + "MatrixSetDiag", + "MatrixSolve", + "MatrixSolveLs", + "MatrixTriangularSolve", + "MaxPool3DGradGrad", + "MaxPoolGradGrad", + "MaxPoolGradGradV2", + "MaxPoolGradGradWithArgmax", + "MaxPoolGradV2", + "MaxPoolGradWithArgmax", + "MaxPoolV2", + "MaxPoolWithArgmax", "MergeSummary", + "MergeV2Checkpoints", + "Mfcc", + "MirrorPadGrad", + "MutableDenseHashTableV2", + "MutableHashTableOfTensorsV2", + "MutableHashTableV2", + "NonMaxSuppression", + "NonMaxSuppressionV2", + "NthElement", + "OneShotIterator", + "OrderedMapClear", + "OrderedMapIncompleteSize", + "OrderedMapPeek", + "OrderedMapSize", + "OrderedMapStage", + "OrderedMapUnstage", + "OrderedMapUnstageNoKey", + "PaddedBatchDataset", + "PaddingFIFOQueueV2", + "ParallelConcat", + "ParallelInterleaveDataset", + "ParallelMapDataset", + "ParameterizedTruncatedNormal", + "ParseExample", + "ParseSingleExample", + "ParseSingleSequenceExample", + "ParseTensor", + "Placeholder", + "PlaceholderWithDefault", + "Polygamma", + "PopulationCount", + "PrefetchDataset", "Print", + "PriorityQueueV2", + "PyFunc", + "PyFuncStateless", + "Qr", + "QuantizeAndDequantizeV3", + "QuantizedAdd", + "QuantizedAvgPool", + "QuantizedBatchNormWithGlobalNormalization", + "QuantizedBiasAdd", + "QuantizedConcat", + "QuantizedConv2D", + "QuantizedInstanceNorm", + "QuantizedMatMul", + "QuantizedMaxPool", + "QuantizedMul", + "QuantizeDownAndShrinkRange", + "QuantizedRelu", + "QuantizedRelu6", + "QuantizedReluX", + "QuantizedReshape", + "QuantizedResizeBilinear", + "QuantizeV2", + "QueueCloseV2", + "QueueDequeueManyV2", + "QueueDequeueUpToV2", + "QueueDequeueV2", + "QueueEnqueueManyV2", + "QueueEnqueueV2", + "QueueIsClosedV2", + "QueueSizeV2", + "RandomDataset", + "RandomGamma", + "RandomPoissonV2", + "RandomShuffle", + "RandomShuffleQueueV2", + "RangeDataset", + "ReaderNumRecordsProducedV2", + "ReaderNumWorkUnitsCompletedV2", + "ReaderReadUpToV2", + "ReaderReadV2", + "ReaderResetV2", + "ReaderRestoreStateV2", + "ReaderSerializeStateV2", + "ReadFile", + "RecordInput", + "ReduceJoin", + "RemoteCall", + "RemoteFusedGraphExecute", + "RepeatDataset", + "RequantizationRange", + "Requantize", + "ResizeArea", + "ResizeBicubic", + "ResizeBicubicGrad", + "ResizeNearestNeighbor", + "ResizeNearestNeighborGrad", + "ResourceApplyAdadelta", + "ResourceApplyAdagradDA", + "ResourceApplyAddSign", + "ResourceApplyCenteredRMSProp", + "ResourceApplyPowerSign", + "ResourceApplyProximalAdagrad", + "ResourceApplyProximalGradientDescent", + "ResourceCountUpTo", + "ResourceScatterAdd", + "ResourceScatterNdUpdate", + "ResourceScatterUpdate", + "ResourceSparseApplyAdadelta", + "ResourceSparseApplyAdagrad", + "ResourceSparseApplyAdagradDA", + "ResourceSparseApplyCenteredRMSProp", + "ResourceSparseApplyFtrl", + "ResourceSparseApplyFtrlV2", + "ResourceSparseApplyMomentum", + "ResourceSparseApplyProximalAdagrad", + "ResourceSparseApplyProximalGradientDescent", + "ResourceSparseApplyRMSProp", + "Restore", + "RestoreSlice", + "RestoreV2", + "ReverseSequence", + "SampleDistortedBoundingBox", + "SampleDistortedBoundingBoxV2", + "Save", + "SaveSlices", + "SaveV2", "ScalarSummary", + "ScanDataset", + "ScatterNd", + "ScatterNdNonAliasingAdd", + "SdcaFprint", + "SdcaOptimizer", + "SegmentMax", + "SegmentMean", + "SegmentMin", + "SegmentProd", + "SegmentSum", + "SelfAdjointEigV2", + "SerializeIterator", + "SerializeManySparse", + "SerializeSparse", + "SerializeTensor", + "SetSize", + "ShardedFilename", + "ShardedFilespec", + "ShuffleAndRepeatDataset", + "ShuffleDataset", + "SkipDataset", + "Snapshot", + "SparseAdd", + "SparseAddGrad", + "SparseConcat", + "SparseCross", + "SparseDenseCwiseAdd", + "SparseDenseCwiseDiv", + "SparseDenseCwiseMul", + "SparseFillEmptyRows", + "SparseFillEmptyRowsGrad", + "SparseReduceMax", + "SparseReduceMaxSparse", + "SparseReduceSum", + "SparseReduceSumSparse", + "SparseReorder", + "SparseReshape", + "SparseSegmentMean", + "SparseSegmentMeanGrad", + "SparseSegmentMeanWithNumSegments", + "SparseSegmentSqrtN", + "SparseSegmentSqrtNGrad", + "SparseSegmentSqrtNWithNumSegments", + "SparseSegmentSum", + "SparseSegmentSumWithNumSegments", + "SparseSlice", + "SparseSoftmax", + "SparseSparseMaximum", + "SparseSparseMinimum", + "SparseSplit", + "SparseTensorDenseAdd", + "SparseTensorDenseMatMul", + "SparseTensorSliceDataset", + "SparseToDense", + "SparseToSparseSetOperation", + "SqlDataset", + "Stage", + "StageClear", + "StagePeek", + "StageSize", + "StatelessTruncatedNormal", + "StatsAggregatorHandle", + "StatsAggregatorSummary", + "StringJoin", + "StringSplit", + "StringToHashBucket", + "StringToHashBucketFast", + "StringToHashBucketStrong", + "StringToNumber", + "Substr", + "Svd", + "TakeDataset", + "TakeManySparseFromTensorsMap", + "TensorDataset", + "TensorListFromTensor", + "TensorListLength", + "TensorListPopBack", + "TensorListPushBack", + "TensorListStack", + "TensorSliceDataset", "TensorSummary", "TensorSummaryV2", - ]) + "TextLineDataset", + "TextLineReaderV2", + "TFRecordDataset", + "TFRecordReaderV2", + "ThreadUnsafeUnigramCandidateSampler", + "TopKV2", + "UniformCandidateSampler", + "Unique", + "UniqueDataset", + "UniqueV2", + "UniqueWithCounts", + "UnsortedSegmentMax", + "Unstage", + "VarHandleOp", + "Where", + "WholeFileReaderV2", + "WriteFile", + "Zeta", + "ZipDataset", +]) _MAX_WARNING_LINES = 5 @@ -124,32 +582,42 @@ class TPUReplicateContext(control_flow_ops.XLAControlFlowContext): def __init__(self, name): super(TPUReplicateContext, self).__init__() self._name = name - self._unsupported_ops = [] - - def report_unsupported_operations(self): - if self._unsupported_ops: - op_str = "\n".join([" %s (%s)" % (op.type, op.name) - for op in self._unsupported_ops[:_MAX_WARNING_LINES]]) - logging.warning("%d unsupported operations found: \n%s", - len(self._unsupported_ops), op_str) - if len(self._unsupported_ops) > _MAX_WARNING_LINES: - logging.warning("... and %d more" % - (len(self._unsupported_ops) - _MAX_WARNING_LINES)) + self._verified_functions = set() def AddOp(self, op): self._AddOpInternal(op) def _AddOpInternal(self, op): - # pylint: disable=protected-access - if op.type in _BLACKLISTED_OPS: - logging.error("Operation of type %s (%s) is not supported on the TPU. " - "Execution will fail if this op is used in the graph. " % - (op.type, op.name)) - if op.type in _NOT_IMPLEMENTED_OPS: - self._unsupported_ops.append(op) + def check_supported_type(op_name, op_type): + # pylint: disable=protected-access + if op_type in _TRANSFORMED_OPS: + pass + elif op_type in _BLACKLISTED_OPS: + logging.error( + "Operation of type `%s` (%s) is not supported on the TPU. " + "Compilation will fail if this op is used in the graph. ", op_type, + op_name) + elif op_type in _DEPRECATED_OPS: + raise NotImplementedError( + "Operation of type %s (%s) is deprecated and won't be supported on" + " TPU." % (op_type, op_name)) + elif op_type in _NOT_IMPLEMENTED_OPS: + raise NotImplementedError( + "Operation of type %s (%s) not supported on TPU." % (op_type, + op_name)) + elif op.graph._is_function(op_type): + if op_type not in self._verified_functions: + fun_def = op.graph._get_function(op_type).definition + for node in fun_def.node_def: + check_supported_type(node.name, node.op) + self._verified_functions.add(op_type) + # pylint: enable=protected-access - if any(x.dtype._is_ref_dtype for x in op.inputs): + # pylint: disable=protected-access + check_supported_type(op.name, op.type) + if any(x.dtype._is_ref_dtype for x in op.inputs) or any( + x.dtype._is_ref_dtype for x in op.outputs): raise NotImplementedError( "Non-resource Variables are not supported inside TPU computations " "(operator name: %s)" % op.name) @@ -360,7 +828,6 @@ def replicate(computation, new_output_tensors.append(array_ops.identity(t)) output_tensors = new_output_tensors finally: - context.report_unsupported_operations() context.Exit() # Fan-out: Builds a TPUReplicatedOutput node for each output. -- GitLab From 67cd3121296671d32c8150e9e57ac8f296f367ae Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 07:59:17 -0800 Subject: [PATCH 173/258] Remove unused ResizeBilinear options. Use a tensor to read new sizes. PiperOrigin-RevId: 183085403 --- .../contrib/lite/kernels/resize_bilinear.cc | 44 ++++++++++--------- .../lite/kernels/resize_bilinear_test.cc | 29 +++++++----- tensorflow/contrib/lite/schema/schema.fbs | 2 - .../testing/generated_examples_zip_test.cc | 5 ++- 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/tensorflow/contrib/lite/kernels/resize_bilinear.cc b/tensorflow/contrib/lite/kernels/resize_bilinear.cc index 1613c9a89f..9a419af023 100644 --- a/tensorflow/contrib/lite/kernels/resize_bilinear.cc +++ b/tensorflow/contrib/lite/kernels/resize_bilinear.cc @@ -33,49 +33,53 @@ enum KernelType { }; constexpr int kInputTensor = 0; +constexpr int kSizeTensor = 1; constexpr int kOutputTensor = 0; TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { - auto* params = - reinterpret_cast(node->builtin_data); - - TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); TfLiteTensor* input = GetInput(context, node, kInputTensor); + TfLiteTensor* size = GetInput(context, node, kSizeTensor); TfLiteTensor* output = GetOutput(context, node, kOutputTensor); // TODO(ahentz): Our current implementations rely on the inputs being 4D. TF_LITE_ENSURE_EQ(context, NumDimensions(input), 4); + TF_LITE_ENSURE_EQ(context, NumDimensions(size), 1); // TODO(ahentz): Our current implementations only support float32. - TF_LITE_ENSURE_EQ(context, output->type, kTfLiteFloat32); - TF_LITE_ENSURE_EQ(context, input->type, output->type); - - TfLiteIntArray* output_size = TfLiteIntArrayCreate(4); - output_size->data[0] = input->dims->data[0]; - output_size->data[1] = params->new_height; - output_size->data[2] = params->new_width; - output_size->data[3] = input->dims->data[3]; - - return context->ResizeTensor(context, output, output_size); + TF_LITE_ENSURE_EQ(context, input->type, kTfLiteFloat32); + TF_LITE_ENSURE_EQ(context, size->type, kTfLiteInt32); + // ResizeBilinear creates a float tensor even when the input is made of + // integers. + output->type = kTfLiteFloat32; + + // TODO(ahentz): if the input is constant, we can allocate here. + output->allocation_type = kTfLiteDynamic; + return kTfLiteOk; } template TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { - auto* params = - reinterpret_cast(node->builtin_data); - TfLiteTensor* input = GetInput(context, node, kInputTensor); TfLiteTensor* output = GetOutput(context, node, kOutputTensor); + TfLiteTensor* size = GetInput(context, node, kSizeTensor); - // We have to fake a tensor here, to satisfy ResizeBilinear(). - int32 output_size_data[2] = {params->new_height, params->new_width}; + // TODO(ahentz): we only need to do this here if it wasn't done in Eval(). + TfLiteIntArray* output_size = TfLiteIntArrayCreate(4); + output_size->data[0] = input->dims->data[0]; + const int32* size_data = GetTensorData(size); + output_size->data[1] = size_data[0]; + output_size->data[2] = size_data[1]; + output_size->data[3] = input->dims->data[3]; + context->ResizeTensor(context, output, output_size); + TfLiteTensorRealloc(output->bytes, output); if (output->type == kTfLiteFloat32) { #define TF_LITE_RESIZE_BILINEAR(type) \ type::ResizeBilinear(GetTensorData(input), GetTensorDims(input), \ - output_size_data, GetTensorDims({1, 1, 1, 2}), \ + GetTensorData(size), GetTensorDims(size), \ GetTensorData(output), GetTensorDims(output)) if (kernel_type == kReference) { diff --git a/tensorflow/contrib/lite/kernels/resize_bilinear_test.cc b/tensorflow/contrib/lite/kernels/resize_bilinear_test.cc index 314a71e210..2b1aaf654f 100644 --- a/tensorflow/contrib/lite/kernels/resize_bilinear_test.cc +++ b/tensorflow/contrib/lite/kernels/resize_bilinear_test.cc @@ -25,47 +25,52 @@ using ::testing::ElementsAreArray; class ResizeBilinearOpModel : public SingleOpModel { public: - ResizeBilinearOpModel(std::initializer_list input_shape, int new_height, - int new_width) { + ResizeBilinearOpModel(std::initializer_list input_shape) { input_ = AddInput(TensorType_FLOAT32); + size_ = AddInput(TensorType_INT32); output_ = AddOutput(TensorType_FLOAT32); - SetBuiltinOp( - BuiltinOperator_RESIZE_BILINEAR, BuiltinOptions_ResizeBilinearOptions, - CreateResizeBilinearOptions(builder_, new_height, new_width).Union()); - BuildInterpreter({input_shape}); + SetBuiltinOp(BuiltinOperator_RESIZE_BILINEAR, + BuiltinOptions_ResizeBilinearOptions, + CreateResizeBilinearOptions(builder_).Union()); + BuildInterpreter({input_shape, {2}}); } void SetInput(std::initializer_list data) { PopulateTensor(input_, data); } + void SetSize(std::initializer_list data) { PopulateTensor(size_, data); } std::vector GetOutput() { return ExtractVector(output_); } private: int input_; + int size_; int output_; }; TEST(ResizeBilinearOpTest, HorizontalResize) { - ResizeBilinearOpModel m({1, 1, 2, 1}, 1, 3); + ResizeBilinearOpModel m({1, 1, 2, 1}); m.SetInput({3, 6}); + m.SetSize({1, 3}); m.Invoke(); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3, 5, 6}))); } TEST(ResizeBilinearOpTest, VerticalResize) { - ResizeBilinearOpModel m({1, 2, 1, 1}, 3, 1); + ResizeBilinearOpModel m({1, 2, 1, 1}); m.SetInput({3, 9}); + m.SetSize({3, 1}); m.Invoke(); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3, 7, 9}))); } TEST(ResizeBilinearOpTest, TwoDimensionalResize) { - ResizeBilinearOpModel m({1, 2, 2, 1}, 3, 3); + ResizeBilinearOpModel m({1, 2, 2, 1}); m.SetInput({ 3, 6, // 9, 12 // }); + m.SetSize({3, 3}); m.Invoke(); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ 3, 5, 6, // @@ -75,13 +80,14 @@ TEST(ResizeBilinearOpTest, TwoDimensionalResize) { } TEST(ResizeBilinearOpTest, TwoDimensionalResizeWithTwoBatches) { - ResizeBilinearOpModel m({2, 2, 2, 1}, 3, 3); + ResizeBilinearOpModel m({2, 2, 2, 1}); m.SetInput({ 3, 6, // 9, 12, // 4, 10, // 10, 16 // }); + m.SetSize({3, 3}); m.Invoke(); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ 3, 5, 6, // @@ -94,11 +100,12 @@ TEST(ResizeBilinearOpTest, TwoDimensionalResizeWithTwoBatches) { } TEST(ResizeBilinearOpTest, ThreeDimensionalResize) { - ResizeBilinearOpModel m({1, 2, 2, 2}, 3, 3); + ResizeBilinearOpModel m({1, 2, 2, 2}); m.SetInput({ 3, 4, 6, 10, // 9, 10, 12, 16, // }); + m.SetSize({3, 3}); m.Invoke(); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ 3, 4, 5, 8, 6, 10, // diff --git a/tensorflow/contrib/lite/schema/schema.fbs b/tensorflow/contrib/lite/schema/schema.fbs index 8ddad4d251..da7db9bcf4 100644 --- a/tensorflow/contrib/lite/schema/schema.fbs +++ b/tensorflow/contrib/lite/schema/schema.fbs @@ -266,8 +266,6 @@ table LSTMOptions { } table ResizeBilinearOptions { - new_height:int; - new_width:int; } // A call operation options diff --git a/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc b/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc index c29cd85c4d..36aa09090b 100644 --- a/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc +++ b/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc @@ -85,7 +85,10 @@ std::map kBrokenTests = { {R"(l2normdim=\[2,3\],epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, // ResizeBilinear looks completely incompatible with Tensorflow - {R"(resize_bilinear)", "67964336"}, + {R"(resize_bilinear.*dtype=tf.int32)", "72401107"}, + {R"(resize_bilinearalign_corners=True,.*,size=\[2,2\])", "72401483"}, + {R"(resize_bilinearalign_corners=True,.*,size=\[4,3\])", "72401483"}, + {R"(resize_bilinearalign_corners=True,.*,size=\[5,6\])", "72401483"}, // Transpose only supports 1D-4D input tensors. {R"(transposedtype=.*,input_shape=\[.,.,.,.,.\],perm=.*)", "71545879"}, -- GitLab From 0f103fbb49b952cfcdcdfcb38d011f59db6dd97e Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Wed, 24 Jan 2018 08:00:10 -0800 Subject: [PATCH 174/258] Automated g4 rollback of changelist 183076718 PiperOrigin-RevId: 183085489 --- tensorflow/compiler/tf2xla/xla_op_registry.cc | 2 - tensorflow/contrib/tpu/python/tpu/tpu.py | 511 +----------------- 2 files changed, 22 insertions(+), 491 deletions(-) diff --git a/tensorflow/compiler/tf2xla/xla_op_registry.cc b/tensorflow/compiler/tf2xla/xla_op_registry.cc index bbe808595d..0dde6a986c 100644 --- a/tensorflow/compiler/tf2xla/xla_op_registry.cc +++ b/tensorflow/compiler/tf2xla/xla_op_registry.cc @@ -255,8 +255,6 @@ void XlaOpRegistry::RegisterCompilationKernels() { std::vector XlaOpRegistry::DeviceKernels( const string& compilation_device_name, bool include_compilation_only_kernels) { - // Ensure compilation kernels registered. - RegisterCompilationKernels(); std::vector kernels; XlaOpRegistry& registry = Instance(); mutex_lock lock(registry.mutex_); diff --git a/tensorflow/contrib/tpu/python/tpu/tpu.py b/tensorflow/contrib/tpu/python/tpu/tpu.py index d552f77f50..8fec379aad 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu.py @@ -37,479 +37,21 @@ from tensorflow.python.util import compat # that's introduced outside of the infeed. _BLACKLISTED_OPS = set([ "Placeholder", - "PlaceholderV2", - "PlaceholderWithDefault", - "ScalarSummary", -]) - -# Operations that are deprecated and won't be implemented. -_DEPRECATED_OPS = set([ - "AdjustContrast", - "AudioSummary", - "BatchCholesky", - "BatchCholeskyGrad", - "BatchFFT", - "BatchFFT2D", - "BatchFFT3D", - "BatchIFFT", - "BatchIFFT2D", - "BatchIFFT3D", - "BatchMatrixBandPart", - "BatchMatrixDeterminant", - "BatchMatrixDiag", - "BatchMatrixDiagPart", - "BatchMatrixInverse", - "BatchMatrixSetDiag", - "BatchMatrixSolve", - "BatchMatrixSolveLs", - "BatchMatrixTriangularSolve", - "BatchNormWithGlobalNormalization", - "BatchNormWithGlobalNormalizationGrad", - "BatchSelfAdjointEig", - "BatchSelfAdjointEigV2", - "BatchSvd", - "Conv3DBackpropFilter", - "Conv3DBackpropInput", - "FixedLengthRecordReader", - "IdentityReader", - "NegTrain", - "PlaceholderV2", - "QuantizeAndDequantize", - "RandomCrop", - "RandomPoisson", - "SelfAdjointEig", - "Skipgram", - "TFRecordReader", - "TensorArray", - "TensorArrayClose", - "TensorArrayCloseV2", - "TensorArrayConcat", - "TensorArrayConcatV2", - "TensorArrayGather", - "TensorArrayGatherV2", - "TensorArrayGrad", - "TensorArrayGradV2", - "TensorArrayPack", - "TensorArrayRead", - "TensorArrayReadV2", - "TensorArrayScatter", - "TensorArrayScatterV2", - "TensorArraySize", - "TensorArraySizeV2", - "TensorArraySplit", - "TensorArraySplitV2", - "TensorArrayUnpack", - "TensorArrayV2", - "TensorArrayWrite", - "TensorArrayWriteV2", - "TextLineReader", - "TileGrad", - "TopK", -]) - -# Operations that don't make it to the TPU but are added to the graph. -_TRANSFORMED_OPS = set([ - "Enter", - "Exit", - "LoopCond", - "Merge", - "NextIteration", - "Switch", - "TPUReplicateMetadata", ]) # These operations will currently fail to compile, but we should be able to # support them eventually via CPU offload or extending our operation set. _NOT_IMPLEMENTED_OPS = set([ - "Abort", - "AccumulateNV2", - "Acos", - "AddManySparseToTensorsMap", - "AddSparseToTensorsMap", - "AddV2", - "AllCandidateSampler", - "Asin", - "AsString", - "Atan", - "AudioSpectrogram", + "AudioSummary", "AudioSummaryV2", - "BatchDataset", - "Betainc", - "Bincount", - "Bitcast", - "BitwiseXor", - "Bucketize", - "BytesProducedStatsDataset", - "CacheDataset", - "CholeskyGrad", - "CompareAndBitpack", - "ComputeAccidentalHits", - "ConcatenateDataset", - "ConjugateTranspose", - "Copy", - "CopyHost", - "CriticalSectionOp", - "CropAndResize", - "CropAndResizeGradBoxes", - "CropAndResizeGradImage", - "CTCBeamSearchDecoder", - "CTCGreedyDecoder", - "CTCLoss", - "Cumprod", - "DataFormatDimMap", - "DataFormatVecPermute", - "DatasetToSingleElement", - "DebugGradientIdentity", - "DebugIdentity", - "DebugNanCount", - "DebugNumericSummary", - "DecodeAndCropJpeg", - "DecodeBase64", - "DecodeBmp", - "DecodeCompressed", - "DecodeCSV", - "DecodeGif", - "DecodeJpeg", - "DecodeJSONExample", - "DecodePng", - "DecodeRaw", - "DecodeWav", - "DeleteSessionTensor", - "DenseToDenseSetOperation", - "DenseToSparseBatchDataset", - "DenseToSparseSetOperation", - "Dequantize", - "DeserializeIterator", - "DeserializeManySparse", - "DeserializeSparse", - "DestroyResourceOp", - "Digamma", - "Dilation2D", - "Dilation2DBackpropFilter", - "Dilation2DBackpropInput", - "DrawBoundingBoxes", - "DynamicPartition", - "EagerPyFunc", - "EditDistance", - "EmptyTensorList", - "EncodeBase64", - "EncodeJpeg", - "EncodePng", - "EncodeWav", - "Erf", - "Erfc", - "ExecuteInCriticalSection", - "ExtractGlimpse", - "ExtractImagePatches", - "ExtractJpegShape", - "Fact", - "FakeQuantWithMinMaxArgs", - "FakeQuantWithMinMaxArgsGradient", - "FakeQuantWithMinMaxVars", - "FakeQuantWithMinMaxVarsGradient", - "FakeQuantWithMinMaxVarsPerChannel", - "FakeQuantWithMinMaxVarsPerChannelGradient", - "FIFOQueueV2", - "FilterDataset", - "FixedLengthRecordDataset", - "FixedLengthRecordReaderV2", - "FixedUnigramCandidateSampler", - "FlatMapDataset", - "FractionalAvgPool", - "FractionalAvgPoolGrad", - "FractionalMaxPool", - "FractionalMaxPoolGrad", - "FusedPadConv2D", - "FusedResizeAndPadConv2D", - "GatherNd", - "GenerateVocabRemapping", - "GetSessionHandle", - "GetSessionHandleV2", - "GetSessionTensor", - "GroupByWindowDataset", - "GuaranteeConst", - "HashTableV2", - "HistogramFixedWidth", "HistogramSummary", - "IdentityReaderV2", - "Igamma", - "Igammac", - "IgnoreErrorsDataset", "ImageSummary", - "ImmutableConst", - "InitializeTableFromTextFileV2", - "InitializeTableV2", - "InterleaveDataset", - "InTopK", - "InTopKV2", - "InvGrad", - "Iterator", - "IteratorFromStringHandle", - "IteratorGetNext", - "IteratorSetStatsAggregator", - "IteratorToStringHandle", - "LatencyStatsDataset", - "LearnedUnigramCandidateSampler", - "Lgamma", - "ListDiff", - "LoadAndRemapMatrix", - "LogMatrixDeterminant", - "LogUniformCandidateSampler", - "LookupTableExportV2", - "LookupTableFindV2", - "LookupTableImportV2", - "LookupTableInsertV2", - "LookupTableSizeV2", - "MakeIterator", - "MapAndBatchDataset", - "MapClear", - "MapDataset", - "MapIncompleteSize", - "MapPeek", - "MapSize", - "MapStage", - "MapUnstage", - "MapUnstageNoKey", - "MatchingFiles", - "MatrixBandPart", - "MatrixDeterminant", - "MatrixExponential", - "MatrixInverse", - "MatrixSetDiag", - "MatrixSolve", - "MatrixSolveLs", - "MatrixTriangularSolve", - "MaxPool3DGradGrad", - "MaxPoolGradGrad", - "MaxPoolGradGradV2", - "MaxPoolGradGradWithArgmax", - "MaxPoolGradV2", - "MaxPoolGradWithArgmax", - "MaxPoolV2", - "MaxPoolWithArgmax", "MergeSummary", - "MergeV2Checkpoints", - "Mfcc", - "MirrorPadGrad", - "MutableDenseHashTableV2", - "MutableHashTableOfTensorsV2", - "MutableHashTableV2", - "NonMaxSuppression", - "NonMaxSuppressionV2", - "NthElement", - "OneShotIterator", - "OrderedMapClear", - "OrderedMapIncompleteSize", - "OrderedMapPeek", - "OrderedMapSize", - "OrderedMapStage", - "OrderedMapUnstage", - "OrderedMapUnstageNoKey", - "PaddedBatchDataset", - "PaddingFIFOQueueV2", - "ParallelConcat", - "ParallelInterleaveDataset", - "ParallelMapDataset", - "ParameterizedTruncatedNormal", - "ParseExample", - "ParseSingleExample", - "ParseSingleSequenceExample", - "ParseTensor", - "Placeholder", - "PlaceholderWithDefault", - "Polygamma", - "PopulationCount", - "PrefetchDataset", "Print", - "PriorityQueueV2", - "PyFunc", - "PyFuncStateless", - "Qr", - "QuantizeAndDequantizeV3", - "QuantizedAdd", - "QuantizedAvgPool", - "QuantizedBatchNormWithGlobalNormalization", - "QuantizedBiasAdd", - "QuantizedConcat", - "QuantizedConv2D", - "QuantizedInstanceNorm", - "QuantizedMatMul", - "QuantizedMaxPool", - "QuantizedMul", - "QuantizeDownAndShrinkRange", - "QuantizedRelu", - "QuantizedRelu6", - "QuantizedReluX", - "QuantizedReshape", - "QuantizedResizeBilinear", - "QuantizeV2", - "QueueCloseV2", - "QueueDequeueManyV2", - "QueueDequeueUpToV2", - "QueueDequeueV2", - "QueueEnqueueManyV2", - "QueueEnqueueV2", - "QueueIsClosedV2", - "QueueSizeV2", - "RandomDataset", - "RandomGamma", - "RandomPoissonV2", - "RandomShuffle", - "RandomShuffleQueueV2", - "RangeDataset", - "ReaderNumRecordsProducedV2", - "ReaderNumWorkUnitsCompletedV2", - "ReaderReadUpToV2", - "ReaderReadV2", - "ReaderResetV2", - "ReaderRestoreStateV2", - "ReaderSerializeStateV2", - "ReadFile", - "RecordInput", - "ReduceJoin", - "RemoteCall", - "RemoteFusedGraphExecute", - "RepeatDataset", - "RequantizationRange", - "Requantize", - "ResizeArea", - "ResizeBicubic", - "ResizeBicubicGrad", - "ResizeNearestNeighbor", - "ResizeNearestNeighborGrad", - "ResourceApplyAdadelta", - "ResourceApplyAdagradDA", - "ResourceApplyAddSign", - "ResourceApplyCenteredRMSProp", - "ResourceApplyPowerSign", - "ResourceApplyProximalAdagrad", - "ResourceApplyProximalGradientDescent", - "ResourceCountUpTo", - "ResourceScatterAdd", - "ResourceScatterNdUpdate", - "ResourceScatterUpdate", - "ResourceSparseApplyAdadelta", - "ResourceSparseApplyAdagrad", - "ResourceSparseApplyAdagradDA", - "ResourceSparseApplyCenteredRMSProp", - "ResourceSparseApplyFtrl", - "ResourceSparseApplyFtrlV2", - "ResourceSparseApplyMomentum", - "ResourceSparseApplyProximalAdagrad", - "ResourceSparseApplyProximalGradientDescent", - "ResourceSparseApplyRMSProp", - "Restore", - "RestoreSlice", - "RestoreV2", - "ReverseSequence", - "SampleDistortedBoundingBox", - "SampleDistortedBoundingBoxV2", - "Save", - "SaveSlices", - "SaveV2", "ScalarSummary", - "ScanDataset", - "ScatterNd", - "ScatterNdNonAliasingAdd", - "SdcaFprint", - "SdcaOptimizer", - "SegmentMax", - "SegmentMean", - "SegmentMin", - "SegmentProd", - "SegmentSum", - "SelfAdjointEigV2", - "SerializeIterator", - "SerializeManySparse", - "SerializeSparse", - "SerializeTensor", - "SetSize", - "ShardedFilename", - "ShardedFilespec", - "ShuffleAndRepeatDataset", - "ShuffleDataset", - "SkipDataset", - "Snapshot", - "SparseAdd", - "SparseAddGrad", - "SparseConcat", - "SparseCross", - "SparseDenseCwiseAdd", - "SparseDenseCwiseDiv", - "SparseDenseCwiseMul", - "SparseFillEmptyRows", - "SparseFillEmptyRowsGrad", - "SparseReduceMax", - "SparseReduceMaxSparse", - "SparseReduceSum", - "SparseReduceSumSparse", - "SparseReorder", - "SparseReshape", - "SparseSegmentMean", - "SparseSegmentMeanGrad", - "SparseSegmentMeanWithNumSegments", - "SparseSegmentSqrtN", - "SparseSegmentSqrtNGrad", - "SparseSegmentSqrtNWithNumSegments", - "SparseSegmentSum", - "SparseSegmentSumWithNumSegments", - "SparseSlice", - "SparseSoftmax", - "SparseSparseMaximum", - "SparseSparseMinimum", - "SparseSplit", - "SparseTensorDenseAdd", - "SparseTensorDenseMatMul", - "SparseTensorSliceDataset", - "SparseToDense", - "SparseToSparseSetOperation", - "SqlDataset", - "Stage", - "StageClear", - "StagePeek", - "StageSize", - "StatelessTruncatedNormal", - "StatsAggregatorHandle", - "StatsAggregatorSummary", - "StringJoin", - "StringSplit", - "StringToHashBucket", - "StringToHashBucketFast", - "StringToHashBucketStrong", - "StringToNumber", - "Substr", - "Svd", - "TakeDataset", - "TakeManySparseFromTensorsMap", - "TensorDataset", - "TensorListFromTensor", - "TensorListLength", - "TensorListPopBack", - "TensorListPushBack", - "TensorListStack", - "TensorSliceDataset", "TensorSummary", "TensorSummaryV2", - "TextLineDataset", - "TextLineReaderV2", - "TFRecordDataset", - "TFRecordReaderV2", - "ThreadUnsafeUnigramCandidateSampler", - "TopKV2", - "UniformCandidateSampler", - "Unique", - "UniqueDataset", - "UniqueV2", - "UniqueWithCounts", - "UnsortedSegmentMax", - "Unstage", - "VarHandleOp", - "Where", - "WholeFileReaderV2", - "WriteFile", - "Zeta", - "ZipDataset", -]) + ]) _MAX_WARNING_LINES = 5 @@ -582,42 +124,32 @@ class TPUReplicateContext(control_flow_ops.XLAControlFlowContext): def __init__(self, name): super(TPUReplicateContext, self).__init__() self._name = name - self._verified_functions = set() + self._unsupported_ops = [] + + def report_unsupported_operations(self): + if self._unsupported_ops: + op_str = "\n".join([" %s (%s)" % (op.type, op.name) + for op in self._unsupported_ops[:_MAX_WARNING_LINES]]) + logging.warning("%d unsupported operations found: \n%s", + len(self._unsupported_ops), op_str) + if len(self._unsupported_ops) > _MAX_WARNING_LINES: + logging.warning("... and %d more" % + (len(self._unsupported_ops) - _MAX_WARNING_LINES)) def AddOp(self, op): self._AddOpInternal(op) def _AddOpInternal(self, op): + # pylint: disable=protected-access + if op.type in _BLACKLISTED_OPS: + logging.error("Operation of type %s (%s) is not supported on the TPU. " + "Execution will fail if this op is used in the graph. " % + (op.type, op.name)) - def check_supported_type(op_name, op_type): - # pylint: disable=protected-access - if op_type in _TRANSFORMED_OPS: - pass - elif op_type in _BLACKLISTED_OPS: - logging.error( - "Operation of type `%s` (%s) is not supported on the TPU. " - "Compilation will fail if this op is used in the graph. ", op_type, - op_name) - elif op_type in _DEPRECATED_OPS: - raise NotImplementedError( - "Operation of type %s (%s) is deprecated and won't be supported on" - " TPU." % (op_type, op_name)) - elif op_type in _NOT_IMPLEMENTED_OPS: - raise NotImplementedError( - "Operation of type %s (%s) not supported on TPU." % (op_type, - op_name)) - elif op.graph._is_function(op_type): - if op_type not in self._verified_functions: - fun_def = op.graph._get_function(op_type).definition - for node in fun_def.node_def: - check_supported_type(node.name, node.op) - self._verified_functions.add(op_type) - # pylint: enable=protected-access + if op.type in _NOT_IMPLEMENTED_OPS: + self._unsupported_ops.append(op) - # pylint: disable=protected-access - check_supported_type(op.name, op.type) - if any(x.dtype._is_ref_dtype for x in op.inputs) or any( - x.dtype._is_ref_dtype for x in op.outputs): + if any(x.dtype._is_ref_dtype for x in op.inputs): raise NotImplementedError( "Non-resource Variables are not supported inside TPU computations " "(operator name: %s)" % op.name) @@ -828,6 +360,7 @@ def replicate(computation, new_output_tensors.append(array_ops.identity(t)) output_tensors = new_output_tensors finally: + context.report_unsupported_operations() context.Exit() # Fan-out: Builds a TPUReplicatedOutput node for each output. -- GitLab From 1fc5c8393ab8903ed43cd8ced39d8b4a9b837960 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 08:35:13 -0800 Subject: [PATCH 175/258] Adds sharding in head_test to prevent timeouts. PiperOrigin-RevId: 183089222 --- tensorflow/python/estimator/BUILD | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/estimator/BUILD b/tensorflow/python/estimator/BUILD index 6343615737..58d540b1ec 100644 --- a/tensorflow/python/estimator/BUILD +++ b/tensorflow/python/estimator/BUILD @@ -624,8 +624,9 @@ py_library( py_test( name = "head_test", - size = "small", + size = "medium", srcs = ["canned/head_test.py"], + shard_count = 4, srcs_version = "PY2AND3", tags = ["no_pip"], deps = [ -- GitLab From a346b737046574a86268bf920e4c88f19a455830 Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Wed, 24 Jan 2018 09:01:25 -0800 Subject: [PATCH 176/258] Don't set unused Operation private fields if the C API is enabled. This helps catch invalid uses of the private fields with the C API enabled, and refactors Operation.__init__ in preparation for enabling the C API and eventually getting rid of the _USE_C_API toggle. PiperOrigin-RevId: 183092099 --- tensorflow/python/framework/ops.py | 31 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index 9d3806e8fe..6c4563f769 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -1583,7 +1583,6 @@ class Operation(object): "Cannot create a tensor proto whose content is larger than 2GB.") if not _VALID_OP_NAME_REGEX.match(node_def.name): raise ValueError("'%s' is not a valid node name" % node_def.name) - self._node_def_val = copy.deepcopy(node_def) c_op = None elif type(node_def).__name__ == "SwigPyObject": assert inputs is None @@ -1592,7 +1591,6 @@ class Operation(object): assert input_types is None assert original_op is None assert op_def is None - self._node_def_val = None c_op = node_def else: raise TypeError("node_def needs to be a NodeDef: %s" % node_def) @@ -1605,24 +1603,22 @@ class Operation(object): inputs = [] elif not isinstance(inputs, list): raise TypeError("inputs needs to be a list of Tensors: %s" % inputs) - self._inputs_val = list(inputs) # Defensive copy. - for a in self._inputs_val: + for a in inputs: if not isinstance(a, Tensor): raise TypeError("input needs to be a Tensor: %s" % a) if input_types is None: - input_types = [i.dtype.base_dtype for i in self._inputs_val] + input_types = [i.dtype.base_dtype for i in inputs] else: if not all( x.is_compatible_with(i.dtype) - for i, x in zip(self._inputs_val, input_types)): + for i, x in zip(inputs, input_types)): raise TypeError("In op '%s', input types (%s) are not compatible " "with expected types (%s)" % - (self.node_def.name, [i.dtype for i in self._inputs_val], + (self.node_def.name, [i.dtype for i in inputs], input_types)) - self._input_types_val = input_types # Build the list of control inputs. - self._control_inputs_val = [] + control_input_ops = [] if control_inputs: for c in control_inputs: control_op = None @@ -1633,11 +1629,20 @@ class Operation(object): else: raise TypeError("Control input must be an Operation, " "a Tensor, or IndexedSlices: %s" % c) - self._control_inputs_val.append(control_op) + control_input_ops.append(control_op) + + # Don't set private fields with C API enabled to catch users who need to + # switch to public API. + # TODO(skyewm): delete these fields once we remove _USE_C_API + if not self._graph._c_graph: + self._inputs_val = list(inputs) # Defensive copy. + self._input_types_val = input_types + self._control_inputs_val = control_input_ops + self._node_def_val = copy.deepcopy(node_def) + self._op_def_val = op_def self._id_value = self._graph._next_id() # pylint: disable=protected-access self._original_op = original_op - self._op_def_val = op_def self._traceback = self._graph._extract_stack() # pylint: disable=protected-access self._control_flow_context = self.graph._get_control_flow_context() # pylint: disable=protected-access @@ -1653,8 +1658,8 @@ class Operation(object): # Refactor so we don't have to do this here. grouped_inputs = self._reconstruct_sequence_inputs( op_def, inputs, node_def.attr) - self._c_op = _create_c_op(self._graph, self._node_def_val, grouped_inputs, - self._control_inputs_val) + self._c_op = _create_c_op(self._graph, node_def, grouped_inputs, + control_input_ops) else: self._c_op = None -- GitLab From 37bfad3c33c005077630b021ca927608dd70bb3e Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Wed, 24 Jan 2018 09:10:53 -0800 Subject: [PATCH 177/258] Allow setting per-thread device copying policies in TFE. PiperOrigin-RevId: 183093407 --- tensorflow/c/eager/c_api.cc | 19 ++++++++++- tensorflow/c/eager/c_api.h | 12 +++++++ tensorflow/c/eager/c_api_internal.h | 7 ++++ tensorflow/c/eager/c_api_test.cc | 49 ++++++++++++++++++++++++++++ tensorflow/python/eager/context.py | 12 +++++++ tensorflow/python/eager/core_test.py | 9 +++++ tensorflow/python/pywrap_tfe.i | 2 ++ 7 files changed, 109 insertions(+), 1 deletion(-) diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc index e56cfa5885..e4e33016c2 100644 --- a/tensorflow/c/eager/c_api.cc +++ b/tensorflow/c/eager/c_api.cc @@ -118,6 +118,23 @@ void TFE_ContextClearCaches(TFE_Context* ctx) { tensorflow::gtl::STLDeleteValues(&ctx->kernel_cache); } +void TFE_ContextSetThreadLocalDevicePlacementPolicy( + TFE_Context* ctx, TFE_ContextDevicePlacementPolicy policy) { + tensorflow::mutex_lock ml(ctx->policy_map_mu); + ctx->thread_local_policies[std::this_thread::get_id()] = policy; +} + +extern TFE_ContextDevicePlacementPolicy TFE_ContextGetDevicePlacementPolicy( + TFE_Context* ctx) { + tensorflow::mutex_lock ml(ctx->policy_map_mu); + auto policy_map_it = + ctx->thread_local_policies.find(std::this_thread::get_id()); + if (policy_map_it != ctx->thread_local_policies.end()) { + return policy_map_it->second; + } + return ctx->policy; +} + TFE_TensorHandle* TFE_NewTensorHandle(TF_Tensor* t, TF_Status* status) { tensorflow::Tensor tensor; status->status = tensorflow::TF_TensorToTensor(t, &tensor); @@ -434,7 +451,7 @@ tensorflow::Status ValidateInputTypeAndPlacement( const tensorflow::Device* actual_device = op->input_devices[i] == nullptr ? host_device : op->input_devices[i]; if (expected_device != actual_device) { - switch (ctx->policy) { + switch (TFE_ContextGetDevicePlacementPolicy(ctx)) { case TFE_DEVICE_PLACEMENT_EXPLICIT: // TODO(xpan): See if we could bubble python related error up // to python level. diff --git a/tensorflow/c/eager/c_api.h b/tensorflow/c/eager/c_api.h index 9b0fd037da..26e6d94753 100644 --- a/tensorflow/c/eager/c_api.h +++ b/tensorflow/c/eager/c_api.h @@ -93,6 +93,18 @@ TF_CAPI_EXPORT extern TF_DeviceList* TFE_ContextListDevices(TFE_Context* ctx, // ops. TF_CAPI_EXPORT extern void TFE_ContextClearCaches(TFE_Context* ctx); +// Sets a thread-local device placement policy. After this call, other calls to +// TFE_Execute in the same thread will use the device policy specified here +// instead of the device policy used to construct the context. This has no +// effect on the device policy used by other program threads. +TF_CAPI_EXPORT extern void TFE_ContextSetThreadLocalDevicePlacementPolicy( + TFE_Context*, TFE_ContextDevicePlacementPolicy); + +// Returns the device placement policy to be used by this context in the current +// thread. +TF_CAPI_EXPORT extern TFE_ContextDevicePlacementPolicy +TFE_ContextGetDevicePlacementPolicy(TFE_Context*); + // A handle to a tensor on a device. // // Like a TF_Tensor, a TFE_TensorHandle refers to a tensor with a value, shape, diff --git a/tensorflow/c/eager/c_api_internal.h b/tensorflow/c/eager/c_api_internal.h index 55a04d48ba..f40c41576c 100644 --- a/tensorflow/c/eager/c_api_internal.h +++ b/tensorflow/c/eager/c_api_internal.h @@ -21,6 +21,7 @@ limitations under the License. #include #include #include +#include #include #include "tensorflow/c/c_api.h" @@ -45,6 +46,12 @@ struct TFE_Context { TFE_ContextDevicePlacementPolicy policy; + // Note: we cannot use C++11 thread_local here as there is no concept of a + // thread-local-object-local variable in C++11. + tensorflow::mutex policy_map_mu; + std::unordered_map + thread_local_policies GUARDED_BY(policy_map_mu); + // TFE_Context is an extension of TF_Session. And TF_Session needs a TF_Graph. TF_Session* session; tensorflow::Rendezvous* rendezvous; diff --git a/tensorflow/c/eager/c_api_test.cc b/tensorflow/c/eager/c_api_test.cc index 423a7e1ff7..18e7a64435 100644 --- a/tensorflow/c/eager/c_api_test.cc +++ b/tensorflow/c/eager/c_api_test.cc @@ -321,6 +321,55 @@ TEST(CAPI, TensorHandleSilentCopy) { EXPECT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); } +TEST(CAPI, TensorHandleSilentCopyLocal) { + std::unique_ptr status( + TF_NewStatus(), TF_DeleteStatus); + TFE_ContextOptions* opts = TFE_NewContextOptions(); + TFE_ContextOptionsSetDevicePlacementPolicy(opts, + TFE_DEVICE_PLACEMENT_EXPLICIT); + TFE_Context* ctx = TFE_NewContext(opts, status.get()); + TFE_ContextSetThreadLocalDevicePlacementPolicy(ctx, + TFE_DEVICE_PLACEMENT_SILENT); + TFE_DeleteContextOptions(opts); + ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + + TFE_TensorHandle* hcpu = TestMatrixTensorHandle(); + TF_Tensor* t = TFE_TensorHandleResolve(hcpu, status.get()); + ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + + TF_DeviceList* devices = TFE_ContextListDevices(ctx, status.get()); + ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + const int num_devices = TF_DeviceListCount(devices); + + // Disable the test if no GPU is present. + if (num_devices > 1) { + const int device_to_use = 1; + const string name(TF_DeviceListName(devices, device_to_use, status.get())); + ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get()); + + TFE_TensorHandle* hgpu = + TFE_TensorHandleCopyToDevice(hcpu, ctx, name.c_str(), status.get()); + ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get()); + + TFE_Op* matmul = MatMulOp(ctx, hcpu, hgpu); + TFE_OpSetDevice(matmul, name.c_str(), status.get()); + ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get()); + TFE_TensorHandle* retvals[1]; + int num_retvals = 1; + TFE_Execute(matmul, &retvals[0], &num_retvals, status.get()); + ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get()); + TFE_DeleteOp(matmul); + TFE_DeleteTensorHandle(retvals[0]); + TFE_DeleteTensorHandle(hgpu); + } + + TF_DeleteDeviceList(devices); + TF_DeleteTensor(t); + TFE_DeleteTensorHandle(hcpu); + TFE_DeleteContext(ctx, status.get()); + EXPECT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); +} + TEST(CAPI, Execute) { TF_Status* status = TF_NewStatus(); TFE_ContextOptions* opts = TFE_NewContextOptions(); diff --git a/tensorflow/python/eager/context.py b/tensorflow/python/eager/context.py index cbf588336d..df483b69c4 100644 --- a/tensorflow/python/eager/context.py +++ b/tensorflow/python/eager/context.py @@ -411,6 +411,18 @@ class Context(object): self._initialize_handle_and_devices() pywrap_tensorflow.TFE_ContextEnableRunMetadata(self._context_handle) + @contextlib.contextmanager + def device_policy(self, policy): + old = pywrap_tensorflow.TFE_ContextGetDevicePlacementPolicy( + self._context_handle) + pywrap_tensorflow.TFE_ContextSetThreadLocalDevicePlacementPolicy( + self._handle, policy) + try: + yield + finally: + pywrap_tensorflow.TFE_ContextSetThreadLocalDevicePlacementPolicy( + self._handle, old) + def disable_run_metadata(self): """Disables tracing of op execution via RunMetadata.""" if not self._context_handle: diff --git a/tensorflow/python/eager/core_test.py b/tensorflow/python/eager/core_test.py index a70fa72804..82438ecadb 100644 --- a/tensorflow/python/eager/core_test.py +++ b/tensorflow/python/eager/core_test.py @@ -173,6 +173,15 @@ class TFETest(test_util.TensorFlowTestCase): with self.assertRaises(RuntimeError): x.gpu(context.context().num_gpus() + 1) + def testCopyScope(self): + if not context.context().num_gpus(): + self.skipTest('No GPUs found') + constant = constant_op.constant(1.0) + with ops.device('gpu:0'): + with context.context().device_policy(context.DEVICE_PLACEMENT_SILENT): + c = constant + 1.0 + self.assertAllEqual(c, 2.0) + def testNumpyForceCPU(self): if not context.context().num_gpus(): self.skipTest('No GPUs found') diff --git a/tensorflow/python/pywrap_tfe.i b/tensorflow/python/pywrap_tfe.i index de0e5856ff..ed7e4b17ad 100644 --- a/tensorflow/python/pywrap_tfe.i +++ b/tensorflow/python/pywrap_tfe.i @@ -24,6 +24,8 @@ limitations under the License. %rename("%s") TFE_ContextDisableRunMetadata; %rename("%s") TFE_ContextExportRunMetadata; %rename("%s") TFE_ContextClearCaches; +%rename("%s") TFE_ContextGetDevicePlacementPolicy; +%rename("%s") TFE_ContextSetThreadLocalDevicePlacementPolicy; %rename("%s") TFE_OpNameGetAttrType; %rename("%s") TFE_Py_InitEagerTensor; %rename("%s") TFE_Py_RegisterExceptionClass; -- GitLab From ffdae0a35785337bd10fed289d3998ba0e7c014b Mon Sep 17 00:00:00 2001 From: Jianwei Xie Date: Wed, 24 Jan 2018 09:15:32 -0800 Subject: [PATCH 178/258] Rename internal field. PiperOrigin-RevId: 183093901 --- tensorflow/python/estimator/run_config.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/estimator/run_config.py b/tensorflow/python/estimator/run_config.py index dc714d4d22..894005550d 100644 --- a/tensorflow/python/estimator/run_config.py +++ b/tensorflow/python/estimator/run_config.py @@ -484,7 +484,7 @@ class RunConfig(object): self._num_ps_replicas = _count_ps(self._cluster_spec) self._num_worker_replicas = _count_worker( self._cluster_spec, chief_task_type=TaskType.CHIEF) - self._global_id = _get_global_id_in_cluster( + self._global_id_in_cluster = _get_global_id_in_cluster( self._cluster_spec, self._task_type, self._task_id, @@ -495,14 +495,14 @@ class RunConfig(object): self._master = _LOCAL_MASTER self._num_ps_replicas = 0 self._num_worker_replicas = 0 - self._global_id = None # undefined + self._global_id_in_cluster = None # undefined self._is_chief = self._task_type == TaskType.CHIEF else: # Local mode. self._task_type = task_env.get(_TASK_TYPE_KEY, TaskType.WORKER) self._task_id = int(task_env.get(_TASK_ID_KEY, 0)) - self._global_id = 0 + self._global_id_in_cluster = 0 if self._task_type != TaskType.WORKER: raise ValueError( @@ -537,7 +537,7 @@ class RunConfig(object): raise ValueError('If `master` node exists in `cluster`, task_type ' '`evaluator` is not supported.') - self._global_id = _get_global_id_in_cluster( + self._global_id_in_cluster = _get_global_id_in_cluster( self._cluster_spec, self._task_type, self._task_id, @@ -619,7 +619,7 @@ class RunConfig(object): Returns: An integer id. """ - return self._global_id + return self._global_id_in_cluster @property def task_type(self): -- GitLab From 4e5da8880a1de695212777628f33db07833675c6 Mon Sep 17 00:00:00 2001 From: Jonathan Hseu Date: Wed, 24 Jan 2018 09:20:45 -0800 Subject: [PATCH 179/258] Remove path_to_str from the public API (#16339) * Remove path_to_str from the public API * Move path_to_str to another file --- tensorflow/python/estimator/estimator.py | 3 +- tensorflow/python/estimator/run_config.py | 4 ++- tensorflow/python/util/compat.py | 15 -------- tensorflow/python/util/compat_internal.py | 34 +++++++++++++++++++ .../tools/api/golden/tensorflow.compat.pbtxt | 4 --- 5 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 tensorflow/python/util/compat_internal.py diff --git a/tensorflow/python/estimator/estimator.py b/tensorflow/python/estimator/estimator.py index bd65d565b5..f53e170acc 100644 --- a/tensorflow/python/estimator/estimator.py +++ b/tensorflow/python/estimator/estimator.py @@ -54,6 +54,7 @@ from tensorflow.python.training import saver from tensorflow.python.training import training from tensorflow.python.training import training_util from tensorflow.python.util import compat +from tensorflow.python.util import compat_internal from tensorflow.python.util import nest @@ -159,7 +160,7 @@ class Estimator(object): self._config = config # Model directory. - model_dir = compat.path_to_str(model_dir) + model_dir = compat_internal.path_to_str(model_dir) if (model_dir is not None) and (self._config.model_dir is not None): if model_dir != self._config.model_dir: # TODO(alanyee): remove this suppression after it is no longer needed diff --git a/tensorflow/python/estimator/run_config.py b/tensorflow/python/estimator/run_config.py index db30329897..ee77961b39 100644 --- a/tensorflow/python/estimator/run_config.py +++ b/tensorflow/python/estimator/run_config.py @@ -28,6 +28,7 @@ from tensorflow.core.protobuf import config_pb2 from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training import server_lib from tensorflow.python.util import compat +from tensorflow.python.util import compat_internal _USE_DEFAULT = object() @@ -444,7 +445,8 @@ class RunConfig(object): if tf_config: logging.info('TF_CONFIG environment variable: %s', tf_config) - model_dir = _get_model_dir(tf_config, compat.path_to_str(model_dir)) + model_dir = _get_model_dir(tf_config, + compat_internal.path_to_str(model_dir)) RunConfig._replace( self, diff --git a/tensorflow/python/util/compat.py b/tensorflow/python/util/compat.py index 3ab0bd16fa..07382d93df 100644 --- a/tensorflow/python/util/compat.py +++ b/tensorflow/python/util/compat.py @@ -21,7 +21,6 @@ In addition to the functions below, `as_str` converts an object to a `str`. @@as_bytes @@as_text @@as_str_any -@@path_to_str ## Types The compatibility module also provides the following types: @@ -109,20 +108,6 @@ def as_str_any(value): return str(value) -def path_to_str(path): - """Returns the file system path representation of a `PathLike` object, else as it is. - - Args: - path: An object that can be converted to path representation. - - Returns: - A `str` object. - """ - if hasattr(path, "__fspath__"): - path = as_str_any(path.__fspath__()) - return path - - # Numpy 1.8 scalars don't inherit from numbers.Integral in Python 3, so we # need to check them specifically. The same goes from Real and Complex. integral_types = (_numbers.Integral, _np.integer) diff --git a/tensorflow/python/util/compat_internal.py b/tensorflow/python/util/compat_internal.py new file mode 100644 index 0000000000..a299b2fc3c --- /dev/null +++ b/tensorflow/python/util/compat_internal.py @@ -0,0 +1,34 @@ +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== + +"""Functions for Python 2 vs. 3 compatibility that are private to TensorFlow.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +def path_to_str(path): + """Returns the file system path representation of a `PathLike` object, else as it is. + + Args: + path: An object that can be converted to path representation. + + Returns: + A `str` object. + """ + if hasattr(path, "__fspath__"): + path = as_str_any(path.__fspath__()) + return path diff --git a/tensorflow/tools/api/golden/tensorflow.compat.pbtxt b/tensorflow/tools/api/golden/tensorflow.compat.pbtxt index bab480ff9b..ccc6031400 100644 --- a/tensorflow/tools/api/golden/tensorflow.compat.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.compat.pbtxt @@ -32,8 +32,4 @@ tf_module { name: "as_text" argspec: "args=[\'bytes_or_text\', \'encoding\'], varargs=None, keywords=None, defaults=[\'utf-8\'], " } - member_method { - name: "path_to_str" - argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" - } } -- GitLab From 21fd0369d932331dd9edc1cf4df437a452b4a335 Mon Sep 17 00:00:00 2001 From: "freedom\" Koan-Sin Tan" Date: Thu, 25 Jan 2018 01:31:13 +0800 Subject: [PATCH 180/258] [tflite] make calling NNAPI work again (#16256) calling PrepareOpsAndTensors() before using NN API looks 1. unnecessary 2. will decrease next_node_to_prepare_ so that the next next_node_to_prepare_ == nodes_and_registration_.size() will fail --- tensorflow/contrib/lite/interpreter.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow/contrib/lite/interpreter.cc b/tensorflow/contrib/lite/interpreter.cc index 5f5981e45a..69a597dc5a 100644 --- a/tensorflow/contrib/lite/interpreter.cc +++ b/tensorflow/contrib/lite/interpreter.cc @@ -291,7 +291,6 @@ TfLiteStatus Interpreter::Invoke() { TfLiteStatus status = kTfLiteOk; if (nnapi_delegate_) { - TF_LITE_ENSURE_STATUS(PrepareOpsAndTensors()); if (next_node_to_prepare_ == nodes_and_registration_.size()) { TF_LITE_ENSURE_OK(&context_, nnapi_delegate_->Invoke(this)); return kTfLiteOk; -- GitLab From 7b62a71e2d46c148df7d5704972f4592bc5e0f1b Mon Sep 17 00:00:00 2001 From: Ian Langmore Date: Wed, 24 Jan 2018 09:49:47 -0800 Subject: [PATCH 181/258] * BUGFIX: See code associated with scale_identity_multiplier * BUGFIX: See code associated with 'weight' inside sample_n * Use parameterization `temperature` rather than `mix_scale`. * Simplify documentation and link to arXiv paper for details * Document that we allow `temperature` to have any shape broadcastable with `mix_loc`. This is a mute point to some degree since we require K = 2 now. * Add some tests PiperOrigin-RevId: 183098275 --- .../kernel_tests/vector_diffeomixture_test.py | 148 +++++++-- .../python/ops/vector_diffeomixture.py | 300 ++++++++---------- 2 files changed, 258 insertions(+), 190 deletions(-) diff --git a/tensorflow/contrib/distributions/python/kernel_tests/vector_diffeomixture_test.py b/tensorflow/contrib/distributions/python/kernel_tests/vector_diffeomixture_test.py index d292b04665..04f047aa0c 100644 --- a/tensorflow/contrib/distributions/python/kernel_tests/vector_diffeomixture_test.py +++ b/tensorflow/contrib/distributions/python/kernel_tests/vector_diffeomixture_test.py @@ -27,6 +27,8 @@ from tensorflow.python.ops.linalg import linear_operator_diag as linop_diag_lib from tensorflow.python.ops.linalg import linear_operator_identity as linop_identity_lib from tensorflow.python.platform import test +rng = np.random.RandomState(0) + class VectorDiffeomixtureTest( test_util.VectorDistributionTestHelpers, test.TestCase): @@ -37,7 +39,7 @@ class VectorDiffeomixtureTest( dims = 4 vdm = vdm_lib.VectorDiffeomixture( mix_loc=[[0.], [1.]], - mix_scale=[1.], + temperature=[1.], distribution=normal_lib.Normal(0., 1.), loc=[ None, @@ -66,7 +68,7 @@ class VectorDiffeomixtureTest( dims = 4 vdm = vdm_lib.VectorDiffeomixture( mix_loc=[[0.], [1.]], - mix_scale=[1.], + temperature=[1.], distribution=normal_lib.Normal(1., 1.5), loc=[ None, @@ -95,7 +97,7 @@ class VectorDiffeomixtureTest( dims = 4 vdm = vdm_lib.VectorDiffeomixture( mix_loc=[[0.], [1.]], - mix_scale=[1.], + temperature=[1.], distribution=normal_lib.Normal(0., 1.), loc=[ None, @@ -122,12 +124,39 @@ class VectorDiffeomixtureTest( self.run_test_sample_consistent_log_prob( sess.run, vdm, radius=4., center=2., rtol=0.01) + def testSampleProbConsistentBroadcastMixTwoBatchDims(self): + dims = 4 + loc_1 = rng.randn(2, 3, dims).astype(np.float32) + + with self.test_session() as sess: + vdm = vdm_lib.VectorDiffeomixture( + mix_loc=(rng.rand(2, 3, 1) - 0.5).astype(np.float32), + temperature=[1.], + distribution=normal_lib.Normal(0., 1.), + loc=[ + None, + loc_1, + ], + scale=[ + linop_identity_lib.LinearOperatorScaledIdentity( + num_rows=dims, + multiplier=[np.float32(1.1)], + is_positive_definite=True), + ] * 2, + validate_args=True) + # Ball centered at component0's mean. + self.run_test_sample_consistent_log_prob( + sess.run, vdm, radius=2., center=0., rtol=0.01) + # Larger ball centered at component1's mean. + self.run_test_sample_consistent_log_prob( + sess.run, vdm, radius=3., center=loc_1, rtol=0.02) + def testMeanCovarianceNoBatch(self): with self.test_session() as sess: dims = 3 vdm = vdm_lib.VectorDiffeomixture( mix_loc=[[0.], [4.]], - mix_scale=[10.], + temperature=[1 / 10.], distribution=normal_lib.Normal(0., 1.), loc=[ np.float32([-2.]), @@ -147,12 +176,94 @@ class VectorDiffeomixtureTest( self.run_test_sample_consistent_mean_covariance( sess.run, vdm, rtol=0.02, cov_rtol=0.08) + def testTemperatureControlsHowMuchThisLooksLikeDiscreteMixture(self): + # As temperature decreases, this should approach a mixture of normals, with + # components at -2, 2. + with self.test_session() as sess: + dims = 1 + vdm = vdm_lib.VectorDiffeomixture( + mix_loc=[0.], + temperature=[[2.], [1.], [0.2]], + distribution=normal_lib.Normal(0., 1.), + loc=[ + np.float32([-2.]), + np.float32([2.]), + ], + scale=[ + linop_identity_lib.LinearOperatorScaledIdentity( + num_rows=dims, + multiplier=np.float32(0.5), + is_positive_definite=True), + ] * 2, # Use the same scale for each component. + quadrature_size=8, + validate_args=True) + + samps = vdm.sample(10000) + self.assertAllEqual((10000, 3, 1), samps.shape) + samps_ = sess.run(samps).reshape(10000, 3) # Make scalar event shape. + + # One characteristic of a discrete mixture (as opposed to a "smear") is + # that more weight is put near the component centers at -2, 2, and thus + # less weight is put near the origin. + prob_of_being_near_origin = (np.abs(samps_) < 1).mean(axis=0) + self.assertGreater( + prob_of_being_near_origin[0], prob_of_being_near_origin[1]) + self.assertGreater( + prob_of_being_near_origin[1], prob_of_being_near_origin[2]) + + # Run this test as well, just because we can. + self.run_test_sample_consistent_mean_covariance( + sess.run, vdm, rtol=0.02, cov_rtol=0.08) + + def testConcentrationLocControlsHowMuchWeightIsOnEachComponent(self): + with self.test_session() as sess: + dims = 1 + vdm = vdm_lib.VectorDiffeomixture( + mix_loc=[[-1.], [0.], [1.]], + temperature=[0.5], + distribution=normal_lib.Normal(0., 1.), + loc=[ + np.float32([-2.]), + np.float32([2.]), + ], + scale=[ + linop_identity_lib.LinearOperatorScaledIdentity( + num_rows=dims, + multiplier=np.float32(0.5), + is_positive_definite=True), + ] * 2, # Use the same scale for each component. + quadrature_size=8, + validate_args=True) + + samps = vdm.sample(10000) + self.assertAllEqual((10000, 3, 1), samps.shape) + samps_ = sess.run(samps).reshape(10000, 3) # Make scalar event shape. + + # One characteristic of putting more weight on a component is that the + # mean is closer to that component's mean. + # Get the mean for each batch member, the names signify the value of + # concentration for that batch member. + mean_neg1, mean_0, mean_1 = samps_.mean(axis=0) + + # Since concentration is the concentration for component 0, + # concentration = -1 ==> more weight on component 1, which has mean = 2 + # concentration = 0 ==> equal weight + # concentration = 1 ==> more weight on component 0, which has mean = -2 + self.assertLess(-2, mean_1) + self.assertLess(mean_1, mean_0) + self.assertLess(mean_0, mean_neg1) + self.assertLess(mean_neg1, 2) + + # Run this test as well, just because we can. + self.run_test_sample_consistent_mean_covariance( + sess.run, vdm, rtol=0.02, cov_rtol=0.08) + def testMeanCovarianceNoBatchUncenteredNonStandardBase(self): with self.test_session() as sess: dims = 3 vdm = vdm_lib.VectorDiffeomixture( mix_loc=[[0.], [4.]], - mix_scale=[10.], + temperature=[0.1], distribution=normal_lib.Normal(-1., 1.5), loc=[ np.float32([-2.]), @@ -177,7 +288,7 @@ class VectorDiffeomixtureTest( dims = 3 vdm = vdm_lib.VectorDiffeomixture( mix_loc=[[0.], [4.]], - mix_scale=[10.], + temperature=[0.1], distribution=normal_lib.Normal(0., 1.), loc=[ np.float32([[-2.]]), @@ -205,7 +316,7 @@ class VectorDiffeomixtureTest( dims = 4 vdm = vdm_lib.VectorDiffeomixture( mix_loc=[0.], - mix_scale=[1.], + temperature=[0.1], distribution=normal_lib.Normal(0., 1.), loc=[ None, @@ -229,29 +340,6 @@ class VectorDiffeomixtureTest( self.run_test_sample_consistent_log_prob( sess.run, vdm, radius=4., center=2., rtol=0.005) - # TODO(jvdillon): We've tested that (i) .sample and .log_prob are consistent, - # (ii) .mean, .stddev etc... and .sample are consistent. However, we haven't - # tested that the quadrature approach well-approximates the integral. - # - # To that end, consider adding these tests: - # - # Test1: In the limit of high mix_scale, this approximates a discrete mixture, - # and there are many discrete mixtures where we can explicitly compute - # mean/var, etc... So test1 would choose one of those discrete mixtures and - # show our mean/var/etc... is close to that. - # - # Test2: In the limit of low mix_scale, the a diffeomixture of Normal(-5, 1), - # Normal(5, 1) should (I believe...must check) should look almost like - # Uniform(-5, 5), and thus (i) .prob(x) should be about 1/10 for x in (-5, 5), - # and (ii) the first few moments should approximately match that of - # Uniform(-5, 5) - # - # Test3: If mix_loc is symmetric, then for any mix_scale, our - # quadrature-based diffeomixture of Normal(-1, 1), Normal(1, 1) should have - # mean zero, exactly. - - # TODO(jvdillon): Add more tests which verify broadcasting. - if __name__ == "__main__": test.main() diff --git a/tensorflow/contrib/distributions/python/ops/vector_diffeomixture.py b/tensorflow/contrib/distributions/python/ops/vector_diffeomixture.py index 7ce8a83fd9..0c747f8e68 100644 --- a/tensorflow/contrib/distributions/python/ops/vector_diffeomixture.py +++ b/tensorflow/contrib/distributions/python/ops/vector_diffeomixture.py @@ -50,20 +50,25 @@ __all__ = [ def quadrature_scheme_softmaxnormal_gauss_hermite( - loc, scale, quadrature_size, + normal_loc, normal_scale, quadrature_size, validate_args=False, name=None): """Use Gauss-Hermite quadrature to form quadrature on `K - 1` simplex. + A `SoftmaxNormal` random variable `Y` may be generated via + + ``` + Y = SoftmaxCentered(X), + X = Normal(normal_loc, normal_scale) + ``` + Note: for a given `quadrature_size`, this method is generally less accurate than `quadrature_scheme_softmaxnormal_quantiles`. Args: - loc: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`, B>=0. - Represents the `location` parameter of the SoftmaxNormal used for - selecting one of the `K` affine transformations. - scale: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`, B>=0. - Represents the `scale` parameter of the SoftmaxNormal used for - selecting one of the `K` affine transformations. + normal_loc: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`, B>=0. + The location parameter of the Normal used to construct the SoftmaxNormal. + normal_scale: `float`-like `Tensor`. Broadcastable with `normal_loc`. + The scale parameter of the Normal used to construct the SoftmaxNormal. quadrature_size: Python `int` scalar representing the number of quadrature points. validate_args: Python `bool`, default `False`. When `True` distribution @@ -80,24 +85,25 @@ def quadrature_scheme_softmaxnormal_gauss_hermite( associated with each grid point. """ with ops.name_scope(name, "quadrature_scheme_softmaxnormal_gauss_hermite", - [loc, scale]): - loc = ops.convert_to_tensor(loc, name="loc") - dt = loc.dtype.base_dtype - scale = ops.convert_to_tensor(scale, dtype=dt, name="scale") + [normal_loc, normal_scale]): + normal_loc = ops.convert_to_tensor(normal_loc, name="normal_loc") + dt = normal_loc.dtype.base_dtype + normal_scale = ops.convert_to_tensor( + normal_scale, dtype=dt, name="normal_scale") - loc = maybe_check_quadrature_param(loc, "loc", validate_args) - scale = maybe_check_quadrature_param(scale, "scale", validate_args) + normal_scale = maybe_check_quadrature_param( + normal_scale, "normal_scale", validate_args) grid, probs = np.polynomial.hermite.hermgauss(deg=quadrature_size) - grid = grid.astype(loc.dtype.as_numpy_dtype) - probs = probs.astype(loc.dtype.as_numpy_dtype) + grid = grid.astype(dt.dtype.as_numpy_dtype) + probs = probs.astype(dt.dtype.as_numpy_dtype) probs /= np.linalg.norm(probs, ord=1, keepdims=True) - probs = ops.convert_to_tensor(probs, name="probs", dtype=loc.dtype) + probs = ops.convert_to_tensor(probs, name="probs", dtype=dt) grid = softmax( -distribution_util.pad( - (loc[..., array_ops.newaxis] + - np.sqrt(2.) * scale[..., array_ops.newaxis] * grid), + (normal_loc[..., array_ops.newaxis] + + np.sqrt(2.) * normal_scale[..., array_ops.newaxis] * grid), axis=-2, front=True), axis=-2) # shape: [B, components, deg] @@ -106,18 +112,23 @@ def quadrature_scheme_softmaxnormal_gauss_hermite( def quadrature_scheme_softmaxnormal_quantiles( - loc, scale, quadrature_size, + normal_loc, normal_scale, quadrature_size, validate_args=False, name=None): """Use SoftmaxNormal quantiles to form quadrature on `K - 1` simplex. + A `SoftmaxNormal` random variable `Y` may be generated via + + ``` + Y = SoftmaxCentered(X), + X = Normal(normal_loc, normal_scale) + ``` + Args: - loc: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`, B>=0. - Represents the `location` parameter of the SoftmaxNormal used for - selecting one of the `K` affine transformations. - scale: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`, B>=0. - Represents the `scale` parameter of the SoftmaxNormal used for - selecting one of the `K` affine transformations. - quadrature_size: Python scalar `int` representing the number of quadrature + normal_loc: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`, B>=0. + The location parameter of the Normal used to construct the SoftmaxNormal. + normal_scale: `float`-like `Tensor`. Broadcastable with `normal_loc`. + The scale parameter of the Normal used to construct the SoftmaxNormal. + quadrature_size: Python `int` scalar representing the number of quadrature points. validate_args: Python `bool`, default `False`. When `True` distribution parameters are checked for validity despite possibly degrading runtime @@ -132,15 +143,17 @@ def quadrature_scheme_softmaxnormal_quantiles( probs: Shape `[b1, ..., bB, K, quadrature_size]` `Tensor` representing the associated with each grid point. """ - with ops.name_scope(name, "softmax_normal_grid_and_probs", [loc, scale]): - loc = ops.convert_to_tensor(loc, name="loc") - dt = loc.dtype.base_dtype - scale = ops.convert_to_tensor(scale, dtype=dt, name="scale") + with ops.name_scope(name, "softmax_normal_grid_and_probs", + [normal_loc, normal_scale]): + normal_loc = ops.convert_to_tensor(normal_loc, name="normal_loc") + dt = normal_loc.dtype.base_dtype + normal_scale = ops.convert_to_tensor( + normal_scale, dtype=dt, name="normal_scale") - loc = maybe_check_quadrature_param(loc, "loc", validate_args) - scale = maybe_check_quadrature_param(scale, "scale", validate_args) + normal_scale = maybe_check_quadrature_param( + normal_scale, "normal_scale", validate_args) - dist = normal_lib.Normal(loc=loc, scale=scale) + dist = normal_lib.Normal(loc=normal_loc, scale=normal_scale) def _get_batch_ndims(): """Helper to get dist.batch_shape.ndims, statically if possible.""" @@ -195,114 +208,51 @@ def quadrature_scheme_softmaxnormal_quantiles( class VectorDiffeomixture(distribution_lib.Distribution): """VectorDiffeomixture distribution. - The VectorDiffeomixture is an approximation to a [compound distribution]( - https://en.wikipedia.org/wiki/Compound_probability_distribution), i.e., + A vector diffeomixture (VDM) is a distribution parameterized by a convex + combination of `K` component `loc` vectors, `loc[k], k = 0,...,K-1`, and `K` + `scale` matrices `scale[k], k = 0,..., K-1`. It approximates the following + [compound distribution] + (https://en.wikipedia.org/wiki/Compound_probability_distribution) ```none - p(x) = int_{X} q(x | v) p(v) dv - = lim_{Q->infty} sum{ prob[i] q(x | loc=sum_k^K lambda[k;i] loc[k], - scale=sum_k^K lambda[k;i] scale[k]) - : i=0, ..., Q-1 } + p(x) = int p(x | z) p(z) dz, + where z is in the K-simplex, and + p(x | z) := p(x | loc=sum_k z[k] loc[k], scale=sum_k z[k] scale[k]) ``` - where `q(x | v)` is a vector version of the `distribution` argument and `p(v)` - is a SoftmaxNormal parameterized by `mix_loc` and `mix_scale`. The - vector-ization of `distribution` entails an affine transformation of iid - samples from `distribution`. The `prob` term is from quadrature and - `lambda[k] = sigmoid(mix_loc[k] + sqrt(2) mix_scale[k] grid[k])` where the - `grid` points correspond to the `prob`s. - - In the non-approximation case, a draw from the mixture distribution (the - "prior") represents the convex weights for different affine transformations. - I.e., draw a mixing vector `v` (from the `K-1`-simplex) and let the final - sample be: `y = (sum_k^K v[k] scale[k]) @ x + (sum_k^K v[k] loc[k])` where `@` - denotes matrix multiplication. However, the non-approximate distribution does - not have an analytical probability density function (pdf). Therefore the - `VectorDiffeomixture` class implements an approximation based on - [numerical quadrature]( - https://en.wikipedia.org/wiki/Numerical_integration) (default: - [Gauss--Hermite quadrature]( - https://en.wikipedia.org/wiki/Gauss%E2%80%93Hermite_quadrature)). I.e., in - Note: although the `VectorDiffeomixture` is approximately the - `SoftmaxNormal-Distribution` compound distribution, it is itself a valid - distribution. It possesses a `sample`, `log_prob`, `mean`, `covariance` which - are all mutually consistent. - - #### Intended Use - - This distribution is noteworthy because it implements a mixture of - `Vector`-ized distributions yet has samples differentiable in the - distribution's parameters (aka "reparameterized"). It has an analytical - density function with `O(dKQ)` complexity. `d` is the vector dimensionality, - `K` is the number of components, and `Q` is the number of quadrature points. - These properties make it well-suited for Bayesian Variational Inference, i.e., - as a surrogate family for the posterior. - - For large values of `mix_scale`, the `VectorDistribution` behaves increasingly - like a discrete mixture. (In most cases this limit is only achievable by also - increasing the quadrature polynomial degree, `Q`.) - - The term `Vector` is consistent with similar named Tensorflow `Distribution`s. - For more details, see the "About `Vector` distributions in Tensorflow." - section. - - The term `Diffeomixture` is a portmanteau of - [diffeomorphism](https://en.wikipedia.org/wiki/Diffeomorphism) and [compound - mixture](https://en.wikipedia.org/wiki/Compound_probability_distribution). For - more details, see the "About `Diffeomixture`s and reparametrization.`" - section. - - #### Mathematical Details - - The `VectorDiffeomixture` approximates a SoftmaxNormal-mixed ("prior") - [compound distribution]( - https://en.wikipedia.org/wiki/Compound_probability_distribution). - Using variable-substitution and [numerical quadrature]( - https://en.wikipedia.org/wiki/Numerical_integration) (default: - [Gauss--Hermite quadrature]( - https://en.wikipedia.org/wiki/Gauss%E2%80%93Hermite_quadrature)) we can - redefine the distribution to be a parameter-less convex combination of `K` - different affine combinations of a `d` iid samples from `distribution`. - - That is, defined over `R**d` this distribution is parameterized by a - (batch of) length-`K` `mix_loc` and `mix_scale` vectors, a length-`K` list of - (a batch of) length-`d` `loc` vectors, and a length-`K` list of `scale` - `LinearOperator`s each operating on a (batch of) length-`d` vector space. - Finally, a `distribution` parameter specifies the underlying base distribution - which is "lifted" to become multivariate ("lifting" is the same concept as in - `TransformedDistribution`). - - The probability density function (pdf) is, + The integral `int p(x | z) p(z) dz` is approximated with a quadrature scheme + adapted to the mixture density `p(z)`. The `N` quadrature points `z_{N, n}` + and weights `w_{N, n}` (which are non-negative and sum to 1) are chosen + such that - ```none - pdf(y; mix_loc, mix_scale, loc, scale, phi) - = sum{ prob[i] phi(f_inverse(x; i)) / abs(det(interp_scale[i])) - : i=0, ..., Q-1 } - ``` + ```q_N(x) := sum_{n=1}^N w_{n, N} p(x | z_{N, n}) --> p(x)``` - where, `phi` is the base distribution pdf, and, + as `N --> infinity`. - ```none - f_inverse(x; i) = inv(interp_scale[i]) @ (x - interp_loc[i]) - interp_loc[i] = sum{ lambda[k; i] loc[k] : k=0, ..., K-1 } - interp_scale[i] = sum{ lambda[k; i] scale[k] : k=0, ..., K-1 } - ``` + Since `q_N(x)` is in fact a mixture (of `N` points), we may sample from + `q_N` exactly. It is important to note that the VDM is *defined* as `q_N` + above, and *not* `p(x)`. Therefore, sampling and pdf may be implemented as + exact (up to floating point error) methods. - and, + A common choice for the conditional `p(x | z)` is a multivariate Normal. - ```none - grid, weight = np.polynomial.hermite.hermgauss(quadrature_size) - prob[k] = weight[k] / sqrt(pi) - lambda[k; i] = sigmoid(mix_loc[k] + sqrt(2) mix_scale[k] grid[i]) + The implemented marginal `p(z)` is the `SoftmaxNormal`, which is a + `K-1` dimensional Normal transformed by a `SoftmaxCentered` bijector, making + it a density on the `K`-simplex. That is, + + ``` + Z = SoftmaxCentered(X), + X = Normal(mix_loc / temperature, 1 / temperature) ``` - The distribution corresponding to `phi` must be a scalar-batch, scalar-event - distribution. Typically it is reparameterized. If not, it must be a function - of non-trainable parameters. + The default quadrature scheme chooses `z_{N, n}` as `N` midpoints of + the quantiles of `p(z)` (generalized quantiles if `K > 2`). - WARNING: If you backprop through a VectorDiffeomixture sample and the "base" - distribution is both: not `FULLY_REPARAMETERIZED` and a function of trainable - variables, then the gradient is not guaranteed correct! + See [1] for more details. + + [1]. "Quadrature Compound: An approximating family of distributions" + Joshua Dillon, Ian Langmore, arXiv preprints + https://arxiv.org/abs/1801.03080 #### About `Vector` distributions in TensorFlow. @@ -310,12 +260,11 @@ class VectorDiffeomixture(distribution_lib.Distribution): particularly useful in [variational Bayesian methods](https://en.wikipedia.org/wiki/Variational_Bayesian_methods). - Conditioned on a draw from the SoftmaxNormal, `Y|v` is a vector whose + Conditioned on a draw from the SoftmaxNormal, `X|z` is a vector whose components are linear combinations of affine transformations, thus is itself - an affine transformation. Therefore `Y|v` lives in the vector space generated - by vectors of affine-transformed distributions. + an affine transformation. - Note: The marginals `Y_1|v, ..., Y_d|v` are *not* generally identical to some + Note: The marginals `X_1|v, ..., X_d|v` are *not* generally identical to some parameterization of `distribution`. This is due to the fact that the sum of draws from `distribution` are not generally itself the same `distribution`. @@ -331,12 +280,16 @@ class VectorDiffeomixture(distribution_lib.Distribution): optimize Monte-Carlo objectives. Such objectives are a finite-sample approximation of an expectation and arise throughout scientific computing. + WARNING: If you backprop through a VectorDiffeomixture sample and the "base" + distribution is both: not `FULLY_REPARAMETERIZED` and a function of trainable + variables, then the gradient is not guaranteed correct! + #### Examples ```python tfd = tf.contrib.distributions - # Create two batches of VectorDiffeomixtures, one with mix_loc=[0.] and + # Create two batches of VectorDiffeomixtures, one with mix_loc=[0.], # another with mix_loc=[1]. In both cases, `K=2` and the affine # transformations involve: # k=0: loc=zeros(dims) scale=LinearOperatorScaledIdentity @@ -344,7 +297,7 @@ class VectorDiffeomixture(distribution_lib.Distribution): dims = 5 vdm = tfd.VectorDiffeomixture( mix_loc=[[0.], [1]], - mix_scale=[1.], + temperature=[1.], distribution=tfd.Normal(loc=0., scale=1.), loc=[ None, # Equivalent to `np.zeros(dims, dtype=np.float32)`. @@ -364,7 +317,7 @@ class VectorDiffeomixture(distribution_lib.Distribution): def __init__(self, mix_loc, - mix_scale, + temperature, distribution, loc=None, scale=None, @@ -373,15 +326,24 @@ class VectorDiffeomixture(distribution_lib.Distribution): validate_args=False, allow_nan_stats=True, name="VectorDiffeomixture"): - """Constructs the VectorDiffeomixture on `R**d`. + """Constructs the VectorDiffeomixture on `R^d`. + + The vector diffeomixture (VDM) approximates the compound distribution + + ```none + p(x) = int p(x | z) p(z) dz, + where z is in the K-simplex, and + p(x | z) := p(x | loc=sum_k z[k] loc[k], scale=sum_k z[k] scale[k]) + ``` Args: - mix_loc: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`. Represents - the `location` parameter of the SoftmaxNormal used for selecting one of - the `K` affine transformations. - mix_scale: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`. - Represents the `scale` parameter of the SoftmaxNormal used for selecting - one of the `K` affine transformations. + mix_loc: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`. + In terms of samples, larger `mix_loc[..., k]` ==> + `Z` is more likely to put more weight on its `kth` component. + temperature: `float`-like `Tensor`. Broadcastable with `mix_loc`. + In terms of samples, smaller `temperature` means one component is more + likely to dominate. I.e., smaller `temperature` makes the VDM look more + like a standard mixture of `K` components. distribution: `tf.Distribution`-like instance. Distribution from which `d` iid samples are used as input to the selected affine transformation. Must be a scalar-batch, scalar-event distribution. Typically @@ -401,8 +363,9 @@ class VectorDiffeomixture(distribution_lib.Distribution): transformation. `LinearOperator`s must have shape `[B1, ..., Bb, d, d]`, `b >= 0`, i.e., characterizes `b`-batches of `d x d` matrices quadrature_size: Python `int` scalar representing number of - quadrature points. - quadrature_fn: Python callable taking `mix_loc`, `mix_scale`, + quadrature points. Larger `quadrature_size` means `q_N(x)` better + approximates `p(x)`. + quadrature_fn: Python callable taking `normal_loc`, `normal_scale`, `quadrature_size`, `validate_args` and returning `tuple(grid, probs)` representing the SoftmaxNormal grid and corresponding normalized weight. normalized) weight. @@ -430,7 +393,7 @@ class VectorDiffeomixture(distribution_lib.Distribution): ValueError: if `not distribution.is_scalar_event`. """ parameters = locals() - with ops.name_scope(name, values=[mix_loc, mix_scale]): + with ops.name_scope(name, values=[mix_loc, temperature]): if not scale or len(scale) < 2: raise ValueError("Must specify list (or list-like object) of scale " "LinearOperators, one for each component with " @@ -473,8 +436,15 @@ class VectorDiffeomixture(distribution_lib.Distribution): raise NotImplementedError("Currently only bimixtures are supported; " "len(scale)={} is not 2.".format(len(scale))) + mix_loc = ops.convert_to_tensor( + mix_loc, dtype=dtype, name="mix_loc") + temperature = ops.convert_to_tensor( + temperature, dtype=dtype, name="temperature") self._grid, probs = tuple(quadrature_fn( - mix_loc, mix_scale, quadrature_size, validate_args)) + mix_loc / temperature, + 1. / temperature, + quadrature_size, + validate_args)) # Note: by creating the logits as `log(prob)` we ensure that # `self.mixture_distribution.logits` is equivalent to @@ -618,7 +588,14 @@ class VectorDiffeomixture(distribution_lib.Distribution): weight = array_ops.gather( array_ops.reshape(self.grid, shape=[-1]), ids + offset) - weight = weight[..., array_ops.newaxis] + # At this point, weight flattened all batch dims into one. + # We also need to append a singleton to broadcast with event dims. + if self.batch_shape.is_fully_defined(): + new_shape = [-1] + self.batch_shape.as_list() + [1] + else: + new_shape = array_ops.concat( + ([-1], self.batch_shape_tensor(), [1]), axis=0) + weight = array_ops.reshape(weight, shape=new_shape) if len(x) != 2: # We actually should have already triggered this exception. However as a @@ -686,7 +663,7 @@ class VectorDiffeomixture(distribution_lib.Distribution): # To compute E[Cov(Z|V)], we'll add matrices within three categories: # scaled-identity, diagonal, and full. Then we'll combine these at the end. - scaled_identity = None + scale_identity_multiplier = None diag = None full = None @@ -694,10 +671,12 @@ class VectorDiffeomixture(distribution_lib.Distribution): s = aff.scale # Just in case aff.scale has side-effects, we'll call once. if (s is None or isinstance(s, linop_identity_lib.LinearOperatorIdentity)): - scaled_identity = add(scaled_identity, p[..., k, array_ops.newaxis]) + scale_identity_multiplier = add(scale_identity_multiplier, + p[..., k, array_ops.newaxis]) elif isinstance(s, linop_identity_lib.LinearOperatorScaledIdentity): - scaled_identity = add(scaled_identity, (p[..., k, array_ops.newaxis] * - math_ops.square(s.multiplier))) + scale_identity_multiplier = add( + scale_identity_multiplier, + (p[..., k, array_ops.newaxis] * math_ops.square(s.multiplier))) elif isinstance(s, linop_diag_lib.LinearOperatorDiag): diag = add(diag, (p[..., k, array_ops.newaxis] * math_ops.square(s.diag_part()))) @@ -709,12 +688,13 @@ class VectorDiffeomixture(distribution_lib.Distribution): full = add(full, x) # We must now account for the fact that the base distribution might have a - # non-unity variance. Recall that `Cov(SX+m) = S.T Cov(X) S = S.T S Var(X)`. + # non-unity variance. Recall that, since X ~ iid Law(X_0), + # `Cov(SX+m) = S Cov(X) S.T = S S.T Diag(Var(X_0))`. # We can scale by `Var(X)` (vs `Cov(X)`) since X corresponds to `d` iid # samples from a scalar-event distribution. v = self.distribution.variance() - if scaled_identity is not None: - scaled_identity *= v + if scale_identity_multiplier is not None: + scale_identity_multiplier *= v if diag is not None: diag *= v[..., array_ops.newaxis] if full is not None: @@ -723,10 +703,10 @@ class VectorDiffeomixture(distribution_lib.Distribution): if diag_only: # Apparently we don't need the full matrix, just the diagonal. r = add(diag, full) - if r is None and scaled_identity is not None: + if r is None and scale_identity_multiplier is not None: ones = array_ops.ones(self.event_shape_tensor(), dtype=self.dtype) - return scaled_identity * ones - return add(r, scaled_identity) + return scale_identity_multiplier[..., array_ops.newaxis] * ones + return add(r, scale_identity_multiplier) # `None` indicates we don't know if the result is positive-definite. is_positive_definite = (True if all(aff.scale.is_positive_definite @@ -742,10 +722,10 @@ class VectorDiffeomixture(distribution_lib.Distribution): to_add.append(linop_full_lib.LinearOperatorFullMatrix( matrix=full, is_positive_definite=is_positive_definite)) - if scaled_identity is not None: + if scale_identity_multiplier is not None: to_add.append(linop_identity_lib.LinearOperatorScaledIdentity( num_rows=self.event_shape_tensor()[0], - multiplier=scaled_identity, + multiplier=scale_identity_multiplier, is_positive_definite=is_positive_definite)) return (linop_add_lib.add_operators(to_add)[0].to_dense() -- GitLab From d9f93c42a50b1f1401d9c186eac0ae8dc9093c3b Mon Sep 17 00:00:00 2001 From: Jianwei Xie Date: Wed, 24 Jan 2018 10:02:35 -0800 Subject: [PATCH 182/258] Merge changes from github. PiperOrigin-RevId: 183100142 --- RELEASE.md | 174 ++- WORKSPACE | 8 +- tensorflow/BUILD | 3 + tensorflow/c/eager/c_api.cc | 3 +- .../compiler/xla/tests/dynamic_ops_test.cc | 28 + tensorflow/contrib/cmake/README.md | 4 +- .../contrib/cmake/external/snappy.cmake | 2 +- tensorflow/contrib/cmake/python_modules.txt | 4 + .../contrib/cmake/python_sanity_test.py | 124 ++ .../contrib/cmake/tf_core_framework.cmake | 2 + tensorflow/contrib/cmake/tf_python.cmake | 9 +- .../cudnn_rnn/kernels/cudnn_rnn_ops.cc | 2 +- .../cudnn_rnn/python/ops/cudnn_rnn_ops.py | 2 +- .../contrib/eager/python/g3doc/guide.md | 2 +- .../estimator/python/estimator/extenders.py | 2 +- .../contrib/ffmpeg/default/ffmpeg_lib.cc | 4 +- .../framework/python/ops/script_ops.py | 1 + tensorflow/contrib/gan/python/train.py | 16 +- .../contrib/layers/python/layers/layers.py | 8 +- .../contrib/lite/download_dependencies.sh | 9 +- tensorflow/contrib/lite/kernels/gather.cc | 7 +- .../contrib/lite/kernels/gather_test.cc | 27 +- .../lite/models/testdata/g3doc/README.md | 4 +- .../contrib/lite/nnapi/NeuralNetworksShim.h | 2 +- .../contrib/lite/testing/generate_examples.py | 2 +- .../lite/toco/g3doc/cmdline_reference.md | 2 +- tensorflow/contrib/lite/tools/BUILD | 21 + .../contrib/makefile/download_dependencies.sh | 13 +- tensorflow/contrib/opt/BUILD | 22 + tensorflow/contrib/opt/__init__.py | 5 +- .../training/model_average_optimizer.py | 299 ++++ .../training/model_average_optimizer_test.py | 200 +++ tensorflow/contrib/periodic_resample/BUILD | 18 + .../kernels/periodic_resample_op.h | 11 + .../periodic_resample/ops/array_ops.cc | 42 +- .../kernel_tests/periodic_resample_op_test.py | 16 +- .../python/kernel_tests/core_rnn_cell_test.py | 6 + .../rnn/python/kernel_tests/rnn_cell_test.py | 95 ++ tensorflow/contrib/rnn/python/ops/rnn_cell.py | 257 +++- .../kernel_tests/beam_search_decoder_test.py | 88 ++ .../seq2seq/python/ops/beam_search_decoder.py | 31 +- tensorflow/contrib/verbs/BUILD | 6 +- tensorflow/contrib/verbs/README.md | 174 ++- .../contrib/verbs/grpc_verbs_service.cc | 12 +- .../verbs/patch_notes_verbs_with_0_copies.md | 87 ++ tensorflow/contrib/verbs/rdma.cc | 1348 ++++++++++------- tensorflow/contrib/verbs/rdma.h | 504 +++--- tensorflow/contrib/verbs/rdma_mgr.cc | 213 ++- tensorflow/contrib/verbs/rdma_mgr.h | 1 + .../contrib/verbs/rdma_rendezvous_mgr.cc | 114 +- tensorflow/contrib/verbs/verbs_server_lib.cc | 1 + tensorflow/contrib/verbs/verbs_service.proto | 6 + .../contrib/verbs/verbs_with_0_copies.png | Bin 0 -> 62862 bytes .../contrib/verbs/verbs_with_0_copies.xml | 1 + .../verbs_with_0_copies_phase1_protocol.jpg | Bin 0 -> 88799 bytes .../verbs_with_0_copies_phase1_protocol.xml | 1 + tensorflow/core/BUILD | 3 + tensorflow/core/framework/types.h | 7 + tensorflow/core/graph/mkl_layout_pass.cc | 58 +- tensorflow/core/kernels/BUILD | 17 + tensorflow/core/kernels/cuda_solvers.h | 2 +- tensorflow/core/kernels/cwise_op_pow.cc | 7 +- tensorflow/core/kernels/cwise_ops.h | 35 + tensorflow/core/kernels/cwise_ops_common.cc | 5 + tensorflow/core/kernels/decode_image_op.cc | 39 +- tensorflow/core/kernels/matmul_op.cc | 1 + tensorflow/core/kernels/mkl_aggregate_ops.cc | 24 + tensorflow/core/kernels/mkl_concat_op.cc | 4 +- .../core/kernels/mkl_conv_grad_filter_ops.cc | 7 + .../core/kernels/mkl_conv_grad_input_ops.cc | 7 + tensorflow/core/kernels/mkl_conv_ops.cc | 7 + tensorflow/core/kernels/mkl_conv_ops.h | 29 +- .../core/kernels/mkl_fused_batch_norm_op.cc | 360 +++-- .../core/kernels/mkl_input_conversion_op.cc | 2 +- tensorflow/core/kernels/mkl_lrn_op.cc | 34 +- tensorflow/core/kernels/mkl_maxpooling_op.cc | 14 +- .../core/kernels/mkl_pooling_ops_common.h | 4 +- tensorflow/core/kernels/mkl_reshape_op.cc | 15 +- tensorflow/core/kernels/mkl_softmax_op.cc | 163 ++ tensorflow/core/kernels/pooling_ops_common.cc | 2 +- .../core/kernels/spectrogram_test_utils.cc | 14 + .../core/kernels/transpose_functor_cpu.cc | 12 + .../core/kernels/transpose_functor_gpu.cu.cc | 21 + tensorflow/core/kernels/xent_op.cc | 10 +- tensorflow/core/lib/gif/gif_io.cc | 16 +- tensorflow/core/lib/gif/gif_io.h | 3 +- tensorflow/core/ops/nn_ops.cc | 8 + tensorflow/core/platform/s3/aws_logging.cc | 1 + tensorflow/core/platform/s3/s3_file_system.cc | 50 +- tensorflow/core/public/version.h | 2 +- .../docs_src/api_guides/python/python_io.md | 10 +- tensorflow/docs_src/install/install_c.md | 2 +- tensorflow/docs_src/install/install_go.md | 2 +- tensorflow/docs_src/install/install_java.md | 22 +- tensorflow/docs_src/install/install_linux.md | 22 +- tensorflow/docs_src/install/install_mac.md | 10 +- .../docs_src/install/install_sources.md | 14 +- .../tutorials/word2vec/word2vec_basic.py | 104 +- .../kernel_tests/batch_dataset_op_test.py | 22 + tensorflow/python/estimator/estimator.py | 8 +- tensorflow/python/estimator/run_config.py | 6 +- tensorflow/python/framework/constant_op.py | 1 - tensorflow/python/kernel_tests/conv1d_test.py | 44 +- .../python/kernel_tests/cwise_ops_test.py | 27 + .../python/kernel_tests/metrics_test.py | 29 +- .../python/kernel_tests/xent_op_test.py | 10 + tensorflow/python/layers/pooling.py | 18 +- tensorflow/python/layers/pooling_test.py | 8 +- tensorflow/python/lib/core/py_func.cc | 19 +- tensorflow/python/ops/histogram_ops.py | 65 + tensorflow/python/ops/histogram_ops_test.py | 53 + tensorflow/python/ops/image_ops_impl.py | 46 +- tensorflow/python/ops/image_ops_test.py | 10 + tensorflow/python/ops/losses/losses_impl.py | 2 +- tensorflow/python/ops/metrics_impl.py | 56 +- tensorflow/python/ops/nn_impl.py | 5 +- tensorflow/python/ops/nn_ops.py | 9 +- tensorflow/python/ops/nn_test.py | 12 +- tensorflow/python/ops/rnn_cell_impl.py | 4 + tensorflow/python/summary/summary.py | 5 +- tensorflow/python/util/compat.py | 15 + .../tools/api/golden/tensorflow.compat.pbtxt | 4 + ...sorflow.nn.rnn_cell.-dropout-wrapper.pbtxt | 4 + tensorflow/tools/api/golden/tensorflow.pbtxt | 4 + .../tools/api/golden/tensorflow.summary.pbtxt | 2 +- tensorflow/tools/benchmark/BUILD | 3 +- tensorflow/tools/benchmark/README.md | 1 + .../tools/ci_build/builds/libtensorflow.sh | 2 +- tensorflow/tools/ci_build/ci_sanity.sh | 39 +- .../docker/parameterized_docker_build.sh | 2 +- tensorflow/tools/pip_package/BUILD | 21 - .../tools/pip_package/check_load_py_test.py | 3 + .../tools/pip_package/pip_smoke_test.py | 9 +- tensorflow/tools/pip_package/setup.py | 2 +- tensorflow/tools/test/BUILD | 9 - tensorflow/tools/test/check_futures_test.py | 2 +- tensorflow/workspace.bzl | 2 + third_party/git/git_configure.bzl | 5 + third_party/toolchains/clang6/BUILD | 1 + third_party/toolchains/clang6/CROSSTOOL.tpl | 587 +++++++ third_party/toolchains/clang6/README.md | 101 ++ third_party/toolchains/clang6/clang.BUILD | 162 ++ third_party/toolchains/clang6/repo.bzl | 30 + 143 files changed, 5265 insertions(+), 1416 deletions(-) create mode 100644 tensorflow/contrib/cmake/python_sanity_test.py create mode 100644 tensorflow/contrib/opt/python/training/model_average_optimizer.py create mode 100644 tensorflow/contrib/opt/python/training/model_average_optimizer_test.py create mode 100644 tensorflow/contrib/verbs/patch_notes_verbs_with_0_copies.md create mode 100644 tensorflow/contrib/verbs/verbs_with_0_copies.png create mode 100644 tensorflow/contrib/verbs/verbs_with_0_copies.xml create mode 100644 tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.jpg create mode 100644 tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.xml create mode 100644 tensorflow/core/kernels/mkl_softmax_op.cc create mode 100644 third_party/toolchains/clang6/BUILD create mode 100644 third_party/toolchains/clang6/CROSSTOOL.tpl create mode 100644 third_party/toolchains/clang6/README.md create mode 100644 third_party/toolchains/clang6/clang.BUILD create mode 100644 third_party/toolchains/clang6/repo.bzl diff --git a/RELEASE.md b/RELEASE.md index b24e83f053..fdf10407fd 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -13,46 +13,146 @@ * [TensorFlow Lite](https://github.com/tensorflow/tensorflow/tree/r1.5/tensorflow/contrib/lite) dev preview is now available. * CUDA 9 and cuDNN 7 support. +* Accelerated Linear Algebra (XLA): + * Add `complex64` support to XLA compiler. + * `bfloat` support is now added to XLA infrastructure. + * Make `ClusterSpec` propagation work with XLA devices. + * Use a determinisitic executor to generate XLA graph. +* `tf.contrib`: + * `tf.contrib.distributions`: + * Add `tf.contrib.distributions.Autoregressive`. + * Make `tf.contrib.distributions` QuadratureCompound classes support batch + * Infer `tf.contrib.distributions.RelaxedOneHotCategorical` `dtype` from arguments. + * Make `tf.contrib.distributions` quadrature family parameterized by + `quadrature_grid_and_prob` vs `quadrature_degree`. + * `auto_correlation` added to `tf.contrib.distributions` + * Add `tf.contrib.bayesflow.layers`, a collection of probabilistic (neural) layers. + * Add `tf.contrib.bayesflow.halton_sequence`. + * Add `tf.contrib.data.make_saveable_from_iterator.` + * Add `tf.contrib.data.shuffle_and_repeat`. + * Add new custom transformation: `tf.contrib.data.scan()`. + * `tf.contrib.distributions.bijectors`: + * Add `tf.contrib.distributions.bijectors.MaskedAutoregressiveFlow`. + * Add `tf.contrib.distributions.bijectors.Permute`. + * Add `tf.contrib.distributions.bijectors.Gumbel`. + * Add `tf.contrib.distributions.bijectors.Reshape`. + * Support shape inference (i.e., shapes containing -1) in the Reshape bijector. +* Add `streaming_precision_recall_at_equal_thresholds,` a method for computing + streaming precision and recall with `O(num_thresholds + size of predictions)` + time and space complexity. +* Change `RunConfig` default behavior to not set a random seed, making random + behavior independently random on distributed workers. We expect this to + generally improve training performance. Models that do rely on determinism + should set a random seed explicitly. +* Replaced the implementation of `tf.flags` with `absl.flags`. +* Add support for `CUBLAS_TENSOR_OP_MATH` in fp16 GEMM +* Add support for CUDA on NVIDIA Tegra devices ## Bug Fixes and Other Changes -* `auto_correlation` added to `tf.contrib.distributions`. -* Add `DenseFlipout` probabilistic layer. -* Restandardize `DenseVariational` as simpler template for other probabilistic layers. -* Make `tf.contrib.distributions` QuadratureCompound classes support batch. +* Documentation updates: + * Clarified that you can only install TensorFlow on 64-bit machines. + * Added a short doc explaining how `Estimator`s save checkpoints. + * Add documentation for ops supported by the `tf2xla` bridge. + * Fix minor typos in the doc of `SpaceToDepth` and `DepthToSpace`. + * Updated documentation comments in `mfcc_mel_filterbank.h` and `mfcc.h` to + clarify that the input domain is squared magnitude spectra and the weighting + is done on linear magnitude spectra (sqrt of inputs). + * Change `tf.contrib.distributions` docstring examples to use `tfd` alias + rather than `ds`, `bs`. + * Fix docstring typos in `tf.distributions.bijectors.Bijector`. + * `tf.assert_equal` no longer raises `ValueError.` It now raises + `InvalidArgumentError,` as documented. + * Update Getting Started docs and API intro. +* Google Cloud Storage (GCS): + * Add userspace DNS caching for the GCS client. + * Customize request timeouts for the GCS filesystem. + * Improve GCS filesystem caching. +* Bug Fixes: + * Fix bug where partitioned integer variables got their wrong shapes. Before + * Fix correctness bug in CPU and GPU implementations of Adadelta. + * Fix a bug in `import_meta_graph`'s handling of partitioned variables when + importing into a scope. WARNING: This may break loading checkpoints of + graphs with partitioned variables saved after using `import_meta_graph` with + a non-empty `import_scope` argument. + * Fix bug in offline debugger which prevented viewing events. + * Added the `WorkerService.DeleteWorkerSession` method to the gRPC interface, + to fix a memory leak. Ensure that your master and worker servers are running + the same version of TensorFlow to avoid compatibility issues. + * Fix bug in peephole implementation of BlockLSTM cell. + * Fix bug by casting dtype of `log_det_jacobian` to match `log_prob` in + `TransformedDistribution`. + * Fix a bug in `import_meta_graph`'s handling of partitioned variables when + * Ensure `tf.distributions.Multinomial` doesn't underflow in `log_prob`. + Before this change, all partitions of an integer variable were initialized + with the shape of the unpartitioned variable; after this change they are + initialized correctly. +* Other: + * Add necessary shape util support for bfloat16. + * Add a way to run ops using a step function to MonitoredSession. + * Add `DenseFlipout` probabilistic layer. + * A new flag `ignore_live_threads` is available on train. If set to `True`, it + will ignore threads that remain running when tearing down infrastructure + after successfully completing training, instead of throwing a RuntimeError. + * Restandardize `DenseVariational` as simpler template for other probabilistic + layers. + * `tf.data` now supports `tf.SparseTensor` components in dataset elements. + * It is now possible to iterate over `Tensor`s. + * Allow `SparseSegmentReduction` ops to have missing segment IDs. + * Modify custom export strategy to account for multidimensional sparse float + splits. + * `Conv2D`, `Conv2DBackpropInput`, `Conv2DBackpropFilter` now supports arbitrary + dilations with GPU and cuDNNv6 support. + * `Estimator` now supports `Dataset`: `input_fn` can return a `Dataset` + instead of `Tensor`s. + * Add `RevBlock`, a memory-efficient implementation of reversible residual layers. + * Reduce BFCAllocator internal fragmentation. + * Add `cross_entropy` and `kl_divergence` to `tf.distributions.Distribution`. + * Add `tf.nn.softmax_cross_entropy_with_logits_v2` which enables backprop + w.r.t. the labels. + * GPU back-end now uses `ptxas` to compile generated PTX. + * `BufferAssignment`'s protocol buffer dump is now deterministic. + * Change embedding op to use parallel version of `DynamicStitch`. + * Add support for sparse multidimensional feature columns. + * Speed up the case for sparse float columns that have only 1 value. + * Allow sparse float splits to support multivalent feature columns. + * Add `quantile` to `tf.distributions.TransformedDistribution`. + * Add `NCHW_VECT_C` support for `tf.depth_to_space` on GPU. + * Add `NCHW_VECT_C` support for `tf.space_to_depth` on GPU. + +## API Changes +* Rename `SqueezeDims` attribute to `Axis` in C++ API for Squeeze op. * `Stream::BlockHostUntilDone` now returns Status rather than bool. -* Customize request timeouts for the GCS filesystem. +* Minor refactor: move stats files from `stochastic` to `common` and remove + `stochastic`. ## Thanks to our Contributors This release contains contributions from many people at Google, as well as: -4d55397500, Abdullah Alrasheed, abenmao, Adam Salvail, Aditya Dhulipala, Ag Ramesh, -Akimasa Kimura, Alan Du, Alan Yee, Alexander, Amit Kushwaha, Amy, Andrei Costinescu, -Andrei Nigmatulin, Andrew Erlichson, Andrew Myers, Andrew Stepanov, Androbin, AngryPowman, -Anish Shah, Anton Daitche, Artsiom Chapialiou, asdf2014, Aseem Raj Baranwal, Ash Hall, -Bart Kiers, Batchu Venkat Vishal, ben, Ben Barsdell, Bill Piel, Carl Thomé, Catalin Voss, -Changming Sun, Chengzhi Chen, Chi Zeng, Chris Antaki, Chris Donahue, Chris Oelmueller, -Chris Tava, Clayne Robison, Codrut, Courtial Florian, Dalmo Cirne, Dan J, Darren Garvey, -David Kristoffersson, David Norman, David RöThlisberger, DavidNorman, Dhruv, DimanNe, -Dorokhov, Duncan Mac-Vicar P, EdwardDixon, EMCP, error.d, FAIJUL, Fan Xia, -Francois Xavier, Fred Reiss, Freedom" Koan-Sin Tan, Fritz Obermeyer, Gao, Xiang, -Guenther Schmuelling, Guo Yejun (郭叶军), Hans Gaiser, HectorSVC, Hyungsuk Yoon, -James Pruegsanusak, Jay Young, Jean Wanka, Jeff Carpenter, Jeremy Rutman, Jeroen BéDorf, -Jett Jones, Jimmy Jia, jinghuangintel, jinze1994, JKurland, Joel Hestness, joetoth, -John B Nelson, John Impallomeni, John Lawson, Jonas, Jonathan Dekhtiar, joshkyh, Jun Luan, -Jun Mei, Kai Sasaki, Karl Lessard, karl@kubx.ca, Kb Sriram, Kenichi Ueno, Kevin Slagle, -Kongsea, Lakshay Garg, lhlmgr, Lin Min, liu.guangcong, Loki Der Quaeler, Louie Helm, -lucasmoura, Luke Iwanski, Lyndon White, Mahmoud Abuzaina, Marcel Puyat, Mark Aaron Shirley, -Michele Colombo, MtDersvan, Namrata-Ibm, Nathan Luehr, Naurril, Nayana Thorat, Nicolas Lopez, -Niranjan Hasabnis, Nolan Liu, Nouce, Oliver Hennigh, osdamv, Patrik Erdes, -Patryk Chrabaszcz, Pavel Christof, Penghao Cen, postBG, Qingqing Cao, Qingying Chen, qjivy, -Raphael, Rasmi, raymondxyang, Renze Yu, resec, Roffel, Ruben Vereecken, Ryohei Kuroki, -sandipmgiri, Santiago Castro, Scott Kirkland, Sean Vig, Sebastian Raschka, Sebastian Weiss, -Sergey Kolesnikov, Sergii Khomenko, Shahid, Shivam Kotwalia, Stuart Berg, Sumit Gouthaman, -superzerg, Sven Mayer, tetris, Ti Zhou, Tiago Freitas Pereira, Tian Jin, Tomoaki Oiki, -Vaibhav Sood, vfdev, Vivek Rane, Vladimir Moskva, wangqr, Weber Xie, Will Frey, -Yan Facai (颜发才), yanivbl6, Yaroslav Bulatov, Yixing Lao, Yong Tang, youkaichao, -Yuan (Terry) Tang, Yue Zhang, Yuxin Wu, Ziming Dong, ZxYuan, 黄璞 +Adam Zahran, Ag Ramesh, Alan Lee, Alan Yee, Alex Sergeev, Alexander, Amir H. Jadidinejad, +Amy, Anastasios Doumoulakis, Andrei Costinescu, Andrei Nigmatulin, Anthony Platanios, +Anush Elangovan, arixlin, Armen Donigian, ArtëM Sobolev, Atlas7, Ben Barsdell, Bill Prin, +Bo Wang, Brett Koonce, Cameron Thomas, Carl Thomé, Cem Eteke, cglewis, Changming Sun, +Charles Shenton, Chi-Hung, Chris Donahue, Chris Filo Gorgolewski, Chris Hoyean Song, +Chris Tava, Christian Grail, Christoph Boeddeker, cinqS, Clayne Robison, codrut3, concerttttt, +CQY, Dan Becker, Dan Jarvis, Daniel Zhang, David Norman, dmaclach, Dmitry Trifonov, +Donggeon Lim, dongpilYu, Dr. Kashif Rasul, Edd Wilder-James, Eric Lv, fcharras, Felix Abecassis, +FirefoxMetzger, formath, FredZhang, Gaojin Cao, Gary Deer, Guenther Schmuelling, Hanchen Li, +Hanmin Qin, hannesa2, hyunyoung2, Ilya Edrenkin, Jackson Kontny, Jan, Javier Luraschi, +Jay Young, Jayaram Bobba, Jeff, Jeff Carpenter, Jeremy Sharpe, Jeroen BéDorf, Jimmy Jia, +Jinze Bai, Jiongyan Zhang, Joe Castagneri, Johan Ju, Josh Varty, Julian Niedermeier, +JxKing, Karl Lessard, Kb Sriram, Keven Wang, Koan-Sin Tan, Kyle Mills, lanhin, LevineHuang, +Loki Der Quaeler, Loo Rong Jie, Luke Iwanski, LáSzló Csomor, Mahdi Abavisani, Mahmoud Abuzaina, +ManHyuk, Marek ŠUppa, MathSquared, Mats Linander, Matt Wytock, Matthew Daley, Maximilian Bachl, +mdymczyk, melvyniandrag, Michael Case, Mike Traynor, miqlas, Namrata-Ibm, Nathan Luehr, +Nathan Van Doorn, Noa Ezra, Nolan Liu, Oleg Zabluda, opensourcemattress, Ouwen Huang, +Paul Van Eck, peisong, Peng Yu, PinkySan, pks, powderluv, Qiao Hai-Jun, Qiao Longfei, +Rajendra Arora, Ralph Tang, resec, Robin Richtsfeld, Rohan Varma, Ryohei Kuroki, SaintNazaire, +Samuel He, Sandeep Dcunha, sandipmgiri, Sang Han, scott, Scott Mudge, Se-Won Kim, Simon Perkins, +Simone Cirillo, Steffen Schmitz, Suvojit Manna, Sylvus, Taehoon Lee, Ted Chang, Thomas Deegan, +Till Hoffmann, Tim, Toni Kunic, Toon Verstraelen, Tristan Rice, Urs KöSter, Utkarsh Upadhyay, +Vish (Ishaya) Abrams, Winnie Tsang, Yan Chen, Yan Facai (颜发才), Yi Yang, Yong Tang, +Youssef Hesham, Yuan (Terry) Tang, Zhengsheng Wei, zxcqwe4906, 张志豪, 田传武 We are also grateful to all who filed issues or helped resolve them, asked and answered questions, and were part of inspiring discussions. @@ -60,7 +160,15 @@ answered questions, and were part of inspiring discussions. # Release 1.4.1 ## Bug Fixes and Other Changes -* `LinearClassifier` fix for the Google Cloud Machine Learning Engine. +* `LinearClassifier` fix. + +# Release 1.4.0 + +## Major Features And Improvements +* `tf.keras` is now part of the core TensorFlow API. +* [`tf.data`](http://tensorflow.org/programmers_guide/datasets) is now part of + the core TensorFlow API. + * The API is now subject to backwards compatibility guarantees. # Release 1.4.0 diff --git a/WORKSPACE b/WORKSPACE index b40913801b..7ae39374f1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -2,11 +2,11 @@ workspace(name = "org_tensorflow") http_archive( name = "io_bazel_rules_closure", - sha256 = "110fe68753413777944b473c25eed6368c4a0487cee23a7bac1b13cc49d3e257", - strip_prefix = "rules_closure-4af89ef1db659eb41f110df189b67d4cf14073e1", + sha256 = "6691c58a2cd30a86776dd9bb34898b041e37136f2dc7e24cadaeaf599c95c657", + strip_prefix = "rules_closure-08039ba8ca59f64248bb3b6ae016460fe9c9914f", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/4af89ef1db659eb41f110df189b67d4cf14073e1.tar.gz", - "https://github.com/bazelbuild/rules_closure/archive/4af89ef1db659eb41f110df189b67d4cf14073e1.tar.gz", # 2017-08-28 + "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/08039ba8ca59f64248bb3b6ae016460fe9c9914f.tar.gz", + "https://github.com/bazelbuild/rules_closure/archive/08039ba8ca59f64248bb3b6ae016460fe9c9914f.tar.gz", # 2018-01-16 ], ) diff --git a/tensorflow/BUILD b/tensorflow/BUILD index 1bf7c741b7..2ea0e38c78 100644 --- a/tensorflow/BUILD +++ b/tensorflow/BUILD @@ -662,6 +662,9 @@ filegroup( "//tensorflow/tools/quantization:all_files", "//tensorflow/tools/test:all_files", "//tensorflow/user_ops:all_files", + "//third_party/eigen3:all_files", + "//third_party/fft2d:all_files", + "//third_party/flatbuffers:all_files", "//third_party/hadoop:all_files", "//third_party/sycl:all_files", "//third_party/sycl/sycl:all_files", diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc index e4e33016c2..ecba8c0109 100644 --- a/tensorflow/c/eager/c_api.cc +++ b/tensorflow/c/eager/c_api.cc @@ -190,6 +190,7 @@ TFE_TensorHandle* TFE_TensorHandleCopyToDevice(TFE_TensorHandle* h, bool is_same_device = (srcd == dstd) || (DeviceName(srcd) == DeviceName(dstd)); const bool dst_cpu = IsCPU(dstd); + const bool src_cpu = IsCPU(srcd); if (is_same_device) { return new TFE_TensorHandle(h->t, dst_cpu ? nullptr : dstd); } @@ -213,7 +214,7 @@ TFE_TensorHandle* TFE_TensorHandleCopyToDevice(TFE_TensorHandle* h, return new TFE_TensorHandle(dst, dst_cpu ? nullptr : dstd); } tensorflow::DeviceContext* src_device_context = nullptr; - if (!IsCPU(srcd)) { + if (!src_cpu) { src_device_context = srcd->tensorflow_gpu_device_info()->default_context; } tensorflow::DeviceContext* dst_device_context = nullptr; diff --git a/tensorflow/compiler/xla/tests/dynamic_ops_test.cc b/tensorflow/compiler/xla/tests/dynamic_ops_test.cc index ae3f887240..877dc7db0e 100644 --- a/tensorflow/compiler/xla/tests/dynamic_ops_test.cc +++ b/tensorflow/compiler/xla/tests/dynamic_ops_test.cc @@ -595,6 +595,11 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousSingleElement) { // Single element, no wrap. std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/1); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousSingleElementBF16) { + // Single element, no wrap. + std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/1); } @@ -602,6 +607,11 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousMultipleElements) { // Multiple element, no wrap. std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/2); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousMultipleElementsBF16) { + // Multiple element, no wrap. + std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/2); } @@ -609,6 +619,11 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousMultipleWrapping) { // Multiple element, wrapping. std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/3, /*size=*/2); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousMultipleWrappingBF16) { + // Multiple element, wrapping. + std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/3, /*size=*/2); } @@ -616,12 +631,21 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousTooLarge) { // Multiple element, update size larger than operand. std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/5, /*size=*/2); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousTooLargeBF16) { + // Multiple element, update size larger than operand. + std::vector operand_shape({4, 5, 2}); RunR3Contiguous(operand_shape, /*index=*/5, /*size=*/2); } XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousUnaligned) { std::vector operand_shape({3, 123, 247}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/1); +} + +XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousUnalignedBF16) { + std::vector operand_shape({3, 123, 247}); RunR3Contiguous(operand_shape, /*index=*/1, /*size=*/1); } @@ -629,6 +653,10 @@ XLA_TEST_F(DynamicUpdateSliceTest, R3ContiguousUnaligned) { XLA_TEST_F(DynamicUpdateSliceTest, DISABLED_ON_GPU(R3ContiguousLarger)) { std::vector operand_shape({32, 128, 1024}); RunR3Contiguous(operand_shape, /*index=*/7, /*size=*/1); +} + +XLA_TEST_F(DynamicUpdateSliceTest, DISABLED_ON_GPU(R3ContiguousLargerBF16)) { + std::vector operand_shape({32, 128, 1024}); RunR3Contiguous(operand_shape, /*index=*/7, /*size=*/1); } diff --git a/tensorflow/contrib/cmake/README.md b/tensorflow/contrib/cmake/README.md index 4be733a280..8f85a75ee4 100644 --- a/tensorflow/contrib/cmake/README.md +++ b/tensorflow/contrib/cmake/README.md @@ -30,7 +30,7 @@ bindings. * CMake version 3.5 or later. -* [Git](http://git-scm.com) +* [Git](https://git-scm.com) * [SWIG](http://www.swig.org/download.html) @@ -48,7 +48,7 @@ bindings. * Microsoft Windows 10 - Microsoft Visual Studio Enterprise 2015 with Visual C++ 2015 - - [Anaconda 4.1.1 (Python 3.5 64-bit)](https://www.continuum.io/downloads) + - [Anaconda 4.1.1 (Python 3.5 64-bit)](https://www.anaconda.com/download/) - [Git for Windows version 2.9.2.windows.1](https://git-scm.com/download/win) - [swigwin-3.0.10](http://www.swig.org/download.html) - [NVidia CUDA Toolkit 8.0](https://developer.nvidia.com/cuda-downloads) diff --git a/tensorflow/contrib/cmake/external/snappy.cmake b/tensorflow/contrib/cmake/external/snappy.cmake index 013b3a862f..fd57734298 100644 --- a/tensorflow/contrib/cmake/external/snappy.cmake +++ b/tensorflow/contrib/cmake/external/snappy.cmake @@ -47,4 +47,4 @@ ExternalProject_Add(snappy ) # actually enables snappy in the source code -add_definitions(-DTF_USE_SNAPPY) \ No newline at end of file +add_definitions(-DTF_USE_SNAPPY) diff --git a/tensorflow/contrib/cmake/python_modules.txt b/tensorflow/contrib/cmake/python_modules.txt index dec6c513ba..7db454bd83 100644 --- a/tensorflow/contrib/cmake/python_modules.txt +++ b/tensorflow/contrib/cmake/python_modules.txt @@ -1,3 +1,5 @@ +# python_sanity_test.py will complain about invalid or missing entries +# problematic entries can be commented for temporary whitelisting tensorflow tensorflow/core tensorflow/core/example @@ -307,6 +309,8 @@ tensorflow/contrib/metrics tensorflow/contrib/metrics/python tensorflow/contrib/metrics/python/metrics tensorflow/contrib/metrics/python/ops +tensorflow/contrib/mpi_collectives/python +tensorflow/contrib/mpi_collectives/python/ops tensorflow/contrib/model_pruning tensorflow/contrib/model_pruning/examples tensorflow/contrib/model_pruning/examples/cifar10 diff --git a/tensorflow/contrib/cmake/python_sanity_test.py b/tensorflow/contrib/cmake/python_sanity_test.py new file mode 100644 index 0000000000..3be5bd1b23 --- /dev/null +++ b/tensorflow/contrib/cmake/python_sanity_test.py @@ -0,0 +1,124 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +""" +Complain about invalid or missing entries in python_*.txt files. +Problematic entries can be commented for temporary whitelisting. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import unittest + + +def abs_path(path): + root = os.path.dirname(__file__) + + for _ in range(3): + root = os.path.join(root, os.pardir) + + path = os.path.join(root, path) + path = os.path.abspath(path) + return path + +def read_entries(test): + with open(abs_path(test.entries_file), "r") as f: + lines = f.readlines() + + lines = [line.strip() for line in lines] + lines = [line for line in lines if line] + + test.entries = [] + test.whitelist = [] + + for line in lines: + # line is comment + if line.startswith('#'): + line = line[1:].strip() + # whitelist entry + if line.startswith('tensorflow/'): + test.whitelist.append(line) + # line has comment -> strip comment + elif line.find('#') != -1: + line = line[:line.find('#')].strip() + test.entries.append(line) + else: + test.entries.append(line) + +def test_invalid_directories(test): + for entry in test.entries: + if not os.path.isdir(abs_path(entry)): + problem = "'" + test.entries_file + "' contains invalid '" + entry + "'" + solution = "Please remove the invalid entry (or add the missing directory)." + raise AssertionError(problem + "\n" + solution) + +def test_missing_directory(test, path): + if path in test.whitelist: + return + + dir_exists = os.path.isdir(abs_path(path)) + entry_exists = path in test.entries + + if dir_exists and not entry_exists: + problem = "'" + test.entries_file + "' is missing '" + path + "'" + solution = "Please add the missing entry (comment to whitelist if needed)." + raise AssertionError(problem + "\n" + solution) + + +class PythonModuleTest(unittest.TestCase): + + def setUp(self): + self.entries_file = "tensorflow/contrib/cmake/python_modules.txt" + read_entries(self) + + def testInvalidEntries(self): + test_invalid_directories(self) + + def testMissingModules(self): + module_names = next(os.walk(abs_path("tensorflow/contrib")))[1] + + for module_name in module_names: + path = "tensorflow/contrib/" + module_name + + test_missing_directory(self, path + "/python") + test_missing_directory(self, path + "/python/ops") + test_missing_directory(self, path + "/python/kernels") + test_missing_directory(self, path + "/python/layers") + + +class PythonProtoTest(unittest.TestCase): + + def setUp(self): + self.entries_file = "tensorflow/contrib/cmake/python_protos.txt" + read_entries(self) + + def testInvalidEntries(self): + test_invalid_directories(self) + + +class PythonProtoCCTest(unittest.TestCase): + + def setUp(self): + self.entries_file = "tensorflow/contrib/cmake/python_protos_cc.txt" + read_entries(self) + + def testInvalidEntries(self): + test_invalid_directories(self) + + +if __name__ == "__main__": + unittest.main() diff --git a/tensorflow/contrib/cmake/tf_core_framework.cmake b/tensorflow/contrib/cmake/tf_core_framework.cmake index 24d7fb82a2..129c208ecd 100644 --- a/tensorflow/contrib/cmake/tf_core_framework.cmake +++ b/tensorflow/contrib/cmake/tf_core_framework.cmake @@ -126,7 +126,9 @@ endfunction() file(GLOB_RECURSE tf_protos_cc_srcs RELATIVE ${tensorflow_source_dir} "${tensorflow_source_dir}/tensorflow/core/*.proto" "${tensorflow_source_dir}/tensorflow/contrib/boosted_trees/proto/*.proto" + "${tensorflow_source_dir}/tensorflow/contrib/tpu/proto/*.proto" ) + RELATIVE_PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${tensorflow_source_dir} ${tf_protos_cc_srcs} ) diff --git a/tensorflow/contrib/cmake/tf_python.cmake b/tensorflow/contrib/cmake/tf_python.cmake index b62a031749..8862390d2b 100755 --- a/tensorflow/contrib/cmake/tf_python.cmake +++ b/tensorflow/contrib/cmake/tf_python.cmake @@ -126,7 +126,8 @@ STRING(REGEX REPLACE ";" "\\\\;" python_protos "${python_protos}") STRING(REGEX REPLACE "\n" ";" python_protos "${python_protos}") foreach(python_proto ${python_protos}) - if(NOT python_proto MATCHES "\#") + if(NOT python_proto MATCHES "^\#") + STRING(REGEX REPLACE " *\#.*" "" python_proto "${python_proto}") if(NOT EXISTS "${tensorflow_source_dir}/${python_proto}") message(SEND_ERROR "Python proto directory not found: ${python_proto}") endif() @@ -147,7 +148,8 @@ STRING(REGEX REPLACE ";" "\\\\;" python_protos_cc "${python_protos_cc}") STRING(REGEX REPLACE "\n" ";" python_protos_cc "${python_protos_cc}") foreach(python_proto_cc ${python_protos_cc}) - if(NOT python_proto_cc MATCHES "\#") + if(NOT python_proto_cc MATCHES "^\#") + STRING(REGEX REPLACE " *\#.*" "" python_proto_cc "${python_proto_cc}") if(NOT EXISTS "${tensorflow_source_dir}/${python_proto_cc}") message(SEND_ERROR "Python proto CC directory not found: ${python_proto_cc}") endif() @@ -209,7 +211,8 @@ STRING(REGEX REPLACE ";" "\\\\;" python_modules "${python_modules}") STRING(REGEX REPLACE "\n" ";" python_modules "${python_modules}") foreach(python_module ${python_modules}) - if(NOT python_module MATCHES "\#") + if(NOT python_module MATCHES "^\#") + STRING(REGEX REPLACE " *\#.*" "" python_module "${python_module}") if(NOT EXISTS "${tensorflow_source_dir}/${python_module}") message(SEND_ERROR "Python module not found: ${python_module}") endif() diff --git a/tensorflow/contrib/cudnn_rnn/kernels/cudnn_rnn_ops.cc b/tensorflow/contrib/cudnn_rnn/kernels/cudnn_rnn_ops.cc index 6b0452e7af..ba9686e94e 100644 --- a/tensorflow/contrib/cudnn_rnn/kernels/cudnn_rnn_ops.cc +++ b/tensorflow/contrib/cudnn_rnn/kernels/cudnn_rnn_ops.cc @@ -649,7 +649,7 @@ class CudnnRNNParamsToCanonical : public CudnnRNNKernelCommon { } const int num_params_per_layer = num_params_ / num_layers / num_dirs; // Number of params applied on inputs. The rest are applied on recurrent - // hiddden states. + // hidden states. const int num_params_input_state = num_params_per_layer / 2; CHECK(num_params_ % (num_layers * num_dirs) == 0) << "Number of params is not a multiple of num_layers * num_dirs."; diff --git a/tensorflow/contrib/cudnn_rnn/python/ops/cudnn_rnn_ops.py b/tensorflow/contrib/cudnn_rnn/python/ops/cudnn_rnn_ops.py index 5f6e3be28f..e87162f0ee 100644 --- a/tensorflow/contrib/cudnn_rnn/python/ops/cudnn_rnn_ops.py +++ b/tensorflow/contrib/cudnn_rnn/python/ops/cudnn_rnn_ops.py @@ -1542,7 +1542,7 @@ class _CudnnRNNNoInputC(_CudnnRNN): params: the parameter buffer created for this model. is_training: whether this operation will be used in training or inference. Returns: - output: the output sequuence. + output: the output sequence. output_h: the final state for h. """ return _cudnn_rnn_no_input_c( diff --git a/tensorflow/contrib/eager/python/g3doc/guide.md b/tensorflow/contrib/eager/python/g3doc/guide.md index 0095ffa0db..7eea93ce1f 100644 --- a/tensorflow/contrib/eager/python/g3doc/guide.md +++ b/tensorflow/contrib/eager/python/g3doc/guide.md @@ -292,7 +292,7 @@ def loss(weight, bias): error = prediction(training_inputs, weight, bias) - training_outputs return tf.reduce_mean(tf.square(error)) -# Function that returns the the derivative of loss with respect to +# Function that returns the derivative of loss with respect to # weight and bias grad = tfe.gradients_function(loss) diff --git a/tensorflow/contrib/estimator/python/estimator/extenders.py b/tensorflow/contrib/estimator/python/estimator/extenders.py index 29c3c73585..c99bf8badb 100644 --- a/tensorflow/contrib/estimator/python/estimator/extenders.py +++ b/tensorflow/contrib/estimator/python/estimator/extenders.py @@ -100,7 +100,7 @@ def add_metrics(estimator, metric_fn): def clip_gradients_by_norm(optimizer, clip_norm): - """Returns an optimizer which clips gradients before appliying them. + """Returns an optimizer which clips gradients before applying them. Example: diff --git a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc index 3c51deefbc..c85b1837ab 100644 --- a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc +++ b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc @@ -82,7 +82,9 @@ std::vector FfmpegVideoCommandLine(const string& input_filename, "-probesize", StrCat(kDefaultProbeSize), "-loglevel", - "error", // Print errors only. + // Info is needed to get the information about stream, etc. + // It is generated to a separate file, not stdout/stderr. + "info", "-hide_banner", // Skip printing build options, version, etc. "-vcodec", "rawvideo", diff --git a/tensorflow/contrib/framework/python/ops/script_ops.py b/tensorflow/contrib/framework/python/ops/script_ops.py index fdbb77bbe4..5d269fefdc 100644 --- a/tensorflow/contrib/framework/python/ops/script_ops.py +++ b/tensorflow/contrib/framework/python/ops/script_ops.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== + """Script Language Operators. See the @{$python/script_ops} guide. @@py_func diff --git a/tensorflow/contrib/gan/python/train.py b/tensorflow/contrib/gan/python/train.py index a32ddd7a06..5d0ac93aec 100644 --- a/tensorflow/contrib/gan/python/train.py +++ b/tensorflow/contrib/gan/python/train.py @@ -279,14 +279,16 @@ def acgan_model( generator_inputs = _convert_tensor_or_l_or_d(generator_inputs) generated_data = generator_fn(generator_inputs) with variable_scope.variable_scope(discriminator_scope) as dis_scope: - (discriminator_gen_outputs, discriminator_gen_classification_logits - ) = _validate_acgan_discriminator_outputs( - discriminator_fn(generated_data, generator_inputs)) + with ops.name_scope(dis_scope.name+'/generated/'): + (discriminator_gen_outputs, discriminator_gen_classification_logits + ) = _validate_acgan_discriminator_outputs( + discriminator_fn(generated_data, generator_inputs)) with variable_scope.variable_scope(dis_scope, reuse=True): - real_data = ops.convert_to_tensor(real_data) - (discriminator_real_outputs, discriminator_real_classification_logits - ) = _validate_acgan_discriminator_outputs( - discriminator_fn(real_data, generator_inputs)) + with ops.name_scope(dis_scope.name+'/real/'): + real_data = ops.convert_to_tensor(real_data) + (discriminator_real_outputs, discriminator_real_classification_logits + ) = _validate_acgan_discriminator_outputs( + discriminator_fn(real_data, generator_inputs)) if check_shapes: if not generated_data.shape.is_compatible_with(real_data.shape): raise ValueError( diff --git a/tensorflow/contrib/layers/python/layers/layers.py b/tensorflow/contrib/layers/python/layers/layers.py index f3229a1605..ef2b673074 100644 --- a/tensorflow/contrib/layers/python/layers/layers.py +++ b/tensorflow/contrib/layers/python/layers/layers.py @@ -479,8 +479,12 @@ def batch_norm(inputs, Sergey Ioffe, Christian Szegedy - Can be used as a normalizer function for conv2d and fully_connected. - + Can be used as a normalizer function for conv2d and fully_connected. The + normalization is over all but the last dimension if `data_format` is `NHWC` + and all but the second dimension if `data_format` is `NCHW`. In case of a 2D + tensor this corresponds to the batch dimension, while in case of a 4D tensor this + corresponds to the batch and space dimensions. + Note: when training, the moving_mean and moving_variance need to be updated. By default the update ops are placed in `tf.GraphKeys.UPDATE_OPS`, so they need to be added as a dependency to the `train_op`. For example: diff --git a/tensorflow/contrib/lite/download_dependencies.sh b/tensorflow/contrib/lite/download_dependencies.sh index 362e5bee25..e1b7b3613a 100755 --- a/tensorflow/contrib/lite/download_dependencies.sh +++ b/tensorflow/contrib/lite/download_dependencies.sh @@ -22,7 +22,14 @@ cd "$SCRIPT_DIR/../../.." DOWNLOADS_DIR=tensorflow/contrib/lite/downloads BZL_FILE_PATH=tensorflow/workspace.bzl -EIGEN_URL="$(grep -o 'http.*bitbucket.org/eigen/eigen/get/.*tar\.gz' "${BZL_FILE_PATH}" | grep -v bazel-mirror | head -n1)" +# Ensure it is being run from repo root +if [ ! -f $BZL_FILE_PATH ]; then + echo "Could not find ${BZL_FILE_PATH}": + echo "Likely you are not running this from the root directory of the repository."; + exit 1; +fi + +EIGEN_URL="$(grep -o 'http.*bitbucket.org/eigen/eigen/get/.*tar\.gz' "${BZL_FILE_PATH}" | grep -v mirror.bazel | head -n1)" GEMMLOWP_URL="$(grep -o 'https://mirror.bazel.build/github.com/google/gemmlowp/.*zip' "${BZL_FILE_PATH}" | head -n1)" GOOGLETEST_URL="https://github.com/google/googletest/archive/release-1.8.0.tar.gz" ABSL_URL="$(grep -o 'https://github.com/abseil/abseil-cpp/.*tar.gz' "${BZL_FILE_PATH}" | head -n1)" diff --git a/tensorflow/contrib/lite/kernels/gather.cc b/tensorflow/contrib/lite/kernels/gather.cc index f8df797daf..0e4187d1ea 100644 --- a/tensorflow/contrib/lite/kernels/gather.cc +++ b/tensorflow/contrib/lite/kernels/gather.cc @@ -42,9 +42,10 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { TF_LITE_ENSURE_EQ(context, positions->type, kTfLiteInt32); // Check that input and output types match. TF_LITE_ENSURE_EQ(context, input->type, output->type); - // TODO(mgubin): only 1D positions are currently supported. - TF_LITE_ENSURE_EQ(context, NumDimensions(positions), 1); + // TODO(mgubin): only 0D or 1D positions are currently supported. + TF_LITE_ENSURE(context, NumDimensions(positions) <= 1); // TODO(mgubin): Only default axis == 0 is supported. + TF_LITE_ENSURE_EQ(context, params->axis, 0); // Check conditions for different types. switch (input->type) { case kTfLiteFloat32: @@ -64,7 +65,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { } const int num_dimensions = NumDimensions(input) + NumDimensions(positions) - 1; - TF_LITE_ENSURE(context, params->axis < num_dimensions); + TF_LITE_ENSURE(context, params->axis <= num_dimensions); TfLiteIntArray* output_shape = TfLiteIntArrayCreate(num_dimensions); int output_index = 0; for (int i = 0; i < params->axis; ++i) { diff --git a/tensorflow/contrib/lite/kernels/gather_test.cc b/tensorflow/contrib/lite/kernels/gather_test.cc index 6343d3b4ef..658d977b8d 100644 --- a/tensorflow/contrib/lite/kernels/gather_test.cc +++ b/tensorflow/contrib/lite/kernels/gather_test.cc @@ -48,8 +48,8 @@ class GatherOpModel : public SingleOpModel { PopulateStringTensor(input_, data); } - void SetPositions(std::initializer_list data) { - PopulateTensor(positions_, data); + void SetPositions(std::initializer_list data) { + PopulateTensor(positions_, data); } std::vector GetOutputFloat() { return ExtractVector(output_); } @@ -76,6 +76,29 @@ TEST(GatherOpTest, Shuffle) { ElementsAreArray(ArrayFloatNear({0.7, 0.8, -2, 0.2}))); } +TEST(GatherOpTest, Test0DIndex) { + GatherOpModel m({2, 2}, TensorType_FLOAT32, {}); + m.SetInputFloat({-2.0, 0.2, 0.7, 0.8}); + m.SetPositions({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputFloat(), + ElementsAreArray(ArrayFloatNear({0.7, 0.8}))); + EXPECT_THAT(m.GetOutputShape(), + ElementsAreArray({2})); +} + +TEST(GatherOpTest, Test0DIndexWith0DResult) { + // 0D tensor is special case in current TFLite. Test it once to make sure + // existing workarounds are fine with it. + GatherOpModel m({3}, TensorType_FLOAT32, {}); + m.SetInputFloat({1.0, 2.0, 3.0}); + m.SetPositions({1}); + m.Invoke(); + EXPECT_THAT(m.GetOutputFloat(), + ElementsAreArray(ArrayFloatNear({2.0}))); + EXPECT_TRUE(m.GetOutputShape().empty()); +} + TEST(FloatGatherOpTest, Duplicate) { GatherOpModel m({1, 2, 2}, TensorType_FLOAT32, {2}); m.SetInputFloat({-2.0, 0.2, 0.7, 0.8}); diff --git a/tensorflow/contrib/lite/models/testdata/g3doc/README.md b/tensorflow/contrib/lite/models/testdata/g3doc/README.md index 667a588383..1c47e00aae 100644 --- a/tensorflow/contrib/lite/models/testdata/g3doc/README.md +++ b/tensorflow/contrib/lite/models/testdata/g3doc/README.md @@ -53,7 +53,7 @@ with the corresponding parameters as shown in the figure. ### Automatic Speech Recognizer (ASR) Acoustic Model (AM) The acoustic model for automatic speech recognition is the neural network model -for matching phonemes to the input autio features. It generates posterior +for matching phonemes to the input audio features. It generates posterior probabilities of phonemes from speech frontend features (log-mel filterbanks). It has an input size of 320 (float), an output size of 42 (float), five LSTM layers and one fully connected layers with a Softmax activation function, with @@ -68,7 +68,7 @@ for predicting the probability of a word given previous words in a sentence. It generates posterior probabilities of the next word based from a sequence of words. The words are encoded as indices in a fixed size dictionary. The model has two inputs both of size one (integer): the current word index and -next word index, an output size of one (float): the log probability. It consits +next word index, an output size of one (float): the log probability. It consists of three embedding layer, three LSTM layers, followed by a multiplication, a fully connected layers and an addition. The corresponding parameters as shown in the figure. diff --git a/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h b/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h index 3cda4bcccc..7019c29959 100644 --- a/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h +++ b/tensorflow/contrib/lite/nnapi/NeuralNetworksShim.h @@ -370,7 +370,7 @@ enum { * Looks up items from a given tensor. * * Each item in the output is a raw copy of the corresponding item in - * the input “values”. If the the given “lookup” indices are out of bounds, + * the input “values”. If the given “lookup” indices are out of bounds, * the op will fail and an error will be reported. * * Inputs: diff --git a/tensorflow/contrib/lite/testing/generate_examples.py b/tensorflow/contrib/lite/testing/generate_examples.py index 6204471e52..c225cd4f00 100644 --- a/tensorflow/contrib/lite/testing/generate_examples.py +++ b/tensorflow/contrib/lite/testing/generate_examples.py @@ -1170,7 +1170,7 @@ def make_pad_tests(zip_path): def make_reshape_tests(zip_path): """Make a set of tests to do reshape.""" - # Alll shapes below are suitable for tensors with 420 elements. + # All shapes below are suitable for tensors with 420 elements. test_parameters = [{ "dtype": [tf.float32, tf.int32], "input_shape": [[3, 4, 5, 7], [4, 105], [21, 5, 2, 2], [420]], diff --git a/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md b/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md index 4776741ab9..5e07795223 100644 --- a/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md +++ b/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md @@ -229,7 +229,7 @@ additional information about the multiple input arrays: well-formed quantized representation of these graphs. Such graphs should be fixed, but as a temporary work-around, setting this reorder_across_fake_quant flag allows the converter to perform necessary - graph transformaitons on them, at the cost of no longer faithfully matching + graph transformations on them, at the cost of no longer faithfully matching inference and training arithmetic. ### Logging flags diff --git a/tensorflow/contrib/lite/tools/BUILD b/tensorflow/contrib/lite/tools/BUILD index 6e2d633765..20df905270 100644 --- a/tensorflow/contrib/lite/tools/BUILD +++ b/tensorflow/contrib/lite/tools/BUILD @@ -27,6 +27,27 @@ tf_cc_binary( ], ) +tf_cc_binary( + name = "benchmark_model", + srcs = ["benchmark_model.cc"], + linkopts = select({ + "//tensorflow:android": [ + "-pie", + "-landroid", + "-lm", + "-z defs", + "-Wl,--exclude-libs,ALL", # Exclude syms in all libs from auto export + ], + "//conditions:default": [], + }), + deps = [ + ":mutable_op_resolver", + "//tensorflow/contrib/lite:framework", + "//tensorflow/contrib/lite:string_util", + "//tensorflow/contrib/lite/kernels:builtin_ops", + ], +) + cc_library( name = "gen_op_registration", srcs = ["gen_op_registration.cc"], diff --git a/tensorflow/contrib/makefile/download_dependencies.sh b/tensorflow/contrib/makefile/download_dependencies.sh index 0a47f50c43..4ae18b2cef 100755 --- a/tensorflow/contrib/makefile/download_dependencies.sh +++ b/tensorflow/contrib/makefile/download_dependencies.sh @@ -63,12 +63,17 @@ download_and_extract() { elif [[ "${url}" == *zip ]]; then tempdir=$(mktemp -d) tempdir2=$(mktemp -d) - wget -P ${tempdir} ${url} - unzip ${tempdir}/* -d ${tempdir2} + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS (AKA darwin) doesn't have wget. + (cd "${tempdir}"; curl --remote-name --silent --location "${url}") + else + wget -P "${tempdir}" "${url}" + fi + unzip "${tempdir}"/* -d "${tempdir2}" # unzip has no strip components, so unzip to a temp dir, and move the files # we want from the tempdir to destination. - cp -R ${tempdir2}/*/* ${dir}/ - rm -rf ${tempdir2} ${tempdir} + cp -R "${tempdir2}"/*/* "${dir}"/ + rm -rf "${tempdir2}" "${tempdir}" fi # Delete any potential BUILD files, which would interfere with Bazel builds. diff --git a/tensorflow/contrib/opt/BUILD b/tensorflow/contrib/opt/BUILD index 9c961f2b9c..827279bd47 100644 --- a/tensorflow/contrib/opt/BUILD +++ b/tensorflow/contrib/opt/BUILD @@ -19,6 +19,7 @@ py_library( "python/training/elastic_average_optimizer.py", "python/training/external_optimizer.py", "python/training/lazy_adam_optimizer.py", + "python/training/model_average_optimizer.py", "python/training/moving_average_optimizer.py", "python/training/multitask_optimizer_wrapper.py", "python/training/nadam_optimizer.py", @@ -193,6 +194,27 @@ tf_py_test( ], ) +tf_py_test( + name = "model_average_optimizer_test", + srcs = ["python/training/model_average_optimizer_test.py"], + additional_deps = [ + ":opt_py", + "//tensorflow/python:client", + "//tensorflow/python:client_testlib", + "//tensorflow/python:array_ops", + "//tensorflow/python:variables", + "//tensorflow/python:framework", + "//tensorflow/python:platform", + "//tensorflow/python:training", + "//tensorflow/python:ops", + "//tensorflow/python:framework_for_generated_wrappers", + "//third_party/py/numpy", + ], + tags = [ + "notap", # This test launches local server. + ], +) + py_test( name = "sign_decay_test", srcs = ["python/training/sign_decay_test.py"], diff --git a/tensorflow/contrib/opt/__init__.py b/tensorflow/contrib/opt/__init__.py index 90d2f92462..6c1bb1adc0 100644 --- a/tensorflow/contrib/opt/__init__.py +++ b/tensorflow/contrib/opt/__init__.py @@ -29,6 +29,7 @@ from tensorflow.contrib.opt.python.training.nadam_optimizer import * from tensorflow.contrib.opt.python.training.powersign import * from tensorflow.contrib.opt.python.training.variable_clipping_optimizer import * from tensorflow.contrib.opt.python.training.elastic_average_optimizer import * +from tensorflow.contrib.opt.python.training.model_average_optimizer import * # pylint: enable=wildcard-import from tensorflow.python.util.all_util import remove_undocumented @@ -48,7 +49,9 @@ _allowed_symbols = [ 'MultitaskOptimizerWrapper', 'clip_gradients_by_global_norm', 'ElasticAverageOptimizer', - 'ElasticAverageCustomGetter' + 'ElasticAverageCustomGetter', + 'ModelAverageOptimizer', + 'ModelAverageCustomGetter' ] remove_undocumented(__name__, _allowed_symbols) diff --git a/tensorflow/contrib/opt/python/training/model_average_optimizer.py b/tensorflow/contrib/opt/python/training/model_average_optimizer.py new file mode 100644 index 0000000000..47509ecca6 --- /dev/null +++ b/tensorflow/contrib/opt/python/training/model_average_optimizer.py @@ -0,0 +1,299 @@ +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== + +"""Wrapper optimizer for Model Average """ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import constant_op +from tensorflow.python.training import optimizer +from tensorflow.python.training import session_run_hook +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import variable_scope +from tensorflow.python.ops import variables +from tensorflow.python.ops import state_ops +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import data_flow_ops + +GLOBAL_VARIABLE_NAME = 'global_center_variable' + + +class ModelAverageCustomGetter(object): + """Custom_getter class is used to do: + 1. Change trainable variables to local collection and place them at worker + device + 2. Generate global variables + Notice that the class should be used with tf.replica_device_setter, + so that the global center variables and global step variable can be placed + at ps device. Besides, use 'tf.get_variable' instead of 'tf.Variable' to + use this custom getter. + + For example, + ma_custom_getter = ModelAverageCustomGetter(worker_device) + with tf.device( + tf.train.replica_device_setter( + worker_device=worker_device, + ps_device="/job:ps/cpu:0", + cluster=cluster)), + tf.variable_scope('',custom_getter=ma_custom_getter): + hid_w = tf.get_variable( + initializer=tf.truncated_normal( + [IMAGE_PIXELS * IMAGE_PIXELS, FLAGS.hidden_units], + stddev=1.0 / IMAGE_PIXELS), + name="hid_w") + hid_b = tf.get_variable(initializer=tf.zeros([FLAGS.hidden_units]), + name="hid_b") + """ + + def __init__(self, worker_device): + """Create a new `ElasticAverageCustomGetter`. + + Args: + worker_device: String. Name of the `worker` job. + """ + self._worker_device = worker_device + self._local_2_global = {} + + def __call__(self, getter, name, trainable, collections, *args, **kwargs): + if trainable: + with ops.device(self._worker_device): + local_var = getter(name, trainable=True, + collections=[ops.GraphKeys.LOCAL_VARIABLES], + *args, **kwargs) + + global_variable = variable_scope.variable( + name='%s/%s' % (GLOBAL_VARIABLE_NAME, name), + initial_value=local_var.initialized_value(), + trainable=False, + collections=[ops.GraphKeys.GLOBAL_VARIABLES]) + + self._local_2_global[local_var] = global_variable + return local_var + else: + return getter(name, trainable, collections, *args, **kwargs) + + +class ModelAverageOptimizer(optimizer.Optimizer): + """Wrapper optimizer that implements the Model Average algorithm. + This is a sync optimizer. During the training, each worker will update + the local variables and maintains its own local_step, which starts from 0 + and is incremented by 1 after each update of local variables. Whenever the + interval_steps divides the local step, the local variables from all the + workers will be averaged and assigned to global center variables. Then the + local variables will be assigned by global center variables. + """ + + def __init__( + self, + opt, + num_worker, + is_chief, + ma_custom_getter, + interval_steps=100, + use_locking=True, + name="ModelAverageOptimizer"): + """Construct a new model average optimizer. + + Args: + opt: The actual optimizer that will be used to update local variables + num_worker: The number of workers + is_chief: whether chief worker + ma_custom_getter: ModelAverageCustomGetter + interval_steps: An int point value to controls the frequency of the + average of local variables + use_locking: If True use locks for update operations + name: string. Optional name of the returned operation + """ + super(ModelAverageOptimizer, self).__init__(use_locking, name) + self._opt = opt + self._num_worker = num_worker + self._is_chief = is_chief + self._local_2_global = ma_custom_getter._local_2_global + self._interval_steps = interval_steps + self._accumulator_list = [] + self._chief_init_op = None + + self._local_step = variable_scope.get_variable( + initializer=0, + trainable=False, + collections=[ops.GraphKeys.LOCAL_VARIABLES], + name="local_step") + + self._opt._prepare() + + def compute_gradients(self, *args, **kwargs): + """Compute gradients of "loss" for the variables in "var_list". + + This simply wraps the compute_gradients() from the real optimizer. + + Args: + *args: Arguments for compute_gradients(). + **kwargs: Keyword arguments for compute_gradients(). + + Returns: + A list of (gradient, variable) pairs. + """ + return self._opt.compute_gradients(*args, **kwargs) + + def _local_vars_update(self, var_list): + """Get the update ops for the local variables in "var_list". + + Args: + var_list: Optional list or tuple of 'tf.Variable' to update + + Returns: + An update op + """ + if not var_list: + raise ValueError( + 'The list of local_variables should not be empty') + update_ops = [] + global_center_vars = [self._local_2_global[var] for var in var_list] + for lvar, gvar in zip(var_list, global_center_vars): + with ops.device(lvar.device): + update_ops.append(state_ops.assign(lvar, gvar.read_value())) + return control_flow_ops.group(*(update_ops)) + + def apply_gradients(self, grads_and_vars, global_step=None, name=None): + """Apply gradients to variables. + + This contains most of the synchronization implementation and also wraps the + apply_gradients() from the real optimizer. The chief work updates global + variables. + + Args: + grads_and_vars: List of (gradient, variable) pairs as returned by + compute_gradients(). + global_step: Optional Variable to increment by one after the + variables have been updated. + name: Optional name for the returned operation. Default to the + name passed to the Optimizer constructor. + + Returns: + A conditional 'Operation' that update both local and global variables or + just local variables + + Raises: + ValueError: If the grads_and_vars is empty. + ValueError: If global step is not provided, the staleness cannot be + checked. + """ + + # update local variables + if not grads_and_vars: + raise ValueError("Must supply at least one variable") + if global_step is None: + raise ValueError("Global step is required") + + apply_updates = self._opt.apply_gradients(grads_and_vars) + with ops.control_dependencies([apply_updates]): + local_update = state_ops.assign_add( + self._local_step, 1, name='local_step_update').op + + # update global variables. + def _Update_global_variables(): + local_vars = [v for g, v in grads_and_vars if g is not None] + global_vars = [self._local_2_global[v] for v in local_vars] + # sync queue + with ops.colocate_with(global_step): + sync_queue = data_flow_ops.FIFOQueue(-1, [dtypes.bool], shapes=[[]], + shared_name='sync_queue') + train_ops = [] + aggregated_vars = [] + with ops.name_scope(None, self._name + '/global'): + for var, gvar in zip(local_vars, global_vars): + with ops.device(gvar.device): + if isinstance(var._ref(), ops.Tensor): + var_accum = data_flow_ops.ConditionalAccumulator( + var.dtype, + shape=var.get_shape(), + shared_name=gvar.name + "/var_accum") + train_ops.append( + var_accum.apply_grad(var._ref(), local_step=global_step)) + aggregated_vars.append(var_accum.take_grad(self._num_worker)) + else: + raise ValueError("Unknown local variable type!") + self._accumulator_list.append((var_accum, gvar.device)) + # chief worker updates global vars and enqueues tokens to the sync queue + if self._is_chief: + update_ops = [] + with ops.control_dependencies(train_ops): + for avg_var, gvar in zip(aggregated_vars, global_vars): + with ops.device(gvar.device): + update_ops.append(state_ops.assign(gvar, avg_var)) + with ops.device(global_step.device): + update_ops.append(state_ops.assign_add(global_step, 1)) + with ops.control_dependencies(update_ops), ops.device( + global_step.device): + tokens = array_ops.fill([self._num_worker - 1], + constant_op.constant(False)) + sync_op = sync_queue.enqueue_many(tokens) + else: + with ops.control_dependencies(train_ops), ops.device( + global_step.device): + sync_op = sync_queue.dequeue() + + with ops.control_dependencies([sync_op]): + local_update_op = self._local_vars_update(local_vars) + return local_update_op + + with ops.control_dependencies([local_update]): + condition = math_ops.equal(math_ops.mod( + self._local_step, self._interval_steps), 0) + conditional_update = control_flow_ops.cond( + condition, _Update_global_variables, control_flow_ops.no_op) + + chief_init_ops = [] + for accum, dev in self._accumulator_list: + with ops.device(dev): + chief_init_ops.append( + accum.set_global_step( + global_step, name="SetGlobalStep")) + self._chief_init_op = control_flow_ops.group(*(chief_init_ops)) + + return conditional_update + + def get_init_op(self): + """Returns the op to let all the local variables equal to the global + variables before the training begins""" + return self._local_vars_update(variables.trainable_variables()) + + def make_session_run_hook(self): + """Creates a hook to handle ModelAverage ops such as initialization.""" + return _ModelAverageOptimizerHook(self, self._is_chief) + + +class _ModelAverageOptimizerHook(session_run_hook.SessionRunHook): + def __init__(self, ma_optimizer, is_chief): + """Creates hook to handle ModelAverageOptimizer initialization ops. + + Args: + ea_optimizer: `ModelAverageOptimizer` which this hook will initialize. + is_chief: `Bool`, whether is this a chief replica or not. + """ + self._ma_optimizer = ma_optimizer + self._is_chief = is_chief + + def begin(self): + self._local_init_op = variables.local_variables_initializer() + self._global_init_op = None + if self._is_chief: + self._global_init_op = variables.global_variables_initializer() + self._chief_init_op = self._ma_optimizer._chief_init_op + self._variable_init_op = self._ma_optimizer.get_init_op() diff --git a/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py b/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py new file mode 100644 index 0000000000..a73aa772bb --- /dev/null +++ b/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py @@ -0,0 +1,200 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for ModelAverageOptimizer.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import portpicker +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import ops +from tensorflow.python.ops import variables +from tensorflow.python.platform import test +from tensorflow.python.training import gradient_descent +from tensorflow.python.training import server_lib +from tensorflow.python.training import training +from tensorflow.python.training import training_util +from tensorflow.python.ops import variable_scope +from tensorflow.python.training import device_setter +from tensorflow.contrib.opt.python.training.model_average_optimizer import \ + ModelAverageOptimizer, ModelAverageCustomGetter, GLOBAL_VARIABLE_NAME + + +def create_local_cluster(num_workers, num_ps, protocol="grpc"): + """Create local GRPC servers and return them.""" + worker_ports = [portpicker.pick_unused_port() for _ in range(num_workers)] + ps_ports = [portpicker.pick_unused_port() for _ in range(num_ps)] + cluster_dict = { + "worker": ["localhost:%s" % port for port in worker_ports], + "ps": ["localhost:%s" % port for port in ps_ports] + } + cs = server_lib.ClusterSpec(cluster_dict) + + workers = [ + server_lib.Server( + cs, job_name="worker", protocol=protocol, task_index=ix, start=True) + for ix in range(num_workers) + ] + ps_servers = [ + server_lib.Server( + cs, job_name="ps", protocol=protocol, task_index=ix, start=True) + for ix in range(num_ps) + ] + + return cluster_dict, workers, ps_servers + + +# Creates the workers and return their sessions, graphs, train_ops. +# Cheif worker will update at last +def _get_workers(num_workers, steps, workers): + sessions = [] + graphs = [] + train_ops = [] + for worker_id in range(num_workers): + graph = ops.Graph() + is_chief = (worker_id == 0) + with graph.as_default(): + worker_device = "/job:worker/task:%d/cpu:0" % (worker_id) + ma_coustom = ModelAverageCustomGetter( + worker_device=worker_device) + with variable_scope.variable_scope('', + custom_getter=ma_coustom), ops.device( + device_setter.replica_device_setter(worker_device=worker_device, + ps_device="/job:ps/task:0/cpu:0", + ps_tasks=1)): + + global_step = variables.Variable(0, name='global_step', + trainable=False) + var_0 = variable_scope.get_variable(initializer=0.0, name="v0") + var_1 = variable_scope.get_variable(initializer=1.0, name="v1") + + with ops.device("/job:worker/task:" + str(worker_id)): + if worker_id == 0: + grads_0 = constant_op.constant(-1.0) + grads_1 = constant_op.constant(-1.0) + else: + grads_0 = constant_op.constant(-2.0) + grads_1 = constant_op.constant(-2.0) + sgd_opt = gradient_descent.GradientDescentOptimizer(1.0) + opt = ModelAverageOptimizer( + opt=sgd_opt, + num_worker=num_workers, + ma_custom_getter=ma_coustom, + is_chief=is_chief, + interval_steps=steps + ) + train_op = [ + opt.apply_gradients( + [[grads_0, var_0], + [grads_1, var_1]], global_step) + ] + easgd_hook = opt.make_session_run_hook() + # Creates MonitoredSession + sess = training.MonitoredTrainingSession(workers[worker_id].target, + hooks=[easgd_hook]) + + sessions.append(sess) + graphs.append(graph) + train_ops.append(train_op) + return sessions, graphs, train_ops + + +class ModelAverageOptimizerTest(test.TestCase): + def _run(self, train_op, sess): + sess.run(train_op) + + def test1Workers2Period(self): + num_workers = 2 + steps = 2 + num_ps = 1 + cluster, workers, _ = create_local_cluster(num_workers=num_workers, + num_ps=num_ps) + + sessions, graphs, train_ops = _get_workers(num_workers, + steps, + workers) + + var_0 = graphs[0].get_tensor_by_name('v0:0') + var_1 = graphs[0].get_tensor_by_name('v1:0') + global_step = training_util.get_global_step(graphs[0]) + global_var_0 = graphs[0].get_tensor_by_name(GLOBAL_VARIABLE_NAME + "/v0:0") + global_var_1 = graphs[0].get_tensor_by_name(GLOBAL_VARIABLE_NAME + "/v1:0") + + # Verify the initialized value. + self.assertAllEqual(0.0, sessions[0].run(var_0)) + self.assertAllEqual(1.0, sessions[0].run(var_1)) + self.assertAllEqual(0.0, sessions[0].run(global_var_0)) + self.assertAllEqual(1.0, sessions[0].run(global_var_1)) + self.assertAllEqual(0, sessions[0].run(global_step)) + + sessions[0].run(train_ops[0]) + sessions[1].run(train_ops[1]) + + self.assertAllEqual(1.0, sessions[0].run(var_0)) + self.assertAllEqual(2.0, sessions[0].run(var_1)) + self.assertAllEqual(0.0, sessions[0].run(global_var_0)) + self.assertAllEqual(1.0, sessions[0].run(global_var_1)) + self.assertAllEqual(0, sessions[0].run(global_step)) + + # iteration 2, global varibale update + thread_0 = self.checkedThread( + target=self._run, args=(train_ops[0], sessions[0])) + thread_1 = self.checkedThread( + target=self._run, args=(train_ops[1], sessions[1])) + thread_0.start() + thread_1.start() + thread_0.join() + thread_1.join() + + self.assertAllEqual(3.0, sessions[0].run(var_0)) + self.assertAllEqual(4.0, sessions[0].run(var_1)) + self.assertAllEqual(3.0, sessions[0].run(global_var_0)) + self.assertAllEqual(4.0, sessions[0].run(global_var_1)) + self.assertAllEqual(1, sessions[0].run(global_step)) + + # iteration 3 + sessions[0].run(train_ops[0]) + + self.assertAllEqual(4.0, sessions[0].run(var_0)) + self.assertAllEqual(5.0, sessions[0].run(var_1)) + self.assertAllEqual(3.0, sessions[0].run(global_var_0)) + self.assertAllEqual(4.0, sessions[0].run(global_var_1)) + self.assertAllEqual(1, sessions[0].run(global_step)) + + def testPS2TasksWithClusterSpecClass(self): + cluster_spec = server_lib.ClusterSpec({ + "ps": ["ps0:2222", "ps1:2222"], + "worker": ["worker0:2222", "worker1:2222", "worker2:2222"] + }) + worker_device = "/job:worker/task:0" + ma_coustom = ModelAverageCustomGetter( + worker_device=worker_device) + from tensorflow.python.training import device_setter + with ops.device( + device_setter.replica_device_setter(cluster=cluster_spec, + worker_device=worker_device, + ps_device="/job:ps")), \ + variable_scope.variable_scope('', custom_getter=ma_coustom): + v = variable_scope.get_variable(initializer=[1, 2], name="v") + w = variable_scope.get_variable(initializer=[2, 1], name='w') + v_g, w_g = ma_coustom._local_2_global[v], ma_coustom._local_2_global[w] + self.assertDeviceEqual("/job:worker/task:0", v.device) + self.assertDeviceEqual("job:ps/task:0", v_g.device) + self.assertDeviceEqual("/job:worker/task:0", w.device) + self.assertDeviceEqual("job:ps/task:1", w_g.device) + + +if __name__ == '__main__': + test.main() diff --git a/tensorflow/contrib/periodic_resample/BUILD b/tensorflow/contrib/periodic_resample/BUILD index 71582f9c9a..bd9078ae76 100644 --- a/tensorflow/contrib/periodic_resample/BUILD +++ b/tensorflow/contrib/periodic_resample/BUILD @@ -6,6 +6,7 @@ exports_files(["LICENSE"]) load( "//tensorflow:tensorflow.bzl", + "py_test", "tf_gen_op_libs", "tf_custom_op_library", "tf_custom_op_py_library", @@ -64,11 +65,28 @@ py_library( "python/__init__.py", ], srcs_version = "PY2AND3", + tags = [ + "notap", + ], deps = [ ":periodic_resample_op_py", ], ) +py_test( + name = "periodic_resample_op_test", + srcs = ["python/kernel_tests/periodic_resample_op_test.py"], + srcs_version = "PY2AND3", + tags = [ + "notap", + ], + deps = [ + ":init_py", + "//tensorflow/contrib/util:util_py", + "//tensorflow/python:framework_test_lib", + ], +) + # py_library( # name = "periodic_resample_op_py", # srcs = ["python/ops/periodic_resample_op.py"], diff --git a/tensorflow/contrib/periodic_resample/kernels/periodic_resample_op.h b/tensorflow/contrib/periodic_resample/kernels/periodic_resample_op.h index bef21f7a5c..ba410f025d 100644 --- a/tensorflow/contrib/periodic_resample/kernels/periodic_resample_op.h +++ b/tensorflow/contrib/periodic_resample/kernels/periodic_resample_op.h @@ -100,6 +100,8 @@ template = input_tensor_shape.dim_size(i), + tensorflow::errors::InvalidArgument( + "periodic_resample expects the size of non-adjustable " + "dimensions be at least as large as size of input tensor." + " Dimension ", i, " input tensor has size ", + input_tensor_shape.dim_size(i), ", desired shape has size ", + desired_shape[i], ".")); + // target_dimensions[i] = desired_shape(i); target_dimensions[i] = desired_shape[i]; new_sliced_size *= target_dimensions[i]; diff --git a/tensorflow/contrib/periodic_resample/ops/array_ops.cc b/tensorflow/contrib/periodic_resample/ops/array_ops.cc index c90fc06c7f..82bd796956 100644 --- a/tensorflow/contrib/periodic_resample/ops/array_ops.cc +++ b/tensorflow/contrib/periodic_resample/ops/array_ops.cc @@ -34,26 +34,40 @@ This function implements a slightly more generic version of the subpixel convolutions found in this [paper](https://arxiv.org/abs/1609.05158). The formula for computing the elements in the `output` tensor is as follows: + `T` = `values` tensor of rank `R` + `S` = desired `shape` of output tensor (vector of length `R`) + `P` = `output` tensor of rank `R` - \((T_1,\ldots,T_R)\) = shape(`T`) - \([S_1,\ldots,S_q,\ldots,S_R]\) = elements of vector `S` - A single element in `S` is left unspecified (denoted \(S_q=-1\)). - Let \(f_i\) denote the (possibly non-integer) factor that relates the original - dimension to the desired dimensions, \(S_i=f_i T_i\), for \(i\neq q\) where - \(f_i>0\). + \\((T_1,\\ldots,T_R)\\) = shape(`T`) + + \\([S_1,\\ldots,S_q,\\ldots,S_R]\\) = elements of vector `S` + + A single element in `S` is left unspecified (denoted \\(S_q=-1\\)). + + Let \\(f_i\\) denote the (possibly non-integer) factor that relates the original + dimension to the desired dimensions, \\(S_i=f_i T_i\\), for \\(i\\neq q\\) where + \\(f_i>0\\). + Define the following: - \(g_i=\lceil f_i\rceil\) - \(t=\prod_i T_i\) - \(s=\prod_{i\neq q} S_i\) - \(S_q\) can then be defined as by \(S_q=\lfloor t/s\rfloor\). + + \\(g_i=\\lceil f_i\\rceil\\) + + \\(t=\\prod_i T_i\\) + + \\(s=\\prod_{i\\neq q} S_i\\) + + \\(S_q\\) can then be defined by \\(S_q=\\lfloor t/s\\rfloor\\). The elements of the resulting tensor are defined as - \(P_{s_1,\ldots,s_R}=T_{h_1,\ldots,h_q,\ldots,h_R}\). - The \(h_i\) (\(i\neq q\)) are defined by \(h_i=\lfloor s_i/g_i\rfloor\). - \(h_q=S_q\sum_{j\neq q}^{q-1}G_j \mathrm{mod}(s_j,g_j) + s_q\), where - \(G_j=\prod_{i}^{j-1}g_i\) (\(G_0=1\)). + + \\(P_{s_1,\\ldots,s_R}=T_{h_1,\\ldots,h_q,\\ldots,h_R}\\). + + The \\(h_i\\) (\\(i\\neq q\\)) are defined by \\(h_i=\\lfloor s_i/g_i\\rfloor\\). + + \\(h_q=S_q\\sum_{j\\neq q}^{q-1}G_j \\mathrm{mod}(s_j,g_j) + s_q\\), where + \\(G_j=\\prod_{i}^{j-1}g_i\\) (\\(G_0=1\\)). One drawback of this method is that whenever the output dimensions are slightly less than integer multiples of the input dimensions, many of the tensor elements diff --git a/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py b/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py index 1d727870f6..30a2077570 100644 --- a/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py +++ b/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py @@ -19,8 +19,9 @@ from __future__ import division from __future__ import print_function import numpy -import tensorflow + from tensorflow.contrib.periodic_resample import periodic_resample +from tensorflow.python.framework import errors_impl from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import googletest @@ -96,6 +97,19 @@ class PeriodicResampleTest(test_util.TensorFlowTestCase): result = periodic_resample(input_tensor, desired_shape).eval() self.assertAllEqual(result, output_tensor) + def testPeriodicResampleErrors(self): + input_tensor = numpy.zeros(shape=[1, 2, 2, 4]) + with self.test_session(): + variables.global_variables_initializer().run() + with self.assertRaisesWithPredicateMatch( + errors_impl.InvalidArgumentError, + 'Dimension 3 input tensor has size 4, desired shape has size 1'): + periodic_resample(input_tensor, [None, 4, 4, 1]).eval() + with self.assertRaisesWithPredicateMatch( + errors_impl.InvalidArgumentError, + '4, to be the same as the length of the desired shape, 3'): + periodic_resample(input_tensor, [None, 4, 4]).eval() + if __name__ == "__main__": googletest.main() diff --git a/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py b/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py index b5d81b7caa..cafeb56ad8 100644 --- a/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py +++ b/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py @@ -663,6 +663,12 @@ class DropoutWrapperTest(test.TestCase): self.assertEqual(res[1].h.shape, (batch_size, 3)) return res + def testWrappedCellProperty(self): + cell = rnn_cell_impl.BasicRNNCell(10) + wrapper = rnn_cell_impl.DropoutWrapper(cell) + # Github issue 15810 + self.assertEqual(wrapper.wrapped_cell, cell) + def testDropoutWrapperKeepAllConstantInput(self): keep = array_ops.ones([]) res = self._testDropoutWrapper( diff --git a/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py b/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py index 73789206f3..70aaba1728 100644 --- a/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py +++ b/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py @@ -1549,5 +1549,100 @@ class BenchmarkLSTMCellXLA(test.Benchmark): benchmark_results["wall_time"]]])) +class WeightNormLSTMCellTest(test.TestCase): + """Compared cell output with pre-calculated values.""" + + def _cell_output(self, cell): + """Calculate cell output""" + + with self.test_session() as sess: + init = init_ops.constant_initializer(0.5) + with variable_scope.variable_scope("root", + initializer=init): + x = array_ops.zeros([1, 2]) + c0 = array_ops.zeros([1, 2]) + h0 = array_ops.zeros([1, 2]) + + state0 = rnn_cell.LSTMStateTuple(c0, h0) + + xout, sout = cell()(x, state0) + + sess.run([variables.global_variables_initializer()]) + res = sess.run([xout, sout], { + x.name: np.array([[1., 1.]]), + c0.name: 0.1 * np.asarray([[0, 1]]), + h0.name: 0.1 * np.asarray([[2, 3]]), + }) + + actual_state_c = res[1].c + actual_state_h = res[1].h + + return actual_state_c, actual_state_h + + def testBasicCell(self): + """Tests cell w/o peepholes and w/o normalisation""" + + def cell(): + return contrib_rnn_cell.WeightNormLSTMCell(2, + norm=False, + use_peepholes=False) + + actual_c, actual_h = self._cell_output(cell) + + expected_c = np.array([[0.65937078, 0.74983585]]) + expected_h = np.array([[0.44923624, 0.49362513]]) + + self.assertAllClose(expected_c, actual_c, 1e-5) + self.assertAllClose(expected_h, actual_h, 1e-5) + + def testNonbasicCell(self): + """Tests cell with peepholes and w/o normalisation""" + + def cell(): + return contrib_rnn_cell.WeightNormLSTMCell(2, + norm=False, + use_peepholes=True) + + actual_c, actual_h = self._cell_output(cell) + + expected_c = np.array([[0.65937084, 0.7574988]]) + expected_h = np.array([[0.4792085, 0.53470564]]) + + self.assertAllClose(expected_c, actual_c, 1e-5) + self.assertAllClose(expected_h, actual_h, 1e-5) + + + def testBasicCellWithNorm(self): + """Tests cell w/o peepholes and with normalisation""" + + def cell(): + return contrib_rnn_cell.WeightNormLSTMCell(2, + norm=True, + use_peepholes=False) + + actual_c, actual_h = self._cell_output(cell) + + expected_c = np.array([[0.50125383, 0.58805949]]) + expected_h = np.array([[0.32770363, 0.37397948]]) + + self.assertAllClose(expected_c, actual_c, 1e-5) + self.assertAllClose(expected_h, actual_h, 1e-5) + + def testNonBasicCellWithNorm(self): + """Tests cell with peepholes and with normalisation""" + + def cell(): + return contrib_rnn_cell.WeightNormLSTMCell(2, + norm=True, + use_peepholes=True) + + actual_c, actual_h = self._cell_output(cell) + + expected_c = np.array([[0.50125383, 0.59587258]]) + expected_h = np.array([[0.35041603, 0.40873795]]) + + self.assertAllClose(expected_c, actual_c, 1e-5) + self.assertAllClose(expected_h, actual_h, 1e-5) + if __name__ == "__main__": test.main() diff --git a/tensorflow/contrib/rnn/python/ops/rnn_cell.py b/tensorflow/contrib/rnn/python/ops/rnn_cell.py index e4667828cd..d7ae6621db 100644 --- a/tensorflow/contrib/rnn/python/ops/rnn_cell.py +++ b/tensorflow/contrib/rnn/python/ops/rnn_cell.py @@ -38,6 +38,7 @@ from tensorflow.python.ops import random_ops from tensorflow.python.ops import rnn_cell_impl from tensorflow.python.ops import variable_scope as vs from tensorflow.python.ops import partitioned_variables +from tensorflow.python.ops import nn_impl from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import nest @@ -328,7 +329,7 @@ class TimeFreqLSTMCell(rnn_cell_impl.RNNCell): def __init__(self, num_units, use_peepholes=False, cell_clip=None, initializer=None, num_unit_shards=1, forget_bias=1.0, - feature_size=None, frequency_skip=None, + feature_size=None, frequency_skip=1, reuse=None): """Initialize the parameters for an LSTM cell. @@ -2723,3 +2724,257 @@ class SRUCell(rnn_cell_impl._LayerRNNCell): h = r * self._activation(c) + (1.0 - r) * inputs return h, c + + +class WeightNormLSTMCell(rnn_cell_impl.RNNCell): + """Weight normalized LSTM Cell. Adapted from `rnn_cell_impl.LSTMCell`. + + The weight-norm implementation is based on: + https://arxiv.org/abs/1602.07868 + Tim Salimans, Diederik P. Kingma. + Weight Normalization: A Simple Reparameterization to Accelerate + Training of Deep Neural Networks + + The default LSTM implementation based on: + http://www.bioinf.jku.at/publications/older/2604.pdf + S. Hochreiter and J. Schmidhuber. + "Long Short-Term Memory". Neural Computation, 9(8):1735-1780, 1997. + + The class uses optional peephole connections, optional cell clipping + and an optional projection layer. + + The optional peephole implementation is based on: + https://research.google.com/pubs/archive/43905.pdf + Hasim Sak, Andrew Senior, and Francoise Beaufays. + "Long short-term memory recurrent neural network architectures for + large scale acoustic modeling." INTERSPEECH, 2014. + """ + + def __init__(self, num_units, norm=True, use_peepholes=False, + cell_clip=None, initializer=None, num_proj=None, + proj_clip=None, forget_bias=1, activation=None, + reuse=None): + """Initialize the parameters of a weight-normalized LSTM cell. + + Args: + num_units: int, The number of units in the LSTM cell + norm: If `True`, apply normalization to the weight matrices. If False, + the result is identical to that obtained from `rnn_cell_impl.LSTMCell` + use_peepholes: bool, set `True` to enable diagonal/peephole connections. + cell_clip: (optional) A float value, if provided the cell state is clipped + by this value prior to the cell output activation. + initializer: (optional) The initializer to use for the weight matrices. + num_proj: (optional) int, The output dimensionality for the projection + matrices. If None, no projection is performed. + proj_clip: (optional) A float value. If `num_proj > 0` and `proj_clip` is + provided, then the projected values are clipped elementwise to within + `[-proj_clip, proj_clip]`. + forget_bias: Biases of the forget gate are initialized by default to 1 + in order to reduce the scale of forgetting at the beginning of + the training. + activation: Activation function of the inner states. Default: `tanh`. + reuse: (optional) Python boolean describing whether to reuse variables + in an existing scope. If not `True`, and the existing scope already has + the given variables, an error is raised. + """ + super(WeightNormLSTMCell, self).__init__(_reuse=reuse) + + self._scope = 'wn_lstm_cell' + self._num_units = num_units + self._norm = norm + self._initializer = initializer + self._use_peepholes = use_peepholes + self._cell_clip = cell_clip + self._num_proj = num_proj + self._proj_clip = proj_clip + self._activation = activation or math_ops.tanh + self._forget_bias = forget_bias + + self._weights_variable_name = "kernel" + self._bias_variable_name = "bias" + + if num_proj: + self._state_size = rnn_cell_impl.LSTMStateTuple(num_units, num_proj) + self._output_size = num_proj + else: + self._state_size = rnn_cell_impl.LSTMStateTuple(num_units, num_units) + self._output_size = num_units + + @property + def state_size(self): + return self._state_size + + @property + def output_size(self): + return self._output_size + + def _normalize(self, weight, name): + """Apply weight normalization. + + Args: + weight: a 2D tensor with known number of columns. + name: string, variable name for the normalizer. + Returns: + A tensor with the same shape as `weight`. + """ + + output_size = weight.get_shape().as_list()[1] + g = vs.get_variable(name, [output_size], dtype=weight.dtype) + return nn_impl.l2_normalize(weight, dim=0) * g + + def _linear(self, args, + output_size, + norm, + bias, + bias_initializer=None, + kernel_initializer=None): + """Linear map: sum_i(args[i] * W[i]), where W[i] is a variable. + + Args: + args: a 2D Tensor or a list of 2D, batch x n, Tensors. + output_size: int, second dimension of W[i]. + bias: boolean, whether to add a bias term or not. + bias_initializer: starting value to initialize the bias + (default is all zeros). + kernel_initializer: starting value to initialize the weight. + + Returns: + A 2D Tensor with shape [batch x output_size] equal to + sum_i(args[i] * W[i]), where W[i]s are newly created matrices. + + Raises: + ValueError: if some of the arguments has unspecified or wrong shape. + """ + if args is None or (nest.is_sequence(args) and not args): + raise ValueError("`args` must be specified") + if not nest.is_sequence(args): + args = [args] + + # Calculate the total size of arguments on dimension 1. + total_arg_size = 0 + shapes = [a.get_shape() for a in args] + for shape in shapes: + if shape.ndims != 2: + raise ValueError("linear is expecting 2D arguments: %s" % shapes) + if shape[1].value is None: + raise ValueError("linear expects shape[1] to be provided for shape %s, " + "but saw %s" % (shape, shape[1])) + else: + total_arg_size += shape[1].value + + dtype = [a.dtype for a in args][0] + + # Now the computation. + scope = vs.get_variable_scope() + with vs.variable_scope(scope) as outer_scope: + weights = vs.get_variable( + self._weights_variable_name, [total_arg_size, output_size], + dtype=dtype, + initializer=kernel_initializer) + if norm: + wn = [] + st = 0 + with ops.control_dependencies(None): + for i in range(len(args)): + en = st + shapes[i][1].value + wn.append(self._normalize(weights[st:en, :], + name='norm_{}'.format(i))) + st = en + + weights = array_ops.concat(wn, axis=0) + + if len(args) == 1: + res = math_ops.matmul(args[0], weights) + else: + res = math_ops.matmul(array_ops.concat(args, 1), weights) + if not bias: + return res + + with vs.variable_scope(outer_scope) as inner_scope: + inner_scope.set_partitioner(None) + if bias_initializer is None: + bias_initializer = init_ops.constant_initializer(0.0, dtype=dtype) + + biases = vs.get_variable( + self._bias_variable_name, [output_size], + dtype=dtype, + initializer=bias_initializer) + + return nn_ops.bias_add(res, biases) + + def call(self, inputs, state): + """Run one step of LSTM. + + Args: + inputs: input Tensor, 2D, batch x num_units. + state: A tuple of state Tensors, both `2-D`, with column sizes + `c_state` and `m_state`. + + Returns: + A tuple containing: + + - A `2-D, [batch x output_dim]`, Tensor representing the output of the + LSTM after reading `inputs` when previous state was `state`. + Here output_dim is: + num_proj if num_proj was set, + num_units otherwise. + - Tensor(s) representing the new state of LSTM after reading `inputs` when + the previous state was `state`. Same type and shape(s) as `state`. + + Raises: + ValueError: If input size cannot be inferred from inputs via + static shape inference. + """ + dtype = inputs.dtype + num_units = self._num_units + sigmoid = math_ops.sigmoid + c, h = state + + input_size = inputs.get_shape().with_rank(2)[1] + if input_size.value is None: + raise ValueError("Could not infer input size from inputs.get_shape()[-1]") + + with vs.variable_scope(self._scope, initializer=self._initializer): + + concat = self._linear([inputs, h], 4 * num_units, + norm=self._norm, bias=True) + + # i = input_gate, j = new_input, f = forget_gate, o = output_gate + i, j, f, o = array_ops.split(value=concat, num_or_size_splits=4, axis=1) + + if self._use_peepholes: + w_f_diag = vs.get_variable("w_f_diag", shape=[num_units], dtype=dtype) + w_i_diag = vs.get_variable("w_i_diag", shape=[num_units], dtype=dtype) + w_o_diag = vs.get_variable("w_o_diag", shape=[num_units], dtype=dtype) + + new_c = (c * sigmoid(f + self._forget_bias + w_f_diag * c) + + sigmoid(i + w_i_diag * c) * self._activation(j)) + else: + new_c = (c * sigmoid(f + self._forget_bias) + + sigmoid(i) * self._activation(j)) + + if self._cell_clip is not None: + # pylint: disable=invalid-unary-operand-type + new_c = clip_ops.clip_by_value(new_c, -self._cell_clip, self._cell_clip) + # pylint: enable=invalid-unary-operand-type + if self._use_peepholes: + new_h = sigmoid(o + w_o_diag * new_c) * self._activation(new_c) + else: + new_h = sigmoid(o) * self._activation(new_c) + + if self._num_proj is not None: + with vs.variable_scope("projection"): + new_h = self._linear(new_h, + self._num_proj, + norm=self._norm, + bias=False) + + if self._proj_clip is not None: + # pylint: disable=invalid-unary-operand-type + new_h = clip_ops.clip_by_value(new_h, + -self._proj_clip, + self._proj_clip) + # pylint: enable=invalid-unary-operand-type + + new_state = rnn_cell_impl.LSTMStateTuple(new_c, new_h) + return new_h, new_state diff --git a/tensorflow/contrib/seq2seq/python/kernel_tests/beam_search_decoder_test.py b/tensorflow/contrib/seq2seq/python/kernel_tests/beam_search_decoder_test.py index d2beac5f31..f498b2bb57 100644 --- a/tensorflow/contrib/seq2seq/python/kernel_tests/beam_search_decoder_test.py +++ b/tensorflow/contrib/seq2seq/python/kernel_tests/beam_search_decoder_test.py @@ -225,6 +225,94 @@ class TestBeamStep(test.TestCase): self.assertAllEqual(next_state_.log_probs, expected_log_probs) +class TestLargeBeamStep(test.TestCase): + """ + Tests a single step of beam search in such + case that beam size is larger than vocabulary size. + """ + + def setUp(self): + super(TestLargeBeamStep, self).setUp() + self.batch_size = 2 + self.beam_width = 8 + self.vocab_size = 5 + self.end_token = 0 + self.length_penalty_weight = 0.6 + + + def test_step(self): + def get_probs(): + """this simulates the initialize method in BeamSearchDecoder""" + log_prob_mask = array_ops.one_hot(array_ops.zeros([self.batch_size], + dtype=dtypes.int32), + depth=self.beam_width, on_value=True, + off_value=False, dtype=dtypes.bool) + + log_prob_zeros = array_ops.zeros([self.batch_size, self.beam_width], + dtype=dtypes.float32) + log_prob_neg_inf = array_ops.ones([self.batch_size, self.beam_width], + dtype=dtypes.float32) * -np.Inf + + log_probs = array_ops.where(log_prob_mask, log_prob_zeros, + log_prob_neg_inf) + return log_probs + + log_probs = get_probs() + dummy_cell_state = array_ops.zeros([self.batch_size, self.beam_width]) + + _finished = array_ops.one_hot( + array_ops.zeros([self.batch_size], dtype=dtypes.int32), + depth=self.beam_width, on_value=False, + off_value=True, dtype=dtypes.bool) + _lengths = np.zeros([self.batch_size, self.beam_width], dtype=np.int64) + _lengths[:, 0]=2 + _lengths = constant_op.constant(_lengths, dtype=dtypes.int64) + + beam_state = beam_search_decoder.BeamSearchDecoderState( + cell_state=dummy_cell_state, + log_probs=log_probs, + lengths=_lengths, + finished=_finished) + + logits_ = np.full([self.batch_size, self.beam_width, self.vocab_size], + 0.0001) + logits_[0, 0, 2] = 1.9 + logits_[0, 0, 3] = 2.1 + logits_[0, 1, 3] = 3.1 + logits_[0, 1, 4] = 0.9 + logits_[1, 0, 1] = 0.5 + logits_[1, 1, 2] = 2.7 + logits_[1, 2, 2] = 10.0 + logits_[1, 2, 3] = 0.2 + logits = constant_op.constant(logits_, dtype=dtypes.float32) + log_probs = nn_ops.log_softmax(logits) + + outputs, next_beam_state = beam_search_decoder._beam_search_step( + time=2, + logits=logits, + next_cell_state=dummy_cell_state, + beam_state=beam_state, + batch_size=ops.convert_to_tensor(self.batch_size), + beam_width=self.beam_width, + end_token=self.end_token, + length_penalty_weight=self.length_penalty_weight) + + with self.test_session() as sess: + outputs_, next_state_, state_, log_probs_ = sess.run( + [outputs, next_beam_state, beam_state, log_probs]) + + self.assertEqual(outputs_.predicted_ids[0, 0], 3) + self.assertEqual(outputs_.predicted_ids[0, 1], 2) + self.assertEqual(outputs_.predicted_ids[1, 0], 1) + neg_inf = -np.Inf + self.assertAllEqual(next_state_.log_probs[:, -3:], + [[neg_inf, neg_inf, neg_inf], + [neg_inf, neg_inf, neg_inf]]) + self.assertEqual((next_state_.log_probs[:, :-3] > neg_inf).all(), True) + self.assertEqual((next_state_.lengths[:, :-3] > 0).all(), True) + self.assertAllEqual(next_state_.lengths[:, -3:], [[0, 0, 0], + [0, 0, 0]]) + class BeamSearchDecoderTest(test.TestCase): def _testDynamicDecodeRNN(self, time_major, has_attention): diff --git a/tensorflow/contrib/seq2seq/python/ops/beam_search_decoder.py b/tensorflow/contrib/seq2seq/python/ops/beam_search_decoder.py index ebe25ce077..a5f7169c31 100644 --- a/tensorflow/contrib/seq2seq/python/ops/beam_search_decoder.py +++ b/tensorflow/contrib/seq2seq/python/ops/beam_search_decoder.py @@ -19,7 +19,6 @@ from __future__ import division from __future__ import print_function import collections - import numpy as np from tensorflow.contrib.seq2seq.python.ops import beam_search_ops @@ -229,8 +228,11 @@ class BeamSearchDecoder(decoder.Decoder): self._start_tokens = array_ops.tile( array_ops.expand_dims(self._start_tokens, 1), [1, self._beam_width]) self._start_inputs = self._embedding_fn(self._start_tokens) - self._finished = array_ops.zeros( - [self._batch_size, self._beam_width], dtype=dtypes.bool) + + self._finished = array_ops.one_hot( + array_ops.zeros([self._batch_size], dtype=dtypes.int32), + depth=self._beam_width, on_value=False, + off_value=True, dtype=dtypes.bool) @property def batch_size(self): @@ -298,11 +300,15 @@ class BeamSearchDecoder(decoder.Decoder): """ finished, start_inputs = self._finished, self._start_inputs + log_probs = array_ops.one_hot( # shape(batch_sz, beam_sz) + array_ops.zeros([self._batch_size], dtype=dtypes.int32), + depth=self._beam_width, on_value=0.0, off_value=-np.Inf, + dtype=nest.flatten(self._initial_cell_state)[0].dtype) + + initial_state = BeamSearchDecoderState( cell_state=self._initial_cell_state, - log_probs=array_ops.zeros( - [self._batch_size, self._beam_width], - dtype=nest.flatten(self._initial_cell_state)[0].dtype), + log_probs=log_probs, finished=finished, lengths=array_ops.zeros( [self._batch_size, self._beam_width], dtype=dtypes.int64)) @@ -563,18 +569,11 @@ def _beam_search_step(time, logits, next_cell_state, beam_state, batch_size, time = ops.convert_to_tensor(time, name="time") # During the first time step we only consider the initial beam scores_shape = array_ops.shape(scores) - scores_flat = control_flow_ops.cond( - time > 0, - lambda: array_ops.reshape(scores, [batch_size, -1]), - lambda: scores[:, 0]) - num_available_beam = control_flow_ops.cond( - time > 0, lambda: math_ops.reduce_prod(scores_shape[1:]), - lambda: math_ops.reduce_prod(scores_shape[2:])) + scores_flat = array_ops.reshape(scores, [batch_size, -1]) # Pick the next beams according to the specified successors function - next_beam_size = math_ops.minimum( - ops.convert_to_tensor(beam_width, dtype=dtypes.int32, name="beam_width"), - num_available_beam) + next_beam_size = ops.convert_to_tensor(beam_width, dtype=dtypes.int32, + name="beam_width") next_beam_scores, word_indices = nn_ops.top_k(scores_flat, k=next_beam_size) next_beam_scores.set_shape([static_batch_size, beam_width]) diff --git a/tensorflow/contrib/verbs/BUILD b/tensorflow/contrib/verbs/BUILD index 38a84ffb10..80a5d07ea4 100644 --- a/tensorflow/contrib/verbs/BUILD +++ b/tensorflow/contrib/verbs/BUILD @@ -99,7 +99,7 @@ cc_library( alwayslink = 1, ) -tf_cuda_library( +cc_library( name = "rdma_rendezvous_mgr", srcs = ["rdma_rendezvous_mgr.cc"], hdrs = ["rdma_rendezvous_mgr.h"], @@ -114,7 +114,7 @@ tf_cuda_library( ], ) -cc_library( +tf_cuda_library( name = "rdma_mgr", srcs = ["rdma_mgr.cc"], hdrs = ["rdma_mgr.h"], @@ -141,6 +141,8 @@ tf_cuda_library( "//conditions:default": [], }), deps = [ + ":grpc_verbs_client", + ":verbs_service_proto_cc", ":verbs_util", "//tensorflow/core:core_cpu_internal", "//tensorflow/core:framework", diff --git a/tensorflow/contrib/verbs/README.md b/tensorflow/contrib/verbs/README.md index 7c1c8ea459..1b99f4ce4f 100644 --- a/tensorflow/contrib/verbs/README.md +++ b/tensorflow/contrib/verbs/README.md @@ -24,66 +24,144 @@ The design is based on TensorFlow r1.0. An RDMA path is added between servers fo During the server setup, an RDMA manager is created to manage low-level RDMA components such as RDMA channel and RDMA adapter, an RDMA rendezvous manager is created to oversee send/recv operations between servers. Following the distributed TensorFlow design philosophy, the send operation is passive, i.e. merely placing a tensor in the local out-going table. It is the receive operation that actually initiates the tensor transfer. -TensorFlow dynamically allocates memory for tensors that are to be sent or received. This causes difficulty for RDMA operations where pinned memory is required. Two remedies are possible, either the memory is pinned, transfer, then unpinned for each and every tensor to be transferred, or a buffer is pre-allocated and pinned for each tensor. The former incurs significant operation overhead since pinning and unpinning memory for each dynamically generated tensor is slow. The latter incurs large memory overhead and extra copying from the tensor to its pinned buffer, but may still be faster than the former. The second approach is adopted in this design. Each RDMA channel, representing a RDMA connection to a peer, contains a table of pinned buffers for all the seen tensors that requires transfer. It is assumed that the tensor size rarely changes across different steps. So only one buffer is created for the same tensor across all the steps. In the rare case when the tensor size does increases, the old buffer is discarded and new buffer of larger size is created and pinned. +TensorFlow dynamically allocates memory for tensors that are to be sent or received. This causes difficulty for RDMA operations where pinned memory is required. Few remedies are possible: +1. The memory is pinned, transfered, then unpinned for each and every tensor to be transferred. This incurs significant operation overhead since pinning and unpinning memory for each dynamically generated tensor is slow. +2. Buffer is pre-allocated and pinned for each tensor. This incurs large memory overhead and extra copying from the tensor to its pinned buffer, but may still be faster than the former. +3. Following HKUST research on the use of GPU direct, and their [GDR implementation](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/gdr/README.md), there is a smart way to benefit from the TensorFlow allocation theme which is mostly pool based, i.e allocators pre-allocate a large memory block, and allocate the tensors from there. By attaching a custom Visitor to relevant alloactors, we can do a single registration of the entire memory block, which zeros the registration overhead. Once the block is registered, each new tensor allocated will be at a registred address, which will allow us to do direct RDMA writes to it. -When a tensor is prepared for transfer, it is first converted to TensorProto, then the proto is serialized to byte array and copied to the pinned buffer. The content of the buffer is transferred to the remote node via RDMA write. On the remote side, the process is reversed. This is illustrated in the diagram below. The conversion of TensorProto is introduced to simplify transfer of string-tensors. Also since the TensorProto lives in host memory, even if the origin tensor lives in the device, the pinned buffers are all allocated in the host memory. -![TensorFlow RDMA path](./design_diagram.png) +For best performance, we will adopt HKUST 0 copies approach in our solution. This means: + +1. Tensor writes will be done directly from the source tensor to the **result** tensor, with no memory copies in between. This should be done for all DMAable tensors which are located either on CPU or on a RDMA compatible GPU device (GPU direct). +2. Non DMAable tensors (CanMemCopy == false) will be serialized to a TensorProto on the sender side, RDMA written to a registered buffer on the receiver side, and then deserialized by the receiver. +3. Tensors which are located on a non-RDMA-compatible GPU, will be RDMA written to a registered CPU **proxy** buffer on the receiver side, and then copied to GPU by the receiver. -The following improvements can be made in the future. First, conversion to TensorProto and serialization can be avoided for numeric (float/int) tensors since their internal buffer can be access directly as byte array. Second, the pinned buffer may be allocated on device if the tensor is located in the device. This avoids extra device-to-host copy at the expense of extra device memory consumption. ## Design details -### RDMA components +### Terminology -* **RDMA adapter:** The base for RDMA communications. It may contain multiple channels and buffers. It is responsible for handling various incoming RDMA messages. -* **RDMA channel:** Responsible for RDMA connection to a particular node. It manages multiple buffers. A channel has a callback table which stores all the callbacks for the requested tensors. -* **RDMA buffer:** Responsible for sending or receiving data. It has a fixed size memory to store the data. It has a queue to store the pending jobs. There are three types of buffers, message buffer, ACK buffer and tensor buffer. A channel has two message buffers, two ack buffers and many tensor buffers. -* **RDMA manager:** Manages the adapter and channels, including channel creation, channel setup via GRPC service, channel lookup, etc. -* **RDMA rendezvous manager:** manages multiple rdma rendezvous. -* **RDMA rendezvous:** a derived class of BaseRemoteRendezvous. This class is the back end for "send" and "recv" ops. When the sendrecv_op wants to send or receive a tensor, it calls the rendezvous' "send" and "recv" functions respectively. Rendezvous are identified by "step_id", a random number, so that tensors for different iterations don't get mixed up. +* **Sender** - The node which sends the tensor. +* **Receiver** - The node which receives the tensor. +* **Result tensor** - The destination tensor, allocated on its appropriate device. +* **Proxy tensor** - A CPU allocated tensor, which will be used in the case where the result tensor cannot be RDMA written to directly (GPU direct is disabled or not available). The RDMA write will therefore be done to the proxy tensor, and afterwards we will do a manual local copy from it to the result tensor. -### The SEND operation +### Messages -In TensorFlow, when rendezvous sends a tensor, it merely puts a tensor in a local table in the corresponding rendezvous. If the tensor has been requested, a callback exists in the table. "send" will activate the callback, which tries to send the tensor across the node. +* RDMA_MESSAGE_TENSOR_REQUEST +* RDMA_MESSAGE_META_DATA_RESPONSE +* RDMA_MESSAGE_TENSOR_RE_REQUEST +### Transport protocol -### The RECV operation +The tensor transfer process is initiated when the receiver requests a tensor. In code it is done by calling **Rendezvous::Recv()** or **Rendezvous::RecvAsync()**. The TensorFlow base implementation handles the case where the requested tensor is located on the same node. The more interesting case where the requested tensor is located on a remote node (receiver != sender) is to be handled in a derivation of the pure virtual **BaseRemoteRendezvous::RecvFromRemoteAsync()**. TensorFlow provides a default GRPC based implementation which comes in the vanilla version but suffers in scalability when running large models. Our RDMA based implementation presumes to be more scalable. HKUST's contrib GDR implementation is more scalable than GRPC, and less scalable than ours, only because we did our evolution based on it. -When a tensor is requested, rendezvous' recv function is called. The function first places a callback in the channel's callback table, which will be activated once the tensor is sent from the source. In the next step, a message is sent to notify the source of the requested tensor. Once the source receives the message, it will check locally for the tensor, if not found, a callback is placed in the table, otherwise, the tensor id will be placed at corresponding RDMA buffer's job queue for future transmission. When a tensor is scheduled to be transmitted, the RDMA buffer needs to have the memory allocated and initialized (registered with the remote buffer info). If the memory is not ready, the transmission is deferred, a message is sent to the destination to establish the memory first. The other case a transmission can be deferred is when the buffer is still being used by an on-going transmission. +Our entry point is the implementation of **RdmaRemoteRendezvous::RecvFromRemoteAsync()**, located in rdma_rendezvous_mgr.cc. The implementation creates a new **RdmaTensorRequest** object, keyed by request index (uint32_t), stores it in a list of pending requests, and calls its **Start()** method. The **Start()** method basically does 2 things: -### Three types of RDMA buffers +1. Allocate the result tensor (and the proxy tensor if required). +2. Send a **RDMA_MESSAGE_TENSOR_REQUEST** to the sender, containing the address of the destination tensor (result/proxy) for RDMA write. -* **Message buffer:** responsible for sending message only. -* **Ack buffer:** once a message is sent, the recipient needs to send an ack via the ack buffer to free up the message buffer. An ack buffer is exclusively for its coupled message buffer. -* **Tensor buffer:** responsible for sending tensors. The recipient needs to send back a message to free up the sending buffer. +In order to allocate the result and proxy tensors, we need to know the tensor's meta-data, i.e. shape and data-type for DMAable tensors, and proto-size for serialized tensors. Unfortunately, this information is only available on the sender side which complicates manners. In order to avoid sending extra messages for querying the meta-data at each step, we store a local meta-data cache per tensor, which will only be update upon changes. Based on the assumption that the meta-data of a tensor rarely changes between steps, we expect that on most times the cache will only be updated once. The sender is responsible to detect changes in the meta-data, and update the receiver. In order for the sender to know that the meta-data had changed, each **RDMA_MESSAGE_TENSOR_REQUEST** will contain the meta-data that the receiver had grabbed from the local cache. The sender will then compare the meta-data from the message to the tensor's new meta-data. -### RDMA packet format +When the sender receives an **RDMA_MESSAGE_TENSOR_REQUEST**, it will create a new **RdmaTensorResponse** object for the given request message, store it in a list of pending responses, and will invoke its **Start()** method. The **Start()** method does the following: -|type|name_size|name|step_id|buffer_size|remote_addr|rkey|is_dead|data_type|tensor_shape|tensor_bytes|tensor_buffer| +1. Grab the source tensor from the local table (In code, **RecvLocalAsync()**). +2. If the source tensor is not DMAable, serialize it to a TensorProto. +3. If the source tensor is located on a device which cannot be DMA written from, copy it to CPU. +4. If it is the first time this tensor is requested, or if the tensor's meta-data changed: + 1. Clone the tensor's data to be sent later. + 2. Send a **RDMA_MESSAGE_META_DATA_RESPONSE** containing the new meta-data. +5. Otherwise: + 1. RDMA write the tensor (or TensorProto) to the destination address and rkey specified in the request message. The immediate value for the write will be the request index. -### Six types of RDMA messages -* RDMA_MESSAGE_ACK -* RDMA_MESSAGE_BUFFER_IDLE -* RDMA_MESSAGE_BUFFER_REQUEST -* RDMA_MESSAGE_BUFFER_RESPONSE -* RDMA_MESSAGE_TENSOR_REQUEST -* RDMA_MESSAGE_TENSOR_WRITE - -### Actions upon receiving RDMA messages -* RDMA_MESSAGE_ACK - * sender: mark local ack buffer idle. - * receiver: mark remote message buffer idle, send next item. -* RDMA_MESSAGE_BUFFER_IDLE - * sender: mark local message buffer idle, send next item. - * receiver: send ack, set remote tensor buffer idle, send next item. -* RDMA_MESSAGE_BUFFER_REQUEST - * sender: mark local message buffer idle, send next item. - * receiver: send ack, find or create tensor buffer, send BUFFER_RESPONSE. -* RDMA_MESSAGE_BUFFER_RESPONSE - * sender: mark local message buffer idle, send next item. - * receiver: send ack, set remote buffer info, set local and remote buffer idle, send next item. -* RDMA_MESSAGE_TENSOR_REQUEST - * sender: mark local message buffer idle, send next item. - * receiver: send ack, find or create tensor buffer, enqueue tensor id, send next item. -* RDMA_MESSAGE_TENSOR_WRITE - * sender: mark local message buffer idle, send next item. - * receiver: run callback. + +When the receiver receives the **RDMA_MESSAGE_META_DATA_RESPONSE**, it will locate the relevant **RdmaTensorRequest** using the request index specified in the message, and invoke its **RecvTensorMetaData()** which does the following: + +1. Update the local meta-data cache. +2. Reallocate the result/proxy tensors. +3. Re-send the tensor request. For tracability, the new message has a different name: **RDMA_MESSAGE_TENSOR_RE_REQUEST**. + +When the sender receives a **RDMA_MESSAGE_TENSOR_RE_REQUEST**, it will locate the relevant **RdmaTensorResponse** using the request index specified in the message, and invoke its **Resume()** method, which will RDMA write the contents of the tensor that was cloned earlier, to the new remote address specified in the re-request. + +When the receiver receives the RDMA write, it will locate the relevant **RdmaTensorRequest** using the request index which is the immediate value. It will then invoke its **RecvTensorContent()** which does the following: + +1. Proxy copy/deserialize if required. +2. Invoke the done callback. +3. Deallocate the result/proxy tensors and remove the request from the pending list. + +![alt text](verbs_with_0_copies.png "Transport protocol") + +### Additional design notes + +1. When the sender receives a tensor request, the source tensor may or may not be ready yet. The situation is handled through a process of tag matching: + * If the request arrives before the tensor is ready, then a callback is put in a local table, and will be invoked once the tensor arrives. + * If the tensor is ready before the request arives, than the tensor is put in a local table. When the request arrives, it will invoke the callback immediatly. + In code it is done by calling **RecvLocalAsync()**, which receives the tensor's key, step-id, and the callback. +2. When the callback is invoked, the relevant tensor is removed from the tag matching table. In the case where we need to send the tensor's meta-data, the **RdmaTensorResponse** will store a copy of the tensor until the re-request arrives. +3. The sending of protocol messages (**RDMA_MESSAGE_TENSOR_REQUEST**, **RDMA_MESSAGE_META_DATA_RESPONSE** and **RDMA_MESSAGE_TENSOR_RE_REQUEST**) is done by the class **RdmaMessageBuffer**. All messages are sent using RDMA writes from/to fixed messages buffers. This implies that we cannot send on a specific channel more than one message at a time. In order to synchronize the messages, the **RdmaMessageBuffer** holds the a local and remote buffer statuses which can be either busy or idle. When a write is issued, both statuses will be changed to busy. When the write-complete event is received, the local status is changed to idle. When the write is received on the remote side, the remote side will parse the message, and return an ACK back to the sending side on which the sending side will update the remote status to idle. When both the local and remote statuses are idle, the next message can be sent. +5. ACK writes are empty writes (hence they require no buffer) with immediate value 0xFFFFFFFE. Message writes have the immediate value 0xFFFFFFFF. All other writes are tensor-content writes whose immediate value is the request-index. + +### RDMA components + +* **enum RdmaImmDataType** - Immediate types to distinguish between different RDMA writes on the remote side. Ack writes and control-message writes have a fixed immediate value. The rest of the writes are tensor writes and the immediate value is the relevant request index. +* **enum RdmaWriteIDType** - Types to distinguish between different RDMA write-complete events: Ack, control message and tensor writes. +* **class RdmaWriteID** - Context for RDMA write complete events. Holds the RdmaWriteIDType and additional data. +* **class RdmaTensorMetaData** - Meta-data for a tensor (type, shape, is_dead, proto_size). +* **class RdmaMemoryMgr** - Manages the meta-data cache, and the registered memory regions. +* **class RdmaTensorRequest** - Holds and manages information for a single tensor request throughout the entire receive cycle. API: + * **Start()** - Start the request sequence. + * Allocate the result tensor (and proxy tensor if required). + * Send RDMA_MESSAGE_TENSOR_REQUEST to the remote side. + * **RecvTensorMetaData()** - Receive meta-data from the remote side. + * Update the local meta-data cache. + * Reallocate the result tensor (and proxy tensor if required). + * Re-send the request to the remote side. + * **RecvTensorContent()** - Receive tensor content from the remote side (RDMA write was completed). + * Decode proto if required and/or move to GPU if the content was not written to it directly (GPU direct is not avaliable). + * Invoke the done callback. +* **class RdmaTensorResponse** - Holds and manages information for a single tensor response throughout the entire send cycle. API: + * **Start()** - Start the response sequence. + * Find the tensor in the local tag-match table. + * Compare the tensor's meta-data to the meta-data in the message (taken from the requester's local cache). + * If meta-data changed: + * Clone the tensor to be sent later. + * Send a meta-data update message and wait for re-request. + * Else: + * Send the tensor's content (using direct RDMA write). + * **Resume()** - Resume the response sequence after a re-request. Send the tensor's content that was cloned earlier. + * **Destroy()** - Destroy the response's resources and remove it form the pending list. +* **class RdmaAdapter** - The base for RDMA communications. It may contain multiple channels and buffers. It is responsible for handling various incoming RDMA messages. +* **class RdmaChannel** - Responsible for RDMA connection to a particular node. It manages messagee buffers. A channel has a request table which stores all the pending tensor requests. +* **class RdmaMessageBuffer** - Responsible for sending or receiving messages. It has a fixed size memory to store the data. It has a queue to store the pending jobs. A channel has two message buffers one for tx and one for rx. +* **class RdmaMgr** - Manages the adapter and channels, including channel creation, channel setup via GRPC service, channel lookup, etc. +* **class RdmaRendezvousMgr** - Manages multiple rdma rendezvous. +* **class RdmaRemoteRendezvous** - A derived class of BaseRemoteRendezvous. This class is the back end for "send" and "recv" ops. When the sendrecv_op wants to send or receive a tensor, it calls the rendezvous' "send" and "recv" functions respectively. Rendezvous are identified by "step_id", a random number, so that tensors for different iterations don't get mixed up. + +### Message structure: + +| type | name_size | name | step_id | request_index | remote_addr/checksum | rkey | is_dead | data_type | tensor_shape | tensor_bytes | error_status | +|------|---------- |------|---------|---------------|----------------------|------|---------|-----------|--------------|--------------|-----------------------| +| 1B | 2B | 512 | 8B | 8B | 8B | 4B | 1B | XB | XB | 8B | Size - 4B, proto - XB | + +* **RDMA_MESSAGE_TENSOR_REQUEST** - (receiver ==> sender) The original tensor request. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * remote_addr/rkey - Address/rkey of the result/proxy tensor. Irrelevant for first-time request. + * is_dead/data_type/tensor_shape/tensor_bytes - The current meta-data as stored in the receiver local cache. The sender will use that information to know if the receiver's cache requires updating. +* **RDMA_MESSAGE_META_DATA_RESPONSE** - (sender ==> receiver) The meta-data update message in case meta-data had changed (or if it is the first time the tensor is requested). + * type - The message type. + * request_index - Request index. + * is_dead/data_type/tensor_shape/tensor_bytes - The up-to-date meta-data. + * checksum - In data validation mode, this will hold the checksum of the source tensor. +* **RDMA_MESSAGE_TENSOR_RE_REQUEST** - (receiver ==> sender) Tensor re-requset after meta-data update and reallocation of result/proxy tensors. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * remote_addr/rkey - Address/rkey of the reallocated result/proxy tensor. +* **RDMA_MESSAGE_ERROR_STATUS** - (sender ==> receiver) Notify the receiver that an error had occured on the sender side, so it can propagate it to the upper levels. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * error_status - The error status (code, message, details). diff --git a/tensorflow/contrib/verbs/grpc_verbs_service.cc b/tensorflow/contrib/verbs/grpc_verbs_service.cc index f2af6b79fb..742f946c95 100644 --- a/tensorflow/contrib/verbs/grpc_verbs_service.cc +++ b/tensorflow/contrib/verbs/grpc_verbs_service.cc @@ -122,17 +122,15 @@ Status GrpcVerbsService::GetRemoteAddressSync( rc->SetRemoteAddress(ra, false); rc->Connect(); int i = 0; - int idx[] = {1, 0, 3, 2}; - std::vector mb(rc->message_buffers()); - CHECK_EQ(request->mr_size(), 4); + int idx[] = {1, 0}; + std::vector mb(rc->message_buffers()); + CHECK_EQ(request->mr_size(), RdmaChannel::kNumMessageBuffers); for (const auto& mr : request->mr()) { // the connections are crossed, i.e. // local tx_message_buffer <---> remote rx_message_buffer_ // local rx_message_buffer <---> remote tx_message_buffer_ - // local tx_ack_buffer <---> remote rx_ack_buffer_ - // local rx_ack_buffer <---> remote tx_ack_buffer_ - // hence idx[] = {1, 0, 3, 2}. - RdmaBuffer* rb = mb[idx[i]]; + // hence idx[] = {1, 0}. + RdmaMessageBuffer* rb = mb[idx[i]]; RemoteMR rmr; rmr.remote_addr = mr.remote_addr(); rmr.rkey = mr.rkey(); diff --git a/tensorflow/contrib/verbs/patch_notes_verbs_with_0_copies.md b/tensorflow/contrib/verbs/patch_notes_verbs_with_0_copies.md new file mode 100644 index 0000000000..956b8f2147 --- /dev/null +++ b/tensorflow/contrib/verbs/patch_notes_verbs_with_0_copies.md @@ -0,0 +1,87 @@ +## Verbs implementation to use direct tensor writes (0 copies) + +### Motivation: + +Following HKUST research on the use of GPU direct, and their [GDR implementation](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/gdr/README.md), we wish to adopt the 0 copies approach and apply it to the current verbs implementation, while keeping the current implementation advantages, such as configurability and the use of RDMA for control messages. + +### Performance: + +Compared with the current GRPC, verbs and GDR implementation, the result implementation gave the best performance for every model, with any number of nodes. For VGG16 on 8 nodes with 4 P100 GPUs each, the prototype beat the second place by over 15%. + +### Implementation requirements: + +1. Tensor writes need to be done directly from the source Tensor to the destination Tensor, with no memory copies in between. This should be done for all DMAble tensors which are located either on CPU or on a RDMA compatible GPU device (GPU direct). +2. Non DMAble tensors (CanMemCopy == false) will be serialized to proto on the sender side, RDMA written to a registered buffer on the receiver side, and then deserialized by the receiver. +3. Tensors which are located on a non-RDMA-compatible GPU, will be RDMA written to a registered CPU proxy buffer on the receiver side, and then copied to GPU by the receiver. + +### Implementation constrains: + +For best stability and proof of correctness, we will divide the implementation to two stages: +1. At first stage we will keep changes to the current implementation to the minimum possible. The expense will be that we may have unused or unnecessary code leftovers, which may also affect performance. +2. At second stage, we will re-iterate over the code and remove irrelevant code parts. +The design of the solution aims that we will achieve both stages with relative ease. + +### Design guidelines: + +1. Since we do not want to do any unnecessary memory copying, we will no longer allocate a fixed CPU buffer as the destination for the RDMA write. Instead we will do the writing directly to the result tensor, or if the result tensor is on a device which does not support RDMA, we will do the writing to a proxy CPU tensor and then copy its content to the result tensor. +2. The address of the destination Tensor needs to be sent to the sender side for writing, meaning that the result/proxy tensor should be pre-allocated on the receiver side, prior to sending the tensor request. In order to do that, we need to know its meta-data, i.e. shape and data-type for DMAble tensors, and proto-size for serialized tensors. Unfortunately, this information is only available on the sender side which complicates manners. In order to avoid sending extra messages for querying the meta-data on each step, we store a local meta-data cache per tensor. Based on the assumption that the meta-data of a tensor rarely changes between steps, we expect that on most times the cache will only be updated once. When the sender receives a request for a tensor, if it is the first time this tensor is requested, or in the rare case that the meta-data did change, the sender will first send a meta-data response, on which the receiver will update the local cache, and reallocate the result/proxy tensors if required. When the receiver sends the tensor request, it will contain also the meta-data currently stored in its local cache, so the sender can compare it to see if there was a change. +3. When the sender writes the tensor content to the result tensor, no additional data is being written with it. That means we need to reside on ibverbs immediate (uint32_t) to indicate which request we are responding to (in order to trigger the receive callback). The easiest and most elegant way is to key the recv callback with a unique request_index (uint32_t), instead of the current key_with_step_id (string). +4. Since the sender no longer writes the tensor from/to fixed buffers, we no longer need to schedule the writes using the local/remote status. In addition we no longer rely on the RmdaTensorBuffer members as the source/destination addresses and rkey/lkey. Instead, each RdmaTensorBuffer will hold multiple "Response" objects (one per step-id), from which we derive destination address and rkey. The source address and lkey are always the ones of the source Tensor. +5. With the addition of tensor pre-allocation, we noticed there is a large code similarity between sending the first tensor request and re-sending the request in case of meta-data changes. After implementing a common method for tensor pre-allocation, it turned out that implementation becomes much simpler by encapsulating the process of request sending/re-sending, meta-data response callback and content response callback, all in a single "Request" class. The request class holds all the relevant request information, which reduces excessive parameter passing and lambda capturing. This decision is purely for elegance and code simplicity, and we decided to implement it in first stage because it makes the implementation much easier. + +### New types/classes: + +* **enum RdmaImmDataType** - Immediate types to distinguish between different RDMA writes on the remote side. Ack writes and control-message writes have a fixed immediate value. The rest of the writes are tensor writes and the immediate value is the relevant request index. +* **enum RdmaWriteIDType** - Types to distinguish between different RDMA write-complete events: Ack, control message, tensor DMA write and tensor proto write. +* **class RdmaWriteID** - Context for RDMA write complete events. Holds the RdmaWriteIDType and additional data. +* **class RemoteAddressContext** - Remote address information (address + mr). Will be passed as write context for tensor proto writes. +* **class RdmaTensorMetaData** - Meta-data for a tensor (type, shape, is_dead, proto_size). +* **class RdmaMemoryMgr** - Manages the meta-data cache, and the registered memory regions. +* **class RdmaTensorRequest** - Holds and manages information for a single tensor request throughout the entire receive cycle. API: + * Start() - Start the request. + * RecvTensorMetaData() - Receive meta-data from the remote side. + * RecvTensorContent() - Receive tensor content from the remote side and invoke the done() callback. +* **class RdmaTensorResponse** - Holds information for a single tensor response, such as destination address and rkey. + +### Protocol changes: + +The protocol messages themselves will remain mostly unchanged at the first stage, but will be used differently, as described below. The current messages structures already have most of the required fields for the new implementation. The only change is the "buffer_size" field which is no longer used since we are no longer sending additional information with the tensor, and thus it is now always equal to the "tensor_bytes" field. Instead, we use that field to pass the "request_index". + +### Message structure: + +| type | name_size | name | step_id | request_index | remote_addr | rkey | is_dead | data_type | tensor_shape | tensor_bytes | +|------|---------- |------|---------|---------------|-------------|------|---------|-----------|--------------|--------------| +| 1B | 2B | 512 | 8B | 8B | 8B | 4B | 1B | XB | XB | 8B | + +* **RDMA_MESSAGE_TENSOR_REQUEST** - (receiver ==> sender) The original tensor request. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * remote_addr/rkey - Address/rkey of the result/proxy tensor. Irrelevant for first-time request. + * is_dead/data_type/tensor_shape/tensor_bytes - The current meta-data as stored in the receiver local cache. The sender will use that information to know if the receiver's cache requires updating. +* **RDMA_MESSAGE_BUFFER_REQUEST** - (sender ==> receiver) The meta-data update message in case meta-data had changed (or if it is the first time the tensor is requested). + * type - The message type. + * request_index - Request index. + * is_dead/data_type/tensor_shape/tensor_bytes - The up-to-date meta-data. +* **RDMA_MESSAGE_BUFFER_RESPONSE** - (receiver ==> sender) Tensor re-requset after meta-data update and reallocation of result/proxy tensors. + * type - The message type. + * name (name_size) - Name of the requested tensor. + * step_id - Step ID. + * request_index - Request index. + * remote_addr/rkey - Address/rkey of the reallocated result/proxy tensor. + * is_dead/data_type/tensor_shape/tensor_bytes - The new meta-data. Will be removed in the next phase. +* **RDMA_MESSAGE_TENSOR_WRITE** - (sender ==> receiver) No longer sent. There is only a direct write of the tensor content to the result/proxy tensor. Request index passed as the immediate value of the write. +* **RDMA_MESSAGE_TENSOR_IDLE** - (receiver ==> sender) No longer sent. + +![alt text](verbs_with_0_copies_phase1_protocol.jpg "Phase 1 message protocol") + +### Second stage optimizations: +1. Remove unused code leftovers. +2. Remove the ACK buffer completely, since we can rely completely on its immediate value. + +### Future optimizations: +1. Map the tensor names to indexes, to significantly reduce the request message size. +2. Understand the purpose of empty tensors and if we can skip remote fetching for them. +3. Consider concatenating multiple requests and/or using multiple message buffers. +4. Consider a no-request architecture. diff --git a/tensorflow/contrib/verbs/rdma.cc b/tensorflow/contrib/verbs/rdma.cc index ae9a384565..ec5271abe0 100644 --- a/tensorflow/contrib/verbs/rdma.cc +++ b/tensorflow/contrib/verbs/rdma.cc @@ -16,18 +16,19 @@ limitations under the License. #ifdef TENSORFLOW_USE_VERBS #include "tensorflow/contrib/verbs/rdma.h" -#include +#include "tensorflow/contrib/verbs/verbs_service.pb.h" #include #include -#include "tensorflow/contrib/verbs/verbs_util.h" #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/common_runtime/dma_helper.h" +#include "tensorflow/core/common_runtime/process_util.h" #if GOOGLE_CUDA #include "tensorflow/core/common_runtime/gpu/gpu_util.h" #include "tensorflow/core/common_runtime/gpu/process_state.h" #endif #include "tensorflow/core/distributed_runtime/rendezvous_mgr_interface.h" #include "tensorflow/core/distributed_runtime/session_mgr.h" +#include "tensorflow/core/distributed_runtime/rpc/grpc_util.h" #include "tensorflow/core/framework/rendezvous.h" #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/lib/core/status.h" @@ -41,32 +42,19 @@ namespace tensorflow { #define RoCE_V2 "RoCE v2" namespace { -// hash name to 32-bit integer -uint32_t NameHash(const string& name) { - return Hash32(name.data(), name.size(), 0x1234ABCD); -} // convenience function for printing message string MessageTypeToString(RdmaMessageType rmt) { switch (rmt) { - case RDMA_MESSAGE_ACK: - return "RDMA_MESSAGE_ACK"; - break; - case RDMA_MESSAGE_BUFFER_IDLE: - return "RDMA_MESSAGE_BUFFER_IDLE"; - break; - case RDMA_MESSAGE_BUFFER_REQUEST: - return "RDMA_MESSAGE_BUFFER_REQUEST"; + case RDMA_MESSAGE_META_DATA_UPDATE: + return "RDMA_MESSAGE_META_DATA_UPDATE"; break; - case RDMA_MESSAGE_BUFFER_RESPONSE: - return "RDMA_MESSAGE_BUFFER_RESPONSE"; + case RDMA_MESSAGE_TENSOR_RE_REQUEST: + return "RDMA_MESSAGE_TENSOR_RE_REQUEST"; break; case RDMA_MESSAGE_TENSOR_REQUEST: return "RDMA_MESSAGE_TENSOR_REQUEST"; break; - case RDMA_MESSAGE_TENSOR_WRITE: - return "RDMA_MESSAGE_TENSOR_WRITE"; - break; default: return "UNKNOWN MESSAGE"; } @@ -347,7 +335,7 @@ uint32_t set_param(uint32_t default_val, const char* env_param) { enum ibv_mtu set_mtu(uint8_t port_num, ibv_context* context) { ibv_port_attr port_attr; - enum ibv_mtu mtu; + enum ibv_mtu mtu = IBV_MTU_512; string mtu_s; int rc, mtu_i; @@ -468,97 +456,70 @@ void RdmaAdapter::Process_CQ() { rc->Recv(); // imm_data is the index of RX buffer in the buffer table. uint32_t imm_data = wc_[i].imm_data; - RdmaBuffer* rb = rc->FindBuffer(imm_data); + RdmaMessageBuffer* rb; RdmaMessage rm; - RdmaMessage::ParseMessage(rm, rb->buffer_); - VLOG(2) << "recv RDMA message: " << MessageTypeToString(rm.type_); - if (rm.type_ == RDMA_MESSAGE_ACK) { + if (imm_data == RDMA_IMM_DATA_ACK) { // receive an ack to a message rb = rc->tx_message_buffer_; rb->SetBufferStatus(remote, idle); rb->SendNextItem(); - } else if (rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) { - // received a request-for-tensor message - // send ack to release remote tx message buffer - RdmaBuffer* ab = rc->tx_ack_buffer_; - ab->SendNextItem(); - // find or create buffer - RdmaBuffer* tb = rc->FindOrCreateBuffer(rm.name_); - string key_with_step_id = - VerbsUtil::AppendStepidToKey(rm.name_, rm.step_id_); - tb->EnqueueItem(key_with_step_id); - // send the next tensor - worker_env_->compute_pool->Schedule([tb]() { tb->SendNextItem(); }); - } else if (rm.type_ == RDMA_MESSAGE_BUFFER_IDLE) { - // receive tensor-buffer-ready message - // send ack to release remote tx message buffer - RdmaBuffer* ab = rc->tx_ack_buffer_; - ab->SendNextItem(); - // find buffer - RdmaTensorBuffer* tb = - reinterpret_cast(rc->FindBuffer(rm.name_)); - tb->SetBufferStatus(remote, idle); - worker_env_->compute_pool->Schedule([tb]() { tb->ReSendNextItem(); }); - } else if (rm.type_ == RDMA_MESSAGE_BUFFER_REQUEST) { - // remote host requests to create a tensor buffer; - // send ack to release remote tx message buffer - RdmaBuffer* ab = rc->tx_ack_buffer_; - ab->SendNextItem(); - // find or create the buffer - RdmaBuffer* tb = rc->FindOrCreateBuffer(rm.name_, TENSOR); - RemoteMR rmr; - rmr.remote_addr = rm.remote_addr_; - rmr.rkey = rm.rkey_; - tb->SetRemoteMR(rmr, true); - tb->CreateCPUBuffer(rm.buffer_size_); - // create RDMA_MESSAGE_BUFFER_RESPONSE message - RdmaMessage br; - br.type_ = RDMA_MESSAGE_BUFFER_RESPONSE; - br.name_size_ = rm.name_.size(); - br.name_ = rm.name_; - br.buffer_size_ = rm.buffer_size_; - br.remote_addr_ = reinterpret_cast(tb->buffer_); - br.rkey_ = tb->self_->rkey; - string message = RdmaMessage::CreateMessage(br); - RdmaBuffer* mb = rc->tx_message_buffer_; - mb->EnqueueItem(message); - mb->SendNextItem(); - } else if (rm.type_ == RDMA_MESSAGE_BUFFER_RESPONSE) { - // remote creates a buffer and responds - // send ack to release remote tx message buffer - RdmaBuffer* ab = rc->tx_ack_buffer_; - ab->SendNextItem(); - // find buffer - RdmaTensorBuffer* tb = - reinterpret_cast(rc->FindBuffer(rm.name_)); - CHECK(rm.buffer_size_ == tb->size_) - << "rm.buffer_size = " << rm.buffer_size_ - << "tb->size_ = " << tb->size_ << "rm.name_ = " << rm.name_; - RemoteMR rmr; - rmr.remote_addr = rm.remote_addr_; - rmr.rkey = rm.rkey_; - tb->SetRemoteMR(rmr, true); - tb->SetBufferStatus(local, idle); - tb->SetBufferStatus(remote, idle); - worker_env_->compute_pool->Schedule([tb]() { tb->ReSendNextItem(); }); - } else if (rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) { - // tensor RDMA write completed - worker_env_->compute_pool->Schedule([rm, rc]() { - string key_with_step_id = - VerbsUtil::AppendStepidToKey(rm.name_, rm.step_id_); - rc->RunRecvCallback(key_with_step_id); - }); + continue; } - } else if (wc_[i].opcode == IBV_WC_RDMA_WRITE) { - RdmaBuffer* rb = reinterpret_cast(wc_[i].wr_id); - rb->SetBufferStatus(local, idle); - RdmaMessage rm; + + if (imm_data <= RDMA_IMM_MAX_REQUEST_ID) { + // receive a tensor RDMA write + uint32_t request_index = imm_data; + RdmaTensorRequest* request = rc->GetTensorRequest(request_index); + request->RecvTensorContent(); + continue; + } + + // receive a control message + rb = rc->rx_message_buffer_; RdmaMessage::ParseMessage(rm, rb->buffer_); - VLOG(2) << "sent RDMA message: " << MessageTypeToString(rm.type_); - if (rm.type_ != RDMA_MESSAGE_ACK) { - worker_env_->compute_pool->Schedule([rb]() { rb->SendNextItem(); }); + RdmaMessageBuffer::SendAck(rc); + RDMA_LOG(1) << "Step 0x" << std::hex << rm.step_id_ << std::dec + << ": Received " << MessageTypeToString(rm.type_) << " " + << "#" << rm.request_index_ << ": " << rm.name_; + + if (rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) { + RdmaTensorResponse* response = rc->AddTensorResponse(rm); + response->Start(); + } else if (rm.type_ == RDMA_MESSAGE_META_DATA_UPDATE) { + RdmaTensorRequest* request = rc->GetTensorRequest(rm.request_index_); + request->RecvTensorMetaData(rm.data_type_, rm.tensor_shape_, + rm.is_dead_, rm.tensor_bytes_); +#ifdef RDMA_DATA_VALIDATION + request->RecvTensorChecksum(rm.checksum_); +#endif + } else if (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST) { + RdmaTensorResponse* response = rc->UpdateTensorResponse(rm); + response->Resume(); + } else if (rm.type_ == RDMA_MESSAGE_ERROR_STATUS) { + RdmaTensorRequest* request = rc->GetTensorRequest(rm.request_index_); + request->RecvErrorStatus(rm.status_); + } + } else if (wc_[i].opcode == IBV_WC_RDMA_WRITE) { + RdmaWriteID* wr_id = reinterpret_cast(wc_[i].wr_id); + RDMA_LOG(2) << "Write complete of type " << wr_id->write_type; + switch (wr_id->write_type) { + case RDMA_WRITE_ID_ACK: + break; + case RDMA_WRITE_ID_MESSAGE: { + RdmaMessageBuffer* rb = + reinterpret_cast(wr_id->write_context); + rb->SetBufferStatus(local, idle); + rb->SendNextItem(); + break; + } + case RDMA_WRITE_ID_TENSOR_WRITE: { + RdmaTensorResponse* response = + reinterpret_cast(wr_id->write_context); + response->Destroy(); + } } + delete wr_id; } } } @@ -588,8 +549,10 @@ int RdmaChannel::PingPostSend() { RdmaChannel::RdmaChannel(const RdmaAdapter* adapter, const string local_name, const string remote_name) - : adapter_(adapter), local_name_(local_name), remote_name_(remote_name) { - + : adapter_(adapter), + local_name_(local_name), + remote_name_(remote_name), + request_serial_(0) { struct ibv_sge list; mr_ = ibv_reg_mr(adapter_->pd_, ping_buff_, kPingBuffSize, @@ -651,29 +614,15 @@ RdmaChannel::RdmaChannel(const RdmaAdapter* adapter, const string local_name, // create message and ack buffers, then initialize the tables. { - const string buffer_names[] = {"tx_message_buffer", "rx_message_buffer", - "tx_ack_buffer", "rx_ack_buffer"}; + const string buffer_names[] = {"tx_message_buffer", "rx_message_buffer"}; tx_message_buffer_ = new RdmaMessageBuffer(this, buffer_names[0]); rx_message_buffer_ = new RdmaMessageBuffer(this, buffer_names[1]); - tx_ack_buffer_ = new RdmaAckBuffer(this, buffer_names[2]); - rx_ack_buffer_ = new RdmaAckBuffer(this, buffer_names[3]); message_buffers_.reserve(kNumMessageBuffers); message_buffers_.push_back(tx_message_buffer_); message_buffers_.push_back(rx_message_buffer_); - message_buffers_.push_back(tx_ack_buffer_); - message_buffers_.push_back(rx_ack_buffer_); // create buffer on host tx_message_buffer_->CreateCPUBuffer(RdmaMessage::kRdmaMessageBufferSize); rx_message_buffer_->CreateCPUBuffer(RdmaMessage::kRdmaMessageBufferSize); - tx_ack_buffer_->CreateCPUBuffer(RdmaMessage::kRdmaAckBufferSize); - rx_ack_buffer_->CreateCPUBuffer(RdmaMessage::kRdmaAckBufferSize); - // bt_mu_.lock() is not used in constructor. - for (int i = 0; i < kNumMessageBuffers; i++) { - uint32_t index = NameHash(buffer_names[i]); - buffer_table_.insert({index, message_buffers_[i]}); - buffer_index_name_table_.insert({index, buffer_names[i]}); - buffer_name_index_table_.insert({buffer_names[i], index}); - } } CHECK(PingPostRecv() == 0) << "Couldn't post receive from " << remote_name_ << " with error " << std::strerror(errno); @@ -684,8 +633,6 @@ RdmaChannel::~RdmaChannel() { CHECK(!ibv_destroy_qp(qp_)) << "Failed to destroy QP"; delete tx_message_buffer_; delete rx_message_buffer_; - delete tx_ack_buffer_; - delete rx_ack_buffer_; } void RdmaChannel::SetRemoteAddress(const RdmaAddress& ra, bool override) { @@ -716,114 +663,31 @@ void RdmaChannel::Recv() { CHECK(!ibv_post_recv(qp_, &wr, &bad_wr)) << "Failed to post recv"; } -// Lookup 32-bit buffer index from buffer name -// Args: -// buffer_name: name of the buffer -// Returns: -// 32-bit index -uint32_t RdmaChannel::LookupBufferIndex(const string& buffer_name) { - mutex_lock lock{bt_mu_}; - BufferNameIndexTable::iterator iter = - buffer_name_index_table_.find(buffer_name); - CHECK(iter != buffer_name_index_table_.end()); - return iter->second; -} - -// Find a buffer by its 32-bit index -// Args: -// index: 32-bit hash code of the tensor buffer name -// Returns: -// name of the tensor buffer -RdmaBuffer* RdmaChannel::FindBuffer(const uint32_t index) { - mutex_lock lock{bt_mu_}; - BufferTable::iterator iter = buffer_table_.find(index); - CHECK(iter != buffer_table_.end()); - return iter->second; -} - -// Find a buffer by its name -// Args: -// name: name of the buffer -// Returns: -// the named rdma buffer -RdmaBuffer* RdmaChannel::FindBuffer(const string& name) { - uint32_t index = LookupBufferIndex(name); - return FindBuffer(index); -} - -// Find a buffer if it exists, otherwise create one. -// The memory inside the created buffer is not allocated. -// Args: -// name: the name of the buffer -// buffer_type: TENSOR, MESSAGE or ACK. -// Returns: -// the named buffer -RdmaBuffer* RdmaChannel::FindOrCreateBuffer(const string& name, - BufferType buffer_type) { - mutex_lock lock{bt_mu_}; - RdmaBuffer* rb; - // find index - BufferNameIndexTable::iterator iter = buffer_name_index_table_.find(name); - if (iter != buffer_name_index_table_.end()) { - uint32_t index = iter->second; - // find buffer - BufferTable::iterator iter = buffer_table_.find(index); - CHECK(iter != buffer_table_.end()); - rb = iter->second; - } else { - uint32_t index = NameHash(name); - if (buffer_type == TENSOR) { - rb = new RdmaTensorBuffer(this, name); - } else if (buffer_type == MESSAGE) { - rb = new RdmaMessageBuffer(this, name); - } else if (buffer_type == ACK) { - rb = new RdmaAckBuffer(this, name); - } - buffer_name_index_table_.insert({name, index}); - buffer_index_name_table_.insert({index, name}); - buffer_table_.insert({index, rb}); +RdmaTensorRequest* RdmaChannel::InsertTensorRequest( + const string& key, int64 step_id, Device* dst_dev, + const Rendezvous::Args recv_args, + const RdmaTensorRequest::RecvDoneCallback& done) { + mutex_lock lock{ct_mu_}; + uint32_t request_index = request_serial_++; + if (request_serial_ > RDMA_IMM_MAX_REQUEST_ID) { + request_serial_ = 0; } - CHECK(rb); - return rb; + RdmaTensorRequest request(request_index, key, step_id, this, dst_dev, + recv_args, done); + auto it = request_table_.emplace(request_index, request); + return &it.first->second; } -// Insert callback to the callback_table. -// The callback is activated when the corresponding tensor is received. -// Arg: -// key: the name of the tensor -// recv_done: the callback associated with the tensor. -// Returns: -// None -void RdmaChannel::InsertRecvCallback(const string& key, - std::function recv_done) { +void RdmaChannel::RemoveTensorRequest(uint32_t request_index) { mutex_lock lock{ct_mu_}; - callback_table_.insert({key, recv_done}); + request_table_.erase(request_index); } -// Remove callback from the callback_table. -// Arg: -// key: the name of the tensor -// Returns: -// None -void RdmaChannel::RemoveRecvCallback(const string& key) { +RdmaTensorRequest* RdmaChannel::GetTensorRequest(uint32_t request_index) { mutex_lock lock{ct_mu_}; - callback_table_.erase(key); -} - -// Run named callback in the callback_table. -// Arg: -// key: the name of the tensor -// Returns: -// None -void RdmaChannel::RunRecvCallback(const string& key) { - std::function recv_done; - { - mutex_lock lock{ct_mu_}; - CallbackTable::iterator iter = callback_table_.find(key); - CHECK(iter != callback_table_.end()); - recv_done = iter->second; - } - recv_done(); + RequestTable::iterator iter = request_table_.find(request_index); + CHECK(iter != request_table_.end()); + return &iter->second; } void RdmaChannel::Connect() { @@ -888,25 +752,22 @@ void RdmaChannel::Connect(const RdmaAddress& remoteAddr) { connected_ = true; } else { - LOG(INFO) << "channel already connected"; + RDMA_LOG(2) << "channel already connected"; } } -RdmaBuffer::RdmaBuffer(RdmaChannel* channel, string name) +RdmaMessageBuffer::RdmaMessageBuffer(RdmaChannel* channel, string name) : channel_(channel), name_(name) {} -RdmaBuffer::~RdmaBuffer() { +RdmaMessageBuffer::~RdmaMessageBuffer() { CHECK(!ibv_dereg_mr(self_)) << "ibv_dereg_mr failed"; FreeBuffer(); } -void RdmaBuffer::FreeBuffer() { +void RdmaMessageBuffer::FreeBuffer() { if ((buffer_ != nullptr) && buffer_on_host_) { free(buffer_); } - // TODO - // release buffer if it is on device. - // We don't support RDMABuffer on device at this moment. } // Allocate CPU memory for the Rdma buffer @@ -915,7 +776,7 @@ void RdmaBuffer::FreeBuffer() { // lock: whether or not mutex_lock the process to protect concurrency. // Returns: // None -void RdmaBuffer::CreateCPUBuffer(size_t size, bool lock) { +void RdmaMessageBuffer::CreateCPUBuffer(size_t size, bool lock) { CHECK(size > 0); if (lock) { mu_.lock(); @@ -943,7 +804,7 @@ void RdmaBuffer::CreateCPUBuffer(size_t size, bool lock) { // override: whether override existing information // Returns: // None -void RdmaBuffer::SetRemoteMR(RemoteMR rmr, bool override) { +void RdmaMessageBuffer::SetRemoteMR(RemoteMR rmr, bool override) { mutex_lock lock{mu_}; if ((override) || (remote_status_ == none)) { remote_.remote_addr = rmr.remote_addr; @@ -956,63 +817,51 @@ void RdmaBuffer::SetRemoteMR(RemoteMR rmr, bool override) { } // Put a task in the buffer's job queue -void RdmaBuffer::EnqueueItem(string item) { +void RdmaMessageBuffer::EnqueueItem(string item) { mutex_lock lock{mu_}; queue_.push(item); } // Rdma-Write the content of the buffer -void RdmaBuffer::Write(uint32_t imm_data, size_t buffer_size) { +void RdmaMessageBuffer::Write(uint32_t imm_data, size_t buffer_size) { + Write(channel_, imm_data, buffer_size, (uint64_t)buffer_, self_->lkey, + remote_.remote_addr, remote_.rkey, RDMA_WRITE_ID_MESSAGE, this); +} + +// Generalized Write method +void RdmaMessageBuffer::Write(const RdmaChannel* channel, uint32_t imm_data, + size_t buffer_size, uint64_t src_addr, + uint32_t lkey, uint64_t remote_addr, + uint32_t rkey, RdmaWriteIDType write_type, + void* write_context) { struct ibv_sge list; - list.addr = (uint64_t)buffer_; + list.addr = src_addr; list.length = buffer_size; - list.lkey = self_->lkey; + list.lkey = lkey; struct ibv_send_wr wr; memset(&wr, 0, sizeof(wr)); - wr.wr_id = (uint64_t) this; + wr.wr_id = (uint64_t) new RdmaWriteID(write_type, write_context); wr.sg_list = &list; wr.num_sge = 1; wr.opcode = IBV_WR_RDMA_WRITE_WITH_IMM; wr.send_flags = IBV_SEND_SIGNALED; wr.imm_data = imm_data; - wr.wr.rdma.remote_addr = (uint64_t)remote_.remote_addr; - wr.wr.rdma.rkey = remote_.rkey; + wr.wr.rdma.remote_addr = remote_addr; + wr.wr.rdma.rkey = rkey; struct ibv_send_wr* bad_wr; - CHECK(!ibv_post_send(channel_->qp_, &wr, &bad_wr)) << "Failed to post send"; -} - -RdmaAckBuffer::RdmaAckBuffer(RdmaChannel* channel, string name) - : RdmaBuffer(channel, name) {} - -RdmaMessageBuffer::RdmaMessageBuffer(RdmaChannel* channel, string name) - : RdmaBuffer(channel, name) {} - -RdmaTensorBuffer::RdmaTensorBuffer(RdmaChannel* channel, string name) - : RdmaBuffer(channel, name) {} - -RdmaTensorBuffer::~RdmaTensorBuffer() { - for (Itable it = retable.begin(); it != retable.end(); ++it) { - delete (it->second); - } + CHECK(!ibv_post_send(channel->qp_, &wr, &bad_wr)) << "Failed to post send"; } // Send the next ack from the buffer's job queue. -void RdmaAckBuffer::SendNextItem() { - uint32_t imm_data = LookupBufferIndex("rx_ack_buffer"); - RdmaMessage rm; - rm.name_ = "rx_ack_buffer"; - rm.type_ = RDMA_MESSAGE_ACK; - rm.name_size_ = rm.name_.size(); - string message = RdmaMessage::CreateMessage(rm); - memcpy(buffer_, message.data(), message.size()); - Write(imm_data, message.size()); +void RdmaMessageBuffer::SendAck(const RdmaChannel* channel) { + Write(channel, RDMA_IMM_DATA_ACK, 0, 0, 0, 0, 0, RDMA_WRITE_ID_ACK, nullptr); } // Send the next message from the buffer's job queue. void RdmaMessageBuffer::SendNextItem() { - uint32_t imm_data = LookupBufferIndex("rx_message_buffer"); + uint32_t imm_data = RDMA_IMM_DATA_MESSAGE; mu_.lock(); if (!queue_.empty() && (local_status_ == idle) && (remote_status_ == idle)) { local_status_ = busy; @@ -1029,244 +878,392 @@ void RdmaMessageBuffer::SendNextItem() { } } -Rendezvous::DoneCallback RdmaTensorBuffer::getRecvTensorCallback( - const string& key_with_step_id, const string& key, int64 step_id, - const Rendezvous::ParsedKey& parsed) { - Rendezvous::DoneCallback cb = [this, key_with_step_id, key, step_id, parsed]( - const Status& status, const Rendezvous::Args& send_args, - const Rendezvous::Args& recv_args, const Tensor& in, bool is_dead) { - CHECK(status.ok()) << "RecvLocalAsync was not ok, key" << key_with_step_id - << " error message: " << status.error_message(); - size_t buffer_size = RdmaMessage::kMessageTotalBytes; - size_t tensor_bytes = 0; - // Figures out which device the tensor is hosted on. - Device* src_dev = nullptr; - Status s = channel_->adapter_->worker_env_->device_mgr->LookupDevice( - parsed.src_device, &src_dev); - CHECK(s.ok()) << "src device not found"; - // Does the device have the right incarnation number we expect? - CHECK(src_dev->attributes().incarnation() == parsed.src_incarnation) - << "RecvTensor expects a different device incarnation: " - << parsed.src_incarnation << " vs. " - << src_dev->attributes().incarnation() - << ". Your worker job was probably restarted. Check your " - << "worker job for the reason why it was restarted."; - Device* dst_dev = nullptr; - // destination is on CPU. - s = channel_->adapter_->worker_env_->device_mgr->LookupDevice("CPU:0", - &dst_dev); - CHECK(s.ok()) << "dst device not found"; - AllocatorAttributes dst_alloc_attr; - dst_alloc_attr.set_on_host(true); - - bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); - // string tensor needs to be serialized - Tensor copy; - TensorProto proto; - if (src_dev->tensorflow_gpu_device_info() && - (!send_args.alloc_attrs.on_host())) { #if GOOGLE_CUDA - CHECK(send_args.device_context) << "send dev name: " << src_dev->name() - << " gpu_info: " - << src_dev->tensorflow_gpu_device_info(); - - if (can_memcpy) { - AllocatorAttributes host_alloc_attrs; - host_alloc_attrs.set_gpu_compatible(true); - host_alloc_attrs.set_on_host(true); - Allocator* alloc = ProcessState::singleton()->GetCUDAHostAllocator(0); - copy = Tensor(alloc, in.dtype(), in.shape()); - tensor_bytes = in.TotalBytes(); - buffer_size += tensor_bytes; - GPUUtil::CopyGPUTensorToCPU( - src_dev, send_args.device_context, &in, ©, - [this, copy, tensor_bytes, buffer_size, key, in, step_id, - key_with_step_id, is_dead, send_args, recv_args](const Status& s) { - CHECK(s.ok()) << "copy tensor from gpu sync"; - StringPiece copy_buf; - copy_buf = copy.tensor_data(); - PostCopyOperations(true, buffer_size, tensor_bytes, key, in, - step_id, is_dead, key_with_step_id, ©, - NULL, ©_buf, send_args, recv_args); - }); - } else { - // "val" is on a GPU. No longer uses GPUUtil to fill the proto, use - // aync instead - GPUUtil::SetProtoFromGPU( - in, src_dev, send_args.device_context, &proto, is_dead, - [this, proto, buffer_size, key, in, step_id, key_with_step_id, - is_dead, send_args, recv_args](const Status& s) mutable { - CHECK(s.ok()) << "copy proto from gpu sync"; - auto tensor_bytes = proto.ByteSize(); - buffer_size += tensor_bytes; - PostCopyOperations(false, buffer_size, tensor_bytes, key, in, - step_id, is_dead, key_with_step_id, NULL, - &proto, NULL, send_args, recv_args); - }); - } -#endif // GOOGLE_CUDA - } else { - // tensor is in CPU memory. - StringPiece copy_buf; - if (can_memcpy) { - copy_buf = in.tensor_data(); - tensor_bytes = in.TotalBytes(); - } else { - in.AsProtoTensorContent(&proto); - tensor_bytes = proto.ByteSize(); - } - buffer_size += tensor_bytes; - PostCopyOperations(can_memcpy, buffer_size, tensor_bytes, key, in, - step_id, is_dead, key_with_step_id, ©, &proto, - ©_buf, send_args, recv_args); +static void CountCopies(const std::string& key, void* src_addr, void* dst_addr, + size_t tensor_bytes, bool is_gpu_to_cpu) { +#ifdef RDMA_COUNT_COPIES + static uint64_t numGPUToCPUCopies = 0; + static uint64_t numGPUToCPUCopiedBytes = 0; + static uint64_t numCPUToGPUCopies = 0; + static uint64_t numCPUToGPUCopiedBytes = 0; + static uint64_t numTotalCopies = 0; + + if (is_gpu_to_cpu) { + ++numGPUToCPUCopies; + numGPUToCPUCopiedBytes += tensor_bytes; + } else { + ++numCPUToGPUCopies; + numCPUToGPUCopiedBytes += tensor_bytes; + } + if ((++numTotalCopies % 0x400) == 0) { + RDMA_LOG(0) << "Tensor copies:" + << " GPU to CPU: " << numGPUToCPUCopies + << " (" << numGPUToCPUCopiedBytes << " Bytes)" + << " CPU to GPU: " << numCPUToGPUCopies + << " (" << numCPUToGPUCopiedBytes << " Bytes)"; + } + RDMA_LOG(2) << "Copying tensor " << key + << " From: " << src_addr << " To: " << dst_addr; +#endif // RDMA_COUNT_COPIES +} +#endif // GOOGLE_CUDA + +#ifdef RDMA_DATA_VALIDATION +static uint64_t Checksum(Device* device, const DeviceContext* device_context, + const Tensor& in) { + uint64 checksum = 0; + if (DataTypeCanUseMemcpy(in.dtype())) { +#if GOOGLE_CUDA + if (in.TotalBytes() == 0) { + return 0; } - }; - return cb; + checksum = (device_context != nullptr) + ? GPUUtil::Checksum(device, device_context, in) + : GPUUtil::Checksum(in); +#endif // GOOGLE_CUDA + } else { + string s = in.SummarizeValue(999999); + checksum = Hash64(s.c_str(), s.size(), 0); + } + return checksum; } -// Send the next tensor from the buffer's job queue. -void RdmaTensorBuffer::SendNextItem() { - // get the key - string key_with_step_id = ""; - { - mutex_lock lock{mu_}; - if (!queue_.empty()) { - key_with_step_id = queue_.front(); - queue_.pop(); +static void ValidateChecksum(uint64_t expected, uint64_t actual, + const Tensor& in, uint32_t request_index, + const std::string& key, const std::string& msg) { + RDMA_LOG(2) << "Request #" << request_index << ": " << key + << ": Checksum: " << std::hex << " Expected = 0x" << expected + << ". Actual = 0x" << actual << "."; + + if (expected != actual) { + // Checksum failed. There is one case where this is allowed - if the + // tensor is an AssignAdd of the global step. Since the data-validation + // always postpones the Tensor response in order to send a checksum message, + // it is possible that the global-step was updated while the response was + // still in queue. + if ((in.TotalBytes() == 8) && (in.dtype() == DT_INT64)) { + int64_t prev_val = *(int64_t*)DMAHelper::base(&in) - 1; + actual = Hash64((const char*)&prev_val, 8, 0); + } + if (expected != actual) { + LOG(FATAL) << "[" << msg << "]: Checksum validation failed for request #" + << request_index << ": " << key << std::hex << " " + << DataTypeString(in.dtype()) << " " + << in.shape().DebugString() << " (0x" << in.TotalBytes() + << " bytes): " + << " Expected 0x" << expected << ". Got 0x" << actual << "."; } } +} +#endif // RDMA_DATA_VALIDATION + +#if GOOGLE_CUDA +// Sync the 'done' operation on the GPU stream, but without all the data +// copying. +static void StreamGPUOp(Device* gpu_device, + const DeviceContext* device_context, + StatusCallback done) { + Tensor dummy1, dummy2; + GPUUtil::CopyGPUTensorToCPU( + gpu_device, device_context, &dummy1, &dummy2, done); +} +#endif // GOOGLE_CUDA + +RdmaTensorResponse* RdmaChannel::AddTensorResponse(const RdmaMessage& rm) { + mutex_lock lock{mu_}; + auto it = + responses_table_.emplace(rm.request_index_, RdmaTensorResponse(this, rm)); + CHECK(it.second) << "Response with the ID " << rm.request_index_ + << " already exists."; + return &it.first->second; +} + +RdmaTensorResponse* RdmaChannel::UpdateTensorResponse(const RdmaMessage& rm) { + mutex_lock lock{mu_}; + auto it = responses_table_.find(rm.request_index_); + CHECK(it != responses_table_.end()) << "No response found."; + RdmaTensorResponse* response = &it->second; + response->Update(rm); + return response; +} - // send the tensor if a key is acquired. - if (key_with_step_id != "") { - VLOG(2) << "try to send tensor: " << key_with_step_id; - string key; - int64 step_id; - VerbsUtil::GetKeyAndStepId(key_with_step_id, key, step_id); - CHECK(key.compare(name_) == 0); - Rendezvous::ParsedKey parsed; - Rendezvous::ParseKey(key, &parsed); - Rendezvous::DoneCallback cb = - getRecvTensorCallback(key_with_step_id, key, step_id, parsed); - channel_->adapter_->worker_env_->rendezvous_mgr->RecvLocalAsync(step_id, - parsed, cb); +void RdmaChannel::RemoveTensorResponse(uint32_t request_index) { + mutex_lock lock{mu_}; + responses_table_.erase(request_index); +} + +void RdmaTensorResponse::Start() { + Rendezvous::ParsedKey parsed; + Status s = Rendezvous::ParseKey(rm_.name_, &parsed); + if (!s.ok()) { + SendErrorStatus(s); + return; } + + channel_->adapter_->worker_env_->rendezvous_mgr->RecvLocalAsync( + rm_.step_id_, parsed, + [this, parsed](const Status& status, const Rendezvous::Args& send_args, + const Rendezvous::Args& recv_args, const Tensor& in, + bool is_dead) { + CHECK(status.ok()) << "RecvLocalAsync was not ok." + << " error message: " << status.error_message(); + RecvHandler(parsed, send_args, recv_args, in, is_dead); + }); } -void RdmaTensorBuffer::ReSendNextItem() { - // get the key - string key_with_step_id = ""; - { - mutex_lock lock{mu_}; - if (!requeue.empty()) { - key_with_step_id = requeue.front(); - requeue.pop(); - } +void RdmaTensorResponse::Resume() { SendContent(*tensor_, *proto_, is_dead_); } + +// Helper for RecvTensor. Validates "key" and returns the source +// device in "*src_dev". +Status RdmaTensorResponse::PrepareRecvTensor( + const Rendezvous::ParsedKey& parsed, Device** src_dev) { + // Figures out which device the tensor is hosted on. + string local_name = DeviceNameUtils::LocalName(parsed.src_device); + TF_RETURN_IF_ERROR(channel_->adapter_->worker_env_->device_mgr->LookupDevice( + local_name, src_dev)); + + // Does the device have the right incarnation number we expect? + if ((*src_dev)->attributes().incarnation() != parsed.src_incarnation) { + return errors::Aborted( + "RecvTensor expects a different device incarnation: ", + parsed.src_incarnation, " vs. ", (*src_dev)->attributes().incarnation(), + ". Your worker job was probably restarted. Check your " + "worker job for the reason why it was restarted."); } - // send the tensor if a key is acquired. - if (key_with_step_id != "") { - VLOG(2) << "try to send tensor: " << key_with_step_id; - string key; - int64 step_id; - VerbsUtil::GetKeyAndStepId(key_with_step_id, key, step_id); - CHECK(key.compare(name_) == 0); - Rendezvous::ParsedKey parsed; - Rendezvous::ParseKey(key, &parsed); - Rendezvous::DoneCallback cb = - getRecvTensorCallback(key_with_step_id, key, step_id, parsed); - ReItem* item; - { - mutex_lock lock{mu_}; - Itable it = retable.find(key_with_step_id); - CHECK(it != retable.end()) << "Could not find dup-recv context"; - item = it->second; - retable.erase(it); + return Status::OK(); +} + +void RdmaTensorResponse::RecvHandler(Rendezvous::ParsedKey parsed, + const Rendezvous::Args& send_args, + const Rendezvous::Args& recv_args, + const Tensor& in, bool is_dead) { + Status s = PrepareRecvTensor(parsed, &src_dev_); + if (!s.ok()) { + SendErrorStatus(s); + return; + } + + meta_data_changed_ = TensorMetaDataChanged(in, is_dead); +#ifdef RDMA_DATA_VALIDATION + // Always send a meta data message with the source checksum + meta_data_changed_ = rm_.type_ == RDMA_MESSAGE_TENSOR_REQUEST; + checksum_ = Checksum(src_dev_, send_args.device_context, in); +#endif + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + // string tensor needs to be serialized + Tensor copy; + TensorProto proto; + const bool on_host = send_args.alloc_attrs.on_host(); + if (src_dev_->tensorflow_gpu_device_info() && !on_host) { +#if GOOGLE_CUDA + DeviceContext* send_dev_context = send_args.device_context; + CHECK(send_dev_context) + << "send dev name: " << src_dev_->name() + << " gpu_info: " << src_dev_->tensorflow_gpu_device_info(); + + if (can_memcpy) { + // If the tensor is located on a GDR compatible GPU, there is no need to + // copy it. We can send directly from the source, just need to make sure + // we are in sync with the GPU stream. + // If the tensor's meta-data changed however, we will need to clone it, + // so anyway we'll have to copy it from GPU to CPU first. If at some + // point in time Clone() is changed to only save a shallow copy, we can + // skip the copy here as well. + if ((in.TotalBytes() > 0) && !meta_data_changed_ && + (RdmaMemoryMgr::Singleton().FindMemoryRegion( + (void*)DMAHelper::base(&in), in.TotalBytes()) != nullptr)) { + StreamGPUOp(src_dev_, send_dev_context, + [this, in, proto, is_dead](const Status& s) { + Send(in, proto, is_dead, s); + }); + return; + } + + // The tensor must be copied from GPU to CPU, because either: + // 1. The tensor is located on a non GDR compatible GPU. + // 2. The tensor's meta-data has changed. + Allocator* alloc = ProcessState::singleton()->GetCUDAHostAllocator(0); + copy = Tensor(alloc, in.dtype(), in.shape()); + CountCopies(rm_.name_, (void*)DMAHelper::base(&in), + (void*)DMAHelper::base(©), in.TotalBytes(), true); + GPUUtil::CopyGPUTensorToCPU( + src_dev_, send_dev_context, &in, ©, + [this, copy, proto, is_dead](const Status& s) { + Send(copy, proto, is_dead, s); + }); + } else { + GPUUtil::SetProtoFromGPU( + in, src_dev_, send_args.device_context, &proto, is_dead, + [this, in, proto, is_dead](const Status& s) mutable { + Send(in, proto, is_dead, s); + }); + } +#else + SendErrorStatus(errors::Internal("No GPU device in process")); +#endif // GOOGLE_CUDA + } else { + // tensor is in CPU memory. + if (!can_memcpy) { + in.AsProtoTensorContent(&proto); } - cb(Status::OK(), item->send_args, item->recv_args, item->in, item->is_dead); - delete (item); + Send(in, proto, is_dead, Status::OK()); + } +} + +void RdmaTensorResponse::Send(const Tensor& in, const TensorProto& proto, + bool is_dead, const Status& status) { + if (!status.ok()) { + SendErrorStatus(status); + return; + } + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + bool proto_size_changed = (!can_memcpy) && + (proto.ByteSize() != rm_.tensor_bytes_); + if (meta_data_changed_ || proto_size_changed) { + Clone(in, proto, is_dead); + SendMetaData(in, proto, is_dead); + } else { + SendContent(in, proto, is_dead); + } +} + +bool RdmaTensorResponse::TensorMetaDataChanged(const Tensor& in, bool is_dead) { + return (rm_.data_type_ != in.dtype()) || (rm_.tensor_shape_ != in.shape()) || + (rm_.is_dead_ != is_dead); +} + +void RdmaTensorResponse::Clone(const Tensor& in, const TensorProto& proto, + bool is_dead) { + // Clone the data to be sent later. For simplicity, we clone the tensor's + // data even if it is already a copy. Performance is less of a concern here + // since the meta-data hardly ever changes. The reason we create a copy, is + // that some tensors share their buffer between different step-ids, so the + // tensor content may change before re-request was completed. + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + if (can_memcpy && (in.TotalBytes() > 0)) { + AllocatorAttributes host_alloc_attrs; + host_alloc_attrs.set_nic_compatible(true); + host_alloc_attrs.set_on_host(true); + Allocator* allocator = src_dev_->GetAllocator(host_alloc_attrs); + tensor_ = new Tensor(allocator, in.dtype(), in.shape()); + memcpy(DMAHelper::base(tensor_), DMAHelper::base(&in), in.TotalBytes()); + } else { + tensor_ = new Tensor(in.dtype(), in.shape()); } + if (!can_memcpy) { + proto_ = new TensorProto(proto); + } + is_dead_ = is_dead; } -void RdmaTensorBuffer::PostCopyOperations( - bool can_memcpy, size_t buffer_size, size_t tensor_bytes, const string& key, - const Tensor& in, int64 step_id, bool is_dead, - const string& key_with_step_id, const Tensor* copy, - const TensorProto* proto, const StringPiece* copy_buf, - const Rendezvous::Args& send_args, const Rendezvous::Args& recv_args) { - // prepare message +void RdmaTensorResponse::SendMetaData(const Tensor& in, + const TensorProto& proto, bool is_dead) { + RDMA_LOG(2) << "Request #" << rm_.request_index_ + << ": Meta data changed: " << rm_.name_; + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + size_t tensor_bytes = (can_memcpy) ? in.TotalBytes() : proto.ByteSize(); + + // Send meta-data update: RdmaMessage rm; - rm.name_size_ = key.size(); - rm.name_ = key; + rm.type_ = RDMA_MESSAGE_META_DATA_UPDATE; + rm.name_size_ = rm_.name_.size(); + rm.name_ = rm_.name_; rm.tensor_shape_ = in.shape(); rm.data_type_ = in.dtype(); - rm.step_id_ = step_id; + rm.step_id_ = rm_.step_id_; rm.is_dead_ = is_dead; rm.tensor_bytes_ = tensor_bytes; - rm.buffer_size_ = buffer_size; - mu_.lock(); - if (local_status_ == none || (buffer_size > size_ && local_status_ == idle && - remote_status_ == idle)) { - if ((local_status_ != none) && (buffer_size > size_)) { - VLOG(2) << "Extend RDMA buffer from " << size_ << " to " << buffer_size; - } - CreateCPUBuffer(buffer_size, false); - // Need to be received again, put into the re-recv queue and the table - requeue.push(key_with_step_id); - ReItem* item = new ReItem(send_args, recv_args, in, is_dead); - retable.insert(std::pair(key_with_step_id, item)); - mu_.unlock(); - // no longer used: put back the key since it is not sent; - // ask the remote to create the same buffer - rm.type_ = RDMA_MESSAGE_BUFFER_REQUEST; - rm.remote_addr_ = reinterpret_cast(buffer_); - rm.rkey_ = self_->rkey; - string message = RdmaMessage::CreateMessage(rm); - channel_->tx_message_buffer_->EnqueueItem(message); - channel_->tx_message_buffer_->SendNextItem(); - } else if ((local_status_ == idle) && (remote_status_ == idle)) { - // both buffers are ready, send the tensor - local_status_ = busy; - remote_status_ = busy; - // local/remote_status_ won't be set back to idle - // unitl Write() is successful - mu_.unlock(); - if (!((buffer_size == size_ && rm.data_type_ != DT_STRING) || - (buffer_size <= size_ && rm.data_type_ == DT_STRING))) { - VLOG(2) << "Tensor and buffer size do not agree," - << " buffer_size = " << size_ - << " requested tensor size = " << buffer_size << in.DebugString(); - } - uint32_t imm_data = LookupBufferIndex(key); - rm.type_ = RDMA_MESSAGE_TENSOR_WRITE; - string message = RdmaMessage::CreateMessage(rm); - memcpy(buffer_, message.data(), message.size()); - if (!is_dead) { - // copy the tensor buffer content - void* output = static_cast(static_cast(buffer_) + - RdmaMessage::kTensorBufferStartIndex); - CHECK(tensor_bytes + RdmaMessage::kTensorBufferStartIndex <= size_); - if (can_memcpy) { - CHECK(copy != NULL) << "callback missing pointer to copy tensor"; - CHECK(copy_buf != NULL) << "callback missing pointer to copy buffer"; - CHECK(copy_buf->size() == tensor_bytes) - << "unexpected tensor size: " << copy_buf->size() - << " != " << tensor_bytes; - memcpy(output, copy_buf->data(), tensor_bytes); - } else { - CHECK(proto != NULL) << "callback missing pointer to proto tensor"; - proto->SerializeToArray(output, tensor_bytes); + rm.request_index_ = rm_.request_index_; +#ifdef RDMA_DATA_VALIDATION + rm.checksum_ = checksum_; +#endif + RDMA_LOG(1) << "Step 0x" << std::hex << rm.step_id_ << std::dec + << ": Sending RDMA_MESSAGE_META_DATA_UPDATE #" + << rm.request_index_ << ": " << rm.name_ + << " (shape = " << rm.tensor_shape_.DebugString() << "." + << " data-type = " << DataTypeString(rm.data_type_) << "." + << " is-dead = " << rm.is_dead_ << ")"; + + string message = RdmaMessage::CreateMessage(rm); + channel_->tx_message_buffer_->EnqueueItem(message); + channel_->tx_message_buffer_->SendNextItem(); +} + +void RdmaTensorResponse::SendContent(const Tensor& in, const TensorProto& proto, + bool is_dead) { + bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); + size_t tensor_bytes = (can_memcpy) ? in.TotalBytes() : proto.ByteSize(); + uint32_t imm_data = rm_.request_index_; + if (!is_dead) { + if (can_memcpy) { + src_buffer_ = const_cast(DMAHelper::buffer(&in)); + if (src_buffer_ != nullptr) { + src_buffer_->Ref(); // Keep buffer alive until write is complete + src_addr_ = src_buffer_->data(); + mr_ = RdmaMemoryMgr::Singleton().FindMemoryRegion(src_addr_, + tensor_bytes); } } else { - buffer_size = RdmaMessage::kMessageTotalBytes; + RDMA_LOG(2) << "Encoding proto: " << rm_.name_ + << " (Size: " << tensor_bytes << ") " << in.DebugString(); + src_addr_ = malloc(tensor_bytes); + mr_ = ibv_reg_mr(channel_->adapter_->pd_, src_addr_, tensor_bytes, + IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); + proto.SerializeToArray(src_addr_, tensor_bytes); } - Write(imm_data, buffer_size); } else { - // Need to be received again, put into the re-recv queue and the table - requeue.push(key_with_step_id); - ReItem* item = new ReItem(send_args, recv_args, in, is_dead); - retable.insert(std::pair(key_with_step_id, item)); - mu_.unlock(); + tensor_bytes = 0; } + + uint32_t lkey = (mr_ == nullptr) ? 0 : mr_->lkey; + RDMA_LOG(1) << "Step 0x" << std::hex << rm_.step_id_ << std::dec + << ": Sending tensor content #" << rm_.request_index_ << " from " + << std::hex << src_addr_ << " (0x" << lkey << ")" + << " to " << rm_.remote_addr_ << " (0x" << rm_.rkey_ + << "): " << rm_.name_ << " (size: 0x" << std::hex << tensor_bytes + << ")"; + + RdmaMessageBuffer::Write(channel_, imm_data, tensor_bytes, + (uint64_t)src_addr_, lkey, rm_.remote_addr_, + rm_.rkey_, RDMA_WRITE_ID_TENSOR_WRITE, this); +} + +void RdmaTensorResponse::SendErrorStatus(const Status& status) { + RdmaMessage rm; + rm.type_ = RDMA_MESSAGE_ERROR_STATUS; + rm.name_size_ = rm_.name_.size(); + rm.name_ = rm_.name_; + rm.step_id_ = rm_.step_id_; + rm.request_index_ = rm_.request_index_; + rm.status_ = status; + LOG(ERROR) << "Step 0x" << std::hex << rm.step_id_ << std::dec + << ": Sending RDMA_MESSAGE_ERROR_STATUS #" + << rm.request_index_ << ": " << rm.name_ + << ". Status: " << status.ToString(); + + string message = RdmaMessage::CreateMessage(rm); + channel_->tx_message_buffer_->EnqueueItem(message); + channel_->tx_message_buffer_->SendNextItem(); + + // Destroy the response. + Destroy(); +} + +void RdmaTensorResponse::Destroy() { + if (src_buffer_ != nullptr) { + src_buffer_->Unref(); + } + if (tensor_ != nullptr) { + delete tensor_; + } + if (proto_ != nullptr) { + ibv_dereg_mr(mr_); + free(src_addr_); + delete proto_; + } + // Remove response from the pending list: + channel_->RemoveTensorResponse(rm_.request_index_); } // Create a RdmaMessage according to the pre-defined format @@ -1276,43 +1273,46 @@ void RdmaTensorBuffer::PostCopyOperations( // message in string format string RdmaMessage::CreateMessage(const RdmaMessage& rm) { // Rdma Message format - // type|name_size|name|step_id|buffer_size|remote_addr|rkey|is_dead|... - // 1B| 2B | 512| 8B | 8B | 8B | 4B | 1B |... - // ...|data_type|tensor_shape|tensor_bytes|tensor_buffer - // ...| XB | XB | 8B |... + // type|name_size|name|step_id|request_index|remote_addr|rkey|is_dead|... + // 1B| 2B | 512| 8B | 8B | 8B | 4B | 1B |... + // ...|data_type|tensor_shape|tensor_bytes|error_status | + // ...| XB | XB | 8B |size - 4B, proto - XB | // - // ACK: type|13|"rx_ack_buffer" - // TENSOR_REQUEST: type|name_size|tensor_name|step_id - // TENSOR_WRITE: type|name_size|tensor_name|step_id|...|is_dead - // |data_type|tensor_shape|tensor_bytes - // BUFFER_IDLE: type|name_size|buffer_name - // BUFFER_REQUEST: - // type|name_size|buffer_name|...|buffer_size|remote_addr|rkey| - // BUFFER_RESPONSE: - // type|name_size|buffer_name|...|buffer_size|remote_addr|rkey| - char message[kMessageTotalBytes]; + // ACK: Imm-type: ACK + // TENSOR_REQUEST: Imm-type: MESSAGE + // Fields: type, request_index, name, step_id, remote_addr, + // rkey, is_dead, data_type, tensor_shape, tensor_bytes + // META_DATA_UPDATE: Imm-type: MESSAGE + // Fields: type, request_index, is_dead, data_type, + // tensor_shape, tensor_bytes + // TENSOR_RE_REQUST: Imm-type: MESSAGE + // Fields: type, request_index, name, step_id, remote_addr, + // rkey, is_dead, data_type, tensor_shape, tensor_bytes + // ERROR_STATUS: Imm-type: MESSAGE + // Fields: type, request_index, name, step_id, error_status + // Tensor content: Imm-type: request_index + size_t message_size = kMessageTotalBytes; + char message[kMessageTotalBytes + kErrorStatusMaxSize]; // type message[kTypeStartIndex] = static_cast(rm.type_) & 0xff; - // size of name - memcpy(&message[kNameSizeStartIndex], &rm.name_size_, sizeof(rm.name_size_)); - // name - memcpy(&message[kNameStartIndex], rm.name_.data(), rm.name_.size()); - // buffer_size, remote_addr, rkey - if ((rm.type_ == RDMA_MESSAGE_BUFFER_REQUEST) || - (rm.type_ == RDMA_MESSAGE_BUFFER_RESPONSE)) { - memcpy(&message[kBufferSizeStartIndex], &rm.buffer_size_, - sizeof(rm.buffer_size_)); + // request index + memcpy(&message[kRequestIndexStartIndex], &rm.request_index_, + sizeof(rm.request_index_)); + // name, step_id, remote_addr, rkey + if ((rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) || + (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST)) { + memcpy(&message[kNameSizeStartIndex], &rm.name_size_, + sizeof(rm.name_size_)); + memcpy(&message[kNameStartIndex], rm.name_.data(), rm.name_.size()); memcpy(&message[kRemoteAddrStartIndex], &rm.remote_addr_, sizeof(rm.remote_addr_)); memcpy(&message[kRkeyStartIndex], &rm.rkey_, sizeof(rm.rkey_)); - } - // step_id - if ((rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) || - (rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST)) { memcpy(&message[kStepIdStartIndex], &rm.step_id_, sizeof(rm.step_id_)); } // is_dead, data_type, tensor_shape, tensor_bytes - if (rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) { + if ((rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) || + (rm.type_ == RDMA_MESSAGE_META_DATA_UPDATE) || + (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST)) { memcpy(&message[kIsDeadStartIndex], &rm.is_dead_, sizeof(rm.is_dead_)); memcpy(&message[kDataTypeStartIndex], &rm.data_type_, @@ -1322,7 +1322,31 @@ string RdmaMessage::CreateMessage(const RdmaMessage& rm) { memcpy(&message[kTensorBytesStartIndex], &rm.tensor_bytes_, sizeof(rm.tensor_bytes_)); } - return string(message, kMessageTotalBytes); + // checksum +#ifdef RDMA_DATA_VALIDATION + memcpy(&message[kChecksumStartIndex], &rm.checksum_, sizeof(rm.checksum_)); +#endif + // error status + if (rm.type_ == RDMA_MESSAGE_ERROR_STATUS) { + ::grpc::Status gs = ToGrpcStatus(rm.status_); + ErrorStatusProto gsProto; + gsProto.set_error_code(gs.error_code()); + gsProto.set_error_message(gs.error_message()); + gsProto.set_error_details(gs.error_details()); + uint32_t gsProtoSize = gsProto.ByteSize(); + if (gsProtoSize + 4 > kErrorStatusMaxSize) { + LOG(ERROR) << "Error status (" << gsProtoSize + 4 << " bytes) " + << "is too big to fit in RDMA message (" + << kErrorStatusMaxSize << " bytes). Truncated."; + gsProtoSize = kErrorStatusMaxSize - 4; + } + uint32_t* proto_size = (uint32_t*)&message[kErrorStatusStartIndex]; + *proto_size = gsProtoSize; + gsProto.SerializeToArray(&message[kErrorStatusStartIndex + 4], + gsProtoSize); + message_size += gsProtoSize + 4; + } + return string(message, message_size); } // Parse a RdmaMessage according to the pre-defined format @@ -1335,26 +1359,24 @@ void RdmaMessage::ParseMessage(RdmaMessage& rm, void* buffer) { char* message = static_cast(buffer); // type rm.type_ = static_cast(message[kTypeStartIndex]); - // name_size_ - memcpy(&rm.name_size_, &message[kNameSizeStartIndex], sizeof(rm.name_size_)); - // name - rm.name_ = string(&message[kNameStartIndex], rm.name_size_); - // buffer_size, remote_addr, rkey - if ((rm.type_ == RDMA_MESSAGE_BUFFER_REQUEST) || - (rm.type_ == RDMA_MESSAGE_BUFFER_RESPONSE)) { - memcpy(&rm.buffer_size_, &message[kBufferSizeStartIndex], - sizeof(rm.buffer_size_)); + // request index + memcpy(&rm.request_index_, &message[kRequestIndexStartIndex], + sizeof(rm.request_index_)); + // name, step_id, remote_addr, rkey + if ((rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) || + (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST)) { + memcpy(&rm.name_size_, &message[kNameSizeStartIndex], + sizeof(rm.name_size_)); + rm.name_ = string(&message[kNameStartIndex], rm.name_size_); memcpy(&rm.remote_addr_, &message[kRemoteAddrStartIndex], sizeof(rm.remote_addr_)); memcpy(&rm.rkey_, &message[kRkeyStartIndex], sizeof(rm.rkey_)); - } - // step_id - if ((rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) || - (rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST)) { memcpy(&rm.step_id_, &message[kStepIdStartIndex], sizeof(rm.step_id_)); } // data_type, tensor_bytes, tensor_shape, is_dead - if (rm.type_ == RDMA_MESSAGE_TENSOR_WRITE) { + if ((rm.type_ == RDMA_MESSAGE_TENSOR_REQUEST) || + (rm.type_ == RDMA_MESSAGE_META_DATA_UPDATE) || + (rm.type_ == RDMA_MESSAGE_TENSOR_RE_REQUEST)) { memcpy(&rm.is_dead_, &message[kIsDeadStartIndex], sizeof(rm.is_dead_)); memcpy(&rm.data_type_, &message[kDataTypeStartIndex], sizeof(rm.data_type_)); @@ -1363,6 +1385,294 @@ void RdmaMessage::ParseMessage(RdmaMessage& rm, void* buffer) { memcpy(&rm.tensor_bytes_, &message[kTensorBytesStartIndex], sizeof(rm.tensor_bytes_)); } + // checksum +#ifdef RDMA_DATA_VALIDATION + memcpy(&rm.checksum_, &message[kChecksumStartIndex], sizeof(rm.checksum_)); +#endif + // error status + if (rm.type_ == RDMA_MESSAGE_ERROR_STATUS) { + ErrorStatusProto gsProto; + uint32_t gsProtoSize = *(uint32_t*)&message[kErrorStatusStartIndex]; + CHECK(ParseProtoUnlimited( + &gsProto, &message[kErrorStatusStartIndex + 4], gsProtoSize)) + << "Failed to parse error status proto from message. Aborting."; + ::grpc::Status gs((::grpc::StatusCode)gsProto.error_code(), + gsProto.error_message(), gsProto.error_details()); + rm.status_ = FromGrpcStatus(gs); + } +} + +//***************************************************************************** +// RdmaMemoryMgr +//***************************************************************************** + +ibv_mr* RdmaMemoryMgr::FindMemoryRegion(void* addr, size_t length) { + mutex_lock l(mrs_mu_); + auto iter = std::upper_bound(mrs_.begin(), mrs_.end(), addr, &Comparator); + if (iter == std::end(mrs_) || iter->get()->addr > addr) { + return nullptr; + } else { + return iter->get(); + } +} + +void RdmaMemoryMgr::InsertMemoryRegion(void* addr, size_t length, + const std::string& allocator_name) { + if (length == 0) return; + ibv_mr* mr = ibv_reg_mr(pd_, addr, length, + IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); + RDMA_LOG(1) << "Insert memory region 0x" << std::hex << mr->rkey << ". [" + << addr << "-" << (void*)((uint64_t)addr + length - 1) << "]" + << " SIZE: 0x" << length << " (" << allocator_name << ")."; + if (mr != nullptr) { + mutex_lock l(mrs_mu_); + auto iter = std::upper_bound(mrs_.begin(), mrs_.end(), addr, &Comparator); + mrs_.insert(iter, {mr, &MRDeleter}); + } else { + LOG(WARNING) << "Cannot register memory region"; + } +} + +void RdmaMemoryMgr::EvictMemoryRegion(void* addr, size_t length) { + if (length == 0) return; + mutex_lock l(mrs_mu_); + auto iter = std::upper_bound(mrs_.begin(), mrs_.end(), addr, &Comparator); + if (iter != std::end(mrs_) && iter->get()->addr == addr) { + mrs_.erase(iter); + RDMA_LOG(1) << "Evict memory region 0x" << std::hex << iter->get()->rkey; + + } else { + LOG(WARNING) << "Failed to de-register memory region"; + } +} + +const TensorMetaData* RdmaMemoryMgr::GetTensorMetaData( + const std::string& tensor_name) { + mutex_lock l(tensor_meta_data_mu_); + auto it = tensors_meta_data_.find(tensor_name); + if (it == tensors_meta_data_.end()) { + return nullptr; + } + return &it->second; +} + +const TensorMetaData* RdmaMemoryMgr::SetTensorMetaData( + const std::string& tensor_name, DataType dtype, const TensorShape& shape, + bool is_dead, size_t proto_size) { + mutex_lock l(tensor_meta_data_mu_); + TensorMetaData& meta_data = tensors_meta_data_[tensor_name]; + meta_data.data_type_ = dtype; + meta_data.tensor_shape_ = shape; + meta_data.proto_size_ = proto_size; + meta_data.is_dead_ = is_dead; + return &meta_data; +} + +//***************************************************************************** +// RdmaTensorRequest +//***************************************************************************** + +RdmaTensorRequest::RdmaTensorRequest( + uint32_t index, const string& key, int64 step_id, RdmaChannel* channel, + Device* dst_dev, const Rendezvous::Args recv_args, + const RdmaTensorRequest::RecvDoneCallback& done) + : index_(index), + key_(key), + step_id_(step_id), + channel_(channel), + dst_dev_(dst_dev), + recv_args_(recv_args), + meta_data_(RdmaMemoryMgr::Singleton().GetTensorMetaData(key)), + result_tensor_(nullptr), + proxy_tensor_(nullptr), + rdma_addr_(nullptr), + mr_(nullptr), + done_(done) {} + +RdmaTensorRequest::~RdmaTensorRequest() { DeallocateTensors(); } + +void RdmaTensorRequest::Done(const Status& s) { + Tensor val = std::move(*result_tensor_); + +#ifdef RDMA_DATA_VALIDATION + // Validate checksum + // Unfortunately we can't always do a Checksum directly on the result tensor. + // If the result tensor is on GPU, then we need to copy it back to CPU. If + // we happen to be in the midst of a proxy callback, then the copying will + // get stuck. + uint64_t checksum = (proxy_tensor_ != nullptr) + ? Checksum(nullptr, nullptr, *proxy_tensor_) + : Checksum(dst_dev_, recv_args_.device_context, val); + ValidateChecksum(checksum_, checksum, val, index_, key_, "RDMA"); +#endif + + Rendezvous::Args recv_args = std::move(recv_args_); + bool is_dead = (meta_data_ == nullptr) ? false : meta_data_->is_dead_; + RecvDoneCallback done = done_; + DeallocateTensors(); + channel_->RemoveTensorRequest(index_); + done(s, Rendezvous::Args(), recv_args, val, is_dead); +} + +void RdmaTensorRequest::DeallocateTensors() { + if (result_tensor_ != nullptr) { + delete result_tensor_; + result_tensor_ = nullptr; + } + if (proxy_tensor_ != nullptr) { + delete proxy_tensor_; + proxy_tensor_ = nullptr; + } +} + +bool RdmaTensorRequest::AllocateTensors() { + result_tensor_ = + new Tensor(dst_dev_->GetAllocator(recv_args_.alloc_attrs), + meta_data_->data_type_, meta_data_->tensor_shape_); + + size_t tensor_size = result_tensor_->TotalBytes(); + bool can_memcpy = DataTypeCanUseMemcpy(result_tensor_->dtype()); + if (can_memcpy) { + if (tensor_size == 0) { + return true; + } + rdma_addr_ = DMAHelper::base(result_tensor_); + mr_ = RdmaMemoryMgr::Singleton().FindMemoryRegion(rdma_addr_, tensor_size); +#if GOOGLE_CUDA + if (mr_ == nullptr) { + // Can't RDMA directly to result. Use a proxy. + proxy_tensor_ = + new Tensor(ProcessState::singleton()->GetCUDAHostAllocator(0), + result_tensor_->dtype(), result_tensor_->shape()); + rdma_addr_ = DMAHelper::base(proxy_tensor_); + mr_ = + RdmaMemoryMgr::Singleton().FindMemoryRegion(rdma_addr_, tensor_size); + } +#endif + } else { + uint32_t proto_size = meta_data_->proto_size_; + rdma_addr_ = malloc(proto_size); + mr_ = ibv_reg_mr(RdmaMemoryMgr::Singleton().pd_, rdma_addr_, proto_size, + IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); + } + CHECK(mr_ != nullptr) << " No memory region found for address " << rdma_addr_ + << ": " << key_; + return true; +} + +void RdmaTensorRequest::AllocateTensorsAsync(StatusCallback done) { + AllocateTensors(); + bool on_host = recv_args_.alloc_attrs.on_host(); + if (dst_dev_->tensorflow_gpu_device_info() && !on_host && + (proxy_tensor_ == nullptr)) { +#if GOOGLE_CUDA + // We need to sync the memory allocation on the GPU: + StreamGPUOp(dst_dev_, recv_args_.device_context, done); +#endif + } else { + done(Status::OK()); + } +} + +void RdmaTensorRequest::Send(RdmaMessageType message_type) { + RdmaMessageBuffer* rb = channel_->tx_message_buffer_; + RdmaMessage rm; + rm.type_ = message_type; + rm.request_index_ = index_; + rm.name_size_ = key_.size(); + rm.name_ = key_; + rm.step_id_ = step_id_; + rm.remote_addr_ = (uint64_t)rdma_addr_; + if (meta_data_ != nullptr) { + rm.data_type_ = meta_data_->data_type_; + rm.tensor_shape_ = meta_data_->tensor_shape_; + rm.is_dead_ = meta_data_->is_dead_; + rm.tensor_bytes_ = meta_data_->proto_size_; + } else { + rm.data_type_ = DT_INVALID; + } + rm.rkey_ = (mr_ == nullptr) ? 0 : mr_->rkey; + + RDMA_LOG(1) << "Step 0x" << std::hex << rm.step_id_ << std::dec + << ": Sending " << MessageTypeToString(message_type) + << " #" << index_ << ": " + << rm.name_ << " on " << rdma_addr_ + << " (rkey: 0x" << std::hex << rm.rkey_ << ")"; + + string message = RdmaMessage::CreateMessage(rm); + rb->EnqueueItem(message); + rb->SendNextItem(); +} + +void RdmaTensorRequest::RecvTensorMetaData(DataType dtype, TensorShape shape, + bool is_dead, size_t proto_size) { + meta_data_ = RdmaMemoryMgr::Singleton().SetTensorMetaData( + key_, dtype, shape, is_dead, proto_size); + + DeallocateTensors(); + AllocateTensorsAsync([this](const Status& s) { + Send(RDMA_MESSAGE_TENSOR_RE_REQUEST); + }); +} + +void RdmaTensorRequest::RecvTensorContent() { + bool can_memcpy = DataTypeCanUseMemcpy(meta_data_->data_type_); + size_t message_size = + can_memcpy ? result_tensor_->TotalBytes() : meta_data_->proto_size_; + RDMA_LOG(1) << "Step 0x" << std::hex << step_id_ << std::dec + << ": Received tensor content #" << index_ << ": " + << key_ << " (Size: 0x" << std::hex << message_size << ")"; + + Tensor val; + +#if GOOGLE_CUDA + if (proxy_tensor_ != nullptr) { + CountCopies(key_, (void*)DMAHelper::base(proxy_tensor_), + (void*)DMAHelper::base(result_tensor_), + result_tensor_->TotalBytes(), false); + GPUUtil::CopyCPUTensorToGPU(proxy_tensor_, recv_args_.device_context, + dst_dev_, result_tensor_, + [this](const Status& s) { + CHECK(s.ok()) << "copy tensor to gpu sync"; + Done(s); + }); + return; + } +#endif + + if (can_memcpy) { + Done(Status::OK()); + } else { + RDMA_LOG(2) << "Decoding proto: " << key_ + << " (Size: " << meta_data_->proto_size_ << ")"; + TensorProto proto; + CHECK(ParseProtoUnlimited(&proto, rdma_addr_, meta_data_->proto_size_)) + << "fail to parse proto from array"; + ibv_dereg_mr(mr_); + free(rdma_addr_); + Status s = dst_dev_->MakeTensorFromProto(proto, recv_args_.alloc_attrs, + result_tensor_); + Done(s); + } +} + +void RdmaTensorRequest::RecvErrorStatus(const Status& status) { + if (result_tensor_ == nullptr) { + result_tensor_ = new Tensor(); + } + LOG(ERROR) << "Received RDMA_MESSAGE_ERROR_STATUS: " << status.ToString(); + Done(status); +} + +void RdmaTensorRequest::Start() { + meta_data_ = RdmaMemoryMgr::Singleton().GetTensorMetaData(key_); + if (meta_data_ != nullptr) { + AllocateTensorsAsync([this](const Status& s) { + Send(RDMA_MESSAGE_TENSOR_REQUEST); + }); + } else { + Send(RDMA_MESSAGE_TENSOR_REQUEST); + } } } // end namespace tensorflow diff --git a/tensorflow/contrib/verbs/rdma.h b/tensorflow/contrib/verbs/rdma.h index fea2327d77..68b3d59f56 100644 --- a/tensorflow/contrib/verbs/rdma.h +++ b/tensorflow/contrib/verbs/rdma.h @@ -27,6 +27,7 @@ limitations under the License. #include #include +#include "tensorflow/contrib/verbs/verbs_util.h" #include "tensorflow/core/distributed_runtime/worker_env.h" #include "tensorflow/core/framework/rendezvous.h" #include "tensorflow/core/framework/tensor.h" @@ -43,6 +44,11 @@ namespace tensorflow { #define SL_DEFAULT 0 #define TRAFFIC_CLASS 0 +#define RDMA_LOG_0 LOG(INFO) +#define RDMA_LOG_1 VLOG(1) +#define RDMA_LOG_2 VLOG(2) +#define RDMA_LOG(LEVEL) RDMA_LOG_##LEVEL + struct RdmaParams { uint8_t port_num; uint8_t sgid_index; @@ -76,29 +82,303 @@ enum Location { local, remote }; -enum BufferType { - ACK, - MESSAGE, - TENSOR -}; + enum RdmaMessageType { - RDMA_MESSAGE_ACK, - RDMA_MESSAGE_BUFFER_IDLE, - RDMA_MESSAGE_BUFFER_REQUEST, - RDMA_MESSAGE_BUFFER_RESPONSE, + RDMA_MESSAGE_META_DATA_UPDATE, + RDMA_MESSAGE_TENSOR_RE_REQUEST, RDMA_MESSAGE_TENSOR_REQUEST, - RDMA_MESSAGE_TENSOR_WRITE + RDMA_MESSAGE_ERROR_STATUS, +}; + +struct RdmaMessage { + RdmaMessageType type_; + uint16_t name_size_; + string name_; + int64 step_id_; + uint64_t request_index_; + union { + uint64_t remote_addr_; +#ifdef RDMA_DATA_VALIDATION + uint64_t checksum_; +#endif + }; + uint32_t rkey_; + bool is_dead_; + DataType data_type_; + TensorShape tensor_shape_; + size_t tensor_bytes_; + + // For error status: + Status status_; + + // type|name_size|name|step_id|request_index|remote_addr/checksum|rkey|... + // 1B| 2B | 512| 8B | 8B | 8B | 4B |... + // ...|is_dead|data_type|tensor_shape|tensor_bytes|error_status | + // ...| 1B | XB | XB | 8B |size - 4B, proto - XB | + static const size_t kNameCapacity = 512; + static const size_t kTypeStartIndex = 0; + static const size_t kNameSizeStartIndex = kTypeStartIndex + sizeof(type_); + static const size_t kNameStartIndex = + kNameSizeStartIndex + sizeof(name_size_); + static const size_t kStepIdStartIndex = kNameStartIndex + kNameCapacity; + static const size_t kRequestIndexStartIndex = + kStepIdStartIndex + sizeof(step_id_); + static const size_t kRemoteAddrStartIndex = + kRequestIndexStartIndex + sizeof(request_index_); + static const size_t kChecksumStartIndex = kRemoteAddrStartIndex; + static const size_t kRkeyStartIndex = + kRemoteAddrStartIndex + sizeof(remote_addr_); + static const size_t kIsDeadStartIndex = kRkeyStartIndex + sizeof(rkey_); + static const size_t kDataTypeStartIndex = + kIsDeadStartIndex + sizeof(is_dead_); + static const size_t kTensorShapeStartIndex = + kDataTypeStartIndex + sizeof(data_type_); + static const size_t kTensorBytesStartIndex = + kTensorShapeStartIndex + sizeof(TensorShape); + static const size_t kErrorStatusStartIndex = + kTensorBytesStartIndex + sizeof(tensor_bytes_); + static const size_t kErrorStatusMaxSize = 4096; + + static const size_t kMessageTotalBytes = kErrorStatusStartIndex; + static const size_t kRdmaMessageBufferSize = + kMessageTotalBytes + kErrorStatusMaxSize; + static string CreateMessage(const RdmaMessage& rm); + static void ParseMessage(RdmaMessage& rm, void* buffer); +}; + +// Immediate types for RDMA write +enum RdmaImmDataType { + RDMA_IMM_MAX_REQUEST_ID = 0xFFFFFFFD, + RDMA_IMM_DATA_ACK = 0xFFFFFFFE, + RDMA_IMM_DATA_MESSAGE = 0xFFFFFFFF +}; + +// Write types for RDMA write-complete events +enum RdmaWriteIDType { + RDMA_WRITE_ID_ACK, + RDMA_WRITE_ID_MESSAGE, + RDMA_WRITE_ID_TENSOR_WRITE +}; + +// Context for RDMA write-complete events +class RdmaWriteID { + public: + RdmaWriteID(RdmaWriteIDType write_type, void* write_context) + : write_type(write_type), write_context(write_context) {} + + RdmaWriteIDType write_type; + void* write_context; +}; + +// Tensor meta-data +class TensorMetaData { + public: + TensorShape tensor_shape_; + DataType data_type_; + size_t proto_size_; + bool is_dead_; + + std::ostream& print(std::ostream& out) const { + out << "Dtype = " << DataTypeString(data_type_) + << ", Shape = " << tensor_shape_.DebugString() << ", Proto size = 0x" + << std::hex << proto_size_ << ", Is dead = " << is_dead_; + return out; + } +}; + +inline std::ostream& operator<<(std::ostream& out, + const TensorMetaData& meta_data) { + return meta_data.print(out); +} + +class RdmaChannel; + +void MRDeleter(ibv_mr* mr); +using MemoryRegionPtr = std::unique_ptr; + +// RdmaMemoryMgr +// Manages the local meta-data cache, and the registered RDMA memory regions. +class RdmaMemoryMgr { + public: + static RdmaMemoryMgr& Singleton() { + static RdmaMemoryMgr instance; + return instance; + } + + // Memory regions + ibv_mr* FindMemoryRegion(void* addr, size_t length); + void InsertMemoryRegion(void* addr, size_t length, + const std::string& allocator_name); + void EvictMemoryRegion(void* addr, size_t length); + + // Tensor meta-data cache + const TensorMetaData* GetTensorMetaData(const std::string& tensor_name); + const TensorMetaData* SetTensorMetaData(const std::string& tensor_name, + DataType dtype, + const TensorShape& shape, + bool is_dead, size_t proto_size); + + struct ibv_pd* pd_; + + protected: + RdmaMemoryMgr() : pd_(nullptr) {} + + static bool Comparator(const void* ptr, const MemoryRegionPtr& other) { + return ptr < reinterpret_cast(other->addr) + other->length; + } + + private: + mutex tensor_meta_data_mu_; + std::unordered_map tensors_meta_data_; + + // Managed memory regions + mutex mrs_mu_; + std::vector mrs_ GUARDED_BY(mrs_mu_); }; -class RdmaBuffer; + +// RdmaTensorRequest +// Represents a single tensor request. +class RdmaTensorRequest { + public: + typedef Rendezvous::DoneCallback RecvDoneCallback; + + // Creates a tensor request identified by index. + RdmaTensorRequest(uint32_t index, const string& key, int64 step_id, + RdmaChannel* channel, Device* dst_dev, + const Rendezvous::Args recv_args, + const RecvDoneCallback& done); + ~RdmaTensorRequest(); + + // Request unique index. + uint32_t index() { return index_; } + + // Start the tensor request sequence. + // + // 1. Allocate the result tensor (and proxy tensor if required). + // 2. Send RDMA_MESSAGE_TENSOR_REQUEST to the remote side. + void Start(); + + // Receive tensor meta-data. + // + // 1. Update the local meta-data cache. + // 2. Reallocate the result tensor (and proxy tensor if required). + // 3. Re-send the request to the remote side. + void RecvTensorMetaData(DataType dtype, TensorShape shape, bool is_dead, + size_t proto_size); + + // Receive tensor content (RDMA write was completed). + // + // Decode proto if required and/or move to GPU if the content was not + // written to it directly (GPU direct is not avaliable). Afterwards, + // invoke Done(). + void RecvTensorContent(); + + // Receive error status (in case of a remote error). + // Invoke Done() with the status code. + void RecvErrorStatus(const Status& status); + +#ifdef RDMA_DATA_VALIDATION + // Receive tensor checksum + // + // For validation: Get and store the Tensor's expected checksum for the + // current request. Compare the result Tensor's checksum with the stored + // checksum right before invoking Done(). + void RecvTensorChecksum(uint64_t checksum) { checksum_ = checksum; } +#endif + + private: + void Done(const Status& s); + void Send(RdmaMessageType message_type); + bool AllocateTensors(); + void AllocateTensorsAsync(StatusCallback done); + void DeallocateTensors(); + + uint32_t index_; + string key_; + int64 step_id_; + RdmaChannel* channel_; + Device* dst_dev_; + Rendezvous::Args recv_args_; + const TensorMetaData* meta_data_; + Tensor* result_tensor_; + Tensor* proxy_tensor_; + void* rdma_addr_; + ibv_mr* mr_; + RecvDoneCallback done_; +#ifdef RDMA_DATA_VALIDATION + uint64_t checksum_; +#endif +}; + +// RdmaTensorResponse +// Represents a single tensor response. +class RdmaTensorResponse { + public: + // Creates a response for request message. + RdmaTensorResponse(RdmaChannel* channel, const RdmaMessage& rm) + : channel_(channel), rm_(rm) {} + + void Update(const RdmaMessage& rm) { rm_ = rm; } + + // Start the tensor response sequence. + // + // 1. Find the tensor in the local tag-match table and invoke RecvHandler. + // (Using RecvLocalAsync()). + // 2. Compare the tensor's meta-data to the meta-data in the message (taken + // from the requester's local cache). + // If meta-data changed: + // a. Clone the tensor to be sent later. + // b. Send a meta-data update message and wait for re-request. + // Else: + // a. Send the tensor's content (using direct RDMA write). + void Start(); + + // Resume the response sequence, after a re-request. + // + // 1. Send the tensor's content that was cloned earlier. + void Resume(); + + // Destroy the response's resources and remove it from the pending list. + void Destroy(); + + private: + void RecvHandler(Rendezvous::ParsedKey parsed, + const Rendezvous::Args& send_args, + const Rendezvous::Args& recv_args, const Tensor& in, + bool is_dead); + void Clone(const Tensor& in, const TensorProto& proto, bool is_dead); + void Send(const Tensor& in, const TensorProto& proto, bool is_dead, + const Status& status); + bool TensorMetaDataChanged(const Tensor& in, bool is_dead); + Status PrepareRecvTensor(const Rendezvous::ParsedKey& parsed, + Device** src_dev); + void SendMetaData(const Tensor& in, const TensorProto& proto, bool is_dead); + void SendContent(const Tensor& in, const TensorProto& proto, bool is_dead); + void SendErrorStatus(const Status& status); + + RdmaChannel* channel_; + RdmaMessage rm_; // The request message + Device* src_dev_ = nullptr; + TensorBuffer* src_buffer_ = nullptr; + void* src_addr_ = nullptr; + ibv_mr* mr_ = nullptr; + uint64_t checksum_ = 0; + bool meta_data_changed_ = false; + + // Re-item: + TensorProto* proto_ = nullptr; + Tensor* tensor_ = nullptr; + bool is_dead_ = false; +}; + +class RdmaMessageBuffer; // Class that represents the Rdma Adapter. // Responsible for creation of the completion queue, and handling // of work completions. class RdmaAdapter { friend class RdmaChannel; - friend class RdmaBuffer; - friend class RdmaAckBuffer; friend class RdmaMessageBuffer; - friend class RdmaTensorBuffer; + friend class RdmaTensorResponse; friend class RdmaMgr; friend class RdmaRemoteRendezvous; @@ -133,10 +413,10 @@ class RdmaAdapter { // Responsible for connecting queue pairs. class RdmaChannel { friend class RdmaAdapter; - friend class RdmaBuffer; - friend class RdmaAckBuffer; friend class RdmaMessageBuffer; friend class RdmaTensorBuffer; + friend class RdmaTensorRequest; + friend class RdmaTensorResponse; friend class RdmaMgr; friend class RdmaRemoteRendezvous; @@ -146,22 +426,28 @@ class RdmaChannel { ~RdmaChannel(); inline const RdmaAddress& self() { return self_; } RdmaAddress address() const; - inline const std::vector& message_buffers() const { + inline const std::vector& message_buffers() const { return message_buffers_; } void Connect(const RdmaAddress& remoteAddr); void Connect(); void Recv(); - RdmaBuffer* FindBuffer(const uint32_t index); - RdmaBuffer* FindBuffer(const string& name); - RdmaBuffer* FindOrCreateBuffer(const string& name, - BufferType buffer_type = TENSOR); - uint32_t LookupBufferIndex(const string& buffer_name); void SetRemoteAddress(const RdmaAddress& ra, bool override); - void InsertRecvCallback(const string& key, std::function recv_done); - void RemoveRecvCallback(const string& key); - void RunRecvCallback(const string& key); - static const int kNumMessageBuffers = 4; + + // Requests: + RdmaTensorRequest* InsertTensorRequest( + const string& key, int64 step_id, Device* dst_dev, + const Rendezvous::Args recv_args, + const RdmaTensorRequest::RecvDoneCallback& done); + void RemoveTensorRequest(uint32_t request_index); + RdmaTensorRequest* GetTensorRequest(uint32_t request_index); + + // Responses: + RdmaTensorResponse* AddTensorResponse(const RdmaMessage& rm); + RdmaTensorResponse* UpdateTensorResponse(const RdmaMessage& rm); + void RemoveTensorResponse(uint32_t request_index); + + static const int kNumMessageBuffers = 2; static const int kPingRecvWrid = 0; private: @@ -179,36 +465,31 @@ class RdmaChannel { string remote_name_; ibv_qp* qp_; mutex mu_; - bool connected_ GUARDED_BY(bt_mu_) = false; - RdmaAddress remote_ GUARDED_BY(bt_mu_); - bool remote_set_ GUARDED_BY(bt_mu_) = false; + bool connected_ GUARDED_BY(mu_) = false; + RdmaAddress remote_ GUARDED_BY(mu_); + bool remote_set_ GUARDED_BY(mu_) = false; mutex ct_mu_; - typedef std::unordered_map > CallbackTable; - CallbackTable callback_table_ GUARDED_BY(ct_mu_); - mutex bt_mu_; - typedef std::unordered_map BufferTable; - BufferTable buffer_table_ GUARDED_BY(bt_mu_); - typedef std::unordered_map BufferIndexNameTable; - BufferIndexNameTable buffer_index_name_table_ GUARDED_BY(bt_mu_); - typedef std::unordered_map BufferNameIndexTable; - BufferNameIndexTable buffer_name_index_table_ GUARDED_BY(bt_mu_); - RdmaBuffer* tx_message_buffer_; - RdmaBuffer* rx_message_buffer_; - RdmaBuffer* tx_ack_buffer_; - RdmaBuffer* rx_ack_buffer_; - std::vector message_buffers_; + typedef std::unordered_map RequestTable; + RequestTable request_table_ GUARDED_BY(ct_mu_); + uint32_t request_serial_ GUARDED_BY(ct_mu_); + mutex responses_mu_; + typedef std::unordered_map ResponsesTable; + ResponsesTable responses_table_ GUARDED_BY(responses_mu_); + RdmaMessageBuffer* tx_message_buffer_; + RdmaMessageBuffer* rx_message_buffer_; + std::vector message_buffers_; }; -// Class that represents a buffer for Rdma writes and reads. -class RdmaBuffer { +// Class that represents a buffer for Rdma message sending. +class RdmaMessageBuffer { friend class RdmaChannel; friend class RdmaAdapter; friend class RdmaMgr; friend class RdmaRemoteRendezvous; public: - explicit RdmaBuffer(RdmaChannel* channel, string name); - virtual ~RdmaBuffer(); + explicit RdmaMessageBuffer(RdmaChannel* channel, string name); + ~RdmaMessageBuffer(); inline void* buffer() const { return buffer_; } inline ibv_mr* self() const { return self_; } @@ -223,13 +504,15 @@ class RdmaBuffer { } void FreeBuffer(); void EnqueueItem(string Item); - virtual void SendNextItem() {}; + void SendNextItem(); void CreateCPUBuffer(size_t size, bool lock = true); void SetRemoteMR(RemoteMR rmi, bool override); - uint32_t LookupBufferIndex(const string& buffer_name) { - return const_cast(channel_)->LookupBufferIndex(buffer_name); - } void Write(uint32_t imm_data, size_t buffer_size); + static void Write(const RdmaChannel* channel, uint32_t imm_data, + size_t buffer_size, uint64_t src_addr, uint32_t lkey, + uint64_t remote_addr, uint32_t rkey, + RdmaWriteIDType write_type, void* write_context); + static void SendAck(const RdmaChannel* channel); protected: const RdmaChannel* channel_; @@ -245,125 +528,6 @@ class RdmaBuffer { BufferStatus remote_status_ GUARDED_BY(mu_) = none; }; -class RdmaAckBuffer : public RdmaBuffer { - public: - explicit RdmaAckBuffer(RdmaChannel* channel, string name); - virtual ~RdmaAckBuffer() override {} - void SendNextItem() override; -}; - -class RdmaMessageBuffer : public RdmaBuffer { - friend class RdmaChannel; - friend class RdmaAapater; - - public: - explicit RdmaMessageBuffer(RdmaChannel* channel, string name); - virtual ~RdmaMessageBuffer() override {} - void SendNextItem() override; -}; - -class RdmaTensorBuffer : public RdmaBuffer { - public: - explicit RdmaTensorBuffer(RdmaChannel* channel, string name); - virtual ~RdmaTensorBuffer() override; - void SendNextItem() override; - void PostCopyOperations(bool can_memcpy, size_t buffer_size, - size_t tensor_bytes, const string& key, - const Tensor& in, int64 step_id, bool is_dead, - const string& key_with_step_id, const Tensor* copy, - const TensorProto* proto, const StringPiece* copy_buf, - const Rendezvous::Args& send_args, - const Rendezvous::Args& recv_args); - - void ReSendNextItem(); - - private: - Rendezvous::DoneCallback getRecvTensorCallback( - const string& key_with_step_id, const string& key, int64 step_id, - const Rendezvous::ParsedKey& parsed); - - struct ReItem { - Rendezvous::Args send_args; - Rendezvous::Args recv_args; - Tensor in; - bool is_dead; - - ReItem(const Rendezvous::Args& send_args_, - const Rendezvous::Args& recv_args_, const Tensor& in_, bool is_dead_) - : send_args(send_args_), - recv_args(recv_args_), - in(in_), - is_dead(is_dead_) { - if (send_args.device_context) { - send_args.device_context->Ref(); - } - if (recv_args.device_context) { - recv_args.device_context->Ref(); - } - } - - ~ReItem() { - if (send_args.device_context) { - send_args.device_context->Unref(); - } - if (recv_args.device_context) { - recv_args.device_context->Unref(); - } - } - }; - typedef std::map Table; - typedef Table::iterator Itable; - - std::queue requeue GUARDED_BY(mu_); - Table retable GUARDED_BY(mu_); -}; - -struct RdmaMessage { - RdmaMessageType type_; - uint16_t name_size_; - string name_; - int64 step_id_; - uint64_t buffer_size_; - uint64_t remote_addr_; - uint32_t rkey_; - bool is_dead_; - DataType data_type_; - TensorShape tensor_shape_; - size_t tensor_bytes_; - - // type|name_size|name|step_id|buffer_size|remote_addr|rkey|is_dead|... - // 1B| 2B | 512| 8B | 8B | 8B | 4B | 1B |... - // ...|data_type|tensor_shape|tensor_bytes|tensor_buffer - // ...| XB | XB | 8B |... - // - static const size_t kNameCapacity = 512; - static const size_t kTypeStartIndex = 0; - static const size_t kNameSizeStartIndex = kTypeStartIndex + sizeof(type_); - static const size_t kNameStartIndex = - kNameSizeStartIndex + sizeof(name_size_); - static const size_t kStepIdStartIndex = kNameStartIndex + kNameCapacity; - static const size_t kBufferSizeStartIndex = - kStepIdStartIndex + sizeof(step_id_); - static const size_t kRemoteAddrStartIndex = - kBufferSizeStartIndex + sizeof(buffer_size_); - static const size_t kRkeyStartIndex = - kRemoteAddrStartIndex + sizeof(remote_addr_); - static const size_t kIsDeadStartIndex = kRkeyStartIndex + sizeof(rkey_); - static const size_t kDataTypeStartIndex = - kIsDeadStartIndex + sizeof(is_dead_); - static const size_t kTensorShapeStartIndex = - kDataTypeStartIndex + sizeof(data_type_); - static const size_t kTensorBytesStartIndex = - kTensorShapeStartIndex + sizeof(TensorShape); - static const size_t kTensorBufferStartIndex = - kTensorBytesStartIndex + sizeof(tensor_bytes_); - static const size_t kMessageTotalBytes = kTensorBufferStartIndex; - static const size_t kRdmaMessageBufferSize = kMessageTotalBytes; - static const size_t kRdmaAckBufferSize = kMessageTotalBytes; - static string CreateMessage(const RdmaMessage& rm); - static void ParseMessage(RdmaMessage& rm, void* buffer); -}; - } // namespace tensorflow #endif // TENSORFLOW_USE_VERBS diff --git a/tensorflow/contrib/verbs/rdma_mgr.cc b/tensorflow/contrib/verbs/rdma_mgr.cc index 9cb307bcfa..f3644af0b4 100644 --- a/tensorflow/contrib/verbs/rdma_mgr.cc +++ b/tensorflow/contrib/verbs/rdma_mgr.cc @@ -16,11 +16,16 @@ limitations under the License. #ifdef TENSORFLOW_USE_VERBS #include "tensorflow/contrib/verbs/rdma_mgr.h" +#include #include #include "tensorflow/contrib/verbs/grpc_verbs_client.h" #include "tensorflow/contrib/verbs/verbs_service.pb.h" +#include "tensorflow/core/common_runtime/bfc_allocator.h" +#include "tensorflow/core/common_runtime/gpu/gpu_util.h" +#include "tensorflow/core/common_runtime/gpu/process_state.h" #include "tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.h" #include "tensorflow/core/distributed_runtime/session_mgr.h" +#include "tensorflow/core/framework/allocator_registry.h" #include "tensorflow/core/lib/core/status.h" namespace tensorflow { @@ -53,7 +58,7 @@ RdmaMgr::RdmaMgr(const WorkerEnv* const worker_env, void RdmaMgr::SetupChannels() { for (const auto& p : channel_table_) { string worker_name = p.first; - LOG(INFO) << "connecting to remote node " << worker_name; + RDMA_LOG(2) << "Connecting to remote node " << worker_name; RdmaChannel* rc = p.second; GetRemoteAddressRequest req; GetRemoteAddressResponse resp; @@ -78,39 +83,49 @@ void RdmaMgr::SetupChannels() { mr->set_rkey(rc->message_buffers_[i]->self_->rkey); } // synchronous call - Status s = client->GetRemoteAddress(&req, &resp); - // save obtained remote addresses - // connect to the remote channel - if (s.ok()) { - CHECK(worker_name.compare(resp.host_name()) == 0); - RdmaAddress ra; - ra.lid = resp.channel().lid(); - ra.qpn = resp.channel().qpn(); - ra.psn = resp.channel().psn(); - ra.snp = resp.channel().snp(); - ra.iid = resp.channel().iid(); - rc->SetRemoteAddress(ra, false); - rc->Connect(); - int i = 0; - int idx[] = {1, 0, 3, 2}; - for (const auto& mr : resp.mr()) { - // the connections are crossed, i.e. - // local tx_message_buffer <---> remote rx_message_buffer_ - // local rx_message_buffer <---> remote tx_message_buffer_ - // local tx_ack_buffer <---> remote rx_ack_buffer_ - // local rx_ack_buffer <---> remote tx_ack_buffer_ - // hence idx[] = {1, 0, 3, 2}. - RdmaBuffer* rb = rc->message_buffers_[idx[i]]; - RemoteMR rmr; - rmr.remote_addr = mr.remote_addr(); - rmr.rkey = mr.rkey(); - rb->SetRemoteMR(rmr, false); - i++; + Status s; + int attempts = 0; + static const int max_num_attempts = 5; + do { + s = client->GetRemoteAddress(&req, &resp); + // save obtained remote addresses + // connect to the remote channel + if (s.ok()) { + CHECK(worker_name.compare(resp.host_name()) == 0); + RdmaAddress ra; + ra.lid = resp.channel().lid(); + ra.qpn = resp.channel().qpn(); + ra.psn = resp.channel().psn(); + ra.snp = resp.channel().snp(); + ra.iid = resp.channel().iid(); + rc->SetRemoteAddress(ra, false); + rc->Connect(); + int i = 0; + int idx[] = {1, 0}; + for (const auto& mr : resp.mr()) { + // the connections are crossed, i.e. + // local tx_message_buffer <---> remote rx_message_buffer_ + // local rx_message_buffer <---> remote tx_message_buffer_ + // hence idx[] = {1, 0}. + RdmaMessageBuffer* rb = rc->message_buffers_[idx[i]]; + RemoteMR rmr; + rmr.remote_addr = mr.remote_addr(); + rmr.rkey = mr.rkey(); + rb->SetRemoteMR(rmr, false); + i++; + } + CHECK(i == RdmaChannel::kNumMessageBuffers); + } else { + LOG(ERROR) << "Connecting to " << worker_name + << ": Got " << s.error_message() << ". Retrying (" + << (attempts + 1) << "/" << max_num_attempts << ")..." ; + if (++attempts == max_num_attempts) { + break; + } + worker_env_->env->SleepForMicroseconds(2000000); } - CHECK(i == RdmaChannel::kNumMessageBuffers); - } else { - LOG(ERROR) << s.error_message(); - } + } while (!s.ok()); + RDMA_LOG(0) << "Connected to remote node " << worker_name; delete client; } } @@ -183,6 +198,138 @@ RdmaChannel* RdmaMgr::FindChannel(const string& name) { return iter->second; } +bool IsGDRAvailable() { +#if defined(__APPLE__) + return false; +#elif defined(PLATFORM_WINDOWS) + return false; +#else + std::ifstream ifs("/proc/modules"); + string line; + while (std::getline(ifs, line)) { + auto sep = line.find(' '); + CHECK_NE(sep, std::string::npos); + if (line.substr(0, sep) == "nv_peer_mem") { + return true; + } + } + return false; +#endif +} + +int TryToReadNumaNode(ibv_device* device) { +#if defined(__APPLE__) + LOG(INFO) << "OS X does not support NUMA - returning NUMA node 0"; + return 0; +#elif defined(PLATFORM_WINDOWS) + // Windows support for NUMA is not currently implemented. Return node 0. + return 0; +#else + VLOG(2) << "Trying to read NUMA node for device: " << device->name; + static const int kUnknownNumaNode = -1; + + auto filename = string(device->ibdev_path) + "/device/numa_node"; + + std::ifstream ifs(filename.c_str()); + string content; + CHECK(std::getline(ifs, content)); + + int32 value; + if (strings::safe_strto32(content, &value)) { + if (value < 0) { + LOG(INFO) << "Successful NUMA node read from SysFS had negative value (" + << value << "), but there must be at least one NUMA node" + ", so returning NUMA node zero"; + return 0; + } + LOG(INFO) << "NUMA node for device: " << device->name << " is " << value; + return value; + } + return kUnknownNumaNode; +#endif +} + +void MRDeleter(ibv_mr* mr) { + if (mr) { + ibv_dereg_mr(mr); + } +} + +// TODO(byronyi): remove this class duplicated from the one in +// common/runtime/gpu/pool_allocator.h when it is available in common_runtime +class BasicCPUAllocator : public SubAllocator { + public: + ~BasicCPUAllocator() override {} + + void* Alloc(size_t alignment, size_t num_bytes) override { + return port::AlignedMalloc(num_bytes, alignment); + } + void Free(void* ptr, size_t) override { port::AlignedFree(ptr); } +}; + +// TODO(byronyi): remove this class and its registration when the default +// cpu_allocator() returns visitable allocator +class BFCRdmaAllocator : public BFCAllocator { + public: + BFCRdmaAllocator() + : BFCAllocator(new BasicCPUAllocator(), 1LL << 36, true, "cpu_rdma_bfc") { + } +}; + +REGISTER_MEM_ALLOCATOR("BFCRdmaAllocator", 101, BFCRdmaAllocator); + +void RdmaMgr::InitAllocators() { + RdmaMemoryMgr::Singleton().pd_ = rdma_adapter_->pd_; + + Allocator* allocators[] = { +#if GOOGLE_CUDA + ProcessState::singleton()->GetCUDAHostAllocator(0), + ProcessState::singleton()->GetCPUAllocator(0), +#endif // GOOGLE_CUDA + cpu_allocator(), + }; + + using namespace std::placeholders; + + std::set instrumented_; + + // Host memory allocators + for (Allocator* allocator : allocators) { + VisitableAllocator::Visitor alloc_visitor = + std::bind(&RdmaMemoryMgr::InsertMemoryRegion, + &RdmaMemoryMgr::Singleton(), _1, _2, allocator->Name()); + VisitableAllocator::Visitor free_visitor = std::bind( + &RdmaMemoryMgr::EvictMemoryRegion, &RdmaMemoryMgr::Singleton(), _1, _2); + + auto* visitable_allocator = dynamic_cast(allocator); + CHECK(visitable_allocator) << "is not visitable for instrumentation" + << allocator->Name(); + // Make sure we don't instrument the same allocator twice + if (instrumented_.find(allocator) == std::end(instrumented_)) { + visitable_allocator->AddAllocVisitor(alloc_visitor); + visitable_allocator->AddFreeVisitor(free_visitor); + instrumented_.insert(allocator); + LOG(INFO) << "Instrumenting CPU allocator " << allocator->Name(); + } + } + +#if GOOGLE_CUDA + if (IsGDRAvailable()) { + // Note we don't free allocated GPU memory so there is no free visitor + int32_t bus_id = TryToReadNumaNode(rdma_adapter_->context_->device) + 1; + + char buf[8]; + sprintf(buf, "gpu"); + VisitableAllocator::Visitor cuda_alloc_visitor = + std::bind(&RdmaMemoryMgr::InsertMemoryRegion, + &RdmaMemoryMgr::Singleton(), _1, _2, std::string(buf)); + + ProcessState::singleton()->AddGPUAllocVisitor(bus_id, cuda_alloc_visitor); + LOG(INFO) << "Instrumenting GPU allocator with bus_id " << bus_id; + } +#endif // GOOGLE_CUDA +} + } // end namespace tensorflow #endif diff --git a/tensorflow/contrib/verbs/rdma_mgr.h b/tensorflow/contrib/verbs/rdma_mgr.h index e711e60478..29227a9544 100644 --- a/tensorflow/contrib/verbs/rdma_mgr.h +++ b/tensorflow/contrib/verbs/rdma_mgr.h @@ -38,6 +38,7 @@ class RdmaMgr { RdmaChannel* FindChannel(const string& key); void SetupChannels(); bool ConnectivityCheck(); + void InitAllocators(); const string& local_worker() { return local_worker_; } private: diff --git a/tensorflow/contrib/verbs/rdma_rendezvous_mgr.cc b/tensorflow/contrib/verbs/rdma_rendezvous_mgr.cc index 74f6681af3..ad3dce1784 100644 --- a/tensorflow/contrib/verbs/rdma_rendezvous_mgr.cc +++ b/tensorflow/contrib/verbs/rdma_rendezvous_mgr.cc @@ -21,10 +21,6 @@ limitations under the License. #include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/common_runtime/dma_helper.h" -#if GOOGLE_CUDA -#include "tensorflow/core/common_runtime/gpu/gpu_util.h" -#include "tensorflow/core/common_runtime/gpu/process_state.h" -#endif // GOOGLE_CUDA #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/strings/numbers.h" #include "tensorflow/core/lib/strings/str_util.h" @@ -36,11 +32,6 @@ class RdmaRemoteRendezvous : public BaseRemoteRendezvous { RdmaRemoteRendezvous(const WorkerEnv* env, int64 step_id, RdmaMgr* rdma_mgr) : BaseRemoteRendezvous(env, step_id), rdma_mgr_(rdma_mgr) {} - void RecvPostCopyOps(const string& key, const string& key_with_step_id, - const Rendezvous::Args& recv_args, - const DoneCallback& done, const RdmaMessage& rm, - RdmaChannel* rc, Tensor& val, const Status& s); - protected: void RecvFromRemoteAsync(const Rendezvous::ParsedKey& parsed, const Rendezvous::Args& args, @@ -74,101 +65,18 @@ void RdmaRemoteRendezvous::RecvFromRemoteAsync( RdmaChannel* rc = rdma_mgr_->FindChannel(src_name); string key(std::move(parsed.FullKey().ToString())); string key_with_step_id = VerbsUtil::AppendStepidToKey(key, step_id_); - // insert callback - rc->InsertRecvCallback(key_with_step_id, [this, key, key_with_step_id, rc, - recv_args, parsed, done]() { - Status src_s, dst_s, s; - Device* src_dev, *dst_dev; - src_s = env_->device_mgr->LookupDevice("CPU:0", &src_dev); - dst_s = env_->device_mgr->LookupDevice(parsed.dst_device, &dst_dev); - if (!src_s.ok() || !dst_s.ok()) { - s = src_s.ok() ? dst_s : src_s; - LOG(ERROR) << "s is not ok, error code " << s.error_message(); - done(s, Args(), recv_args, Tensor(), true); - return; - } - RdmaBuffer* rb = rc->FindBuffer(key); - RdmaMessage rm; - CHECK(rb->size_ >= RdmaMessage::kMessageTotalBytes); - RdmaMessage::ParseMessage(rm, rb->buffer_); - CHECK(rm.type_ == RDMA_MESSAGE_TENSOR_WRITE); - Tensor val; - if (!rm.is_dead_) { - void* input = static_cast(rb->buffer_) + - RdmaMessage::kTensorBufferStartIndex; - bool can_memcpy = DataTypeCanUseMemcpy(rm.data_type_); - if (can_memcpy) { - if (dst_dev->tensorflow_gpu_device_info() && - (!recv_args.alloc_attrs.on_host())) { -#if GOOGLE_CUDA - CHECK(recv_args.device_context) - << "send dev name: " << src_dev->name() - << " gpu_info: " << src_dev->tensorflow_gpu_device_info(); - Allocator* alloc = ProcessState::singleton()->GetCUDAHostAllocator(0); - Tensor copy(alloc, rm.data_type_, rm.tensor_shape_); - memcpy(DMAHelper::base(©), input, rm.tensor_bytes_); - - Allocator* dst_alloc = dst_dev->GetAllocator(recv_args.alloc_attrs); - Tensor gpu_copy(dst_alloc, rm.data_type_, rm.tensor_shape_); - - GPUUtil::CopyCPUTensorToGPU( - ©, recv_args.device_context, dst_dev, &gpu_copy, - [this, gpu_copy, key, key_with_step_id, recv_args, done, rm, rc]( - const Status& s) { - CHECK(s.ok()) << "copy tensor to gpu sync"; - Tensor val; - val = std::move(gpu_copy); - RecvPostCopyOps(key, key_with_step_id, recv_args, done, rm, rc, - val, s); - }); -#endif // GOOGLE_CUDA - return; - } else { - AllocatorAttributes host_alloc_attrs; - host_alloc_attrs.set_gpu_compatible(true); - host_alloc_attrs.set_on_host(true); - Allocator* alloc = dst_dev->GetAllocator(host_alloc_attrs); - Tensor copy(alloc, rm.data_type_, rm.tensor_shape_); - memcpy(DMAHelper::base(©), input, rm.tensor_bytes_); - val = std::move(copy); - } - } else { - TensorProto proto; - CHECK(rm.tensor_bytes_ + RdmaMessage::kTensorBufferStartIndex <= - rb->size_); - CHECK(ParseProtoUnlimited(&proto, input, rm.tensor_bytes_)) - << "fail to parse proto from array"; - s = dst_dev->MakeTensorFromProto(proto, recv_args.alloc_attrs, &val); - } - } - RecvPostCopyOps(key, key_with_step_id, recv_args, done, rm, rc, val, s); - }); - // append key to message queue - RdmaBuffer* rb = rc->tx_message_buffer_; - RdmaMessage rm; - rm.type_ = RDMA_MESSAGE_TENSOR_REQUEST; - rm.name_size_ = key.size(); - rm.name_ = key; - rm.step_id_ = step_id_; - string message = RdmaMessage::CreateMessage(rm); - rb->EnqueueItem(message); - rb->SendNextItem(); -} -void RdmaRemoteRendezvous::RecvPostCopyOps( - const string& key, const string& key_with_step_id, - const Rendezvous::Args& recv_args, const DoneCallback& done, - const RdmaMessage& rm, RdmaChannel* rc, Tensor& val, const Status& s) { - rc->RemoveRecvCallback(key_with_step_id); - RdmaMessage br; - br.type_ = RDMA_MESSAGE_BUFFER_IDLE; - br.name_size_ = key.size(); - br.name_ = key; - string message = RdmaMessage::CreateMessage(br); - RdmaBuffer* tb = rc->tx_message_buffer_; - tb->EnqueueItem(message); - tb->SendNextItem(); - done(s, Args(), recv_args, val, rm.is_dead_); + Device* dst_dev; + s = env_->device_mgr->LookupDevice(parsed.dst_device, &dst_dev); + CHECK(s.ok()) << "s is not ok, error code " << s.error_message(); + if (!s.ok()) { + done(s, Args(), recv_args, Tensor(), true); + return; + } + + RdmaTensorRequest* request = + rc->InsertTensorRequest(key, step_id_, dst_dev, recv_args, done); + request->Start(); } RdmaRendezvousMgr::RdmaRendezvousMgr(const WorkerEnv* env) diff --git a/tensorflow/contrib/verbs/verbs_server_lib.cc b/tensorflow/contrib/verbs/verbs_server_lib.cc index a606ef75a4..47ed83f521 100644 --- a/tensorflow/contrib/verbs/verbs_server_lib.cc +++ b/tensorflow/contrib/verbs/verbs_server_lib.cc @@ -104,6 +104,7 @@ Status VerbsServer::Start() { [this] { verbs_service_->HandleRPCsLoop(); })); rdma_mgr_->SetupChannels(); CHECK(rdma_mgr_->ConnectivityCheck()) << "Connectivity check failed!"; + rdma_mgr_->InitAllocators(); verbs_state_ = CONNECTED; } } diff --git a/tensorflow/contrib/verbs/verbs_service.proto b/tensorflow/contrib/verbs/verbs_service.proto index 0df1fed4b9..abdae1d84f 100644 --- a/tensorflow/contrib/verbs/verbs_service.proto +++ b/tensorflow/contrib/verbs/verbs_service.proto @@ -50,6 +50,12 @@ message GetRemoteAddressResponse { repeated MemoryRegion mr = 3; } +message ErrorStatusProto { + int32 error_code = 1; + string error_message = 2; + string error_details = 3; +} + //////////////////////////////////////////////////////////////////////////////// // // VerbsService diff --git a/tensorflow/contrib/verbs/verbs_with_0_copies.png b/tensorflow/contrib/verbs/verbs_with_0_copies.png new file mode 100644 index 0000000000000000000000000000000000000000..0641e2fd50da3738e3b8113f4324156063bf52a2 GIT binary patch literal 62862 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 \ No newline at end of file diff --git a/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.jpg b/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8bc69b889d68f0a6a8faa64f08eab22637646842 GIT binary patch literal 88799 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 z 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 literal 0 HcmV?d00001 diff --git a/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.xml b/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.xml new file mode 100644 index 0000000000..484e7c78ae --- /dev/null +++ b/tensorflow/contrib/verbs/verbs_with_0_copies_phase1_protocol.xml @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index fc49825748..94973a0e52 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -279,6 +279,7 @@ cc_library( "platform/platform.h", "platform/protobuf.h", "platform/types.h", + "platform/windows/cpu_info.h", "lib/bfloat16/bfloat16.h", ] + tf_additional_proto_hdrs() + glob(tf_env_time_hdrs()), copts = tf_copts(), @@ -865,6 +866,7 @@ cc_library( "//tensorflow/core/kernels:mkl_pooling_ops", "//tensorflow/core/kernels:mkl_relu_op", "//tensorflow/core/kernels:mkl_reshape_op", + "//tensorflow/core/kernels:mkl_softmax_op", "//tensorflow/core/kernels:mkl_tfconv_op", "//tensorflow/core/kernels:mkl_aggregate_ops", ]), @@ -2831,6 +2833,7 @@ tf_cc_test_mkl( "//tensorflow/core/kernels:mkl_pooling_ops", "//tensorflow/core/kernels:mkl_relu_op", "//tensorflow/core/kernels:mkl_reshape_op", + "//tensorflow/core/kernels:mkl_softmax_op", "//tensorflow/core/kernels:mkl_tfconv_op", ]), ) diff --git a/tensorflow/core/framework/types.h b/tensorflow/core/framework/types.h index cb8e77f1df..ded6aa0991 100644 --- a/tensorflow/core/framework/types.h +++ b/tensorflow/core/framework/types.h @@ -453,6 +453,13 @@ inline bool DataTypeIsInteger(DataType dt) { return kDataTypeIsInteger.Contains(dt); } +// Is the dtype a signed integral type? +constexpr DataTypeSet kDataTypeIsSigned = + ToSet(DT_INT8) | ToSet(DT_INT16) | ToSet(DT_INT32) | ToSet(DT_INT64); +inline bool DataTypeIsSigned(DataType dt) { + return kDataTypeIsSigned.Contains(dt); +} + // Is the dtype an unsigned integral type? constexpr DataTypeSet kDataTypeIsUnsigned = ToSet(DT_UINT8) | ToSet(DT_UINT16) | ToSet(DT_UINT32) | ToSet(DT_UINT64); diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 89b23f22fd..55bc401b9d 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2456,9 +2456,9 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // NOTE: names are alphabetically sorted. rinfo_.push_back({csinfo_.addn, mkl_op_registry::GetMklOpName(csinfo_.addn), CopyAttrsAddN, AddNRewrite}); - rinfo_.push_back({csinfo_.add, + /* rinfo_.push_back({csinfo_.add, mkl_op_registry::GetMklOpName(csinfo_.add), - CopyAttrsDataType, AlwaysRewrite}); + CopyAttrsDataType, AlwaysRewrite}); */ rinfo_.push_back({csinfo_.avg_pool, mkl_op_registry::GetMklOpName(csinfo_.avg_pool), CopyAttrsPooling, AlwaysRewrite}); @@ -3117,7 +3117,9 @@ void MklLayoutRewritePass::GetDummyMklTensorNode(std::unique_ptr* g, Node* orig_input0 = nullptr; TF_CHECK_OK(orig_node->input_node(0, const_cast(&orig_input0))); - CHECK_NOTNULL((*g)->AddControlEdge(orig_input0, *out)); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(orig_input0, *out, true)); } (*out)->set_assigned_device_name(orig_node->assigned_device_name()); @@ -3382,8 +3384,8 @@ void MklLayoutRewritePass::GetDummyWorkspaceTensorNode( std::unique_ptr* g, Node** out, Node* orig_node) { // We use a tensor of shape {1} and value 0 to represent // dummy float tensor. We need this as a dummy workspace tensor. - // Workspace tensor has type float. - const DataType dt = DataTypeToEnum::v(); + // Workspace tensor has type uint8. + const DataType dt = DataTypeToEnum::v(); TensorProto proto; proto.set_dtype(dt); float zero[1] = {0}; @@ -3413,7 +3415,9 @@ void MklLayoutRewritePass::GetDummyWorkspaceTensorNode( Node* orig_input0 = nullptr; TF_CHECK_OK(orig_node->input_node(0, const_cast(&orig_input0))); - CHECK_NOTNULL((*g)->AddControlEdge(orig_input0, *out)); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(orig_input0, *out, true)); } (*out)->set_assigned_device_name(orig_node->assigned_device_name()); @@ -3863,12 +3867,16 @@ Status MklLayoutRewritePass::MergeConv2DWithBiasAdd(std::unique_ptr* g, // node are already copied in BuildNode. We handle control edges now. for (const Edge* e : pred->in_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node)); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node, true)); } } for (const Edge* e : succ->in_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node)); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node, true)); } } @@ -3876,14 +3884,18 @@ Status MklLayoutRewritePass::MergeConv2DWithBiasAdd(std::unique_ptr* g, // First, we will fix outgoing control edges from 'pred' node. for (const Edge* e : pred->out_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst())); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst(), true)); } } // Second, we will fix outgoing control and data edges from 'succ' node. for (const Edge* e : succ->out_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst())); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst(), true)); } else { // BiasAdd has only 1 output (at slot 0) and merged node also has only 1 // output (at slot 0). @@ -3966,12 +3978,16 @@ Status MklLayoutRewritePass::MergeConv2DBackpropFilterWithBiasAddGrad( // edges now. for (const Edge* e : badd->in_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node)); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node, true)); } } for (const Edge* e : fltr->in_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node)); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node, true)); } } @@ -3987,7 +4003,9 @@ Status MklLayoutRewritePass::MergeConv2DBackpropFilterWithBiasAddGrad( for (const Edge* e : badd->out_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst())); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst(), true)); } else { CHECK_NOTNULL((*g)->AddEdge(new_node, kMergedNodeBiasGradOutputIdx, e->dst(), e->dst_input())); @@ -3997,7 +4015,11 @@ Status MklLayoutRewritePass::MergeConv2DBackpropFilterWithBiasAddGrad( // Second, we will fix outgoing control and data edges from 'fltr' node. for (const Edge* e : fltr->out_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst())); + // We allow duplicate edge for this case since we already add control + // edge from new_node in line 3990. Line below could be adding same + // edge to same destination again. In such case, if we do not allow + // duplicate edge, then this call will fail. + CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst(), true)); } else { CHECK_NOTNULL((*g)->AddEdge(new_node, kMergedNodeFilterGradOutputIdx, e->dst(), e->dst_input())); @@ -4091,7 +4113,9 @@ Status MklLayoutRewritePass::RewriteNode(std::unique_ptr* g, // already copied in BuildNode. We need to handle control edges now. for (const Edge* e : orig_node->in_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node)); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(e->src(), new_node, true)); } } @@ -4104,7 +4128,9 @@ Status MklLayoutRewritePass::RewriteNode(std::unique_ptr* g, // GetTensorDataIndex provides this mapping function. for (const Edge* e : orig_node->out_edges()) { if (e->IsControlEdge()) { - CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst())); + // Allow duplicate while adding control edge as it would fail (return + // NULL) if we try to add duplicate edge. + CHECK_NOTNULL((*g)->AddControlEdge(new_node, e->dst(), true)); } else { CHECK_NOTNULL((*g)->AddEdge(new_node, GetTensorDataIndex(e->src_output(), e->src()->num_outputs()), diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD index 96f0feaf3d..fd99409c9b 100644 --- a/tensorflow/core/kernels/BUILD +++ b/tensorflow/core/kernels/BUILD @@ -5846,6 +5846,23 @@ tf_mkl_kernel_library( ]), ) +tf_mkl_kernel_library( + name = "mkl_softmax_op", + prefix = "mkl_softmax", + deps = [ + ":bounds_check", + ":ops_util", + "//tensorflow/core:core_cpu", + "//tensorflow/core:framework", + "//tensorflow/core:lib", + "//tensorflow/core:lib_internal", + "//tensorflow/core:nn_ops_op_lib", + ] + if_mkl([ + "//third_party/mkl:intel_binary_blob", + "@mkl_dnn//:mkl_dnn", + ]), +) + tf_mkl_kernel_library( name = "mkl_fused_batch_norm_op", srcs = ["mkl_fused_batch_norm_op.cc"], diff --git a/tensorflow/core/kernels/cuda_solvers.h b/tensorflow/core/kernels/cuda_solvers.h index 3c389a82ab..ecfa23750c 100644 --- a/tensorflow/core/kernels/cuda_solvers.h +++ b/tensorflow/core/kernels/cuda_solvers.h @@ -427,7 +427,7 @@ inline DeviceLapackInfo CudaSolver::GetDeviceLapackInfo( int64 size, const string& debug_info) { DeviceLapackInfo new_dev_info(context_, size, debug_info); scratch_tensor_refs_.emplace_back(new_dev_info.tensor()); - return std::move(new_dev_info); + return new_dev_info; } } // namespace tensorflow diff --git a/tensorflow/core/kernels/cwise_op_pow.cc b/tensorflow/core/kernels/cwise_op_pow.cc index 5fb0735ac1..cf86478b0f 100644 --- a/tensorflow/core/kernels/cwise_op_pow.cc +++ b/tensorflow/core/kernels/cwise_op_pow.cc @@ -16,8 +16,9 @@ limitations under the License. #include "tensorflow/core/kernels/cwise_ops_common.h" namespace tensorflow { -REGISTER7(BinaryOp, CPU, "Pow", functor::pow, float, Eigen::half, double, int32, - int64, complex64, complex128); +REGISTER5(BinaryOp, CPU, "Pow", functor::pow, float, Eigen::half, double, + complex64, complex128); +REGISTER2(BinaryOp, CPU, "Pow", functor::safe_pow, int32, int64); #if GOOGLE_CUDA REGISTER4(BinaryOp, GPU, "Pow", functor::pow, float, Eigen::half, double, @@ -25,5 +26,5 @@ REGISTER4(BinaryOp, GPU, "Pow", functor::pow, float, Eigen::half, double, #endif #ifdef TENSORFLOW_USE_SYCL REGISTER2(BinaryOp, SYCL, "Pow", functor::pow, float, double); -#endif // TENSORFLOW_USE_SYCL +#endif // TENSORFLOW_USE_SYCL } // namespace tensorflow diff --git a/tensorflow/core/kernels/cwise_ops.h b/tensorflow/core/kernels/cwise_ops.h index da70b1e314..06918075a4 100644 --- a/tensorflow/core/kernels/cwise_ops.h +++ b/tensorflow/core/kernels/cwise_ops.h @@ -21,6 +21,7 @@ limitations under the License. #include #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" + #include "tensorflow/core/framework/numeric_types.h" #include "tensorflow/core/framework/tensor_types.h" #include "tensorflow/core/kernels/bounds_check.h" @@ -115,6 +116,35 @@ struct functor_traits> { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; +template +struct safe_scalar_binary_pow_op { + static_assert(std::is_integral::value, "Integer type expected"); + static_assert(std::is_integral::value && + std::is_signed::value, + "Signed integer type expected"); + + bool* const error; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE safe_scalar_binary_pow_op(bool* error) + : error(error) {} + + EIGEN_DEVICE_FUNC inline Scalar operator()(const Scalar& a, + const Exponent& b) const { + const Exponent safe_b = tensorflow::internal::SubtleMustCopy(b); + if (TF_PREDICT_TRUE(safe_b >= 0)) { + return numext::pow(a, safe_b); + } else { + *error = true; + return 0; + } + } +}; + +template +struct functor_traits> { + enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; +}; + template struct safe_div_or_mod_op { static_assert(std::is_integral::value, "Integer type expected"); @@ -741,6 +771,11 @@ struct floor_div_real : base> {}; template struct pow : base> {}; +template +struct safe_pow : base> { + static const bool has_errors = true; +}; + template struct maximum : base> {}; diff --git a/tensorflow/core/kernels/cwise_ops_common.cc b/tensorflow/core/kernels/cwise_ops_common.cc index 693c6467ac..e561e59cf5 100644 --- a/tensorflow/core/kernels/cwise_ops_common.cc +++ b/tensorflow/core/kernels/cwise_ops_common.cc @@ -40,6 +40,11 @@ void BinaryOpShared::SetComputeError(OpKernelContext* ctx) { if ((op == "Div" || op == "Mod" || op == "FloorMod" || op == "FloorDiv") && DataTypeIsInteger(ctx->op_kernel().input_type(0))) { ctx->CtxFailure(errors::InvalidArgument("Integer division by zero")); + } else if ((op == "Pow") && + DataTypeIsInteger(ctx->op_kernel().input_type(0)) && + DataTypeIsSigned(ctx->op_kernel().input_type(1))) { + ctx->CtxFailure(errors::InvalidArgument( + "Integers to negative integer powers are not allowed")); } else { ctx->CtxFailure( errors::Internal("Unexpected error in binary operator " diff --git a/tensorflow/core/kernels/decode_image_op.cc b/tensorflow/core/kernels/decode_image_op.cc index ceb152c3f0..44dcbf834c 100644 --- a/tensorflow/core/kernels/decode_image_op.cc +++ b/tensorflow/core/kernels/decode_image_op.cc @@ -87,11 +87,10 @@ class DecodeImageOp : public OpKernel { channels_ = 3; } else { OP_REQUIRES_OK(context, context->GetAttr("channels", &channels_)); - OP_REQUIRES( - context, - channels_ == 0 || channels_ == 1 || channels_ == 3 || channels_ == 4, - errors::InvalidArgument("channels must be 0, 1, 3, or 4, got ", - channels_)); + OP_REQUIRES(context, channels_ == 0 || channels_ == 1 || channels_ == 3 || + channels_ == 4, + errors::InvalidArgument( + "channels must be 0, 1, 3, or 4, got ", channels_)); } flags_.components = channels_; @@ -115,9 +114,8 @@ class DecodeImageOp : public OpKernel { if (format_ == kJpgFormat) { OP_REQUIRES_OK(context, context->GetAttr("ratio", &flags_.ratio)); - OP_REQUIRES(context, - flags_.ratio == 1 || flags_.ratio == 2 || flags_.ratio == 4 || - flags_.ratio == 8, + OP_REQUIRES(context, flags_.ratio == 1 || flags_.ratio == 2 || + flags_.ratio == 4 || flags_.ratio == 8, errors::InvalidArgument("ratio must be 1, 2, 4, or 8, got ", flags_.ratio)); OP_REQUIRES_OK(context, context->GetAttr("fancy_upscaling", @@ -132,9 +130,8 @@ class DecodeImageOp : public OpKernel { string dct_method; OP_REQUIRES_OK(context, context->GetAttr("dct_method", &dct_method)); OP_REQUIRES( - context, - (dct_method.empty() || dct_method == "INTEGER_FAST" || - dct_method == "INTEGER_ACCURATE"), + context, (dct_method.empty() || dct_method == "INTEGER_FAST" || + dct_method == "INTEGER_ACCURATE"), errors::InvalidArgument("dct_method must be one of " "{'', 'INTEGER_FAST', 'INTEGER_ACCURATE'}")); if (dct_method == "INTEGER_FAST") { @@ -160,9 +157,9 @@ class DecodeImageOp : public OpKernel { errors::InvalidArgument("Expected image (JPEG, PNG, or GIF), got ", FileFormatString(magic, input))); OP_REQUIRES(context, input.size() <= std::numeric_limits::max(), - errors::InvalidArgument( - FileFormatString(magic, input), - " contents are too large for int: ", input.size())); + errors::InvalidArgument(FileFormatString(magic, input), + " contents are too large for int: ", + input.size())); OP_REQUIRES(context, magic == kPngFormat || channel_bits_ == 8, errors::InvalidArgument(FileFormatString(magic, input), " does not support uint16 output")); @@ -215,10 +212,9 @@ class DecodeImageOp : public OpKernel { input.data(), input.size(), flags, nullptr /* nwarn */, [=, &output](int width, int height, int channels) -> uint8* { Status status(context->allocate_output( - 0, - format_ == kGifFormat - ? TensorShape({1, height, width, channels}) - : TensorShape({height, width, channels}), + 0, format_ == kGifFormat + ? TensorShape({1, height, width, channels}) + : TensorShape({height, width, channels}), &output)); if (!status.ok()) { VLOG(1) << status; @@ -294,6 +290,7 @@ class DecodeImageOp : public OpKernel { // Decode GIF, allocating tensor once the size is known. Tensor* output = nullptr; + string error_string; OP_REQUIRES( context, gif::Decode(input.data(), input.size(), @@ -320,8 +317,10 @@ class DecodeImageOp : public OpKernel { return nullptr; } return output->flat().data(); - }), - errors::InvalidArgument("Invalid GIF data, size ", input.size())); + }, + &error_string), + errors::InvalidArgument("Invalid GIF data (size ", input.size(), "), ", + error_string)); } private: diff --git a/tensorflow/core/kernels/matmul_op.cc b/tensorflow/core/kernels/matmul_op.cc index b3acb91202..cb68690f28 100644 --- a/tensorflow/core/kernels/matmul_op.cc +++ b/tensorflow/core/kernels/matmul_op.cc @@ -539,6 +539,7 @@ struct MatMulFunctor { REGISTER_KERNEL_BUILDER( \ Name("MatMul").Device(DEVICE_CPU).TypeConstraint("T").Label("eigen"), \ MatMulOp); + #define REGISTER_CPU(T) \ REGISTER_KERNEL_BUILDER( \ Name("MatMul").Device(DEVICE_CPU).TypeConstraint("T"), \ diff --git a/tensorflow/core/kernels/mkl_aggregate_ops.cc b/tensorflow/core/kernels/mkl_aggregate_ops.cc index 44b94be3a0..bb5eceab27 100644 --- a/tensorflow/core/kernels/mkl_aggregate_ops.cc +++ b/tensorflow/core/kernels/mkl_aggregate_ops.cc @@ -61,6 +61,18 @@ class MklAddNOp : public OpKernel { GetMklShape(ctx, src2_idx, &(mkl_context.input2_shape)); bool input2_in_mkl_format = mkl_context.input2_shape.IsMklTensor(); + // if the shapes of two tensors are not same raise op error + TensorShape src1_shape, src2_shape; + src1_shape = input0.shape(); + src2_shape = input1.shape(); + if (!src1_shape.IsSameSize(src2_shape) ){ + ctx->SetStatus( + errors::InvalidArgument( + "Inputs to operation ", this->name(), " of type ", this->type_string(), + " must have the same size and shape. Input 0: ", + src1_shape.DebugString(), " != input 1: ", + src2_shape.DebugString())); + } // handle the case of a scalar if (!input1_in_mkl_format && input0.dims() == 0) { const TensorShape& o_shape = input0.shape(); @@ -307,6 +319,18 @@ class MklAddNOp : public OpKernel { src1_mkl_shape.GetDimension(): src1_tensor.dims(); int src2_dims_size = input2_in_mkl_format? src2_mkl_shape.GetDimension(): src2_tensor.dims(); + // if the shapes of two tensors are not same raise op error + TensorShape src1_shape, src2_shape; + src1_shape = src1_tensor.shape(); + src2_shape = src2_tensor.shape(); + if (!src1_shape.IsSameSize(src2_shape) ){ + ctx->SetStatus( + errors::InvalidArgument( + "Inputs to operation ", this->name(), " of type ", this->type_string(), + " must have the same size and shape. Input 0: ", + src1_shape.DebugString(), " != input 1: ", + src2_shape.DebugString())); + } if (!input1_in_mkl_format && src1_dims_size == 0) { Tensor* dst_tensor = nullptr; diff --git a/tensorflow/core/kernels/mkl_concat_op.cc b/tensorflow/core/kernels/mkl_concat_op.cc index 82771792d7..d109bb6bcf 100644 --- a/tensorflow/core/kernels/mkl_concat_op.cc +++ b/tensorflow/core/kernels/mkl_concat_op.cc @@ -598,7 +598,6 @@ class MklConcatOp : public OpKernel { concat_dim_tensor.shape().DebugString())); int32 concat_dim = internal::SubtleMustCopy( concat_dim_tensor.scalar()()); - if (concat_dim < 0) concat_dim = N + concat_dim; // check that ranks of all tensors match // and that their shapes match except for concat_dim. @@ -609,6 +608,9 @@ class MklConcatOp : public OpKernel { input_shapes[0].GetTfShape() : input_tensors[0].shape(); size_t expected_dims = expected_shape.dims(); + + if (concat_dim < 0) concat_dim = expected_dims + concat_dim; + for (auto& s : input_shapes) { if (s == expected_shape) {++i; continue;} diff --git a/tensorflow/core/kernels/mkl_conv_grad_filter_ops.cc b/tensorflow/core/kernels/mkl_conv_grad_filter_ops.cc index 793fa24d99..54d4916d49 100644 --- a/tensorflow/core/kernels/mkl_conv_grad_filter_ops.cc +++ b/tensorflow/core/kernels/mkl_conv_grad_filter_ops.cc @@ -467,6 +467,13 @@ class MklConv2DCustomBackpropFilterOp : return filter_tf_shape; } + TensorShape GetOutputTfShape(const TensorShape& input_shape, + const TensorShape& filter_shape, + const TensorShape& outbprop_shape) { + // Shape of output of Conv2DBackpropFilter is same as shape of filter. + return filter_shape; + } + const memory::dims& GetOutputDims(const memory::dims& fwd_input_dims, const memory::dims& fwd_filter_dims) { // Shape of output of Conv2DBackpropFilter is same as shape of filter. diff --git a/tensorflow/core/kernels/mkl_conv_grad_input_ops.cc b/tensorflow/core/kernels/mkl_conv_grad_input_ops.cc index db9e97e7ca..ef6db58d31 100644 --- a/tensorflow/core/kernels/mkl_conv_grad_input_ops.cc +++ b/tensorflow/core/kernels/mkl_conv_grad_input_ops.cc @@ -396,6 +396,13 @@ class MklConv2DCustomBackpropInputOp : return GetTfShape(context, kInputIndex_Filter); } + TensorShape GetOutputTfShape(const TensorShape& input_shape, + const TensorShape& filter_shape, + const TensorShape& outbprop_shape) { + // Output Shape of Conv2DBackpropInput is same as shape of Conv2D 'input'. + return input_shape; + } + const memory::dims& GetOutputDims(const memory::dims& fwd_input_dims, const memory::dims& fwd_filter_dims) { // Output Shape of Conv2DBackpropInput is same as shape of Conv2D 'input'. diff --git a/tensorflow/core/kernels/mkl_conv_ops.cc b/tensorflow/core/kernels/mkl_conv_ops.cc index a4e139bb54..0e77b45993 100644 --- a/tensorflow/core/kernels/mkl_conv_ops.cc +++ b/tensorflow/core/kernels/mkl_conv_ops.cc @@ -551,6 +551,13 @@ class MklConv2DOp : public OpKernel { output_mkl_shape.SetMklTensor(false); AllocateOutputSetMklShape(context, kOutputIndex_Dst, &output_tensor, src_tf_shape, output_mkl_shape); + + // MklConv2D also outputs converted filter as 2nd output of Conv2D. + filter_mkl_shape.SetMklTensor(false); + Tensor* output_filter_tensor = nullptr; + AllocateOutputSetMklShape(context, kOutputIndex_Filter, + &output_filter_tensor, + filter_tf_shape, filter_mkl_shape); return; } diff --git a/tensorflow/core/kernels/mkl_conv_ops.h b/tensorflow/core/kernels/mkl_conv_ops.h index b6883dbaa2..c6456bd5c3 100644 --- a/tensorflow/core/kernels/mkl_conv_ops.h +++ b/tensorflow/core/kernels/mkl_conv_ops.h @@ -390,6 +390,29 @@ class MklConv2DBackpropCommonOp : public OpKernel { TensorShape filter_tf_shape = MakeFilterTfShape(context, filter_tensor); TensorShape outbprop_tf_shape = GetTfShape(context, kOutbpropIdx); + // Corner cases: output with 0 elements and 0 batch size. + Tensor* output_tensor = nullptr; + if (input_tf_shape.num_elements() == 0 || + filter_tf_shape.num_elements() == 0 || + outbprop_tf_shape.num_elements() == 0) { + MklDnnShape output_mkl_shape; + output_mkl_shape.SetMklTensor(false); + TensorShape output_tf_shape = GetOutputTfShape(input_tf_shape, + filter_tf_shape, + outbprop_tf_shape); + const int kOutputIdx = 0; + AllocateOutputSetMklShape(context, kOutputIdx, &output_tensor, + output_tf_shape, output_mkl_shape); + CHECK_NOTNULL(output_tensor); + + // if output tensor has more than 0 elements, we need to 0 them out. + for (size_t i = 0; i < output_tf_shape.num_elements(); ++i) { + output_tensor->flat().data()[i] = 0; + } + + return; + } + // By default, all dims are in MKL order. Only dims in TF order // are those with prefix tf_order. memory::dims outbprop_dims, fwd_input_dims, fwd_filter_dims; @@ -471,7 +494,6 @@ class MklConv2DBackpropCommonOp : public OpKernel { output.SetOpMemDesc(bwd_output_dims, memory::format::any); // Operator-specific call to create and execute primitive. - Tensor* output_tensor = nullptr; CreatePrimitive(context, cpu_engine, fwd_pd, &input, &filter, &outbackprop, &output, &output_tensor, strides, padding_l, padding_r, @@ -507,6 +529,11 @@ class MklConv2DBackpropCommonOp : public OpKernel { virtual TensorShape MakeFilterTfShape(OpKernelContext* context, const Tensor& filter_tensor) = 0; + /// Get the TensorFlow shape of output tensor. + virtual TensorShape GetOutputTfShape(const TensorShape& input_shape, + const TensorShape& filter_shape, + const TensorShape& outbprop_shape) = 0; + /// Get shape of output in MKL-DNN order. Computes shape of output from /// input shape (fwd_input_dims) and filter shape (fwd_filter_dims). virtual diff --git a/tensorflow/core/kernels/mkl_fused_batch_norm_op.cc b/tensorflow/core/kernels/mkl_fused_batch_norm_op.cc index a761562a4b..8340a91d05 100644 --- a/tensorflow/core/kernels/mkl_fused_batch_norm_op.cc +++ b/tensorflow/core/kernels/mkl_fused_batch_norm_op.cc @@ -703,27 +703,31 @@ class MklFusedBatchNormOp : public OpKernel { void Compute(OpKernelContext* context) override { try { auto cpu_engine = engine(engine::cpu, 0); - const size_t src_index = 0; // index of src input tensor - const size_t scale_index = 1; // index of scale tensor - const size_t shift_index = 2; // index of shift tensor - const size_t mean_index = 3; // index of est_mean tensor - const size_t var_index = 4; // index of est_variance tensor - - const Tensor& src_tensor = MklGetInput(context, src_index); - const Tensor& scale_tensor = MklGetInput(context, scale_index); - const Tensor& shift_tensor = MklGetInput(context, shift_index); - const Tensor& est_mean_tensor = MklGetInput(context, mean_index); - const Tensor& est_variance_tensor = MklGetInput(context, var_index); - + const size_t kSrcIndex = 0; // index of src input tensor + const size_t kScaleIndex = 1; // index of scale tensor + const size_t kShiftIndex = 2; // index of shift tensor + const size_t kMeanIndex = 3; // index of est_mean tensor + const size_t kVarianceIndex = 4; // index of est_variance tensor + + const Tensor& src_tensor = MklGetInput(context, kSrcIndex); + const Tensor& scale_tensor = MklGetInput(context, kScaleIndex); + const Tensor& shift_tensor = MklGetInput(context, kShiftIndex); + const Tensor& est_mean_tensor = MklGetInput(context, kMeanIndex); + const Tensor& est_variance_tensor = MklGetInput(context, + kVarianceIndex); + + TensorShape tf_shape_src; MklDnnShape dnn_shape_src; - GetMklShape(context, src_index, &dnn_shape_src); + GetMklShape(context, kSrcIndex, &dnn_shape_src); if (dnn_shape_src.IsMklTensor()) { + tf_shape_src = dnn_shape_src.GetTfShape(); OP_REQUIRES(context, dnn_shape_src.GetDimension() == 4, errors::InvalidArgument( "input must be 4-dimensional", src_tensor.shape().DebugString())); } else { + tf_shape_src = src_tensor.shape(); OP_REQUIRES(context, src_tensor.dims() == 4, errors::InvalidArgument( "input must be 4-dimensional", @@ -756,39 +760,35 @@ class MklFusedBatchNormOp : public OpKernel { est_variance_tensor.shape().DebugString())); } + // special case: input with 0 element and 0 batch size + Tensor* dst_tensor = nullptr; + if (tf_shape_src.num_elements() == 0) { + HandleEmptyInput(context, + tf_shape_src, + scale_tensor.shape(), + &dst_tensor); + return; + } + if (dnn_shape_src.IsMklTensor()) depth_ = dnn_shape_src.DimSize(MklDnnDims::Dim_C); else ExtractParams(context); // Indices of output tensors - const size_t dst_index = 0; - const size_t batch_mean_index = 1; - const size_t batch_variance_index = 2; - const size_t saved_mean_index = 3; - const size_t saved_variance_index = 4; + const size_t kDstIndex = 0; - // allocate batch mean output tensor + // allocate 4 output TF tensors Tensor* batch_mean_tensor = nullptr; - MklDnnShape mkl_shape_batch_mean; - mkl_shape_batch_mean.SetMklTensor(false); - AllocateOutputSetMklShape(context, - batch_mean_index, - &batch_mean_tensor, - scale_tensor.shape(), - mkl_shape_batch_mean); - CHECK_NOTNULL(batch_mean_tensor); - - // Batch variance Tensor* batch_variance_tensor = nullptr; - MklDnnShape mkl_shape_batch_variance; - mkl_shape_batch_variance.SetMklTensor(false); - AllocateOutputSetMklShape(context, - batch_variance_index, - &batch_variance_tensor, - scale_tensor.shape(), - mkl_shape_batch_variance); - CHECK_NOTNULL(batch_variance_tensor); + Tensor* saved_mean_tensor = nullptr; + Tensor* saved_variance_tensor = nullptr; + AllocateTFOutputs(context, + scale_tensor.shape(), + &batch_mean_tensor, + &batch_variance_tensor, + &saved_mean_tensor, + &saved_variance_tensor); if (is_training_) SetMeanVariance(*batch_mean_tensor, *batch_variance_tensor); @@ -844,26 +844,6 @@ class MklFusedBatchNormOp : public OpKernel { weights_data[k + depth_] = shift_tf[k]; } - // Mean and variance (without Bessel's correction) saved for backward - // computation to serve as pre-computed mean and variance. - Tensor* saved_mean_tensor = nullptr; - MklDnnShape mkl_shape_saved_mean; - mkl_shape_saved_mean.SetMklTensor(false); - AllocateOutputSetMklShape(context, saved_mean_index, - &saved_mean_tensor, - scale_tensor.shape(), - mkl_shape_saved_mean); - CHECK_NOTNULL(saved_mean_tensor); - - Tensor* saved_variance_tensor = nullptr; - MklDnnShape mkl_shape_saved_variance; - mkl_shape_saved_variance.SetMklTensor(false); - AllocateOutputSetMklShape(context, saved_variance_index, - &saved_variance_tensor, - scale_tensor.shape(), - mkl_shape_saved_variance); - CHECK_NOTNULL(saved_variance_tensor); - // set mean primitive auto mean_desc = memory::desc({1, depth_}, MklDnnType(), @@ -902,7 +882,6 @@ class MklFusedBatchNormOp : public OpKernel { // allocate dst tensor MklDnnShape dnn_shape_dst; TensorShape tf_shape_dst; - Tensor* dst_tensor = nullptr; if (dnn_shape_src.IsMklTensor()) { dnn_shape_dst.SetMklTensor(true); auto dst_pd = bnrm_fwd_pd.dst_primitive_desc(); @@ -915,7 +894,7 @@ class MklFusedBatchNormOp : public OpKernel { dnn_shape_dst.SetMklTensor(false); tf_shape_dst = src_tensor.shape(); } - AllocateOutputSetMklShape(context, dst_index, &dst_tensor, + AllocateOutputSetMklShape(context, kDstIndex, &dst_tensor, tf_shape_dst, dnn_shape_dst); // Output of batchnorm has same shape as input. @@ -958,10 +937,8 @@ class MklFusedBatchNormOp : public OpKernel { size_t adjust_size = orig_size - 1; adjust_factor = (static_cast(orig_size)) / adjust_size; } - T* batch_variance_data_tf = reinterpret_cast( - batch_variance_tensor->flat().data()); for (int k=0; k < depth_; k++) - batch_variance_data_tf[k] = + batch_variance_tensor->flat().data()[k] = (reinterpret_cast(variance_m.get_data_handle()))[k] * adjust_factor; } catch (mkldnn::error &e) { @@ -994,8 +971,100 @@ class MklFusedBatchNormOp : public OpKernel { variance_values_ = reinterpret_cast( const_cast(variance.flat().data())); } -}; + void HandleEmptyInput(OpKernelContext* context, + TensorShape tf_shape_src, + TensorShape tf_shape_scale, + Tensor** dst_tensor) { + CHECK_NOTNULL(dst_tensor); + + const size_t kDstIndex = 0; + MklDnnShape dnn_shape_dst; + dnn_shape_dst.SetMklTensor(false); + AllocateOutputSetMklShape(context, kDstIndex, dst_tensor, + tf_shape_src, dnn_shape_dst); + CHECK_NOTNULL(*dst_tensor); + memset(const_cast((*dst_tensor)->tensor_data().data()), 0, + (*dst_tensor)->tensor_data().size()); + + Tensor* batch_mean_tensor = nullptr; + Tensor* batch_variance_tensor = nullptr; + Tensor* saved_mean_tensor = nullptr; + Tensor* saved_variance_tensor = nullptr; + AllocateTFOutputs(context, tf_shape_scale, + &batch_mean_tensor, + &batch_variance_tensor, + &saved_mean_tensor, + &saved_variance_tensor); + } + + void AllocateTFOutputs(OpKernelContext* context, + TensorShape tf_shape_scale, + Tensor** batch_mean_tensor, + Tensor** batch_variance_tensor, + Tensor** saved_mean_tensor, + Tensor** saved_variance_tensor) { + CHECK_NOTNULL(batch_mean_tensor); + CHECK_NOTNULL(batch_variance_tensor); + CHECK_NOTNULL(saved_mean_tensor); + CHECK_NOTNULL(saved_variance_tensor); + + const size_t kBatchMeanIndex = 1; + const size_t kBatchVarianceIndex = 2; + const size_t kSavedMeanIndex = 3; + const size_t kSavedVarianceIndex = 4; + + // allocate batch mean output tensor + MklDnnShape mkl_shape_batch_mean; + mkl_shape_batch_mean.SetMklTensor(false); + AllocateOutputSetMklShape(context, + kBatchMeanIndex, + batch_mean_tensor, + tf_shape_scale, + mkl_shape_batch_mean); + CHECK_NOTNULL(*batch_mean_tensor); + // set NAN mean value in case of empty input tensor + for (int k=0; k < tf_shape_scale.num_elements(); k++) + (*batch_mean_tensor)->flat().data()[k] = NAN; + + // allocate batch variance output tensor + MklDnnShape mkl_shape_batch_variance; + mkl_shape_batch_variance.SetMklTensor(false); + AllocateOutputSetMklShape(context, + kBatchVarianceIndex, + batch_variance_tensor, + tf_shape_scale, + mkl_shape_batch_variance); + CHECK_NOTNULL(*batch_variance_tensor); + // set NAN variance value in case of empty input tensor + for (int k=0; k < tf_shape_scale.num_elements(); k++) + (*batch_variance_tensor)->flat().data()[k] = NAN; + + // Mean and variance (without Bessel's correction) saved for backward + // computation to serve as pre-computed mean and variance. + MklDnnShape mkl_shape_saved_mean; + mkl_shape_saved_mean.SetMklTensor(false); + AllocateOutputSetMklShape(context, kSavedMeanIndex, + saved_mean_tensor, + tf_shape_scale, + mkl_shape_saved_mean); + CHECK_NOTNULL(*saved_mean_tensor); + // set NAN mean value in case of empty input tensor + for (int k=0; k < tf_shape_scale.num_elements(); k++) + (*saved_mean_tensor)->flat().data()[k] = NAN; + + MklDnnShape mkl_shape_saved_variance; + mkl_shape_saved_variance.SetMklTensor(false); + AllocateOutputSetMklShape(context, kSavedVarianceIndex, + saved_variance_tensor, + tf_shape_scale, + mkl_shape_saved_variance); + CHECK_NOTNULL(*saved_variance_tensor); + // set NAN variance value in case of empty input tensor + for (int k=0; k < tf_shape_scale.num_elements(); k++) + (*saved_variance_tensor)->flat().data()[k] = NAN; + } +}; template class MklFusedBatchNormGradOp : public OpKernel { @@ -1009,34 +1078,37 @@ class MklFusedBatchNormGradOp : public OpKernel { OP_REQUIRES_OK(context, context->GetAttr("data_format", &tensor_format)); OP_REQUIRES(context, FormatFromString(tensor_format, &tensor_format_), errors::InvalidArgument("Invalid data format")); + OP_REQUIRES_OK(context, context->GetAttr("is_training", &is_training_)); } void Compute(OpKernelContext* context) override { try { auto cpu_engine = engine(engine::cpu, 0); - - const size_t diff_dst_index = 0; // index of diff_dst tensor - const size_t src_index = 1; // index of src input tensor - const size_t scale_index = 2; // index of scale tensor - const size_t mean_index = 3; // index of saved_mean tensor - const size_t variance_index = 4; // index of saved_variance tensor - const Tensor& diff_dst_tensor = MklGetInput(context, diff_dst_index); - const Tensor& src_tensor = MklGetInput(context, src_index); - const Tensor& scale_tensor = MklGetInput(context, scale_index); - const Tensor& saved_mean_tensor = MklGetInput(context, mean_index); + const size_t kDiffDstIndex = 0; // index of diff_dst tensor + const size_t kSrcIndex = 1; // index of src input tensor + const size_t kScaleIndex = 2; // index of scale tensor + const size_t kMeanIndex = 3; // index of saved_mean tensor + const size_t kVarianceIndex = 4; // index of saved_variance tensor + const Tensor& diff_dst_tensor = MklGetInput(context, kDiffDstIndex); + const Tensor& src_tensor = MklGetInput(context, kSrcIndex); + const Tensor& scale_tensor = MklGetInput(context, kScaleIndex); + const Tensor& saved_mean_tensor = MklGetInput(context, kMeanIndex); const Tensor& saved_variance_tensor = MklGetInput(context, - variance_index); + kVarianceIndex); MklDnnShape dnn_shape_src, dnn_shape_diff_dst; - GetMklShape(context, src_index, &dnn_shape_src); - GetMklShape(context, diff_dst_index, &dnn_shape_diff_dst); + GetMklShape(context, kSrcIndex, &dnn_shape_src); + GetMklShape(context, kDiffDstIndex, &dnn_shape_diff_dst); + TensorShape tf_shape_src, tf_shape_diff_dst; if (dnn_shape_diff_dst.IsMklTensor()) { + tf_shape_diff_dst = dnn_shape_diff_dst.GetTfShape(); OP_REQUIRES(context, dnn_shape_diff_dst.GetDimension() == 4, errors::InvalidArgument( "input must be 4-dimensional", diff_dst_tensor.shape().DebugString())); } else { + tf_shape_diff_dst = diff_dst_tensor.shape(); OP_REQUIRES(context, diff_dst_tensor.dims() == 4, errors::InvalidArgument( "input must be 4-dimensional", @@ -1044,11 +1116,13 @@ class MklFusedBatchNormGradOp : public OpKernel { } if (dnn_shape_src.IsMklTensor()) { + tf_shape_src = dnn_shape_src.GetTfShape(); OP_REQUIRES(context, dnn_shape_src.GetDimension() == 4, errors::InvalidArgument( "input must be 4-dimensional", src_tensor.shape().DebugString())); } else { + tf_shape_src = src_tensor.shape(); OP_REQUIRES(context, src_tensor.dims() == 4, errors::InvalidArgument( "input must be 4-dimensional", @@ -1069,6 +1143,15 @@ class MklFusedBatchNormGradOp : public OpKernel { "saved variance must be 1-dimensional", saved_variance_tensor.shape().DebugString())); + Tensor* diff_src_tensor = nullptr; + if (tf_shape_src.num_elements() == 0 || + tf_shape_diff_dst.num_elements() == 0) { + HandleEmptyInput(context, tf_shape_src, + scale_tensor.shape(), + &diff_src_tensor); + return; + } + if (dnn_shape_src.IsMklTensor()) depth_ = dnn_shape_src.DimSize(MklDnnDims::Dim_C); else @@ -1165,25 +1248,21 @@ class MklFusedBatchNormGradOp : public OpKernel { auto diff_weights_m = memory(diff_weights_pd); auto bnrm_fwd_desc = batch_normalization_forward::desc( - prop_kind::forward_training, - src.GetUsrMemDesc(), - epsilon_, - use_scale_shift); + prop_kind::forward_training, + src.GetUsrMemDesc(), + epsilon_, + is_training_ ? use_scale_shift : + (use_scale_shift | use_global_stats)); auto bnrm_fwd_pd = batch_normalization_forward::primitive_desc( bnrm_fwd_desc, cpu_engine); // Indices of output tensors - const size_t diff_src_index = 0; // index of diff_src tensor - const size_t diff_scale_index = 1; // index of diff_scale tensor - const size_t diff_shift_index = 2; // index of diff_shift tensor - const size_t p1_index = 3; // index of 1st placeholder tensor - const size_t p2_index = 4; // index of 2nd placeholder tensor + const size_t kDiffSrcIndex = 0; // index of diff_src tensor // allocate diff_src tensor MklDnnShape dnn_shape_diff_src; TensorShape tf_shape_diff_src; - Tensor* diff_src_tensor = nullptr; if (dnn_shape_src.IsMklTensor()) { dnn_shape_diff_src.SetMklTensor(true); auto diff_src_pd = bnrm_fwd_pd.dst_primitive_desc(); @@ -1201,7 +1280,7 @@ class MklFusedBatchNormGradOp : public OpKernel { dnn_shape_diff_src.SetMklTensor(false); tf_shape_diff_src = src_tensor.shape(); } - AllocateOutputSetMklShape(context, diff_src_index, &diff_src_tensor, + AllocateOutputSetMklShape(context, kDiffSrcIndex, &diff_src_tensor, tf_shape_diff_src, dnn_shape_diff_src); diff_src.SetUsrMem(src_md, diff_src_tensor); @@ -1212,7 +1291,15 @@ class MklFusedBatchNormGradOp : public OpKernel { diff_src.GetUsrMemDesc(), src.GetUsrMemDesc(), epsilon_, - use_scale_shift); + /* for inference, specify use_global_stats + 1. on fwd prop, use mean and variance + provided as inputs + 2. on bwd prop, mean and variance are + considered as constants. Thus, + reduce the amout of MKL computations + */ + is_training_ ? use_scale_shift : + (use_scale_shift | use_global_stats)); auto bnrm_bwd_pd = batch_normalization_backward::primitive_desc( bnrm_bwd_desc, cpu_engine, @@ -1232,41 +1319,22 @@ class MklFusedBatchNormGradOp : public OpKernel { net.push_back(bnrm_bwd_op); stream(stream::kind::eager).submit(net).wait(); - // separate out scale and shift grad and copy to individual tensors - const TensorShape& tf_shape_scale_shift = scale_tensor.shape(); + // allocate 4 output TF tensors Tensor* diff_scale_tensor = nullptr; - MklDnnShape mkl_shape_diff_scale; - mkl_shape_diff_scale.SetMklTensor(false); - AllocateOutputSetMklShape(context, diff_scale_index, &diff_scale_tensor, - tf_shape_scale_shift, mkl_shape_diff_scale); - Tensor* diff_shift_tensor = nullptr; - MklDnnShape mkl_shape_diff_shift; - mkl_shape_diff_shift.SetMklTensor(false); - AllocateOutputSetMklShape(context, diff_shift_index, &diff_shift_tensor, - tf_shape_scale_shift, mkl_shape_diff_shift); + AllocateTFOutputs(context, scale_tensor.shape(), + &diff_scale_tensor, + &diff_shift_tensor); // copy data: diff_scale and diff_shift T* diff_weights_data_dnn = reinterpret_cast (diff_weights_m.get_data_handle()); - float* diff_scale_data_tf = const_cast( - static_cast(diff_scale_tensor->flat().data())); - float* diff_shift_data_tf = const_cast( - static_cast(diff_shift_tensor->flat().data())); for (int i = 0; i < depth_; i++) { - diff_scale_data_tf[i] = diff_weights_data_dnn[i]; - diff_shift_data_tf[i] = diff_weights_data_dnn[i + depth_]; + diff_scale_tensor->flat().data()[i] = + diff_weights_data_dnn[i]; + diff_shift_tensor->flat().data()[i] = + diff_weights_data_dnn[i + depth_]; } - - // Placeholders for estimated_mean and estimated_variance, which are - // used for inference and thus not needed here for gradient computation. - Tensor* p1_tensor = nullptr, *p2_tensor = nullptr; - MklDnnShape mkl_shape_p; - mkl_shape_p.SetMklTensor(false); - AllocateOutputSetMklShape(context, p1_index, &p1_tensor, - TensorShape({}), mkl_shape_p); - AllocateOutputSetMklShape(context, p2_index, &p2_tensor, - TensorShape({}), mkl_shape_p); } catch (mkldnn::error &e) { string error_msg = "Status: " + std::to_string(e.status) + ", message: " + string(e.message) + @@ -1282,12 +1350,74 @@ class MklFusedBatchNormGradOp : public OpKernel { T epsilon_; TensorFormat tensor_format_; int depth_; // batch normalization is done for per channel. + bool is_training_; void ExtractParams(OpKernelContext* context) { const Tensor& input = MklGetInput(context, 0); depth_ = static_cast(GetTensorDim(input, tensor_format_, 'C')); } + void HandleEmptyInput(OpKernelContext* context, + TensorShape tf_shape_src, + TensorShape tf_shape_scale_shift, + Tensor** diff_src_tensor) { + const size_t kDiffSrcIndex = 0; + + MklDnnShape dnn_shape_diff_src; + dnn_shape_diff_src.SetMklTensor(false); + AllocateOutputSetMklShape(context, kDiffSrcIndex, diff_src_tensor, + tf_shape_src, dnn_shape_diff_src); + for (size_t i=0; i < (*diff_src_tensor)->shape().num_elements(); i++) + (*diff_src_tensor)->flat().data()[i] = 0; + + Tensor* diff_scale_tensor = nullptr; + Tensor* diff_shift_tensor = nullptr; + AllocateTFOutputs(context, + tf_shape_scale_shift, + &diff_scale_tensor, + &diff_shift_tensor); + } + + void AllocateTFOutputs(OpKernelContext* context, + TensorShape tf_shape_scale_shift, + Tensor** diff_scale_tensor, + Tensor** diff_shift_tensor) { + CHECK_NOTNULL(diff_scale_tensor); + CHECK_NOTNULL(diff_shift_tensor); + + const size_t kDiffScaleIndex = 1; + const size_t kDiffShiftIndex = 2; + const size_t kP1Index = 3; + const size_t kP2Index = 4; + + // separate out scale and shift grad and copy to individual tensors + MklDnnShape mkl_shape_diff_scale; + mkl_shape_diff_scale.SetMklTensor(false); + AllocateOutputSetMklShape(context, kDiffScaleIndex, diff_scale_tensor, + tf_shape_scale_shift, mkl_shape_diff_scale); + CHECK_NOTNULL(*diff_scale_tensor); + for (size_t i=0; i < (*diff_scale_tensor)->shape().num_elements(); i++) + (*diff_scale_tensor)->flat().data()[i] = 0; + + MklDnnShape mkl_shape_diff_shift; + mkl_shape_diff_shift.SetMklTensor(false); + AllocateOutputSetMklShape(context, kDiffShiftIndex, diff_shift_tensor, + tf_shape_scale_shift, mkl_shape_diff_shift); + CHECK_NOTNULL(*diff_shift_tensor); + for (size_t i=0; i < (*diff_shift_tensor)->shape().num_elements(); i++) + (*diff_shift_tensor)->flat().data()[i] = 0; + + // Placeholders for estimated_mean and estimated_variance, which are + // used for inference and thus not needed here for gradient computation. + Tensor* p1_tensor = nullptr, *p2_tensor = nullptr; + MklDnnShape mkl_shape_p; + mkl_shape_p.SetMklTensor(false); + AllocateOutputSetMklShape(context, kP1Index, &p1_tensor, + TensorShape({}), mkl_shape_p); + AllocateOutputSetMklShape(context, kP2Index, &p2_tensor, + TensorShape({}), mkl_shape_p); + } + memory::dims GetMeanVarianceDims() { return memory::dims({1, depth_}); } diff --git a/tensorflow/core/kernels/mkl_input_conversion_op.cc b/tensorflow/core/kernels/mkl_input_conversion_op.cc index 001834b13b..4b5f7b8310 100644 --- a/tensorflow/core/kernels/mkl_input_conversion_op.cc +++ b/tensorflow/core/kernels/mkl_input_conversion_op.cc @@ -396,7 +396,7 @@ class MklInputConversionOp : public OpKernel { auto cpu_engine = engine(engine::cpu, 0); MklDnnData tf_input(&cpu_engine); auto input_tf_md = mkl_output_mkl_shape.GetTfLayout(); - tf_input.SetUsrMem(input_tf_md, &tf_tensor); + tf_input.SetUsrMem(input_tf_md, tf_tensor); // Create reorder between tensorflow layout and Mkl layout. std::vector net; diff --git a/tensorflow/core/kernels/mkl_lrn_op.cc b/tensorflow/core/kernels/mkl_lrn_op.cc index a8f28202f4..95e0404ba8 100644 --- a/tensorflow/core/kernels/mkl_lrn_op.cc +++ b/tensorflow/core/kernels/mkl_lrn_op.cc @@ -43,7 +43,7 @@ limitations under the License. using mkldnn::lrn_forward; using mkldnn::lrn_backward; using mkldnn::prop_kind; -using mkldnn::algorithm::lrn_across_channels; +using mkldnn::lrn_across_channels; using mkldnn::stream; #endif @@ -910,17 +910,23 @@ class MklLRNOp : public OpKernel { Eigen::Tensor multiplier(depth, depth); GetBandMatrix(depth, depth_radius_, &multiplier); - Tensor *output_dnn_data, *workspace; - MklDnnShape mkl_output_mkl_shape, mkl_workspace_mkl_shape; + Tensor *output_dnn_data = nullptr; + MklDnnShape mkl_output_mkl_shape; mkl_output_mkl_shape.SetMklTensor(false); mkl_output_mkl_shape.SetDimensions(4); AllocateOutputSetMklShape(context, kIdxOutput, &output_dnn_data, input.shape(), mkl_output_mkl_shape); + CHECK_NOTNULL(output_dnn_data); - mkl_workspace_mkl_shape.SetMklTensor(false); - mkl_workspace_mkl_shape.SetDimensions(4); - AllocateOutputSetMklShape(context, kIdxWorkspace, &workspace, - input.shape(), mkl_workspace_mkl_shape); + Tensor* workspace_tensor = nullptr; + MklDnnShape workspace_mkl_shape; + workspace_mkl_shape.SetMklTensor(false); + TensorShape workspace_tf_shape; + workspace_tf_shape.AddDim(0); + AllocateOutputSetMklShape(context, kIdxWorkspace, + &workspace_tensor, + workspace_tf_shape, workspace_mkl_shape); + CHECK_NOTNULL(workspace_tensor); auto out_shaped = output_dnn_data->shaped({nodes * batch, depth}); Eigen::array dims = {{DimPair(1, 0)}}; @@ -1344,12 +1350,14 @@ class MklLRNGradOp : public OpKernel { errors::InvalidArgument("Output image must be 4-dimensional")); } - if (workspace_dnn_shape.IsMklTensor()) { - OP_REQUIRES(context, workspace_dnn_shape.IsMklTensor() == false, - errors::InvalidArgument("Workspace should not be MKL Tensor.")); - } else { - OP_REQUIRES(context, workspace_tensor.dims() == 1, - errors::InvalidArgument("Workspace must be 1-dimensional")); + if (workspace_enabled_) { + if (workspace_dnn_shape.IsMklTensor()) { + OP_REQUIRES(context, workspace_dnn_shape.IsMklTensor() == false, + errors::InvalidArgument("Workspace should not be MKL Tensor.")); + } else { + OP_REQUIRES(context, workspace_tensor.dims() == 1, + errors::InvalidArgument("Workspace must be 1-dimensional")); + } } } diff --git a/tensorflow/core/kernels/mkl_maxpooling_op.cc b/tensorflow/core/kernels/mkl_maxpooling_op.cc index de4d7d2e72..82c5229bab 100644 --- a/tensorflow/core/kernels/mkl_maxpooling_op.cc +++ b/tensorflow/core/kernels/mkl_maxpooling_op.cc @@ -517,7 +517,7 @@ class MklMaxPoolingOp : public MklPoolingForwardOpBase { MklDnnData dnn_data_input(&cpu_engine); MklDnnData dnn_data_output(&cpu_engine); - MklDnnData dnn_data_wksp(&cpu_engine); + MklDnnData dnn_data_wksp(&cpu_engine); // initialize variables for the pooling op MklPoolParameters pool_params; @@ -588,16 +588,16 @@ class MklMaxPoolingOp : public MklPoolingForwardOpBase { void AllocateWorkspaceTensor(OpKernelContext* context, const pooling_forward::primitive_desc& pool_fwd_prim_desc, - MklDnnData* dnn_data_wksp) { + MklDnnData* dnn_data_wksp) { CHECK_NOTNULL(dnn_data_wksp); Tensor* workspace_tensor = nullptr; memory::primitive_desc workspace_pd = pool_fwd_prim_desc.workspace_primitive_desc(); - size_t workspace_t_elems = this->GetNumTElements(workspace_pd); + size_t workspace_bytes = workspace_pd.get_size(); MklDnnShape workspace_mkl_shape; workspace_mkl_shape.SetMklTensor(false); TensorShape workspace_tf_shape; - workspace_tf_shape.AddDim(workspace_t_elems); + workspace_tf_shape.AddDim(workspace_bytes); AllocateOutputSetMklShape(context, kOutputTensorIndexWorkspace, &workspace_tensor, workspace_tf_shape, workspace_mkl_shape); @@ -651,7 +651,7 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { if (!context->status().ok()) return; MklDnnData grad_dnn_data(&cpu_engine); - MklDnnData workspace_dnn_data(&cpu_engine); + MklDnnData workspace_dnn_data(&cpu_engine); MklDnnData output_dnn_data(&cpu_engine); Tensor* output_tensor = nullptr; MklPoolParameters pool_params; @@ -770,7 +770,7 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { void ConfigureWorkspace(const Tensor& workspace_tensor, memory::primitive_desc workspace_pd, - MklDnnData *workspace_dnn_data) { + MklDnnData *workspace_dnn_data) { CHECK_NOTNULL(workspace_dnn_data); workspace_dnn_data->SetUsrMem(workspace_pd, &workspace_tensor); @@ -811,7 +811,7 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { errors::InvalidArgument("Gradient must be " "4-dimensional")); } - if (this->workspace_enabled_){ + if (this->workspace_enabled_) { // The workspace should not be an MKL tensor OP_REQUIRES(context, workspace_mkl_shape.IsMklTensor() == false, errors::InvalidArgument("Workspace tensor should not" diff --git a/tensorflow/core/kernels/mkl_pooling_ops_common.h b/tensorflow/core/kernels/mkl_pooling_ops_common.h index d33e91a15d..b974b2c59a 100644 --- a/tensorflow/core/kernels/mkl_pooling_ops_common.h +++ b/tensorflow/core/kernels/mkl_pooling_ops_common.h @@ -231,7 +231,7 @@ class MklPoolingForwardOpBase : public MklPoolingOpBase { const pooling_forward::primitive_desc& pool_fwd_desc, const MklDnnData* src, MklDnnData* dst, - MklDnnData* wksp = nullptr) { + MklDnnData* wksp = nullptr) { std::vector net; // Create pooling primitive and add it to net @@ -307,7 +307,7 @@ class MklPoolingBackwardOpBase : public MklPoolingOpBase { MklDnnData* input_gradient_diff_dst, MklDnnData* output_diff_src, const memory::primitive_desc& target_diff_dst_pd, - const MklDnnData* workspace = nullptr) { + const MklDnnData* workspace = nullptr) { std::vector net; diff --git a/tensorflow/core/kernels/mkl_reshape_op.cc b/tensorflow/core/kernels/mkl_reshape_op.cc index 11c92ebdb4..b41e529357 100644 --- a/tensorflow/core/kernels/mkl_reshape_op.cc +++ b/tensorflow/core/kernels/mkl_reshape_op.cc @@ -256,11 +256,18 @@ class MklReshapeOp : public OpKernel { AllocateOutputSetMklShape(context, kOutputSlotIdx, &output_tensor, shape_to, mkl_shape_output); - // Insert reorder between Mkl layout and TensorFlow layout. + // Insert reorder between Mkl layout and TensorFlow layout if + // needed. If reorder is not needed but reshape is needed (since + // shape_from != shape_to), then we just copy input tensor to + // output tensor with target shape (we cannot forward Mkl layout + // in such case because shape has changed.) std::vector net; - CHECK_EQ(dnn_data_input.CheckReorderToOpMem(output_tf_pd, - output_tensor, &net), true); - stream(stream::kind::eager).submit(net).wait(); + if (dnn_data_input.CheckReorderToOpMem(output_tf_pd, + output_tensor, &net)) { + stream(stream::kind::eager).submit(net).wait(); + } else { + output_tensor->CopyFrom(input_tensor, shape_to); + } return; } else { // If dimensions that are being expanded or collapsed are diff --git a/tensorflow/core/kernels/mkl_softmax_op.cc b/tensorflow/core/kernels/mkl_softmax_op.cc new file mode 100644 index 0000000000..896d562933 --- /dev/null +++ b/tensorflow/core/kernels/mkl_softmax_op.cc @@ -0,0 +1,163 @@ +/* Copyright 2015 The TensorFlow Authors. 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. +==============================================================================*/ + +// See docs in ../ops/nn_ops.cc. +#ifdef INTEL_MKL +#ifdef INTEL_MKL_DNN + +#include "tensorflow/core/framework/numeric_op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/framework/tensor.h" +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/util/tensor_format.h" +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" + +#include "mkldnn.h" +#include "mkldnn_types.h" +#include "tensorflow/core/platform/default/logging.h" +#include "tensorflow/core/util/mkl_util.h" + +#include "mkldnn.hpp" +using mkldnn::stream; +using mkldnn::prop_kind; +using mkldnn::softmax_forward; + +namespace tensorflow { + +typedef Eigen::ThreadPoolDevice CPUDevice; + + + +template +class MklSoftmaxOp : public OpKernel { + public: + ~MklSoftmaxOp() {} + + explicit MklSoftmaxOp(OpKernelConstruction* context) : OpKernel(context) {} + + void Compute(OpKernelContext* context) override { + try { + auto cpu_engine = engine(engine::cpu, 0); + + // src_tensor now points to the 0-th input of global data struct "context" + size_t src_idx = 0; + const Tensor& src_tensor = MklGetInput(context, src_idx); + + // Add: get MklShape + MklDnnShape src_mkl_shape; + GetMklShape(context, src_idx, &src_mkl_shape); + + + // src_dims is the dimenstion of src_tensor + // dim of the dst will also be same as src_dims + auto src_tf_shape = src_mkl_shape.IsMklTensor() ? + src_mkl_shape.GetTfShape() : src_tensor.shape(); + auto src_dims = TFShapeToMklDnnDims(src_tf_shape); + auto output_dims = src_dims; + + // Create softmax memory for src, dst: both are defined in mkl_util.h, + // they are wrapper + MklDnnData src(&cpu_engine); + MklDnnData dst(&cpu_engine); + + // If input is in MKL layout, then simply grab input layout; otherwise, + // construct input Tf layout. For TF layout, although input shape + // (src_dims) required is in MKL-DNN order, the layout is Tensorflow's + // layout + auto src_md = src_mkl_shape.IsMklTensor() + ? src_mkl_shape.GetMklLayout() + : memory::desc(src_dims, MklDnnType(), + memory::format::nc); + + // src: setting memory descriptor and op memory descriptor + // Basically following two functions maps the TF "src_tensor" to mkl + // tensor object "src" + // following functions are in mkl_util.h + // data format is "nc" for src and dst; since the src and dst buffer is + // always in 2D shape + src.SetUsrMem(src_md, &src_tensor); + src.SetOpMemDesc(src_dims, memory::format::nc); + + // creating a memory descriptor + int axis = 1; // axis to which softmax will be applied + auto softmax_fwd_desc = softmax_forward::desc(prop_kind::forward_scoring, + src.GetOpMemDesc(), axis); + auto softmax_fwd_pd = softmax_forward::primitive_desc(softmax_fwd_desc, + cpu_engine); + + // add: output + Tensor* output_tensor = nullptr; + MklDnnShape output_mkl_shape; + TensorShape output_tf_shape; // shape of output TF tensor. + // Softmax MklDnn output layout is same as input layout. + auto dst_pd = src.GetUsrMemPrimDesc(); + + // if input is MKL shape, ouput is also MKL shape. + // if input is TF shape, output is also TF shape + if (src_mkl_shape.IsMklTensor()) { + output_mkl_shape.SetMklTensor(true); + output_mkl_shape.SetMklLayout(&dst_pd); + output_mkl_shape.SetElemType(MklDnnType()); + output_mkl_shape.SetTfLayout(output_dims.size(), output_dims, + memory::format::nc); + output_tf_shape.AddDim((dst_pd.get_size() / sizeof(T))); + } else { // then output is also TF shape + output_mkl_shape.SetMklTensor(false); + output_tf_shape = MklDnnDimsToTFShape(output_dims); + } + // Allocate output shape (MKL or TF based on the above) + AllocateOutputSetMklShape(context, 0, &output_tensor, output_tf_shape, + output_mkl_shape); + + // Output_dims and input_dims are same + dst.SetUsrMem(src_md, output_tensor); + + // finally creating the "softmax op" using the primitive descriptor, src + // and dst + auto softmax_fwd = + softmax_forward(softmax_fwd_pd, src.GetOpMem(), dst.GetOpMem()); + + // execute net (pushing to the stream) + // following 3 are common for all mkl dnn ops + std::vector net; + net.push_back(softmax_fwd); + stream(stream::kind::eager).submit(net).wait(); + } catch (mkldnn::error& e) { + string error_msg = "Status: " + std::to_string(e.status) + ", message: " + + string(e.message) + ", in file " + string(__FILE__) + + ":" + std::to_string(__LINE__); + OP_REQUIRES_OK( + context, + errors::Aborted("Operation received an exception:", error_msg)); + } + } +}; + +/* Register DNN kernels for supported operations and supported types - right now + * it is only Softmax and f32 */ +#define REGISTER_SOFTMAX_MKL_SUPPORTED_KERNELS_TYPES(type) \ + REGISTER_KERNEL_BUILDER(Name("_MklSoftmax") \ + .Device(DEVICE_CPU) \ + .TypeConstraint("T") \ + .Label(mkl_op_registry::kMklOpLabel), \ + MklSoftmaxOp); +TF_CALL_float(REGISTER_SOFTMAX_MKL_SUPPORTED_KERNELS_TYPES); + + +} // namespace tensorflow + +#endif // INTEL_MKL_DNN +#endif // INTEL_MKL diff --git a/tensorflow/core/kernels/pooling_ops_common.cc b/tensorflow/core/kernels/pooling_ops_common.cc index 6a52a15c93..d4241b5809 100644 --- a/tensorflow/core/kernels/pooling_ops_common.cc +++ b/tensorflow/core/kernels/pooling_ops_common.cc @@ -222,7 +222,7 @@ void DnnPoolingOp::Compute( output_desc, &output_data) .ok(); OP_REQUIRES(context, status, - errors::Internal("cudnn PoolBackward launch failed")); + errors::Internal("cudnn PoolForward launch failed")); if (data_format == FORMAT_NHWC) { /// Transform the output data from NCHW back to NHWC diff --git a/tensorflow/core/kernels/spectrogram_test_utils.cc b/tensorflow/core/kernels/spectrogram_test_utils.cc index 046f6344df..bc30330d61 100644 --- a/tensorflow/core/kernels/spectrogram_test_utils.cc +++ b/tensorflow/core/kernels/spectrogram_test_utils.cc @@ -70,10 +70,24 @@ bool ReadRawFloatFileToComplexVector( int offset = 0; const int end = data_string.size(); while (offset < end) { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + char arr[4]; + for (int i = 0; i < kBytesPerValue; ++i ) { + arr[3 - i] = *(data_string.data() + offset + i); + } + memcpy(&real_out, arr, kBytesPerValue); + offset += kBytesPerValue; + for (int i = 0; i < kBytesPerValue; ++i ) { + arr[3 - i] = *(data_string.data() + offset + i); + } + memcpy(&imag_out, arr, kBytesPerValue); + offset += kBytesPerValue; +#else memcpy(&real_out, data_string.data() + offset, kBytesPerValue); offset += kBytesPerValue; memcpy(&imag_out, data_string.data() + offset, kBytesPerValue); offset += kBytesPerValue; +#endif if (row_counter >= row_length) { data->push_back(data_row); data_row.clear(); diff --git a/tensorflow/core/kernels/transpose_functor_cpu.cc b/tensorflow/core/kernels/transpose_functor_cpu.cc index 41b73fdaf4..6594f7ee7b 100644 --- a/tensorflow/core/kernels/transpose_functor_cpu.cc +++ b/tensorflow/core/kernels/transpose_functor_cpu.cc @@ -88,6 +88,18 @@ struct Transpose { internal::TransposeUsingEigen(d, in, perm, conjugate, out); break; + case 6: + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + break; + case 7: + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + break; + case 8: + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + break; default: TransposeSimple(d, in, perm, out); break; diff --git a/tensorflow/core/kernels/transpose_functor_gpu.cu.cc b/tensorflow/core/kernels/transpose_functor_gpu.cu.cc index 493dac9a7c..d6a237d6c1 100644 --- a/tensorflow/core/kernels/transpose_functor_gpu.cu.cc +++ b/tensorflow/core/kernels/transpose_functor_gpu.cu.cc @@ -201,6 +201,27 @@ struct Transpose { out); } break; + case 6: + if (!internal::TransposeUsingTile::run(d, in, perm, + out)) { + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + } + break; + case 7: + if (!internal::TransposeUsingTile::run(d, in, perm, + out)) { + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + } + break; + case 8: + if (!internal::TransposeUsingTile::run(d, in, perm, + out)) { + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + } + break; default: internal::TransposeSimple(d, in, perm, out); break; diff --git a/tensorflow/core/kernels/xent_op.cc b/tensorflow/core/kernels/xent_op.cc index dc21cee3a8..0f8d027caa 100644 --- a/tensorflow/core/kernels/xent_op.cc +++ b/tensorflow/core/kernels/xent_op.cc @@ -67,10 +67,12 @@ class SoftmaxXentWithLogitsOp : public OpKernel { // Try to reuse the logits_in buffer for the backprop output. OP_REQUIRES_OK(context, context->forward_input_or_allocate_output( {0}, 1, logits_in.shape(), &back_out)); - functor::XentFunctor functor; - functor(context->eigen_device(), logits_in.matrix(), - labels_in.matrix(), scratch.matrix(), loss_out->vec(), - back_out->matrix()); + if (logits_in.dim_size(0) > 0) { + functor::XentFunctor functor; + functor(context->eigen_device(), logits_in.matrix(), + labels_in.matrix(), scratch.matrix(), loss_out->vec(), + back_out->matrix()); + } } }; diff --git a/tensorflow/core/lib/gif/gif_io.cc b/tensorflow/core/lib/gif/gif_io.cc index b5c0d9f621..0f6999c88f 100644 --- a/tensorflow/core/lib/gif/gif_io.cc +++ b/tensorflow/core/lib/gif/gif_io.cc @@ -17,6 +17,7 @@ limitations under the License. #include "tensorflow/core/lib/gif/gif_io.h" #include "tensorflow/core/lib/gtl/cleanup.h" +#include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/gif.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/mem.h" @@ -44,7 +45,8 @@ int input_callback(GifFileType* gif_file, GifByteType* buf, int size) { } uint8* Decode(const void* srcdata, int datasize, - std::function allocate_output) { + const std::function& allocate_output, + string* error_string) { int error_code = D_GIF_SUCCEEDED; InputBufferInfo info = {reinterpret_cast(srcdata), datasize}; GifFileType* gif_file = @@ -57,17 +59,17 @@ uint8* Decode(const void* srcdata, int datasize, } }); if (error_code != D_GIF_SUCCEEDED) { - LOG(ERROR) << "Fail to open gif file, reason: " - << GifErrorString(error_code); + *error_string = strings::StrCat("failed to open gif file: ", + GifErrorString(error_code)); return nullptr; } if (DGifSlurp(gif_file) != GIF_OK) { - LOG(ERROR) << "Fail to slurp gif file, reason: " - << GifErrorString(gif_file->Error); + *error_string = strings::StrCat("failed to slurp gif file: ", + GifErrorString(gif_file->Error)); return nullptr; } if (gif_file->ImageCount <= 0) { - LOG(ERROR) << "Gif file does not contain any image"; + *error_string = strings::StrCat("gif file does not contain any image"); return nullptr; } @@ -83,7 +85,7 @@ uint8* Decode(const void* srcdata, int datasize, GifImageDesc* img_desc = &this_image->ImageDesc; if (img_desc->Left != 0 || img_desc->Top != 0 || img_desc->Width != width || img_desc->Height != height) { - LOG(ERROR) << "Can't process optimized gif."; + *error_string = strings::StrCat("can't process optimized gif"); return nullptr; } diff --git a/tensorflow/core/lib/gif/gif_io.h b/tensorflow/core/lib/gif/gif_io.h index 5399e6a538..0a7967a5a1 100644 --- a/tensorflow/core/lib/gif/gif_io.h +++ b/tensorflow/core/lib/gif/gif_io.h @@ -43,7 +43,8 @@ namespace tensorflow { namespace gif { uint8* Decode(const void* srcdata, int datasize, - std::function allocate_output); + const std::function& allocate_output, + string* error_string); } // namespace gif } // namespace tensorflow diff --git a/tensorflow/core/ops/nn_ops.cc b/tensorflow/core/ops/nn_ops.cc index 536fc7c0c1..3f72b41569 100644 --- a/tensorflow/core/ops/nn_ops.cc +++ b/tensorflow/core/ops/nn_ops.cc @@ -1818,7 +1818,11 @@ REGISTER_OP("_MklMaxPool") .Input("input: T") .Input("mkl_input: uint8") .Output("output: T") +#ifndef INTEL_MKL_DNN .Output("workspace: T") +#else + .Output("workspace: uint8") +#endif .Output("mkl_output: uint8") .Output("mkl_workspace: uint8") .SetShapeFn(shape_inference::MaxPoolShape) @@ -1840,7 +1844,11 @@ REGISTER_OP("_MklMaxPoolGrad") .Input("orig_input: T") .Input("orig_output: T") .Input("grad: T") +#ifndef INTEL_MKL_DNN .Input("workspace: T") +#else + .Input("workspace: uint8") +#endif .Input("mkl_orig_input: uint8") .Input("mkl_orig_output: uint8") .Input("mkl_grad: uint8") diff --git a/tensorflow/core/platform/s3/aws_logging.cc b/tensorflow/core/platform/s3/aws_logging.cc index 41b854d634..fbca0acc36 100644 --- a/tensorflow/core/platform/s3/aws_logging.cc +++ b/tensorflow/core/platform/s3/aws_logging.cc @@ -48,6 +48,7 @@ void AWSLogSystem::LogStream(Aws::Utils::Logging::LogLevel log_level, void AWSLogSystem::LogMessage(Aws::Utils::Logging::LogLevel log_level, const std::string& message) { + if (message == "Initializing Curl library") return; switch (log_level) { case Aws::Utils::Logging::LogLevel::Info: LOG(INFO) << message; diff --git a/tensorflow/core/platform/s3/s3_file_system.cc b/tensorflow/core/platform/s3/s3_file_system.cc index 397f26ec0b..ebda3a2065 100644 --- a/tensorflow/core/platform/s3/s3_file_system.cc +++ b/tensorflow/core/platform/s3/s3_file_system.cc @@ -14,11 +14,13 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/platform/s3/s3_file_system.h" #include "tensorflow/core/lib/io/path.h" +#include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/core/platform/mutex.h" #include "tensorflow/core/platform/s3/aws_logging.h" #include "tensorflow/core/platform/s3/s3_crypto.h" #include +#include #include #include #include @@ -54,13 +56,37 @@ Aws::Client::ClientConfiguration& GetDefaultClientConfig() { cfg.endpointOverride = Aws::String(endpoint); } const char* region = getenv("AWS_REGION"); + if (!region) { + // TODO (yongtang): `S3_REGION` should be deprecated after 2.0. + region = getenv("S3_REGION"); + } if (region) { cfg.region = Aws::String(region); } else { - // TODO (yongtang): `S3_REGION` should be deprecated after 2.0. - const char* region = getenv("S3_REGION"); - if (region) { - cfg.region = Aws::String(region); + // Load config file (e.g., ~/.aws/config) only if AWS_SDK_LOAD_CONFIG + // is set with a truthy value. + const char* load_config_env = getenv("AWS_SDK_LOAD_CONFIG"); + string load_config = + load_config_env ? str_util::Lowercase(load_config_env) : ""; + if (load_config == "true" || load_config == "1") { + Aws::String config_file; + // If AWS_CONFIG_FILE is set then use it, otherwise use ~/.aws/config. + const char* config_file_env = getenv("AWS_CONFIG_FILE"); + if (config_file_env) { + config_file = config_file_env; + } else { + const char* home_env = getenv("HOME"); + if (home_env) { + config_file = home_env; + config_file += "/.aws/config"; + } + } + Aws::Config::AWSConfigFileProfileConfigLoader loader(config_file); + loader.Load(); + auto profiles = loader.GetProfiles(); + if (!profiles["default"].GetRegion().empty()) { + cfg.region = profiles["default"].GetRegion(); + } } } const char* use_https = getenv("S3_USE_HTTPS"); @@ -79,6 +105,22 @@ Aws::Client::ClientConfiguration& GetDefaultClientConfig() { cfg.verifySSL = true; } } + const char* connect_timeout = getenv("S3_CONNECT_TIMEOUT_MSEC"); + if (connect_timeout) { + int64 timeout; + + if (strings::safe_strto64(connect_timeout, &timeout)) { + cfg.connectTimeoutMs = timeout; + } + } + const char* request_timeout = getenv("S3_REQUEST_TIMEOUT_MSEC"); + if (request_timeout) { + int64 timeout; + + if (strings::safe_strto64(request_timeout, &timeout)) { + cfg.requestTimeoutMs = timeout; + } + } init = true; } diff --git a/tensorflow/core/public/version.h b/tensorflow/core/public/version.h index 836efc079f..67da7bf452 100644 --- a/tensorflow/core/public/version.h +++ b/tensorflow/core/public/version.h @@ -24,7 +24,7 @@ limitations under the License. // TF_VERSION_SUFFIX is non-empty for pre-releases (e.g. "-alpha", "-alpha.1", // "-beta", "-rc", "-rc.1") -#define TF_VERSION_SUFFIX "-rc0" +#define TF_VERSION_SUFFIX "-rc1" #define TF_STR_HELPER(x) #x #define TF_STR(x) TF_STR_HELPER(x) diff --git a/tensorflow/docs_src/api_guides/python/python_io.md b/tensorflow/docs_src/api_guides/python/python_io.md index a5444408fe..06282e49d5 100644 --- a/tensorflow/docs_src/api_guides/python/python_io.md +++ b/tensorflow/docs_src/api_guides/python/python_io.md @@ -14,16 +14,16 @@ suitable if fast sharding or other non-sequential access is desired. ## TFRecords Format Details -A TFRecords file contains a sequence of strings with CRC hashes. Each record -has the format +A TFRecords file contains a sequence of strings with CRC32C (32-bit CRC using +the Castagnoli polynomial) hashes. Each record has the format uint64 length uint32 masked_crc32_of_length byte data[length] uint32 masked_crc32_of_data -and the records are concatenated together to produce the file. The CRC32s -are [described here](https://en.wikipedia.org/wiki/Cyclic_redundancy_check), -and the mask of a CRC is +and the records are concatenated together to produce the file. CRCs are +[described here](https://en.wikipedia.org/wiki/Cyclic_redundancy_check), and +the mask of a CRC is masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul diff --git a/tensorflow/docs_src/install/install_c.md b/tensorflow/docs_src/install/install_c.md index d79cd1415d..ba1a4118ae 100644 --- a/tensorflow/docs_src/install/install_c.md +++ b/tensorflow/docs_src/install/install_c.md @@ -38,7 +38,7 @@ enable TensorFlow for C: OS="linux" # Change to "darwin" for macOS TARGET_DIRECTORY="/usr/local" curl -L \ - "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-${OS}-x86_64-1.5.0-rc0.tar.gz" | + "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-${OS}-x86_64-1.5.0-rc1.tar.gz" | sudo tar -C $TARGET_DIRECTORY -xz The `tar` command extracts the TensorFlow C library into the `lib` diff --git a/tensorflow/docs_src/install/install_go.md b/tensorflow/docs_src/install/install_go.md index 49f5350405..87cc647317 100644 --- a/tensorflow/docs_src/install/install_go.md +++ b/tensorflow/docs_src/install/install_go.md @@ -38,7 +38,7 @@ steps to install this library and enable TensorFlow for Go: TF_TYPE="cpu" # Change to "gpu" for GPU support TARGET_DIRECTORY='/usr/local' curl -L \ - "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-$(go env GOOS)-x86_64-1.5.0-rc0.tar.gz" | + "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-$(go env GOOS)-x86_64-1.5.0-rc1.tar.gz" | sudo tar -C $TARGET_DIRECTORY -xz The `tar` command extracts the TensorFlow C library into the `lib` diff --git a/tensorflow/docs_src/install/install_java.md b/tensorflow/docs_src/install/install_java.md index 47b1251427..37e109a6e4 100644 --- a/tensorflow/docs_src/install/install_java.md +++ b/tensorflow/docs_src/install/install_java.md @@ -36,7 +36,7 @@ following to the project's `pom.xml` to use the TensorFlow Java APIs: org.tensorflow tensorflow - 1.5.0-rc0 + 1.5.0-rc1 ``` @@ -65,7 +65,7 @@ As an example, these steps will create a Maven project that uses TensorFlow: org.tensorflow tensorflow - 1.5.0-rc0 + 1.5.0-rc1 @@ -123,12 +123,12 @@ instead: org.tensorflow libtensorflow - 1.4.0 + 1.5.0-rc1 org.tensorflow libtensorflow_jni_gpu - 1.4.0 + 1.5.0-rc1 ``` @@ -147,7 +147,7 @@ refer to the simpler instructions above instead. Take the following steps to install TensorFlow for Java on Linux or macOS: 1. Download - [libtensorflow.jar](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.5.0-rc0.jar), + [libtensorflow.jar](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.5.0-rc1.jar), which is the TensorFlow Java Archive (JAR). 2. Decide whether you will run TensorFlow for Java on CPU(s) only or with @@ -166,7 +166,7 @@ Take the following steps to install TensorFlow for Java on Linux or macOS: OS=$(uname -s | tr '[:upper:]' '[:lower:]') mkdir -p ./jni curl -L \ - "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-${TF_TYPE}-${OS}-x86_64-1.5.0-rc0.tar.gz" | + "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-${TF_TYPE}-${OS}-x86_64-1.5.0-rc1.tar.gz" | tar -xz -C ./jni ### Install on Windows @@ -174,10 +174,10 @@ Take the following steps to install TensorFlow for Java on Linux or macOS: Take the following steps to install TensorFlow for Java on Windows: 1. Download - [libtensorflow.jar](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.5.0-rc0.jar), + [libtensorflow.jar](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.5.0-rc1.jar), which is the TensorFlow Java Archive (JAR). 2. Download the following Java Native Interface (JNI) file appropriate for - [TensorFlow for Java on Windows](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-cpu-windows-x86_64-1.5.0-rc0.zip). + [TensorFlow for Java on Windows](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-cpu-windows-x86_64-1.5.0-rc1.zip). 3. Extract this .zip file. @@ -225,7 +225,7 @@ must be part of your `classpath`. For example, you can include the downloaded `.jar` in your `classpath` by using the `-cp` compilation flag as follows: -

javac -cp libtensorflow-1.5.0-rc0.jar HelloTF.java
+
javac -cp libtensorflow-1.5.0-rc1.jar HelloTF.java
### Running @@ -239,11 +239,11 @@ two files are available to the JVM: For example, the following command line executes the `HelloTF` program on Linux and macOS X: -
java -cp libtensorflow-1.5.0-rc0.jar:. -Djava.library.path=./jni HelloTF
+
java -cp libtensorflow-1.5.0-rc1.jar:. -Djava.library.path=./jni HelloTF
And the following command line executes the `HelloTF` program on Windows: -
java -cp libtensorflow-1.5.0-rc0.jar;. -Djava.library.path=jni HelloTF
+
java -cp libtensorflow-1.5.0-rc1.jar;. -Djava.library.path=jni HelloTF
If the program prints Hello from version, you've successfully installed TensorFlow for Java and are ready to use the API. If the program diff --git a/tensorflow/docs_src/install/install_linux.md b/tensorflow/docs_src/install/install_linux.md index bb1d9a9f57..03f12dff08 100644 --- a/tensorflow/docs_src/install/install_linux.md +++ b/tensorflow/docs_src/install/install_linux.md @@ -188,7 +188,7 @@ Take the following steps to install TensorFlow with Virtualenv: Virtualenv environment:
(tensorflow)$ pip3 install --upgrade \
-     https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc0-cp34-cp34m-linux_x86_64.whl
+ https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc1-cp34-cp34m-linux_x86_64.whl
If you encounter installation problems, see [Common Installation Problems](#common_installation_problems). @@ -293,7 +293,7 @@ take the following steps:
      $ sudo pip3 install --upgrade \
-     https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc0-cp34-cp34m-linux_x86_64.whl
+     https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc1-cp34-cp34m-linux_x86_64.whl
      
If this step fails, see @@ -480,7 +480,7 @@ Take the following steps to install TensorFlow in an Anaconda environment:
      (tensorflow)$ pip install --ignore-installed --upgrade \
-     https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc0-cp34-cp34m-linux_x86_64.whl
+ https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc1-cp34-cp34m-linux_x86_64.whl @@ -648,14 +648,14 @@ This section documents the relevant values for Linux installations. CPU only:
-https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc0-cp27-none-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc1-cp27-none-linux_x86_64.whl
 
GPU support:
-https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.5.0rc0-cp27-none-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.5.0rc1-cp27-none-linux_x86_64.whl
 
Note that GPU support requires the NVIDIA hardware and software described in @@ -667,14 +667,14 @@ Note that GPU support requires the NVIDIA hardware and software described in CPU only:
-https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc0-cp34-cp34m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc1-cp34-cp34m-linux_x86_64.whl
 
GPU support:
-https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.5.0rc0-cp34-cp34m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.5.0rc1-cp34-cp34m-linux_x86_64.whl
 
Note that GPU support requires the NVIDIA hardware and software described in @@ -686,14 +686,14 @@ Note that GPU support requires the NVIDIA hardware and software described in CPU only:
-https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc0-cp35-cp35m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc1-cp35-cp35m-linux_x86_64.whl
 
GPU support:
-https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.5.0rc0-cp35-cp35m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.5.0rc1-cp35-cp35m-linux_x86_64.whl
 
@@ -705,14 +705,14 @@ Note that GPU support requires the NVIDIA hardware and software described in CPU only:
-https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc0-cp36-cp36m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.5.0rc1-cp36-cp36m-linux_x86_64.whl
 
GPU support:
-https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.5.0rc0-cp36-cp36m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.5.0rc1-cp36-cp36m-linux_x86_64.whl
 
diff --git a/tensorflow/docs_src/install/install_mac.md b/tensorflow/docs_src/install/install_mac.md index cf1c5157f8..e13ddadab7 100644 --- a/tensorflow/docs_src/install/install_mac.md +++ b/tensorflow/docs_src/install/install_mac.md @@ -115,7 +115,7 @@ Take the following steps to install TensorFlow with Virtualenv: TensorFlow in the active Virtualenv is as follows:
 $ pip3 install --upgrade \
-     https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc0-py2-none-any.whl
+ https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc1-py2-none-any.whl If you encounter installation problems, see [Common Installation Problems](#common-installation-problems). @@ -238,7 +238,7 @@ take the following steps: issue the following command:
 $ sudo pip3 install --upgrade \
-     https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc0-py2-none-any.whl 
+ https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc1-py2-none-any.whl If the preceding command fails, see [installation problems](#common-installation-problems). @@ -347,7 +347,7 @@ Take the following steps to install TensorFlow in an Anaconda environment: TensorFlow for Python 2.7:
 (targetDirectory)$ pip install --ignore-installed --upgrade \
-     https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc0-py2-none-any.whl
+ https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc1-py2-none-any.whl @@ -520,7 +520,7 @@ This section documents the relevant values for Mac OS installations.
-https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc0-py2-none-any.whl
+https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc1-py2-none-any.whl
 
@@ -528,5 +528,5 @@ https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc0-py2-none-a
-https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc0-py3-none-any.whl
+https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.5.0rc1-py3-none-any.whl
 
diff --git a/tensorflow/docs_src/install/install_sources.md b/tensorflow/docs_src/install/install_sources.md index 90e93f56c5..f494cc7a7c 100644 --- a/tensorflow/docs_src/install/install_sources.md +++ b/tensorflow/docs_src/install/install_sources.md @@ -361,10 +361,10 @@ Invoke `pip install` to install that pip package. The filename of the `.whl` file depends on your platform. For example, the following command will install the pip package -for TensorFlow 1.5.0rc0 on Linux: +for TensorFlow 1.5.0rc1 on Linux:
-$ sudo pip install /tmp/tensorflow_pkg/tensorflow-1.5.0rc0-py2-none-any.whl
+$ sudo pip install /tmp/tensorflow_pkg/tensorflow-1.5.0rc1-py2-none-any.whl
 
## Validate your installation @@ -462,9 +462,12 @@ Stack Overflow and specify the `tensorflow` tag. **Linux** + + + - + @@ -477,8 +480,9 @@ Stack Overflow and specify the `tensorflow` tag. **Mac**
Version:CPU/GPU:Python Version:Compiler:Build Tools:cuDNN:CUDA:
tensorflow-1.5.0-rc1CPU2.7, 3.3-3.6GCC 4.8Bazel 0.8.0N/AN/A
tensorflow_gpu-1.5.0-rc1GPU2.7, 3.3-3.6GCC 4.8Bazel 0.8.079
tensorflow-1.4.0CPU2.7, 3.3-3.6GCC 4.8Bazel 0.5.4N/AN/A
tensorflow_gpu-1.4.0GPU2.7, 3.3-3.6GCC 4.8Bazel 0.5.468
tensorflow-1.3.0CPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.5N/AN/A
tensorflow-1.3.0CPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.5N/AN/A
tensorflow_gpu-1.3.0GPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.568
tensorflow-1.2.0CPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.5N/AN/A
tensorflow_gpu-1.2.0GPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.55.18
+ - + @@ -489,6 +493,8 @@ Stack Overflow and specify the `tensorflow` tag. **Windows**
Version:CPU/GPU:Python Version:Compiler:Build Tools:cuDNN:CUDA:
tensorflow-1.5.0-rc1CPU2.7, 3.3-3.6Clang from xcodeBazel 0.8.1N/AN/A
tensorflow-1.4.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.5.4N/AN/A
tensorflow-1.3.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.5N/AN/A
tensorflow-1.3.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.5N/AN/A
tensorflow-1.2.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.5N/AN/A
tensorflow-1.1.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.2N/AN/A
tensorflow_gpu-1.1.0GPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.25.18
+ + diff --git a/tensorflow/examples/tutorials/word2vec/word2vec_basic.py b/tensorflow/examples/tutorials/word2vec/word2vec_basic.py index 87cd95165e..7d1650f05e 100644 --- a/tensorflow/examples/tutorials/word2vec/word2vec_basic.py +++ b/tensorflow/examples/tutorials/word2vec/word2vec_basic.py @@ -21,6 +21,8 @@ from __future__ import print_function import collections import math import os +import sys +import argparse import random from tempfile import gettempdir import zipfile @@ -30,6 +32,24 @@ from six.moves import urllib from six.moves import xrange # pylint: disable=redefined-builtin import tensorflow as tf +from tensorflow.contrib.tensorboard.plugins import projector + +# Give a folder path as an argument with '--log_dir' to save +# TensorBoard summaries. Default is a log folder in current directory. +current_path = os.path.dirname(os.path.realpath(sys.argv[0])) + +parser = argparse.ArgumentParser() +parser.add_argument( + '--log_dir', + type=str, + default=os.path.join(current_path, 'log'), + help='The log directory for TensorBoard summaries.') +FLAGS, unparsed = parser.parse_known_args() + +# Create the directory for TensorBoard variables if there is not. +if not os.path.exists(FLAGS.log_dir): + os.makedirs(FLAGS.log_dir) + # Step 1: Download the data. url = 'http://mattmahoney.net/dc/' @@ -156,38 +176,47 @@ graph = tf.Graph() with graph.as_default(): # Input data. - train_inputs = tf.placeholder(tf.int32, shape=[batch_size]) - train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1]) - valid_dataset = tf.constant(valid_examples, dtype=tf.int32) + with tf.name_scope('inputs'): + train_inputs = tf.placeholder(tf.int32, shape=[batch_size]) + train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1]) + valid_dataset = tf.constant(valid_examples, dtype=tf.int32) # Ops and variables pinned to the CPU because of missing GPU implementation with tf.device('/cpu:0'): # Look up embeddings for inputs. - embeddings = tf.Variable( - tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0)) - embed = tf.nn.embedding_lookup(embeddings, train_inputs) + with tf.name_scope('embeddings'): + embeddings = tf.Variable( + tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0)) + embed = tf.nn.embedding_lookup(embeddings, train_inputs) # Construct the variables for the NCE loss - nce_weights = tf.Variable( - tf.truncated_normal([vocabulary_size, embedding_size], - stddev=1.0 / math.sqrt(embedding_size))) - nce_biases = tf.Variable(tf.zeros([vocabulary_size])) + with tf.name_scope('weights'): + nce_weights = tf.Variable( + tf.truncated_normal([vocabulary_size, embedding_size], + stddev=1.0 / math.sqrt(embedding_size))) + with tf.name_scope('biases'): + nce_biases = tf.Variable(tf.zeros([vocabulary_size])) # Compute the average NCE loss for the batch. # tf.nce_loss automatically draws a new sample of the negative labels each # time we evaluate the loss. # Explanation of the meaning of NCE loss: # http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/ - loss = tf.reduce_mean( - tf.nn.nce_loss(weights=nce_weights, - biases=nce_biases, - labels=train_labels, - inputs=embed, - num_sampled=num_sampled, - num_classes=vocabulary_size)) + with tf.name_scope('loss'): + loss = tf.reduce_mean( + tf.nn.nce_loss(weights=nce_weights, + biases=nce_biases, + labels=train_labels, + inputs=embed, + num_sampled=num_sampled, + num_classes=vocabulary_size)) + + # Add the loss value as a scalar to summary. + tf.summary.scalar('loss', loss) # Construct the SGD optimizer using a learning rate of 1.0. - optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss) + with tf.name_scope('optimizer'): + optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss) # Compute the cosine similarity between minibatch examples and all embeddings. norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True)) @@ -197,13 +226,22 @@ with graph.as_default(): similarity = tf.matmul( valid_embeddings, normalized_embeddings, transpose_b=True) + # Merge all summaries. + merged = tf.summary.merge_all() + # Add variable initializer. init = tf.global_variables_initializer() + # Create a saver. + saver = tf.train.Saver() + # Step 5: Begin training. num_steps = 100001 with tf.Session(graph=graph) as session: + # Open a writer to write summaries. + writer = tf.summary.FileWriter(FLAGS.log_dir, session.graph) + # We must initialize all variables before we use them. init.run() print('Initialized') @@ -214,10 +252,21 @@ with tf.Session(graph=graph) as session: batch_size, num_skips, skip_window) feed_dict = {train_inputs: batch_inputs, train_labels: batch_labels} + # Define metadata variable. + run_metadata = tf.RunMetadata() + # We perform one update step by evaluating the optimizer op (including it # in the list of returned values for session.run() - _, loss_val = session.run([optimizer, loss], feed_dict=feed_dict) + # Also, evaluate the merged op to get all summaries from the returned "summary" variable. + # Feed metadata variable to session for visualizing the graph in TensorBoard. + _, summary, loss_val = session.run([optimizer, merged, loss], feed_dict=feed_dict, run_metadata=run_metadata) average_loss += loss_val + + # Add returned summaries to writer in each step. + writer.add_summary(summary, step) + # Add metadata to visualize the graph for the last run. + if step == (num_steps - 1): + writer.add_run_metadata(run_metadata, 'step%d' % step) if step % 2000 == 0: if step > 0: @@ -240,6 +289,23 @@ with tf.Session(graph=graph) as session: print(log_str) final_embeddings = normalized_embeddings.eval() + # Write corresponding labels for the embeddings. + with open(FLAGS.log_dir + '/metadata.tsv', 'w') as f: + for i in xrange(vocabulary_size): + f.write(reverse_dictionary[i] + '\n') + + # Save the model for checkpoints. + saver.save(session, os.path.join(FLAGS.log_dir, "model.ckpt")) + + # Create a configuration for visualizing embeddings with the labels in TensorBoard. + config = projector.ProjectorConfig() + embedding_conf = config.embeddings.add() + embedding_conf.tensor_name = embeddings.name + embedding_conf.metadata_path = os.path.join(FLAGS.log_dir, 'metadata.tsv') + projector.visualize_embeddings(writer, config) + +writer.close() + # Step 6: Visualize the embeddings. diff --git a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py index 53c8be1d1d..eac1c1960d 100644 --- a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright 2017 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -301,6 +302,27 @@ class BatchDatasetTest(test.TestCase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + def testPaddedBatchDatasetUnicode(self): + # See GitHub issue 16149 + def generator(): + data = [ + [u'Простой', u'тест', u'юникода'], + [u'никогда', u'не', u'бывает', u'простым']] + + for seq in data: + yield seq, [0, 1, 2, 3] + + dataset = dataset_ops.Dataset.from_generator( + generator, + (dtypes.string, dtypes.int32), + (tensor_shape.TensorShape([None]), tensor_shape.TensorShape([None]))) + padded_dataset = dataset.padded_batch(2, padded_shapes=([None], [None]), + padding_values=('', 0)) + with self.test_session() as sess: + next_element = padded_dataset.make_one_shot_iterator().get_next() + sess.run(next_element) + + def testPaddedBatchDatasetShapeSpecifications(self): int_placeholder = array_ops.placeholder(dtypes.int32) float_placeholder = array_ops.placeholder(dtypes.float32) diff --git a/tensorflow/python/estimator/estimator.py b/tensorflow/python/estimator/estimator.py index b4c6b2747e..2e914fa7e0 100644 --- a/tensorflow/python/estimator/estimator.py +++ b/tensorflow/python/estimator/estimator.py @@ -128,9 +128,10 @@ class Estimator(object): model_dir: Directory to save model parameters, graph and etc. This can also be used to load checkpoints from the directory into a estimator to - continue training a previously saved model. If `None`, the model_dir in - `config` will be used if set. If both are set, they must be same. If - both are `None`, a temporary directory will be used. + continue training a previously saved model. If `PathLike` object, the + path will be resolved. If `None`, the model_dir in `config` will be used + if set. If both are set, they must be same. If both are `None`, a + temporary directory will be used. config: Configuration object. params: `dict` of hyper parameters that will be passed into `model_fn`. Keys are names of parameters, values are basic python types. @@ -158,6 +159,7 @@ class Estimator(object): self._config = config # Model directory. + model_dir = compat.path_to_str(model_dir) if (model_dir is not None) and (self._config.model_dir is not None): if model_dir != self._config.model_dir: # TODO(alanyee): remove this suppression after it is no longer needed diff --git a/tensorflow/python/estimator/run_config.py b/tensorflow/python/estimator/run_config.py index 894005550d..61a537022b 100644 --- a/tensorflow/python/estimator/run_config.py +++ b/tensorflow/python/estimator/run_config.py @@ -27,6 +27,7 @@ import six from tensorflow.core.protobuf import config_pb2 from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training import server_lib +from tensorflow.python.util import compat _USE_DEFAULT = object() @@ -399,7 +400,8 @@ class RunConfig(object): Args: model_dir: directory where model parameters, graph, etc are saved. If - `None`, will use a default value set by the Estimator. + `PathLike` object, the path will be resolved. If `None`, will use a + default value set by the Estimator. tf_random_seed: Random seed for TensorFlow initializers. Setting this value allows consistency between reruns. save_summary_steps: Save summaries every this many steps. @@ -442,7 +444,7 @@ class RunConfig(object): if tf_config: logging.info('TF_CONFIG environment variable: %s', tf_config) - model_dir = _get_model_dir(tf_config, model_dir) + model_dir = _get_model_dir(tf_config, compat.path_to_str(model_dir)) RunConfig._replace( self, diff --git a/tensorflow/python/framework/constant_op.py b/tensorflow/python/framework/constant_op.py index 0a56d3f64d..d3d8c9c154 100644 --- a/tensorflow/python/framework/constant_op.py +++ b/tensorflow/python/framework/constant_op.py @@ -60,7 +60,6 @@ def _eager_reshape(tensor, shape, ctx): attr_t = tensor._datatype_enum() # pylint: disable=protected-access attr_tshape, (shape,) = execute.args_to_matching_eager( [shape], ctx, dtypes.int32) - attr_tshape = attr_tshape inputs_flat = [tensor, shape] attrs = ("T", attr_t, "Tshape", attr_tshape) result, = execute.execute( diff --git a/tensorflow/python/kernel_tests/conv1d_test.py b/tensorflow/python/kernel_tests/conv1d_test.py index d92797a7d3..e2e6205911 100644 --- a/tensorflow/python/kernel_tests/conv1d_test.py +++ b/tensorflow/python/kernel_tests/conv1d_test.py @@ -30,27 +30,29 @@ from tensorflow.python.platform import test class Conv1DTest(test.TestCase): def testBasic(self): - """Test that argument passing to conv2d is handled properly.""" - - x = constant_op.constant([1, 2, 3, 4], dtype=dtypes.float32) - x = array_ops.expand_dims(x, 0) # Add batch dimension - x = array_ops.expand_dims(x, 2) # And depth dimension - filters = constant_op.constant([2, 1], dtype=dtypes.float32) - filters = array_ops.expand_dims(filters, 1) # in_channels - filters = array_ops.expand_dims(filters, 2) # out_channels - # Filters is 2x1x1 - for stride in [1, 2]: - with self.test_session(use_gpu=test.is_gpu_available()): - c = nn_ops.conv1d(x, filters, stride, padding="VALID") - reduced = array_ops.squeeze(c) - output = reduced.eval() - if stride == 1: - self.assertEqual(len(output), 3) - self.assertAllClose(output, - [2 * 1 + 1 * 2, 2 * 2 + 1 * 3, 2 * 3 + 1 * 4]) - else: - self.assertEqual(len(output), 2) - self.assertAllClose(output, [2 * 1 + 1 * 2, 2 * 3 + 1 * 4]) + """Test that argument passing to conv1d is handled properly.""" + # TODO(yongtang): dtypes.float64 can only be enabled once conv2d support + # dtypes.float64, as conv1d implicitly calls conv2d after expand_dims. + for dtype in [dtypes.float16, dtypes.float32]: + x = constant_op.constant([1, 2, 3, 4], dtype=dtype) + x = array_ops.expand_dims(x, 0) # Add batch dimension + x = array_ops.expand_dims(x, 2) # And depth dimension + filters = constant_op.constant([2, 1], dtype=dtype) + filters = array_ops.expand_dims(filters, 1) # in_channels + filters = array_ops.expand_dims(filters, 2) # out_channels + # Filters is 2x1x1 + for stride in [1, 2]: + with self.test_session(use_gpu=test.is_gpu_available()): + c = nn_ops.conv1d(x, filters, stride, padding="VALID") + reduced = array_ops.squeeze(c) + output = reduced.eval() + if stride == 1: + self.assertEqual(len(output), 3) + self.assertAllClose(output, + [2 * 1 + 1 * 2, 2 * 2 + 1 * 3, 2 * 3 + 1 * 4]) + else: + self.assertEqual(len(output), 2) + self.assertAllClose(output, [2 * 1 + 1 * 2, 2 * 3 + 1 * 4]) def testConv1DTranspose(self): with self.test_session(): diff --git a/tensorflow/python/kernel_tests/cwise_ops_test.py b/tensorflow/python/kernel_tests/cwise_ops_test.py index cea12ea8ec..a91917b27f 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes as dtypes_lib +from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.ops import array_ops @@ -1168,6 +1169,32 @@ class BinaryOpTest(test.TestCase): self._compareCpu(x1, x2, np.arctan2, math_ops.atan2) self._compareGpu(x1, x2, np.arctan2, math_ops.atan2) + def testPowNegativeExponent(self): + for dtype in [np.int32, np.int64]: + with self.test_session(use_gpu=False) as sess: + with self.assertRaisesRegexp( + errors_impl.InvalidArgumentError, + "Integers to negative integer powers are not allowed"): + x = np.array([5, 2]).astype(dtype) + y = np.array([-2, 3]).astype(dtype) + sess.run(math_ops.pow(x, y)) + + with self.test_session(use_gpu=False) as sess: + with self.assertRaisesRegexp( + errors_impl.InvalidArgumentError, + "Integers to negative integer powers are not allowed"): + x = np.array([5, 2]).astype(dtype) + y = np.array([2, -3]).astype(dtype) + sess.run(math_ops.pow(x, y)) + + with self.test_session(use_gpu=False) as sess: + with self.assertRaisesRegexp( + errors_impl.InvalidArgumentError, + "Integers to negative integer powers are not allowed"): + x = np.array([5, 2]).astype(dtype) + y = -3 + sess.run(math_ops.pow(x, y)) + class ComparisonOpTest(test.TestCase): diff --git a/tensorflow/python/kernel_tests/metrics_test.py b/tensorflow/python/kernel_tests/metrics_test.py index 3358b78efd..e0e752147c 100644 --- a/tensorflow/python/kernel_tests/metrics_test.py +++ b/tensorflow/python/kernel_tests/metrics_test.py @@ -3628,7 +3628,8 @@ class MeanPerClassAccuracyTest(test.TestCase): predictions=array_ops.ones([10, 1]), labels=array_ops.ones([10, 1]), num_classes=2) - _assert_metric_variables(self, ('mean_accuracy/total_confusion_matrix:0',)) + _assert_metric_variables(self, ('mean_accuracy/count:0', + 'mean_accuracy/total:0')) def testMetricsCollections(self): my_collection_name = '__metrics__' @@ -3797,23 +3798,6 @@ class MeanPerClassAccuracyTest(test.TestCase): desired_output = np.mean([1.0 / 2.0, 2.0 / 3.0, 0.]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) - def testUpdateOpEvalIsAccumulatedConfusionMatrix(self): - predictions = array_ops.concat([ - constant_op.constant(0, shape=[5]), constant_op.constant(1, shape=[5]) - ], 0) - labels = array_ops.concat([ - constant_op.constant(0, shape=[3]), constant_op.constant(1, shape=[7]) - ], 0) - num_classes = 2 - with self.test_session() as sess: - mean_accuracy, update_op = metrics.mean_per_class_accuracy( - labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) - confusion_matrix = update_op.eval() - self.assertAllEqual([[3, 0], [2, 5]], confusion_matrix) - desired_mean_accuracy = np.mean([3. / 3., 5. / 7.]) - self.assertAlmostEqual(desired_mean_accuracy, mean_accuracy.eval()) - def testAllCorrect(self): predictions = array_ops.zeros([40]) labels = array_ops.zeros([40]) @@ -3822,7 +3806,7 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) sess.run(variables.local_variables_initializer()) - self.assertEqual(40, update_op.eval()[0]) + self.assertEqual(1.0, update_op.eval()[0]) self.assertEqual(1.0, mean_accuracy.eval()) def testAllWrong(self): @@ -3833,7 +3817,7 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) sess.run(variables.local_variables_initializer()) - self.assertAllEqual([[0, 0], [40, 0]], update_op.eval()) + self.assertAllEqual([0.0, 0.0], update_op.eval()) self.assertEqual(0., mean_accuracy.eval()) def testResultsWithSomeMissing(self): @@ -3852,8 +3836,9 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes, weights=weights) sess.run(variables.local_variables_initializer()) - self.assertAllEqual([[2, 0], [2, 4]], update_op.eval()) - desired_mean_accuracy = np.mean([2. / 2., 4. / 6.]) + desired_accuracy = np.array([2. / 2., 4. / 6.], dtype=np.float32) + self.assertAllEqual(desired_accuracy, update_op.eval()) + desired_mean_accuracy = np.mean(desired_accuracy) self.assertAlmostEqual(desired_mean_accuracy, mean_accuracy.eval()) diff --git a/tensorflow/python/kernel_tests/xent_op_test.py b/tensorflow/python/kernel_tests/xent_op_test.py index 43be08f8a1..c6c7c4e26c 100644 --- a/tensorflow/python/kernel_tests/xent_op_test.py +++ b/tensorflow/python/kernel_tests/xent_op_test.py @@ -240,6 +240,16 @@ class XentTest(test.TestCase): self._testXentWrapper(features, labels, dim=-1, use_gpu=False) self._testXentWrapper(features, labels, dim=-1, use_gpu=True) + def testZeroDimension(self): + features = np.zeros([0, 2, 4]).astype(np.float32) + labels = np.zeros([0, 2, 4]).astype(np.float32) + np_loss, _ = self._npXent(features, labels) + with self.test_session(use_gpu=True) as sess: + loss = nn_ops.softmax_cross_entropy_with_logits( + labels=labels, logits=features) + tf_loss = sess.run(loss) + self.assertAllEqual(np_loss, tf_loss) + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/layers/pooling.py b/tensorflow/python/layers/pooling.py index c6bd7aae07..ab06a3a408 100644 --- a/tensorflow/python/layers/pooling.py +++ b/tensorflow/python/layers/pooling.py @@ -63,14 +63,18 @@ class _Pooling1D(base.Layer): def call(self, inputs): # There is no TF op for 1D pooling, hence we make the inputs 4D. if self.data_format == 'channels_last': - inputs = array_ops.expand_dims(inputs, 2) - pool_shape = (1,) + self.pool_size + (1, 1) - strides = (1,) + self.strides + (1, 1) - data_format = 'NHWC' - else: + # input is NWC, make it NHWC inputs = array_ops.expand_dims(inputs, 1) + # pool on the W dim pool_shape = (1, 1) + self.pool_size + (1,) strides = (1, 1) + self.strides + (1,) + data_format = 'NHWC' + else: + # input is NCW, make it NCHW + inputs = array_ops.expand_dims(inputs, 2) + # pool on the W dim + pool_shape = (1, 1, 1) + self.pool_size + strides = (1, 1, 1) + self.strides data_format = 'NCHW' outputs = self.pool_function( @@ -81,9 +85,9 @@ class _Pooling1D(base.Layer): data_format=data_format) if self.data_format == 'channels_last': - return array_ops.squeeze(outputs, 2) - else: return array_ops.squeeze(outputs, 1) + else: + return array_ops.squeeze(outputs, 2) def compute_output_shape(self, input_shape): input_shape = tensor_shape.TensorShape(input_shape).as_list() diff --git a/tensorflow/python/layers/pooling_test.py b/tensorflow/python/layers/pooling_test.py index 589fee5f71..e4d4ed4a2a 100644 --- a/tensorflow/python/layers/pooling_test.py +++ b/tensorflow/python/layers/pooling_test.py @@ -110,19 +110,19 @@ class PoolingTest(test.TestCase): def testCreateMaxPooling1DChannelsFirst(self): width = 7 - images = random_ops.random_uniform((5, width, 4)) + images = random_ops.random_uniform((5, 4, width)) layer = pooling_layers.MaxPooling1D( 2, strides=2, data_format='channels_first') output = layer.apply(images) - self.assertListEqual(output.get_shape().as_list(), [5, 3, 4]) + self.assertListEqual(output.get_shape().as_list(), [5, 4, 3]) def testCreateAveragePooling1DChannelsFirst(self): width = 7 - images = random_ops.random_uniform((5, width, 4)) + images = random_ops.random_uniform((5, 4, width)) layer = pooling_layers.AveragePooling1D( 2, strides=2, data_format='channels_first') output = layer.apply(images) - self.assertListEqual(output.get_shape().as_list(), [5, 3, 4]) + self.assertListEqual(output.get_shape().as_list(), [5, 4, 3]) def testCreateMaxPooling3D(self): depth, height, width = 6, 7, 9 diff --git a/tensorflow/python/lib/core/py_func.cc b/tensorflow/python/lib/core/py_func.cc index dc56b39486..d3bfa0ee33 100644 --- a/tensorflow/python/lib/core/py_func.cc +++ b/tensorflow/python/lib/core/py_func.cc @@ -31,6 +31,7 @@ limitations under the License. #include "tensorflow/python/lib/core/ndarray_tensor_bridge.h" #include "tensorflow/python/lib/core/py_util.h" #include "tensorflow/python/lib/core/safe_ptr.h" + #include namespace tensorflow { @@ -141,7 +142,8 @@ bool IsSingleNone(PyObject* obj) { return false; } std::array indices; - char* item_ptr = static_cast(PyArray_GetPtr(array_obj, indices.data())); + char* item_ptr = + static_cast(PyArray_GetPtr(array_obj, indices.data())); PyObject* item = PyArray_GETITEM(array_obj, item_ptr); CHECK(item); return item == Py_None; @@ -301,13 +303,22 @@ Status ConvertNdarrayToTensor(PyObject* obj, Tensor* ret) { if (PyBytes_AsStringAndSize(input_data[i], &el, &el_size) == -1) { #if PY_MAJOR_VERSION >= 3 el = PyUnicode_AsUTF8AndSize(input_data[i], &el_size); - if (!el) { +#else + el = nullptr; + if (PyUnicode_Check(input_data[i])) { + PyObject* unicode = PyUnicode_AsUTF8String(input_data[i]); + if (unicode) { + if (PyString_AsStringAndSize(unicode, &el, &el_size) == -1) { + Py_DECREF(unicode); + el = nullptr; + } + } + } #endif + if (!el) { return errors::Unimplemented("Unsupported object type ", input_data[i]->ob_type->tp_name); -#if PY_MAJOR_VERSION >= 3 } -#endif } tflat(i) = string(el, el_size); } diff --git a/tensorflow/python/ops/histogram_ops.py b/tensorflow/python/ops/histogram_ops.py index d46084a41f..b2de2e5015 100644 --- a/tensorflow/python/ops/histogram_ops.py +++ b/tensorflow/python/ops/histogram_ops.py @@ -17,6 +17,7 @@ Please see @{$python/histogram_ops} guide. +@@histogram_fixed_width_bins @@histogram_fixed_width """ @@ -33,6 +34,70 @@ from tensorflow.python.ops import math_ops from tensorflow.python.util.tf_export import tf_export +def histogram_fixed_width_bins(values, + value_range, + nbins=100, + dtype=dtypes.int32, + name=None): + """Bins the given values for use in a histogram. + + Given the tensor `values`, this operation returns a rank 1 `Tensor` + representing the indices of a histogram into which each element + of `values` would be binned. The bins are equal width and + determined by the arguments `value_range` and `nbins`. + + Args: + values: Numeric `Tensor`. + value_range: Shape [2] `Tensor` of same `dtype` as `values`. + values <= value_range[0] will be mapped to hist[0], + values >= value_range[1] will be mapped to hist[-1]. + nbins: Scalar `int32 Tensor`. Number of histogram bins. + dtype: dtype for returned histogram. + name: A name for this operation (defaults to 'histogram_fixed_width'). + + Returns: + A `Tensor` holding the indices of the binned values whose shape matches + `values`. + + Examples: + + ```python + # Bins will be: (-inf, 1), [1, 2), [2, 3), [3, 4), [4, inf) + nbins = 5 + value_range = [0.0, 5.0] + new_values = [-1.0, 0.0, 1.5, 2.0, 5.0, 15] + + with tf.get_default_session() as sess: + indices = tf.histogram_fixed_width_bins(new_values, value_range, nbins=5) + variables.global_variables_initializer().run() + sess.run(indices) => [0, 0, 1, 2, 4] + ``` + """ + with ops.name_scope(name, 'histogram_fixed_width_bins', + [values, value_range, nbins]) as scope: + values = ops.convert_to_tensor(values, name='values') + shape = array_ops.shape(values) + + values = array_ops.reshape(values, [-1]) + value_range = ops.convert_to_tensor(value_range, name='value_range') + nbins = ops.convert_to_tensor(nbins, dtype=dtypes.int32, name='nbins') + nbins_float = math_ops.cast(nbins, values.dtype) + + # Map tensor values that fall within value_range to [0, 1]. + scaled_values = math_ops.truediv(values - value_range[0], + value_range[1] - value_range[0], + name='scaled_values') + + # map tensor values within the open interval value_range to {0,.., nbins-1}, + # values outside the open interval will be zero or less, or nbins or more. + indices = math_ops.floor(nbins_float * scaled_values, name='indices') + + # Clip edge cases (e.g. value = value_range[1]) or "outliers." + indices = math_ops.cast( + clip_ops.clip_by_value(indices, 0, nbins_float - 1), dtypes.int32) + return array_ops.reshape(indices, shape) + + @tf_export('histogram_fixed_width') def histogram_fixed_width(values, value_range, diff --git a/tensorflow/python/ops/histogram_ops_test.py b/tensorflow/python/ops/histogram_ops_test.py index 19ad6cd2ba..80ee090575 100644 --- a/tensorflow/python/ops/histogram_ops_test.py +++ b/tensorflow/python/ops/histogram_ops_test.py @@ -21,11 +21,64 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import constant_op from tensorflow.python.ops import array_ops from tensorflow.python.ops import histogram_ops from tensorflow.python.platform import test +class BinValuesFixedWidth(test.TestCase): + + def test_empty_input_gives_all_zero_counts(self): + # Bins will be: + # (-inf, 1), [1, 2), [2, 3), [3, 4), [4, inf) + value_range = [0.0, 5.0] + values = [] + expected_bins = [] + with self.test_session(): + bins = histogram_ops.histogram_fixed_width_bins(values, value_range, nbins=5) + self.assertEqual(dtypes.int32, bins.dtype) + self.assertAllClose(expected_bins, bins.eval()) + + def test_1d_values_int32_output(self): + # Bins will be: + # (-inf, 1), [1, 2), [2, 3), [3, 4), [4, inf) + value_range = [0.0, 5.0] + values = [-1.0, 0.0, 1.5, 2.0, 5.0, 15] + expected_bins = [0, 0, 1, 2, 4, 4] + with self.test_session(): + bins = histogram_ops.histogram_fixed_width_bins( + values, value_range, nbins=5, dtype=dtypes.int64) + self.assertEqual(dtypes.int32, bins.dtype) + self.assertAllClose(expected_bins, bins.eval()) + + def test_1d_float64_values_int32_output(self): + # Bins will be: + # (-inf, 1), [1, 2), [2, 3), [3, 4), [4, inf) + value_range = np.float64([0.0, 5.0]) + values = np.float64([-1.0, 0.0, 1.5, 2.0, 5.0, 15]) + expected_bins = [0, 0, 1, 2, 4, 4] + with self.test_session(): + bins = histogram_ops.histogram_fixed_width_bins( + values, value_range, nbins=5) + self.assertEqual(dtypes.int32, bins.dtype) + self.assertAllClose(expected_bins, bins.eval()) + + def test_2d_values(self): + # Bins will be: + # (-inf, 1), [1, 2), [2, 3), [3, 4), [4, inf) + value_range = [0.0, 5.0] + values = constant_op.constant( + [[-1.0, 0.0, 1.5], [2.0, 5.0, 15]], + shape=(2, 3)) + expected_bins = [[0, 0, 1], [2, 4, 4]] + with self.test_session(): + bins = histogram_ops.histogram_fixed_width_bins( + values, value_range, nbins=5) + self.assertEqual(dtypes.int32, bins.dtype) + self.assertAllClose(expected_bins, bins.eval()) + + class HistogramFixedWidthTest(test.TestCase): def setUp(self): diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index d860a3b618..b713c44717 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -148,6 +148,28 @@ def _Check3DImage(image, require_static=True): return [] +def _Assert3DImage(image): + """Assert that we are working with a properly shaped image. + + Performs the check statically if possible (i.e. if the shape + is statically known). Otherwise adds a control dependency + to an assert op that checks the dynamic shape. + + Args: + image: 3-D Tensor of shape [height, width, channels] + + Raises: + ValueError: if `image.shape` is not a 3-vector. + + Returns: + If the shape of `image` could be verified statically, `image` is + returned unchanged, otherwise there will be a control dependency + added that asserts the correct dynamic shape. + """ + return control_flow_ops.with_dependencies( + _Check3DImage(image, require_static=False), image) + + def _CheckAtLeast3DImage(image, require_static=True): """Assert that we are working with properly shaped image. @@ -223,8 +245,7 @@ def random_flip_up_down(image, seed=None): """ with ops.name_scope(None, 'random_flip_up_down', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) result = control_flow_ops.cond(mirror_cond, @@ -255,8 +276,7 @@ def random_flip_left_right(image, seed=None): """ with ops.name_scope(None, 'random_flip_left_right', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) result = control_flow_ops.cond(mirror_cond, @@ -286,8 +306,7 @@ def flip_left_right(image): """ with ops.name_scope(None, 'flip_left_right', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) return fix_image_flip_shape(image, array_ops.reverse(image, [1], name=scope)) @@ -312,8 +331,7 @@ def flip_up_down(image): """ with ops.name_scope(None, 'flip_up_down', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) return fix_image_flip_shape(image, array_ops.reverse(image, [0], name=scope)) @@ -332,8 +350,7 @@ def rot90(image, k=1, name=None): """ with ops.name_scope(name, 'rot90', [image, k]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) k = ops.convert_to_tensor(k, dtype=dtypes.int32, name='k') k.get_shape().assert_has_rank(0) k = math_ops.mod(k, 4) @@ -373,8 +390,7 @@ def transpose_image(image): """ with ops.name_scope(None, 'transpose_image', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) return array_ops.transpose(image, [1, 0, 2], name=scope) @@ -410,8 +426,7 @@ def central_crop(image, central_fraction): if central_fraction == 1.0: return image - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) img_shape = array_ops.shape(image) depth = image.get_shape()[2] @@ -848,8 +863,7 @@ def per_image_standardization(image): """ with ops.name_scope(None, 'per_image_standardization', [image]) as scope: image = ops.convert_to_tensor(image, name='image') - image = control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + image = _Assert3DImage(image) num_pixels = math_ops.reduce_prod(array_ops.shape(image)) image = math_ops.cast(image, dtype=dtypes.float32) diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index 3a49d41c9e..80911ffe07 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -2833,6 +2833,16 @@ class PngTest(test_util.TensorFlowTestCase): class GifTest(test_util.TensorFlowTestCase): + def testOptimizedGifErrorString(self): + filename = "tensorflow/core/lib/gif/testdata/optimized.gif" + + with self.test_session(use_gpu=True) as sess: + gif = io_ops.read_file(filename) + image = image_ops.decode_gif(gif) + with self.assertRaisesRegexp( + errors.InvalidArgumentError, "can't process optimized gif"): + gif, image = sess.run([gif, image]) + def testValid(self): # Read some real GIFs prefix = "tensorflow/core/lib/gif/testdata/" diff --git a/tensorflow/python/ops/losses/losses_impl.py b/tensorflow/python/ops/losses/losses_impl.py index e292bccc2c..72508eb435 100644 --- a/tensorflow/python/ops/losses/losses_impl.py +++ b/tensorflow/python/ops/losses/losses_impl.py @@ -512,7 +512,7 @@ def mean_pairwise_squared_error( Raises: ValueError: If the shape of `predictions` doesn't match that of `labels` or - if the shape of `weights` is invalid. Also if `labels` or `predictions + if the shape of `weights` is invalid. Also if `labels` or `predictions` is None. """ if labels is None: diff --git a/tensorflow/python/ops/metrics_impl.py b/tensorflow/python/ops/metrics_impl.py index 92b3ff2250..2d77e26081 100644 --- a/tensorflow/python/ops/metrics_impl.py +++ b/tensorflow/python/ops/metrics_impl.py @@ -831,8 +831,8 @@ def mean_per_class_accuracy(labels, Calculates the accuracy for each class, then takes the mean of that. For estimation of the metric over a stream of data, the function creates an - `update_op` operation that updates these variables and returns the - `mean_accuracy`. + `update_op` operation that updates the accuracy of each class and returns + them. If `weights` is `None`, weights default to 1. Use weights of 0 to mask values. @@ -843,8 +843,8 @@ def mean_per_class_accuracy(labels, shape is [batch size] and type `int32` or `int64`. The tensor will be flattened if its rank > 1. num_classes: The possible number of labels the prediction task can - have. This value must be provided, since a confusion matrix of - dimension = [num_classes, num_classes] will be allocated. + have. This value must be provided, since two variables with shape = + [num_classes] will be allocated. weights: Optional `Tensor` whose rank is either 0, or the same rank as `labels`, and must be broadcastable to `labels` (i.e., all dimensions must be either `1`, or the same as the corresponding `labels` dimension). @@ -857,7 +857,7 @@ def mean_per_class_accuracy(labels, Returns: mean_accuracy: A `Tensor` representing the mean per class accuracy. - update_op: An operation that increments the confusion matrix. + update_op: An operation that updates the accuracy tensor. Raises: ValueError: If `predictions` and `labels` have mismatched shapes, or if @@ -872,27 +872,43 @@ def mean_per_class_accuracy(labels, with variable_scope.variable_scope(name, 'mean_accuracy', (predictions, labels, weights)): + labels = math_ops.to_int64(labels) + + # Flatten the input if its rank > 1. + if labels.get_shape().ndims > 1: + labels = array_ops.reshape(labels, [-1]) + + if predictions.get_shape().ndims > 1: + predictions = array_ops.reshape(predictions, [-1]) + # Check if shape is compatible. predictions.get_shape().assert_is_compatible_with(labels.get_shape()) - total_cm, update_op = _streaming_confusion_matrix( - labels, predictions, num_classes, weights=weights) + total = metric_variable([num_classes], dtypes.float32, name='total') + count = metric_variable([num_classes], dtypes.float32, name='count') - def compute_mean_accuracy(name): - """Compute the mean per class accuracy via the confusion matrix.""" - per_row_sum = math_ops.to_float(math_ops.reduce_sum(total_cm, 1)) - cm_diag = math_ops.to_float(array_ops.diag_part(total_cm)) - denominator = per_row_sum + ones = array_ops.ones([array_ops.size(labels)], dtypes.float32) - # If the value of the denominator is 0, set it to 1 to avoid - # zero division. - denominator = array_ops.where( - math_ops.greater(denominator, 0), denominator, - array_ops.ones_like(denominator)) - accuracies = math_ops.div(cm_diag, denominator) - return math_ops.reduce_mean(accuracies, name=name) + if labels.dtype != predictions.dtype: + predictions = math_ops.cast(predictions, labels.dtype) + is_correct = math_ops.to_float(math_ops.equal(predictions, labels)) + + if weights is not None: + if weights.get_shape().ndims > 1: + weights = array_ops.reshape(weights, [-1]) + weights = math_ops.to_float(weights) + + is_correct = is_correct * weights + ones = ones * weights + + update_total_op = state_ops.scatter_add(total, labels, ones) + update_count_op = state_ops.scatter_add(count, labels, is_correct) + + per_class_accuracy = _safe_div(count, total, None) - mean_accuracy_v = compute_mean_accuracy('mean_accuracy') + mean_accuracy_v = math_ops.reduce_mean(per_class_accuracy, + name='mean_accuracy') + update_op = _safe_div(update_count_op, update_total_op, name='update_op') if metrics_collections: ops.add_to_collections(metrics_collections, mean_accuracy_v) diff --git a/tensorflow/python/ops/nn_impl.py b/tensorflow/python/ops/nn_impl.py index 67eee1c29e..837ee02e64 100644 --- a/tensorflow/python/ops/nn_impl.py +++ b/tensorflow/python/ops/nn_impl.py @@ -196,7 +196,10 @@ def weighted_cross_entropy_with_logits(targets, logits, pos_weight, name=None): targets * -log(sigmoid(logits)) + (1 - targets) * -log(1 - sigmoid(logits)) - The argument `pos_weight` is used as a multiplier for the positive targets: + A value `pos_weights > 1` decreases the false negative count, hence increasing the recall. + Conversely setting `pos_weights < 1` decreases the false positive count and increases the precision. + This can be seen from the fact that `pos_weight` is introduced as a multiplicative coefficient for the positive targets term + in the loss expression: targets * -log(sigmoid(logits)) * pos_weight + (1 - targets) * -log(1 - sigmoid(logits)) diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 09aa45dae1..32b14f86b5 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -1558,7 +1558,8 @@ def leaky_relu(features, alpha=0.2, name=None): http://web.stanford.edu/~awni/papers/relu_hybrid_icml2013_final.pdf Args: - features: A `Tensor` representing preactivation values. + features: A `Tensor` representing preactivation values. Must be one of + the following types: `float16`, `float32`, `float64`, `int32`, `int64`. alpha: Slope of the activation function at x < 0. name: A name for the operation (optional). @@ -1567,7 +1568,9 @@ def leaky_relu(features, alpha=0.2, name=None): """ with ops.name_scope(name, "LeakyRelu", [features, alpha]): features = ops.convert_to_tensor(features, name="features") - alpha = ops.convert_to_tensor(alpha, name="alpha") + if features.dtype.is_integer: + features = math_ops.to_float(features) + alpha = ops.convert_to_tensor(alpha, dtype=features.dtype, name="alpha") return math_ops.maximum(alpha * features, features) @@ -2323,7 +2326,7 @@ def conv1d(value, filters, stride, padding, returned to the caller. Args: - value: A 3D `Tensor`. Must be of type `float32` or `float64`. + value: A 3D `Tensor`. Must be of type `float16` or `float32`. filters: A 3D `Tensor`. Must have the same type as `input`. stride: An `integer`. The number of entries by which the filter is moved right at each step. diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py index 66bc0803b7..6767564024 100644 --- a/tensorflow/python/ops/nn_test.py +++ b/tensorflow/python/ops/nn_test.py @@ -878,11 +878,13 @@ class LeakyReluTest(test_lib.TestCase): self.assertAllClose(inputs, outputs) def testValues(self): - np_values = np.array([-1.0, 0.0, 0.5, 1.0, 2.0], dtype=np.float32) - outputs = nn_ops.leaky_relu(constant_op.constant(np_values)) - with self.test_session() as sess: - outputs = sess.run(outputs) - self.assertAllClose(outputs, [-0.2, 0.0, 0.5, 1.0, 2.0]) + for dtype in [np.int32, np.int64, np.float16, np.float32, np.float64]: + np_values = np.array([-2, -1, 0, 1, 2], dtype=dtype) + outputs = nn_ops.leaky_relu(constant_op.constant(np_values)) + with self.test_session() as sess: + outputs = sess.run(outputs) + tol = 2e-3 if dtype == np.float16 else 1e-6 + self.assertAllClose(outputs, [-0.4, -0.2, 0.0, 1.0, 2.0], rtol=tol, atol=tol) class SwishTest(test_lib.TestCase): diff --git a/tensorflow/python/ops/rnn_cell_impl.py b/tensorflow/python/ops/rnn_cell_impl.py index 1bf5551aff..f1ac3e9baf 100644 --- a/tensorflow/python/ops/rnn_cell_impl.py +++ b/tensorflow/python/ops/rnn_cell_impl.py @@ -987,6 +987,10 @@ class DropoutWrapper(RNNCell): string = (str(self._seed) + salt).encode("utf-8") return int(hashlib.md5(string).hexdigest()[:8], 16) & 0x7FFFFFFF + @property + def wrapped_cell(self): + return self._cell + @property def state_size(self): return self._cell.state_size diff --git a/tensorflow/python/summary/summary.py b/tensorflow/python/summary/summary.py index 355593eca5..92c1fcadd2 100644 --- a/tensorflow/python/summary/summary.py +++ b/tensorflow/python/summary/summary.py @@ -286,12 +286,13 @@ def merge(inputs, collections=None, name=None): return val -def merge_all(key=_ops.GraphKeys.SUMMARIES): +def merge_all(key=_ops.GraphKeys.SUMMARIES, scope=None): """Merges all summaries collected in the default graph. Args: key: `GraphKey` used to collect the summaries. Defaults to `GraphKeys.SUMMARIES`. + scope: Optional scope used to filter the summary ops, using `re.match` Returns: If no summaries were collected, returns None. Otherwise returns a scalar @@ -310,7 +311,7 @@ def merge_all(key=_ops.GraphKeys.SUMMARIES): raise RuntimeError( 'Merging tf.summary.* ops is not compatible with eager execution. ' 'Use tf.contrib.summary instead.') - summary_ops = _ops.get_collection(key) + summary_ops = _ops.get_collection(key, scope=scope) if not summary_ops: return None else: diff --git a/tensorflow/python/util/compat.py b/tensorflow/python/util/compat.py index 07382d93df..3ab0bd16fa 100644 --- a/tensorflow/python/util/compat.py +++ b/tensorflow/python/util/compat.py @@ -21,6 +21,7 @@ In addition to the functions below, `as_str` converts an object to a `str`. @@as_bytes @@as_text @@as_str_any +@@path_to_str ## Types The compatibility module also provides the following types: @@ -108,6 +109,20 @@ def as_str_any(value): return str(value) +def path_to_str(path): + """Returns the file system path representation of a `PathLike` object, else as it is. + + Args: + path: An object that can be converted to path representation. + + Returns: + A `str` object. + """ + if hasattr(path, "__fspath__"): + path = as_str_any(path.__fspath__()) + return path + + # Numpy 1.8 scalars don't inherit from numbers.Integral in Python 3, so we # need to check them specifically. The same goes from Real and Complex. integral_types = (_numbers.Integral, _np.integer) diff --git a/tensorflow/tools/api/golden/tensorflow.compat.pbtxt b/tensorflow/tools/api/golden/tensorflow.compat.pbtxt index ccc6031400..bab480ff9b 100644 --- a/tensorflow/tools/api/golden/tensorflow.compat.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.compat.pbtxt @@ -32,4 +32,8 @@ tf_module { name: "as_text" argspec: "args=[\'bytes_or_text\', \'encoding\'], varargs=None, keywords=None, defaults=[\'utf-8\'], " } + member_method { + name: "path_to_str" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } } diff --git a/tensorflow/tools/api/golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt b/tensorflow/tools/api/golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt index f61a5a28e3..97edf245f6 100644 --- a/tensorflow/tools/api/golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.nn.rnn_cell.-dropout-wrapper.pbtxt @@ -88,6 +88,10 @@ tf_class { name: "weights" mtype: "" } + member { + name: "wrapped_cell" + mtype: "" + } member_method { name: "__init__" argspec: "args=[\'self\', \'cell\', \'input_keep_prob\', \'output_keep_prob\', \'state_keep_prob\', \'variational_recurrent\', \'input_size\', \'dtype\', \'seed\', \'dropout_state_filter_visitor\'], varargs=None, keywords=None, defaults=[\'1.0\', \'1.0\', \'1.0\', \'False\', \'None\', \'None\', \'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/tensorflow.pbtxt b/tensorflow/tools/api/golden/tensorflow.pbtxt index 35917e94ad..db1ed42185 100644 --- a/tensorflow/tools/api/golden/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.pbtxt @@ -1160,6 +1160,10 @@ tf_module { name: "histogram_fixed_width" argspec: "args=[\'values\', \'value_range\', \'nbins\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'100\', \"\", \'None\'], " } + member_method { + name: "histogram_fixed_width_bins" + argspec: "args=[\'values\', \'value_range\', \'nbins\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'100\', \"\", \'None\'], " + } member_method { name: "identity" argspec: "args=[\'input\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/api/golden/tensorflow.summary.pbtxt b/tensorflow/tools/api/golden/tensorflow.summary.pbtxt index 326e077d39..871ebb5247 100644 --- a/tensorflow/tools/api/golden/tensorflow.summary.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.summary.pbtxt @@ -50,7 +50,7 @@ tf_module { } member_method { name: "merge_all" - argspec: "args=[\'key\'], varargs=None, keywords=None, defaults=[\'summaries\'], " + argspec: "args=[\'key\', \'scope\'], varargs=None, keywords=None, defaults=[\'summaries\', \'None\'], " } member_method { name: "scalar" diff --git a/tensorflow/tools/benchmark/BUILD b/tensorflow/tools/benchmark/BUILD index caa6629c49..6ed2594e6a 100644 --- a/tensorflow/tools/benchmark/BUILD +++ b/tensorflow/tools/benchmark/BUILD @@ -61,10 +61,11 @@ tf_cc_test( # 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 \ +# bazel build tensorflow/core:android_tensorflow_lib \ # --crosstool_top=//external:android/crosstool \ # --cpu=armeabi-v7a \ # --host_crosstool_top=@bazel_tools//tools/cpp:toolchain +# --config monolithic tf_cc_binary( name = "benchmark_model", testonly = 1, diff --git a/tensorflow/tools/benchmark/README.md b/tensorflow/tools/benchmark/README.md index ca0da2d41b..e64af2bfe1 100644 --- a/tensorflow/tools/benchmark/README.md +++ b/tensorflow/tools/benchmark/README.md @@ -17,6 +17,7 @@ bazel build -c opt \ --crosstool_top=//external:android/crosstool \ --cpu=armeabi-v7a \ --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \ + --config monolithic \ tensorflow/tools/benchmark:benchmark_model ``` diff --git a/tensorflow/tools/ci_build/builds/libtensorflow.sh b/tensorflow/tools/ci_build/builds/libtensorflow.sh index aadf480d37..9b3ff0cba7 100755 --- a/tensorflow/tools/ci_build/builds/libtensorflow.sh +++ b/tensorflow/tools/ci_build/builds/libtensorflow.sh @@ -51,7 +51,7 @@ function build_libtensorflow_tarball() { rm -rf ${DIR} TARBALL_SUFFIX="${1}" - BAZEL_OPTS="-c opt" + BAZEL_OPTS="-c opt --cxxopt=-D_GLIBCXX_USE_CXX11_ABI=0" export CC_OPT_FLAGS='-mavx' if [ "${TF_NEED_CUDA}" == "1" ]; then BAZEL_OPTS="${BAZEL_OPTS} --config=cuda" diff --git a/tensorflow/tools/ci_build/ci_sanity.sh b/tensorflow/tools/ci_build/ci_sanity.sh index b728c878da..aa341b144c 100755 --- a/tensorflow/tools/ci_build/ci_sanity.sh +++ b/tensorflow/tools/ci_build/ci_sanity.sh @@ -26,6 +26,8 @@ SCRIPT_DIR=$( cd ${0%/*} && pwd -P ) source "${SCRIPT_DIR}/builds/builds_common.sh" +ROOT_DIR=$( cd "$SCRIPT_DIR/../../.." && pwd -P ) + # Helper functions die() { echo $@ @@ -418,15 +420,8 @@ do_bazel_nobuild() { } do_pip_smoke_test() { - BUILD_CMD="bazel build ${BAZEL_FLAGS} //tensorflow/tools/pip_package:pip_smoke_test" - ${BUILD_CMD} - cmd_status \ - "Pip smoke test has failed. Please make sure any new TensorFlow are added to the tensorflow/tools/pip_package:build_pip_package dependencies." - - RUN_CMD="bazel-bin/tensorflow/tools/pip_package/pip_smoke_test" - ${RUN_CMD} - cmd_status \ - "The pip smoke test failed." + cd "$ROOT_DIR/tensorflow/tools/pip_package" + python pip_smoke_test.py } do_code_link_check() { @@ -500,20 +495,23 @@ do_clang_format_check() { } do_check_load_py_test() { - BUILD_CMD="bazel build ${BAZEL_FLAGS} //tensorflow/tools/pip_package:check_load_py_test" - ${BUILD_CMD} - cmd_status \ - "check_load_py_test failed to build." + cd "$ROOT_DIR/tensorflow/tools/pip_package" + python check_load_py_test.py +} - BUILD_CMD="bazel-bin/tensorflow/tools/pip_package/check_load_py_test" - ${BUILD_CMD} - cmd_status \ - "check_load_py_test failed." +do_cmake_python_sanity() { + cd "$ROOT_DIR/tensorflow/contrib/cmake" + python -m unittest -v python_sanity_test +} + +do_check_futures_test() { + cd "$ROOT_DIR/tensorflow/tools/test" + python check_futures_test.py } # Supply all sanity step commands and descriptions -SANITY_STEPS=("do_pylint PYTHON2" "do_pylint PYTHON3" "do_buildifier" "do_bazel_nobuild" "do_pip_package_licenses_check" "do_lib_package_licenses_check" "do_java_package_licenses_check" "do_pip_smoke_test" "do_check_load_py_test" "do_code_link_check") -SANITY_STEPS_DESC=("Python 2 pylint" "Python 3 pylint" "buildifier check" "bazel nobuild" "pip: license check for external dependencies" "C library: license check for external dependencies" "Java Native Library: license check for external dependencies" "Pip Smoke Test: Checking py_test dependencies exist in pip package" "Check load py_test: Check that BUILD files with py_test target properly load py_test" "Code Link Check: Check there are no broken links") +SANITY_STEPS=("do_pylint PYTHON2" "do_pylint PYTHON3" "do_check_futures_test" "do_buildifier" "do_bazel_nobuild" "do_pip_package_licenses_check" "do_lib_package_licenses_check" "do_java_package_licenses_check" "do_pip_smoke_test" "do_check_load_py_test" "do_code_link_check" "do_cmake_python_sanity") +SANITY_STEPS_DESC=("Python 2 pylint" "Python 3 pylint" "Check that python files have certain __future__ imports" "buildifier check" "bazel nobuild" "pip: license check for external dependencies" "C library: license check for external dependencies" "Java Native Library: license check for external dependencies" "Pip Smoke Test: Checking py_test dependencies exist in pip package" "Check load py_test: Check that BUILD files with py_test target properly load py_test" "Code Link Check: Check there are no broken links" "Test entries in /tensorflow/contrib/cmake/python_{modules|protos|protos_cc}.txt for validity and consistency") INCREMENTAL_FLAG="" DEFAULT_BAZEL_CONFIGS="--config=hdfs --config=gcp" @@ -548,7 +546,10 @@ while [[ ${COUNTER} -lt "${#SANITY_STEPS[@]}" ]]; do "${SANITY_STEPS[COUNTER]} (${SANITY_STEPS_DESC[COUNTER]}) ===" echo "" + # subshell: don't leak variables or changes of working directory + ( ${SANITY_STEPS[COUNTER]} ${INCREMENTAL_FLAG} + ) RESULT=$? if [[ ${RESULT} != "0" ]]; then diff --git a/tensorflow/tools/docker/parameterized_docker_build.sh b/tensorflow/tools/docker/parameterized_docker_build.sh index 1214b6b0a3..fa867b65db 100755 --- a/tensorflow/tools/docker/parameterized_docker_build.sh +++ b/tensorflow/tools/docker/parameterized_docker_build.sh @@ -414,7 +414,7 @@ if [[ ! -z "${TF_DOCKER_BUILD_PUSH_WITH_CREDENTIALS}" ]]; then if [[ $? != "0" ]]; then die "FAIL: Unable to login. Invalid credentials." fi - docker push $1 + docker push "${FINAL_IMG}" if [[ $? == "0" ]]; then docker logout echo "Successfully pushed Docker image ${FINAL_IMG}" diff --git a/tensorflow/tools/pip_package/BUILD b/tensorflow/tools/pip_package/BUILD index ff5dd6a0b0..c789e2ba0c 100644 --- a/tensorflow/tools/pip_package/BUILD +++ b/tensorflow/tools/pip_package/BUILD @@ -47,27 +47,6 @@ py_binary( deps = ["//tensorflow:tensorflow_py"], ) -py_test( - name = "pip_smoke_test", - srcs = ["pip_smoke_test.py"], - data = [ - "//tensorflow:all_opensource_files", - ], - tags = [ - "manual", - "notap", - ], -) - -py_binary( - name = "check_load_py_test", - srcs = ["check_load_py_test.py"], - data = [ - "//tensorflow:all_opensource_files", - ], - srcs_version = "PY2AND3", -) - # On Windows, python binary is a zip file of runfiles tree. # Add everything to its data dependency for generating a runfiles tree # for building the pip package on Windows. diff --git a/tensorflow/tools/pip_package/check_load_py_test.py b/tensorflow/tools/pip_package/check_load_py_test.py index 79d11b08ce..e2fe1121d7 100644 --- a/tensorflow/tools/pip_package/check_load_py_test.py +++ b/tensorflow/tools/pip_package/check_load_py_test.py @@ -22,6 +22,9 @@ import os import subprocess +os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))) + + def check_output_despite_error(args): """Get output of args from command line, even if there are errors. diff --git a/tensorflow/tools/pip_package/pip_smoke_test.py b/tensorflow/tools/pip_package/pip_smoke_test.py index cddf9c8f44..8eee489e2d 100644 --- a/tensorflow/tools/pip_package/pip_smoke_test.py +++ b/tensorflow/tools/pip_package/pip_smoke_test.py @@ -23,8 +23,13 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import os import subprocess + +os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))) + + PIP_PACKAGE_QUERY_EXPRESSION = \ 'deps(//tensorflow/tools/pip_package:build_pip_package)' @@ -134,8 +139,8 @@ def main(): raise RuntimeError("""One or more dependencies are not in the pip package. Please either blacklist the dependencies in -tensorflow/tensorflow/tensorflow/tools/pip_package/pip_smoke_test.py -or add them to tensorflow/tensorflow/tensorflow/tools/pip_package/BUILD.""") +//tensorflow/tools/pip_package/pip_smoke_test.py +or add them to //tensorflow/tools/pip_package/BUILD.""") else: print("TEST PASSED") diff --git a/tensorflow/tools/pip_package/setup.py b/tensorflow/tools/pip_package/setup.py index b2ca4a43c1..62df6453fb 100644 --- a/tensorflow/tools/pip_package/setup.py +++ b/tensorflow/tools/pip_package/setup.py @@ -29,7 +29,7 @@ from setuptools.dist import Distribution # This version string is semver compatible, but incompatible with pip. # For pip, we will remove all '-' characters from this string, and use the # result for pip. -_VERSION = '1.5.0-rc0' +_VERSION = '1.5.0-rc1' REQUIRED_PACKAGES = [ 'absl-py >= 0.1.6', diff --git a/tensorflow/tools/test/BUILD b/tensorflow/tools/test/BUILD index 28d651e910..159a8c1cfb 100644 --- a/tensorflow/tools/test/BUILD +++ b/tensorflow/tools/test/BUILD @@ -104,12 +104,3 @@ filegroup( ), visibility = ["//tensorflow:__subpackages__"], ) - -py_test( - name = "check_futures_test", - size = "small", - srcs = ["check_futures_test.py"], - data = ["//tensorflow:all_opensource_files"], - srcs_version = "PY2AND3", - deps = ["@six_archive//:six"], -) diff --git a/tensorflow/tools/test/check_futures_test.py b/tensorflow/tools/test/check_futures_test.py index 1c07511888..9181c9bd4a 100644 --- a/tensorflow/tools/test/check_futures_test.py +++ b/tensorflow/tools/test/check_futures_test.py @@ -33,7 +33,7 @@ import re import six -BASE_DIR = os.path.normpath(os.path.join(__file__, '../../..')) +BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')) FUTURES_PATTERN = re.compile(r'^from __future__ import (\w+)\s*$') FUTURES_PATTERN_2 = re.compile( r'^from __future__ import (\w+), (\w+), (\w+)\s*$') diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index d17dc81024..79e14e0e92 100644 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -5,6 +5,7 @@ load("//third_party/mkl:build_defs.bzl", "mkl_repository") load("//third_party/git:git_configure.bzl", "git_configure") load("//third_party/py:python_configure.bzl", "python_configure") load("//third_party/sycl:sycl_configure.bzl", "sycl_configure") +load("//third_party/toolchains/clang6:repo.bzl", "clang6_configure") load("//third_party/toolchains/cpus/arm:arm_compiler_configure.bzl", "arm_compiler_configure") load("//third_party:repo.bzl", "tf_http_archive") load("@io_bazel_rules_closure//closure/private:java_import_external.bzl", "java_import_external") @@ -65,6 +66,7 @@ def tf_workspace(path_prefix="", tf_repo_name=""): # files, in case the parsing of those build files depends on the bazel # version we require here. check_bazel_version_at_least("0.5.4") + clang6_configure(name="local_config_clang6") cuda_configure(name="local_config_cuda") git_configure(name="local_config_git") sycl_configure(name="local_config_sycl") diff --git a/third_party/git/git_configure.bzl b/third_party/git/git_configure.bzl index 47e2125854..8e2839bdc2 100644 --- a/third_party/git/git_configure.bzl +++ b/third_party/git/git_configure.bzl @@ -38,6 +38,11 @@ def _git_conf_impl(repository_ctx): Label("@org_tensorflow//tensorflow/tools/git:gen_git_source.py")) generated_files_path = repository_ctx.path("gen") + r = repository_ctx.execute( + ["test", "-f", "%s/.git/logs/HEAD" % tensorflow_root_path]) + if r.return_code == 0: + unused_var = repository_ctx.path(Label("//:.git/HEAD")) # pylint: disable=unused-variable + result = repository_ctx.execute([ _get_python_bin(repository_ctx), python_script_path, "--configure", tensorflow_root_path, diff --git a/third_party/toolchains/clang6/BUILD b/third_party/toolchains/clang6/BUILD new file mode 100644 index 0000000000..ffd0fb0cdc --- /dev/null +++ b/third_party/toolchains/clang6/BUILD @@ -0,0 +1 @@ +package(default_visibility = ["//visibility:public"]) diff --git a/third_party/toolchains/clang6/CROSSTOOL.tpl b/third_party/toolchains/clang6/CROSSTOOL.tpl new file mode 100644 index 0000000000..6b7e5a8808 --- /dev/null +++ b/third_party/toolchains/clang6/CROSSTOOL.tpl @@ -0,0 +1,587 @@ +major_version: "v1" +minor_version: "llvm:6.0.0" +default_target_cpu: "k8" + +default_toolchain { + cpu: "k8" + toolchain_identifier: "k8-clang-6.0-cxx-4.8-linux-gnu" +} + +toolchain { + compiler: "clang6" # bazel build --compiler=clang6 + target_cpu: "k8" # bazel build --cpu=k8 + target_libc: "GLIBC_2.19" # bazel build --glibc=GLIBC_2.19 + + abi_libc_version: "2.19" + abi_version: "gcc-4.8-cxx11" + builtin_sysroot: "" + cc_target_os: "linux-gnu" + default_python_version: "python2.7" + dynamic_runtimes_filegroup: "dynamic-runtime-libs-k8" + host_system_name: "x86_64-unknown-linux-gnu" + needsPic: true + static_runtimes_filegroup: "static-runtime-libs-k8" + supports_embedded_runtimes: true + supports_fission: true + supports_gold_linker: true + supports_incremental_linker: true + supports_interface_shared_objects: true + supports_normalizing_ar: true + supports_start_end_lib: true + supports_thin_archives: true + target_system_name: "x86_64-unknown-linux-gnu" + toolchain_identifier: "k8-clang-6.0-cxx-4.8-linux-gnu" + + tool_path { name: "ar" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-ar" } + tool_path { name: "as" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-as" } + tool_path { name: "compat-ld" path: "%package(@local_config_clang6//clang6)%/llvm/bin/ld.lld" } + tool_path { name: "cpp" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-cpp" } + tool_path { name: "dwp" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-dwp" } + tool_path { name: "gcc" path: "%package(@local_config_clang6//clang6)%/llvm/bin/clang" } + tool_path { name: "gcov" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-cov" } + tool_path { name: "ld" path: "%package(@local_config_clang6//clang6)%/llvm/bin/ld.lld" } + tool_path { name: "llvm-profdata" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-profdata" } + tool_path { name: "nm" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-nm" } + tool_path { name: "objcopy" path: "%package(@local_config_clang6//clang6)%/llvm/bin/llvm-objcopy" } + tool_path { name: "objdump" path: "%package(@local_config_clang6//clang6)%/sbin/objdump" } + tool_path { name: "strip" path: "%package(@local_config_clang6//clang6)%/sbin/strip" } + + unfiltered_cxx_flag: "-no-canonical-prefixes" + + # Make C++ compilation deterministic. Use linkstamping instead of these + # compiler symbols. + unfiltered_cxx_flag: "-Wno-builtin-macro-redefined" + unfiltered_cxx_flag: "-D__DATE__=\"redacted\"" + unfiltered_cxx_flag: "-D__TIMESTAMP__=\"redacted\"" + unfiltered_cxx_flag: "-D__TIME__=\"redacted\"" + + objcopy_embed_flag: "-I" + objcopy_embed_flag: "binary" + + # This action_config makes features flags propagate + # to CC_FLAGS for genrules, and eventually skylark. + action_config { + action_name: "cc-flags-make-variable" + config_name: "cc-flags-make-variable" + } + + # Security hardening on by default. + # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. + # We need to undef it before redefining it as some distributions now have + # it enabled by default. + compiler_flag: "-U_FORTIFY_SOURCE" + compiler_flag: "-D_FORTIFY_SOURCE=1" + compiler_flag: "-fstack-protector" + linker_flag: "-Wl,-z,relro,-z,now" + + # This adds a little bit more durability to our Clang build. + # + # At the moment, this only only be needed for: + # - add_boringssl_s390x.patch: --Wa,--noexecstack + # + # Folks who do maintenance work on TF Bazel Clang should consider + # commenting out these lines, while doing that work, to gain a better + # understanding of what the intersection of support looks like between GCC + # and Clang. Please note that, Bazel does not support + # -Xclang-only / -Xgcc-only. + compiler_flag: "-Wno-unknown-warning-option" + compiler_flag: "-Wno-unused-command-line-argument" + compiler_flag: "-Wno-ignored-optimization-argument" + + #### Common compiler options. #### + compiler_flag: "-D_REENTRANT" + compiler_flag: "-D__STDC_FORMAT_MACROS" + compiler_flag: "-DSUPPRESS_USE_FILE_OFFSET64" + compiler_flag: "-Wall" + compiler_flag: "-Wformat-security" + compiler_flag: "-Wframe-larger-than=16384" + compiler_flag: "-Wno-char-subscripts" + compiler_flag: "-Wno-error=deprecated-declarations" + compiler_flag: "-Wno-uninitialized" + compiler_flag: "-Wno-sign-compare" + compiler_flag: "-Wno-strict-overflow" + compiler_flag: "-Wno-unused-function" + compiler_flag: "-fdiagnostics-show-option" + compiler_flag: "-fmessage-length=0" + compiler_flag: "-fno-exceptions" + compiler_flag: "-fno-omit-frame-pointer" + compiler_flag: "-fno-strict-aliasing" + compiler_flag: "-fno-use-init-array" + compiler_flag: "-funsigned-char" + compiler_flag: "-gmlt" + cxx_flag: "-Wno-deprecated" + cxx_flag: "-Wno-invalid-offsetof" # Needed for protobuf code (2017-11-07) + cxx_flag: "-fshow-overloads=best" + compiler_flag: "-Wthread-safety-analysis" + + # Python extensions unfortunately make this go wild. + compiler_flag: "-Wno-writable-strings" + + # GCC's warning produces too many false positives: + cxx_flag: "-Woverloaded-virtual" + cxx_flag: "-Wnon-virtual-dtor" + + # Enable coloring even if there's no attached terminal. Bazel removes the + # escape sequences if --nocolor is specified. This isn't supported by gcc + # on Ubuntu 14.04. + compiler_flag: "-fcolor-diagnostics" + + # Disable some broken warnings from Clang. + compiler_flag: "-Wno-ambiguous-member-template" + compiler_flag: "-Wno-pointer-sign" + + # These warnings have a low signal to noise ratio. + compiler_flag: "-Wno-reserved-user-defined-literal" + compiler_flag: "-Wno-return-type-c-linkage" + compiler_flag: "-Wno-invalid-source-encoding" + + # Per default we switch off any layering related warnings. + compiler_flag: "-Wno-private-header" + + # Clang-specific warnings that we explicitly enable for TensorFlow. Some of + # these aren't on by default, or under -Wall, or are subsets of warnings + # turned off above. + compiler_flag: "-Wfloat-overflow-conversion" + compiler_flag: "-Wfloat-zero-conversion" + compiler_flag: "-Wfor-loop-analysis" + compiler_flag: "-Wgnu-redeclared-enum" + compiler_flag: "-Winfinite-recursion" + compiler_flag: "-Wliteral-conversion" + compiler_flag: "-Wself-assign" + compiler_flag: "-Wstring-conversion" + compiler_flag: "-Wtautological-overlap-compare" + compiler_flag: "-Wunused-comparison" + compiler_flag: "-Wvla" + cxx_flag: "-Wdeprecated-increment-bool" + + # Clang code-generation flags for performance optimization. + compiler_flag: "-faligned-allocation" + compiler_flag: "-fnew-alignment=8" + + # Clang defaults to C99 while GCC defaults to C89. GCC plugins are written in + # C89 and don't have a BUILD rule we could add a copts flag to. + gcc_plugin_compiler_flag: "-std=gnu89" + + compilation_mode_flags { + mode: FASTBUILD + } + + compilation_mode_flags { + mode: DBG + compiler_flag: "-g" + } + + compilation_mode_flags { + mode: OPT + compiler_flag: "-g0" + compiler_flag: "-fdebug-types-section" + compiler_flag: "-DNDEBUG" + compiler_flag: "-fno-split-dwarf-inlining" + compiler_flag: "-Os" + compiler_flag: "-fexperimental-new-pass-manager" + compiler_flag: "-fdebug-info-for-profiling" + compiler_flag: "-ffunction-sections" + compiler_flag: "-fdata-sections" + linker_flag: "-Wl,--gc-sections" + linker_flag: "-Wl,-z,relro,-z,now" + } + + # Features indicating whether this is a host compile or not. Exactly one of + # these will be implicitly provided by bazel. + feature { name: "host" } + feature { name: "nonhost" } + + # Features indicating which compiler will be used for code generation. + feature { + name: "llvm_codegen" + provides: "codegen" + enabled: true + } + + # Features for compilation modes. Exactly one of these will be implicitly + # provided by bazel. + feature { name: "fastbuild" } + feature { name: "dbg" } + feature { name: "opt" } + + # Features controlling the C++ language mode. + feature { + name: "c++11" + provides: "c++std" + flag_set { + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++11" + flag: "-Wc++14-extensions" + flag: "-Wc++2a-extensions" + flag: "-Wno-binary-literal" + } + } + } + feature { + name: "c++14" + provides: "c++std" + flag_set { + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++14" + flag: "-Wc++11-compat" + flag: "-Wno-c++11-compat-binary-literal" + flag: "-Wc++2a-extensions" + } + } + } + feature { + name: "c++17" + provides: "c++std" + flag_set { + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++17" + flag: "-Wc++11-compat" + flag: "-Wno-c++11-compat-binary-literal" + flag: "-Wc++2a-extensions" + } + } + } + feature { + name: "c++2a" + provides: "c++std" + flag_set { + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++2a" + flag: "-Wc++11-compat" + flag: "-Wno-c++11-compat-binary-literal" + } + } + } + feature { + name: "c++default" + enabled: true + flag_set { + # Provide the c++11 flags if no standard is selected + with_feature { + not_feature: "c++11" + not_feature: "c++14" + not_feature: "c++17" + not_feature: "c++2a" + } + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "linkstamp-compile" + flag_group { + flag: "-nostdinc++" + flag: "-std=c++11" + flag: "-Wc++14-extensions" + flag: "-Wc++2a-extensions" + flag: "-Wno-binary-literal" + } + } + } + + feature { + name: "use_compiler_rt" + requires { feature: "llvm_codegen" } + # TODO(saugustine): At the moment, "use_compiler_rt" also + # requires "linking_mode_flags { mode: FULLY_STATIC" ... }, + # but that isn't a feature. We should probably convert it. + flag_set { + action: "c++-link" + action: "c++-link-interface-dynamic-library" + action: "c++-link-dynamic-library" + action: "c++-link-executable" + # "link" is a misnomer for these actions. They are really just + # invocations of ar. + #action: "c++-link-pic-static-library" + #action: "c++-link-static-library" + #action: "c++-link-alwayslink-static-library" + #action: "c++-link-pic-static-library" + #action: "c++-link-alwayslink-pic-static-library" + flag_group { + flag: "-rtlib=compiler-rt" + flag: "-lunwind" + } + } + } + + feature { + name: "pie" + flag_set { + action: "assemble" + action: "preprocess-assemble" + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "c++-module-codegen" + action: "cc-flags-make-variable" + action: "lto-backend" + action: "linkstamp-compile" + flag_group { + flag: "-mpie-copy-relocations" + flag: "-fPIE" + } + } + flag_set { + action: "cc-flags-make-variable" + action: "c++-link-executable" + flag_group { + flag: "-pie" + } + } + } + + # Pic must appear after pie, because pic may need to override pie, and bazel + # turns it on selectively. These don't interact with other options. + # + # TODO: In practice, normal vs pic vs pie is a ternary mode. We should + # implement it that way. This will require changes to bazel, which only + # calculates whether or not pic is needed, not pie. + # + # NOTE: Bazel might make this all a moot point. + feature { + name: "pic" + flag_set { + action: "assemble" + action: "preprocess-assemble" + action: "c-compile" + action: "c++-compile" + action: "c++-module-codegen" + action: "c++-module-compile" + action: "linkstamp-compile" + expand_if_all_available: "pic" + flag_group { + flag: "-fPIC" + } + } + } + + feature { + name: "gold" + enabled: true + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-interface-dynamic-library" + flag_group { + expand_if_none_available: "lto" + flag: "-fuse-ld=gold" + } + } + } + + # This is great if you want linking TensorFlow to take ten minutes. + feature { + name: "lto" + requires { feature: "nonhost" } + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-flto=thin" + } + } + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-interface-dynamic-library" + flag_group { + flag: "-flto=thin" + } + } + } + + feature { + name: "parse_headers" + flag_set { + action: "c++-header-parsing" + flag_group { + flag: "-xc++-header" + flag: "-fsyntax-only" + } + } + } + + feature { + name: "preprocess_headers" + flag_set { + action: "c++-header-preprocessing" + flag_group { + flag: "-xc++" + flag: "-E" + } + } + } + + feature { + name: "per_object_debug_info" + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-module-codegen" + action: "assemble" + action: "preprocess-assemble" + action: "lto-backend" + flag_group { + flag: "-gsplit-dwarf" + flag: "-ggnu-pubnames" + } + } + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-interface-dynamic-library" + flag_group { + expand_if_all_available: "is_using_fission" + flag: "-Wl,--gdb-index" + } + } + } + + feature { + name: "xray" + requires { + feature: "llvm_codegen" + feature: "nonhost" + } + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "c++-link-interface-dynamic-library" + action: "c++-link-dynamic-library" + action: "c++-link-executable" + flag_group { + flag: "-fxray-instrument" + } + } + } + + feature { + name: "minimal_ubsan" + requires { feature: "llvm_codegen" } + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "c++-module-codegen" + flag_group { + flag: "-fsanitize=return,returns-nonnull-attribute,vla-bound,unreachable,float-cast-overflow" + flag: "-fsanitize-trap=all" + flag: "-DUNDEFINED_BEHAVIOR_SANITIZER" + } + } + } + + feature { + name: "minimal_ubsan_enabled_by_default" + requires { + feature: "llvm_codegen" + feature: "fastbuild" + } + enabled: true + implies: "minimal_ubsan" + } + + cxx_builtin_include_directory: "%package(@local_config_clang6//clang6)%/llvm/lib/clang/6.0.0/include" + cxx_builtin_include_directory: "/usr/include" + + unfiltered_cxx_flag: "-cxx-isystem" + unfiltered_cxx_flag: "/usr/include/c++/4.8" + unfiltered_cxx_flag: "-cxx-isystem" + unfiltered_cxx_flag: "/usr/include/x86_64-linux-gnu/c++/4.8" + unfiltered_cxx_flag: "-isystem" + unfiltered_cxx_flag: "%package(@local_config_clang6//clang6)%/llvm/lib/clang/6.0.0/include" + unfiltered_cxx_flag: "-isystem" + unfiltered_cxx_flag: "/usr/include/x86_64-linux-gnu" + unfiltered_cxx_flag: "-isystem" + unfiltered_cxx_flag: "/usr/include" + + linker_flag: "-Wl,--build-id=md5" + linker_flag: "-Wl,--fatal-warnings" + linker_flag: "-Wl,--hash-style=gnu" + linker_flag: "-no-canonical-prefixes" + linker_flag: "--target=x86_64-unknown-linux-gnu" + + linker_flag: "-L/usr/lib/gcc/x86_64-linux-gnu/4.8" + + # This is the minimum x86 architecture TensorFlow supports. + compiler_flag: "-DARCH_K8" + compiler_flag: "-m64" + + # These are for Linux. + ld_embed_flag: "-melf_x86_64" + linker_flag: "-Wl,--eh-frame-hdr" + linker_flag: "-Wl,-z,max-page-size=0x1000" + + # Google never uses the stack like a heap, e.g. alloca(), because tcmalloc + # and jemalloc are so fast. However copts=["$(STACK_FRAME_UNLIMITED)"] can be + # specified when that can't be the case. + make_variable { + name: "STACK_FRAME_UNLIMITED" + value: "-Wframe-larger-than=100000000 -Wno-vla" + } + + # These flags are for folks who build C/C++ code inside genrules. + make_variable { + name: "CC_FLAGS" + value: "-no-canonical-prefixes --target=x86_64-unknown-linux-gnu -fno-omit-frame-pointer -fno-tree-vrp -msse3" + } + + feature { + name: "copts" + flag_set { + expand_if_all_available: "copts" + action: "assemble" + action: "preprocess-assemble" + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-header-preprocessing" + action: "c++-module-compile" + action: "c++-module-codegen" + action: "lto-backend" + flag_group { + iterate_over: "copts" + flag: "%{copts}" + } + } + } + + # Please do not statically link libstdc++. This would probably lead to a lot + # of bloat since OpKernels need to use linkstatic=1 because b/27630669 and + # it could cause memory leaks since Python uses dlopen() on our libraries: + # https://stackoverflow.com/a/35015415 + linker_flag: "-lstdc++" + linker_flag: "-lm" + linker_flag: "-lpthread" + linker_flag: "-l:/lib/x86_64-linux-gnu/libc-2.19.so" +} diff --git a/third_party/toolchains/clang6/README.md b/third_party/toolchains/clang6/README.md new file mode 100644 index 0000000000..0c6be25a0e --- /dev/null +++ b/third_party/toolchains/clang6/README.md @@ -0,0 +1,101 @@ +# TensorFlow Bazel Clang + +This is a specialized toolchain that uses an old Debian with a new Clang that +can cross compile to any x86_64 microarchitecture. It's intended to build Linux +binaries that only require the following ABIs: + +- GLIBC_2.18 +- CXXABI_1.3.7 (GCC 4.8.3) +- GCC_4.2.0 + +Which are available on at least the following Linux platforms: + +- Ubuntu 14+ +- CentOS 7+ +- Debian 8+ +- SuSE 13.2+ +- Mint 17.3+ +- Manjaro 0.8.11 + +# System Install + +On Debian 8 (Jessie) Clang 6.0 can be installed as follows: + +```sh +cat >>/etc/apt/sources.list <<'EOF' +deb http://apt.llvm.org/jessie/ llvm-toolchain-jessie main +deb-src http://apt.llvm.org/jessie/ llvm-toolchain-jessie main +EOF +wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - +apt-key fingerprint |& grep '6084 F3CF 814B 57C1 CF12 EFD5 15CF 4D18 AF4F 7421' +apt-get update +apt-get install clang lld +``` + +# Bazel Configuration + +This toolchain can compile TensorFlow in 2m30s on a 96-core Skylake GCE VM if +the following `.bazelrc` settings are added: + +``` +startup --host_jvm_args=-Xmx30G +startup --host_jvm_args=-Xms30G +startup --host_jvm_args=-XX:MaxNewSize=3g +startup --host_jvm_args=-XX:-UseAdaptiveSizePolicy +startup --host_jvm_args=-XX:+UseConcMarkSweepGC +startup --host_jvm_args=-XX:TargetSurvivorRatio=70 +startup --host_jvm_args=-XX:SurvivorRatio=6 +startup --host_jvm_args=-XX:+UseCMSInitiatingOccupancyOnly +startup --host_jvm_args=-XX:CMSFullGCsBeforeCompaction=1 +startup --host_jvm_args=-XX:CMSInitiatingOccupancyFraction=75 + +build --jobs=100 +build --local_resources=200000,100,100 +build --crosstool_top=@local_config_clang6//clang6 +build --noexperimental_check_output_files +build --nostamp +build --config=opt +build --noexperimental_check_output_files +build --copt=-march=native +build --host_copt=-march=native +``` + +# x86_64 Microarchitectures + +## Intel CPU Line + +- 2003 P6 M SSE SSE2 +- 2004 prescott SSE3 SSSE3 (-march=prescott) +- 2006 core X64 SSE4.1 (only on 45nm variety) (-march=core2) +- 2008 nehalem SSE4.2 VT-x VT-d (-march=nehalem) +- 2010 westmere CLMUL AES (-march=westmere) +- 2012 sandybridge AVX TXT (-march=sandybridge) +- 2012 ivybridge F16C MOVBE (-march=ivybridge) +- 2013 haswell AVX2 TSX BMI2 FMA (-march=haswell) +- 2014 broadwell RDSEED ADCX PREFETCHW (-march=broadwell - works on trusty gcc4.9) +- 2015 skylake SGX ADX MPX AVX-512[xeon-only] (-march=skylake / -march=skylake-avx512 - needs gcc7) +- 2018 cannonlake AVX-512 SHA (-march=cannonlake - needs clang5) + +## Intel Low Power CPU Line + +- 2013 silvermont SSE4.1 SSE4.2 VT-x (-march=silvermont) +- 2016 goldmont SHA (-march=goldmont - needs clang5) + +## AMD CPU Line + +- 2003 k8 SSE SSE2 (-march=k8) +- 2005 k8 (Venus) SSE3 (-march=k8-sse3) +- 2008 barcelona SSE4a?! (-march=barcelona) +- 2011 bulldozer SSE4.1 SSE4.2 CLMUL AVX AES FMA4?! (-march=bdver1) +- 2011 piledriver FMA (-march=bdver2) +- 2015 excavator AVX2 BMI2 MOVBE (-march=bdver4) + +## Google Compute Engine Supported CPUs + +- 2012 sandybridge 2.6gHz -march=sandybridge +- 2012 ivybridge 2.5gHz -march=ivybridge +- 2013 haswell 2.3gHz -march=haswell +- 2014 broadwell 2.2gHz -march=broadwell +- 2015 skylake 2.0gHz -march=skylake-avx512 + +See: diff --git a/third_party/toolchains/clang6/clang.BUILD b/third_party/toolchains/clang6/clang.BUILD new file mode 100644 index 0000000000..802d62c17c --- /dev/null +++ b/third_party/toolchains/clang6/clang.BUILD @@ -0,0 +1,162 @@ +package(default_visibility = ["//visibility:public"]) + +# Please note that the output of these tools is unencumbered. +licenses(["restricted"]) # NCSA, GPLv3 (e.g. gold) + +filegroup( + name = "ar", + srcs = ["llvm/bin/llvm-ar"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "as", + srcs = ["llvm/bin/llvm-as"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "cpp", + srcs = ["llvm/bin/llvm-cpp"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "dwp", + srcs = ["llvm/bin/llvm-dwp"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "gcc", + srcs = ["llvm/bin/clang"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "gcov", + srcs = ["llvm/bin/llvm-cov"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "ld", + srcs = ["llvm/bin/ld.lld"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "nm", + srcs = ["llvm/bin/llvm-nm"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "objcopy", + srcs = ["llvm/bin/llvm-objcopy"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "objdump", + srcs = ["llvm/bin/llvm-objdump"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "profdata", + srcs = ["llvm/bin/llvm-profdata"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "strip", + srcs = ["sbin/strip"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "xray", + srcs = ["llvm/bin/llvm-xray"], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "includes", + srcs = glob(["llvm/lib/clang/6.0.0/include/**"]), + output_licenses = ["unencumbered"], +) + +filegroup( + name = "libraries", + srcs = glob([ + "lib/*.*", + "lib/clang/6.0.0/lib/linux/*.*", + ]), + output_licenses = ["unencumbered"], +) + +filegroup( + name = "compiler_files", + srcs = [ + ":as", + ":gcc", + ":includes", + ], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "linker_files", + srcs = [ + ":ar", + ":ld", + ":libraries", + ], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "all_files", + srcs = [ + ":compiler_files", + ":dwp", + ":gcov", + ":linker_files", + ":nm", + ":objcopy", + ":objdump", + ":profdata", + ":strip", + ":xray", + ], + output_licenses = ["unencumbered"], +) + +filegroup( + name = "empty", + srcs = [], # bazel crashes without this + output_licenses = ["unencumbered"], +) + +cc_toolchain_suite( + name = "clang6", + toolchains = { + "k8|clang6": ":clang6-k8", + }, +) + +cc_toolchain( + name = "clang6-k8", + all_files = ":all_files", + compiler_files = ":compiler_files", + cpu = "k8", + dwp_files = ":dwp", + dynamic_runtime_libs = [":empty"], + linker_files = ":linker_files", + objcopy_files = ":objcopy", + output_licenses = ["unencumbered"], + static_runtime_libs = [":empty"], + strip_files = ":strip", + supports_param_files = 1, +) diff --git a/third_party/toolchains/clang6/repo.bzl b/third_party/toolchains/clang6/repo.bzl new file mode 100644 index 0000000000..b81f44506f --- /dev/null +++ b/third_party/toolchains/clang6/repo.bzl @@ -0,0 +1,30 @@ +"""Repository rule for Debian 8 Jessie Clang-6.0 portable Linux builds.""" + +def _clang6_configure(ctx): + # TODO(jart): It'd probably be better to use Bazel's struct.to_proto() + # method to generate a gigantic CROSSTOOL file that allows + # Clang to support everything. + ctx.symlink( + ctx.os.environ.get('TF_LLVM_PATH', + '/usr/lib/llvm-6.0'), + 'clang6/llvm') + ctx.symlink( + ctx.os.environ.get('STRIP', '/usr/bin/strip'), + 'clang6/sbin/strip') + ctx.symlink( + ctx.os.environ.get('OBJDUMP', '/usr/bin/objdump'), + 'clang6/sbin/objdump') + ctx.symlink(ctx.attr._build, 'clang6/BUILD') + ctx.template('clang6/CROSSTOOL', ctx.attr._crosstool, { + '%package(@local_config_clang6//clang6)%': str(ctx.path('clang6')), + }) + +clang6_configure = repository_rule( + implementation = _clang6_configure, + attrs = { + '_build': attr.label( + default=str(Label('//third_party/toolchains/clang6:clang.BUILD'))), + '_crosstool': attr.label( + default=str(Label('//third_party/toolchains/clang6:CROSSTOOL.tpl'))), + }, +) -- GitLab From 0d14f82da314f58bb7c9c4f5c866f1ffed056841 Mon Sep 17 00:00:00 2001 From: Loo Rong Jie Date: Thu, 25 Jan 2018 02:37:24 +0800 Subject: [PATCH 183/258] [Bazel/Windows] Don't use -Wl and -lm on Windows (#16341) --- tensorflow/tensorflow.bzl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tensorflow/tensorflow.bzl b/tensorflow/tensorflow.bzl index 383c97344a..cbb64a3489 100644 --- a/tensorflow/tensorflow.bzl +++ b/tensorflow/tensorflow.bzl @@ -258,6 +258,8 @@ def _rpath_linkopts(name): clean_dep("//tensorflow:darwin"): [ "-Wl,%s" % (_make_search_paths("@loader_path", levels_to_root),), ], + clean_dep("//tensorflow:windows"): [], + clean_dep("//tensorflow:windows_msvc"): [], "//conditions:default": [ "-Wl,%s" % (_make_search_paths("$$ORIGIN", levels_to_root),), ], @@ -600,6 +602,8 @@ def tf_cc_test(name, "//tensorflow:android": [ "-pie", ], + clean_dep("//tensorflow:windows"): [], + clean_dep("//tensorflow:windows_msvc"): [], "//conditions:default": [ "-lpthread", "-lm" @@ -1246,6 +1250,8 @@ def tf_custom_op_library(name, srcs=[], gpu_srcs=[], deps=[], linkopts=[]): "//conditions:default": [ "-lm", ], + clean_dep("//tensorflow:windows"): [], + clean_dep("//tensorflow:windows_msvc"): [], clean_dep("//tensorflow:darwin"): [], }),) -- GitLab From 32e3acde7fd75c2a34fd10b6f11cd2df864e6e32 Mon Sep 17 00:00:00 2001 From: Akshay Agrawal Date: Wed, 24 Jan 2018 10:34:07 -0800 Subject: [PATCH 184/258] TFE: Add graph benchmark for linear regression, for comparison with our eager execution benchmark. PiperOrigin-RevId: 183105403 --- .../python/examples/linear_regression/BUILD | 10 +++ .../linear_regression/linear_regression.py | 18 ++-- .../linear_regression_graph_test.py | 85 +++++++++++++++++++ .../linear_regression_test.py | 8 +- 4 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 tensorflow/contrib/eager/python/examples/linear_regression/linear_regression_graph_test.py diff --git a/tensorflow/contrib/eager/python/examples/linear_regression/BUILD b/tensorflow/contrib/eager/python/examples/linear_regression/BUILD index bab7ad0c70..f86331af6f 100644 --- a/tensorflow/contrib/eager/python/examples/linear_regression/BUILD +++ b/tensorflow/contrib/eager/python/examples/linear_regression/BUILD @@ -23,3 +23,13 @@ cuda_py_test( "//tensorflow:tensorflow_py", ], ) + +cuda_py_test( + name = "linear_regression_graph_test", + size = "small", + srcs = ["linear_regression_graph_test.py"], + additional_deps = [ + ":linear_regression", + "//tensorflow:tensorflow_py", + ], +) diff --git a/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression.py b/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression.py index f4b7d67f94..6ce4de6ee0 100644 --- a/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression.py +++ b/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression.py @@ -63,6 +63,10 @@ class LinearModel(tfe.Network): return self._hidden_layer(xs) +def mean_square_loss(model, xs, ys): + return tf.reduce_mean(tf.square(model(xs) - ys)) + + def fit(model, dataset, optimizer, verbose=False, logdir=None): """Fit the linear-regression model. @@ -76,10 +80,8 @@ def fit(model, dataset, optimizer, verbose=False, logdir=None): """ # The loss function to optimize. - def mean_square_loss(xs, ys): - return tf.reduce_mean(tf.square(model(xs) - ys)) - - loss_and_grads = tfe.implicit_value_and_gradients(mean_square_loss) + mse = lambda xs, ys: mean_square_loss(model, xs, ys) + loss_and_grads = tfe.implicit_value_and_gradients(mse) tf.train.get_or_create_global_step() if logdir: @@ -103,14 +105,20 @@ def fit(model, dataset, optimizer, verbose=False, logdir=None): def synthetic_dataset(w, b, noise_level, batch_size, num_batches): """tf.data.Dataset that yields synthetic data for linear regression.""" + return synthetic_dataset_helper(w, b, + tf.shape(w)[0], noise_level, batch_size, + num_batches) + +def synthetic_dataset_helper(w, b, num_features, noise_level, batch_size, + num_batches): # w is a matrix with shape [N, M] # b is a vector with shape [M] # So: # - Generate x's as vectors with shape [batch_size N] # - y = tf.matmul(x, W) + b + noise def batch(_): - x = tf.random_normal([batch_size, tf.shape(w)[0]]) + x = tf.random_normal([batch_size, num_features]) y = tf.matmul(x, w) + b + noise_level * tf.random_normal([]) return x, y diff --git a/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression_graph_test.py b/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression_graph_test.py new file mode 100644 index 0000000000..557ad42752 --- /dev/null +++ b/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression_graph_test.py @@ -0,0 +1,85 @@ +# Copyright 2017 The TensorFlow Authors. 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. +"""Graph benchmark for linear regression, to contrast with eager execution.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import tensorflow as tf +from tensorflow.contrib.eager.python.examples.linear_regression import linear_regression + + +class GraphLinearRegressionBenchmark(tf.test.Benchmark): + + def benchmarkGraphLinearRegression(self): + num_epochs = 10 + num_batches = 200 + batch_size = 64 + dataset = linear_regression.synthetic_dataset_helper( + w=tf.random_uniform([3, 1]), + b=tf.random_uniform([1]), + num_features=3, + noise_level=0.01, + batch_size=batch_size, + num_batches=num_batches) + iterator = dataset.make_initializable_iterator() + x, y = iterator.get_next() + + model = linear_regression.LinearModel() + + if tf.test.is_gpu_available(): + use_gpu = True + device = "/device:GPU:0" + else: + use_gpu = False + device = "/device:CPU:0" + + with tf.device(device): + loss = linear_regression.mean_square_loss(model, x, y) + optimization_step = tf.train.GradientDescentOptimizer( + learning_rate=0.1).minimize(loss) + + with tf.Session() as sess: + sess.run(tf.global_variables_initializer()) + + def train(num_epochs): + for _ in range(num_epochs): + sess.run(iterator.initializer) + try: + while True: + _, _ = sess.run([optimization_step, loss]) + except tf.errors.OutOfRangeError: + pass + + # Warmup: a single epoch. + train(1) + + start_time = time.time() + train(num_epochs) + wall_time = time.time() - start_time + + examples_per_sec = num_epochs * num_batches * batch_size / wall_time + self.report_benchmark( + name="graph_train_%s" % + ("gpu" if use_gpu else "cpu"), + iters=num_epochs * num_batches, + extras={"examples_per_sec": examples_per_sec}, + wall_time=wall_time) + + +if __name__ == "__main__": + tf.test.main() diff --git a/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression_test.py b/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression_test.py index 39e7aabd7b..e53234b51a 100644 --- a/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression_test.py +++ b/tensorflow/contrib/eager/python/examples/linear_regression/linear_regression_test.py @@ -83,6 +83,7 @@ class LinearRegressionTest(tf.test.TestCase): class EagerLinearRegressionBenchmark(tf.test.Benchmark): def benchmarkEagerLinearRegression(self): + num_epochs = 10 num_batches = 200 batch_size = 64 dataset = linear_regression.synthetic_dataset( @@ -102,14 +103,15 @@ class EagerLinearRegressionBenchmark(tf.test.Benchmark): linear_regression.fit(model, burn_in_dataset, optimizer) start_time = time.time() - linear_regression.fit(model, dataset, optimizer) + for _ in range(num_epochs): + linear_regression.fit(model, dataset, optimizer) wall_time = time.time() - start_time - examples_per_sec = num_batches * batch_size / wall_time + examples_per_sec = num_epochs * num_batches * batch_size / wall_time self.report_benchmark( name="eager_train_%s" % ("gpu" if tfe.num_gpus() > 0 else "cpu"), - iters=num_batches, + iters=num_epochs * num_batches, extras={"examples_per_sec": examples_per_sec}, wall_time=wall_time) -- GitLab From 4ce6decdbb8ca5e394d986bb327848dba767cc15 Mon Sep 17 00:00:00 2001 From: Cesc Date: Thu, 25 Jan 2018 02:38:59 +0800 Subject: [PATCH 185/258] support preconditioner for `conjugated_gradient()` in `linear_equations.py` (#16237) * support preconditioner for conjugated_gradient() in linear_equations.py * support preconditioner for conjugated_gradient() in linear_equations.py amend email to pass CLA check * add jacobi, None test, insert np extra op when preconditioner=None * using linalg_ops.norm() instead of util.l2norm_squared() --- .../kernel_tests/linear_equations_test.py | 51 +++++++++++++----- .../solvers/python/kernel_tests/util_test.py | 35 +++++++++++++ .../solvers/python/ops/linear_equations.py | 52 ++++++++++++++----- tensorflow/contrib/solvers/python/ops/util.py | 17 ++++++ 4 files changed, 129 insertions(+), 26 deletions(-) diff --git a/tensorflow/contrib/solvers/python/kernel_tests/linear_equations_test.py b/tensorflow/contrib/solvers/python/kernel_tests/linear_equations_test.py index 930df2414b..7b609ae96b 100644 --- a/tensorflow/contrib/solvers/python/kernel_tests/linear_equations_test.py +++ b/tensorflow/contrib/solvers/python/kernel_tests/linear_equations_test.py @@ -45,32 +45,55 @@ def _get_linear_equations_tests(dtype_, use_static_shape_, shape_): low=-1.0, high=1.0, size=np.prod(shape_)).reshape(shape_).astype(dtype_) # Make a selfadjoint, positive definite. a_np = np.dot(a_np.T, a_np) + # jacobi preconditioner + jacobi_np = np.zeros_like(a_np) + jacobi_np[range(a_np.shape[0]), range(a_np.shape[1])] = (1.0 / + a_np.diagonal()) rhs_np = np.random.uniform( low=-1.0, high=1.0, size=shape_[0]).astype(dtype_) + x_np = np.zeros_like(rhs_np) tol = 1e-6 if dtype_ == np.float64 else 1e-3 max_iter = 20 with self.test_session() as sess: if use_static_shape_: a = constant_op.constant(a_np) rhs = constant_op.constant(rhs_np) + x = constant_op.constant(x_np) + jacobi = constant_op.constant(jacobi_np) else: a = array_ops.placeholder(dtype_) rhs = array_ops.placeholder(dtype_) + x = array_ops.placeholder(dtype_) + jacobi = array_ops.placeholder(dtype_) operator = util.create_operator(a) - cg_graph = linear_equations.conjugate_gradient( - operator, rhs, tol=tol, max_iter=max_iter) - if use_static_shape_: - cg_val = sess.run(cg_graph) - else: - cg_val = sess.run(cg_graph, feed_dict={a: a_np, rhs: rhs_np}) - norm_r0 = np.linalg.norm(rhs_np) - norm_r = np.sqrt(cg_val.gamma) - self.assertLessEqual(norm_r, tol * norm_r0) - # Validate that we get an equally small residual norm with numpy - # using the computed solution. - r_np = rhs_np - np.dot(a_np, cg_val.x) - norm_r_np = np.linalg.norm(r_np) - self.assertLessEqual(norm_r_np, tol * norm_r0) + preconditioners = [None, util.identity_operator(a), + util.create_operator(jacobi)] + cg_results = [] + for preconditioner in preconditioners: + cg_graph = linear_equations.conjugate_gradient( + operator, rhs, preconditioner=preconditioner, + x=x, tol=tol, max_iter=max_iter) + if use_static_shape_: + cg_val = sess.run(cg_graph) + else: + cg_val = sess.run(cg_graph, feed_dict={a: a_np, rhs: rhs_np, x: x_np, + jacobi: jacobi_np}) + norm_r0 = np.linalg.norm(rhs_np) + norm_r = np.linalg.norm(cg_val.r) + self.assertLessEqual(norm_r, tol * norm_r0) + # Validate that we get an equally small residual norm with numpy + # using the computed solution. + r_np = rhs_np - np.dot(a_np, cg_val.x) + norm_r_np = np.linalg.norm(r_np) + self.assertLessEqual(norm_r_np, tol * norm_r0) + cg_results.append(cg_val) + # Validate that we get same results using identity_preconditioner + # and None + self.assertEqual(cg_results[0].i, cg_results[1].i) + self.assertAlmostEqual(cg_results[0].gamma, cg_results[1].gamma) + self.assertAllClose(cg_results[0].r, cg_results[1].r, rtol=tol) + self.assertAllClose(cg_results[0].x, cg_results[1].x, rtol=tol) + self.assertAllClose(cg_results[0].p, cg_results[1].p, rtol=tol) return [test_conjugate_gradient] diff --git a/tensorflow/contrib/solvers/python/kernel_tests/util_test.py b/tensorflow/contrib/solvers/python/kernel_tests/util_test.py index 1566984b27..12e94369cb 100644 --- a/tensorflow/contrib/solvers/python/kernel_tests/util_test.py +++ b/tensorflow/contrib/solvers/python/kernel_tests/util_test.py @@ -63,6 +63,41 @@ class UtilTest(test.TestCase): def testCreateOperatorUnknownShape(self): self._testCreateOperator(False) + def _testIdentityOperator(self, use_static_shape_): + for dtype in np.float32, np.float64: + a_np = np.array([[1., 2.], [3., 4.], [5., 6.]], dtype=dtype) + x_np = np.array([[2.], [-3.]], dtype=dtype) + y_np = np.array([[2], [-3.], [5.]], dtype=dtype) + with self.test_session() as sess: + if use_static_shape_: + a = constant_op.constant(a_np, dtype=dtype) + x = constant_op.constant(x_np, dtype=dtype) + y = constant_op.constant(y_np, dtype=dtype) + else: + a = array_ops.placeholder(dtype) + x = array_ops.placeholder(dtype) + y = array_ops.placeholder(dtype) + id_op = util.identity_operator(a) + ax = id_op.apply(x) + aty = id_op.apply_adjoint(y) + op_shape = ops.convert_to_tensor(id_op.shape) + if use_static_shape_: + op_shape_val, ax_val, aty_val = sess.run([op_shape, ax, aty]) + else: + op_shape_val, ax_val, aty_val = sess.run( + [op_shape, ax, aty], feed_dict={a: a_np, + x: x_np, + y: y_np}) + self.assertAllEqual(op_shape_val, [3, 2]) + self.assertAllClose(ax_val, x_np) + self.assertAllClose(aty_val, y_np) + + def testIdentityOperator(self): + self._testIdentityOperator(True) + + def testIdentityOperatorUnknownShape(self): + self._testIdentityOperator(False) + def testL2Norm(self): with self.test_session(): x_np = np.array([[2], [-3.], [5.]]) diff --git a/tensorflow/contrib/solvers/python/ops/linear_equations.py b/tensorflow/contrib/solvers/python/ops/linear_equations.py index 8cba56eba6..4dfaa97ac9 100644 --- a/tensorflow/contrib/solvers/python/ops/linear_equations.py +++ b/tensorflow/contrib/solvers/python/ops/linear_equations.py @@ -27,10 +27,13 @@ from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops +from tensorflow.python.ops import linalg_ops def conjugate_gradient(operator, rhs, + preconditioner=None, + x=None, tol=1e-4, max_iter=20, name="conjugate_gradient"): @@ -55,6 +58,15 @@ def conjugate_gradient(operator, vector with the result of applying the operator to `x`, i.e. if `operator` represents matrix `A`, `apply` should return `A * x`. rhs: A rank-1 `Tensor` of shape `[N]` containing the right-hand size vector. + preconditioner: An object representing a linear operator, see `operator` + for detail. The preconditioner should approximate the inverse of `A`. + An efficient preconditioner could dramatically improve the rate of + convergence. If `preconditioner` represents matrix `M`(`M` approximates + `A^{-1}`), the algorithm uses `preconditioner.apply(x)` to estimate + `A^{-1}x`. For this to be useful, the cost of applying `M` should be + much lower than computing `A^{-1}` directly. + x: A rank-1 `Tensor` of shape `[N]` containing the initial guess for the + solution. tol: A float scalar convergence tolerance. max_iter: An integer giving the maximum number of iterations. name: A name scope for the operation. @@ -65,35 +77,51 @@ def conjugate_gradient(operator, - x: A rank-1 `Tensor` of shape `[N]` containing the computed solution. - r: A rank-1 `Tensor` of shape `[M]` containing the residual vector. - p: A rank-1 `Tensor` of shape `[N]`. `A`-conjugate basis vector. - - gamma: \\(||r||_2^2\\) + - gamma: \\(r \dot M \dot r\\), equivalent to \\(||r||_2^2\\) when + `preconditioner=None`. """ # ephemeral class holding CG state. cg_state = collections.namedtuple("CGState", ["i", "x", "r", "p", "gamma"]) def stopping_criterion(i, state): - return math_ops.logical_and(i < max_iter, state.gamma > tol) + return math_ops.logical_and(i < max_iter, + linalg_ops.norm(state.r) > tol) - # TODO(rmlarsen): add preconditioning def cg_step(i, state): z = operator.apply(state.p) alpha = state.gamma / util.dot(state.p, z) x = state.x + alpha * state.p r = state.r - alpha * z - gamma = util.l2norm_squared(r) - beta = gamma / state.gamma - p = r + beta * state.p + if preconditioner is None: + gamma = util.dot(r, r) + beta = gamma / state.gamma + p = r + beta * state.p + else: + q = preconditioner.apply(r) + gamma = util.dot(r, q) + beta = gamma / state.gamma + p = q + beta * state.p return i + 1, cg_state(i + 1, x, r, p, gamma) with ops.name_scope(name): n = operator.shape[1:] rhs = array_ops.expand_dims(rhs, -1) - gamma0 = util.l2norm_squared(rhs) - tol = tol * tol * gamma0 - x = array_ops.expand_dims( - array_ops.zeros( - n, dtype=rhs.dtype.base_dtype), -1) + if x is None: + x = array_ops.expand_dims( + array_ops.zeros( + n, dtype=rhs.dtype.base_dtype), -1) + r0 = rhs + else: + x = array_ops.expand_dims(x, -1) + r0 = rhs - operator.apply(x) + if preconditioner is None: + p0 = r0 + else: + p0 = preconditioner.apply(r0) + gamma0 = util.dot(r0, p0) + tol = tol * linalg_ops.norm(r0) i = constant_op.constant(0, dtype=dtypes.int32) - state = cg_state(i=i, x=x, r=rhs, p=rhs, gamma=gamma0) + state = cg_state(i=i, x=x, r=r0, p=p0, gamma=gamma0) _, state = control_flow_ops.while_loop(stopping_criterion, cg_step, [i, state]) return cg_state( diff --git a/tensorflow/contrib/solvers/python/ops/util.py b/tensorflow/contrib/solvers/python/ops/util.py index 777e0c185d..96947e8eea 100644 --- a/tensorflow/contrib/solvers/python/ops/util.py +++ b/tensorflow/contrib/solvers/python/ops/util.py @@ -45,6 +45,23 @@ def create_operator(matrix): apply_adjoint=lambda v: math_ops.matmul(matrix, v, adjoint_a=True)) +def identity_operator(matrix): + """Creates a linear operator from a rank-2 identity tensor.""" + + linear_operator = collections.namedtuple( + "LinearOperator", ["shape", "dtype", "apply", "apply_adjoint"]) + shape = matrix.get_shape() + if shape.is_fully_defined(): + shape = shape.as_list() + else: + shape = array_ops.shape(matrix) + return linear_operator( + shape=shape, + dtype=matrix.dtype, + apply=lambda v: v, + apply_adjoint=lambda v: v) + + # TODO(rmlarsen): Measure if we should just call matmul. def dot(x, y): return math_ops.reduce_sum(math_ops.conj(x) * y) -- GitLab From 18cb45c1cc056648cfc98311963a94cfe0f984b3 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 10:35:22 -0800 Subject: [PATCH 186/258] Internal Change PiperOrigin-RevId: 183105591 --- .../lite/models/smartreply/predictor_test.cc | 8 +- .../lite/models/speech_asr_am_model_test.cc | 127 ------------------ .../lite/models/speech_asr_lm_model_test.cc | 122 ----------------- .../models/speech_endpointer_model_test.cc | 104 -------------- .../lite/models/speech_hotword_model_test.cc | 114 ---------------- .../models/speech_speakerid_model_test.cc | 121 ----------------- .../lite/models/speech_tts_model_test.cc | 116 ---------------- tensorflow/contrib/lite/models/test_utils.h | 84 ------------ 8 files changed, 7 insertions(+), 789 deletions(-) delete mode 100644 tensorflow/contrib/lite/models/speech_asr_am_model_test.cc delete mode 100644 tensorflow/contrib/lite/models/speech_asr_lm_model_test.cc delete mode 100644 tensorflow/contrib/lite/models/speech_endpointer_model_test.cc delete mode 100644 tensorflow/contrib/lite/models/speech_hotword_model_test.cc delete mode 100644 tensorflow/contrib/lite/models/speech_speakerid_model_test.cc delete mode 100644 tensorflow/contrib/lite/models/speech_tts_model_test.cc delete mode 100644 tensorflow/contrib/lite/models/test_utils.h diff --git a/tensorflow/contrib/lite/models/smartreply/predictor_test.cc b/tensorflow/contrib/lite/models/smartreply/predictor_test.cc index 97d3c650e2..e6c8d966f1 100644 --- a/tensorflow/contrib/lite/models/smartreply/predictor_test.cc +++ b/tensorflow/contrib/lite/models/smartreply/predictor_test.cc @@ -22,8 +22,9 @@ limitations under the License. #include #include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" -#include "tensorflow/contrib/lite/models/test_utils.h" +//#include "tensorflow/contrib/lite/models/test_utils.h" #include "tensorflow/contrib/lite/string_util.h" +#include "tensorflow/core/platform/test.h" namespace tflite { namespace custom { @@ -33,6 +34,11 @@ namespace { const char kModelName[] = "smartreply_ondevice_model.bin"; const char kSamples[] = "smartreply_samples.tsv"; +string TestDataPath() { + return string(StrCat(tensorflow::testing::TensorFlowSrcRoot(), "/", + "contrib/lite/models/testdata/")); +} + MATCHER_P(IncludeAnyResponesIn, expected_response, "contains the response") { bool has_expected_response = false; for (const auto &item : *arg) { diff --git a/tensorflow/contrib/lite/models/speech_asr_am_model_test.cc b/tensorflow/contrib/lite/models/speech_asr_am_model_test.cc deleted file mode 100644 index bf95b313f3..0000000000 --- a/tensorflow/contrib/lite/models/speech_asr_am_model_test.cc +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ -// Unit test for speech ASR AM model using TFLite Ops. - -#include - -#include -#include - -#include "base/logging.h" -#include "file/base/path.h" -#include "testing/base/public/googletest.h" -#include -#include "tensorflow/contrib/lite/context.h" -#include "tensorflow/contrib/lite/interpreter.h" -#include "tensorflow/contrib/lite/kernels/register.h" -#include "tensorflow/contrib/lite/model.h" -#include "tensorflow/contrib/lite/models/test_utils.h" - -namespace tflite { -namespace models { - -constexpr int kModelInputTensor = 0; -constexpr int kLstmLayer1OutputStateTensor = 19; -constexpr int kLstmLayer1CellStateTensor = 20; -constexpr int kLstmLayer2OutputStateTensor = 40; -constexpr int kLstmLayer2CellStateTensor = 41; -constexpr int kLstmLayer3OutputStateTensor = 61; -constexpr int kLstmLayer3CellStateTensor = 62; -constexpr int kLstmLayer4OutputStateTensor = 82; -constexpr int kLstmLayer4CellStateTensor = 83; -constexpr int kLstmLayer5OutputStateTensor = 103; -constexpr int kLstmLayer5CellStateTensor = 104; -constexpr int kModelOutputTensor = 109; - -TEST(SpeechAsrAm, RandomIOTest) { - // Read the model. - string tflite_file_path = - file::JoinPath(TestDataPath(), "speech_asr_am_model.tflite"); - auto model = FlatBufferModel::BuildFromFile(tflite_file_path.c_str()); - CHECK(model) << "Failed to mmap model " << tflite_file_path; - - // Initialize the interpreter. - ops::builtin::BuiltinOpResolver builtins; - std::unique_ptr interpreter; - InterpreterBuilder(*model, builtins)(&interpreter); - CHECK(interpreter != nullptr); - interpreter->AllocateTensors(); - - // Load the input frames. - Frames input_frames; - const string input_file_path = - file::JoinPath(TestDataPath(), "speech_asr_am_model_in.csv"); - ReadFrames(input_file_path, &input_frames); - - // Load the golden output results. - Frames output_frames; - const string output_file_path = - file::JoinPath(TestDataPath(), "speech_asr_am_model_out.csv"); - ReadFrames(output_file_path, &output_frames); - - const int speech_batch_size = - interpreter->tensor(kModelInputTensor)->dims->data[0]; - const int speech_input_size = - interpreter->tensor(kModelInputTensor)->dims->data[1]; - const int speech_output_size = - interpreter->tensor(kModelOutputTensor)->dims->data[1]; - - float* input_ptr = interpreter->tensor(kModelInputTensor)->data.f; - float* output_ptr = interpreter->tensor(kModelOutputTensor)->data.f; - - // Clear the LSTM state for layers. - memset(interpreter->tensor(kLstmLayer1OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer1CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer2OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer2CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer3OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer3OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer3CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer3CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer4OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer4OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer4CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer4CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer5OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer5OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer5CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer5CellStateTensor)->bytes); - - - for (int i = 0; i < input_frames.size(); i++) { - // Feed the input to model. - int frame_ptr = 0; - for (int k = 0; k < speech_input_size * speech_batch_size; k++) { - input_ptr[k] = input_frames[i][frame_ptr++]; - } - // Run the model. - interpreter->Invoke(); - // Validate the output. - for (int k = 0; k < speech_output_size; k++) { - ASSERT_NEAR(output_ptr[k], output_frames[i][k], 5.2e-4); - } - } -} - -} // namespace models -} // namespace tflite diff --git a/tensorflow/contrib/lite/models/speech_asr_lm_model_test.cc b/tensorflow/contrib/lite/models/speech_asr_lm_model_test.cc deleted file mode 100644 index 53f2b66da4..0000000000 --- a/tensorflow/contrib/lite/models/speech_asr_lm_model_test.cc +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ -// Unit test for speech ASR LM model using TFLite Ops. - -#include - -#include -#include - -#include "base/logging.h" -#include "file/base/path.h" -#include "testing/base/public/googletest.h" -#include -#include "tensorflow/contrib/lite/context.h" -#include "tensorflow/contrib/lite/interpreter.h" -#include "tensorflow/contrib/lite/kernels/register.h" -#include "tensorflow/contrib/lite/model.h" -#include "tensorflow/contrib/lite/models/test_utils.h" - -namespace tflite { -namespace models { - -constexpr int kModelInput1Tensor = 0; -constexpr int kModelInput2Tensor = 66; -constexpr int kLstmLayer1OutputStateTensor = 21; -constexpr int kLstmLayer1CellStateTensor = 22; -constexpr int kLstmLayer2OutputStateTensor = 42; -constexpr int kLstmLayer2CellStateTensor = 43; -constexpr int kLstmLayer3OutputStateTensor = 63; -constexpr int kLstmLayer3CellStateTensor = 64; -constexpr int kModelOutputTensor = 75; - -static void ClearLstmStates(Interpreter* interpreter) { - memset(interpreter->tensor(kLstmLayer1OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer1CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer2OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer2CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer3OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer3OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer3CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer3CellStateTensor)->bytes); -} - -TEST(SpeechAsrLm, EndToEndTest) { - // Read the model. - string tflite_file_path = - file::JoinPath(TestDataPath(), "speech_asr_lm_model.tflite"); - auto model = FlatBufferModel::BuildFromFile(tflite_file_path.c_str()); - CHECK(model) << "Failed to mmap model " << tflite_file_path; - - // Initialize the interpreter. - ops::builtin::BuiltinOpResolver builtins; - std::unique_ptr interpreter; - InterpreterBuilder(*model, builtins)(&interpreter); - CHECK(interpreter != nullptr); - interpreter->AllocateTensors(); - - // Load the input frames. - Frames input_frames; - const string input_file_path = - file::JoinPath(TestDataPath(), "speech_asr_lm_model_in.csv"); - ReadFrames(input_file_path, &input_frames); - - // Load the golden output results. - Frames output_frames; - const string output_file_path = - file::JoinPath(TestDataPath(), "speech_asr_lm_model_out.csv"); - ReadFrames(output_file_path, &output_frames); - - CHECK_EQ(interpreter->tensor(kModelInput1Tensor)->dims->size, 1); - const int input1_size = - interpreter->tensor(kModelInput1Tensor)->dims->data[0]; - CHECK_EQ(input1_size, 1); - CHECK_EQ(interpreter->tensor(kModelInput2Tensor)->dims->size, 1); - const int output_size = - interpreter->tensor(kModelOutputTensor)->dims->data[0]; - CHECK_EQ(output_size, 1); - - int* input_lookup_ptr = interpreter->tensor(kModelInput1Tensor)->data.i32; - int* output_lookup_ptr = interpreter->tensor(kModelInput2Tensor)->data.i32; - float* output_ptr = interpreter->tensor(kModelOutputTensor)->data.f; - - - for (int i = 0; i < input_frames.size(); i++) { - float output_score = 0.0f; - // Reset LSTM states for each sequence. - ClearLstmStates(interpreter.get()); - // For subsequent inputs feed them sequentially, one-by-one. - for (int k = 1; k < input_frames[i].size(); k++) { - // Feed the inputs to model. - input_lookup_ptr[0] = static_cast(input_frames[i][k - 1]); - output_lookup_ptr[0] = static_cast(input_frames[i][k]); - // Run the model. - interpreter->Invoke(); - // Sum up the outputs. - output_score += output_ptr[0]; - } - // Validate the output. - ASSERT_NEAR(output_score, output_frames[i][0], 1.4e-5); - } -} - -} // namespace models -} // namespace tflite diff --git a/tensorflow/contrib/lite/models/speech_endpointer_model_test.cc b/tensorflow/contrib/lite/models/speech_endpointer_model_test.cc deleted file mode 100644 index f7e136113a..0000000000 --- a/tensorflow/contrib/lite/models/speech_endpointer_model_test.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ -// Unit test for speech EndPointer model using TFLite Ops. - -#include - -#include -#include - -#include "base/logging.h" -#include "testing/base/public/googletest.h" -#include -#include "absl/strings/str_cat.h" -#include "tensorflow/contrib/lite/context.h" -#include "tensorflow/contrib/lite/interpreter.h" -#include "tensorflow/contrib/lite/kernels/register.h" -#include "tensorflow/contrib/lite/model.h" -#include "tensorflow/contrib/lite/models/test_utils.h" - -namespace tflite { -namespace models { - -constexpr int kModelInputTensor = 0; -constexpr int kLstmLayer1OutputStateTensor = 28; -constexpr int kLstmLayer1CellStateTensor = 29; -constexpr int kLstmLayer2OutputStateTensor = 49; -constexpr int kLstmLayer2CellStateTensor = 50; -constexpr int kModelOutputTensor = 58; - -TEST(SpeechEndpointer, EndpointerTest) { - // Read the model. - string tflite_file_path = - StrCat(TestDataPath(), "/", "speech_endpointer_model.tflite"); - auto model = FlatBufferModel::BuildFromFile(tflite_file_path.c_str()); - CHECK(model) << "Failed to read model from file " << tflite_file_path; - - // Initialize the interpreter. - ops::builtin::BuiltinOpResolver builtins; - std::unique_ptr interpreter; - InterpreterBuilder(*model, builtins)(&interpreter); - CHECK(interpreter != nullptr); - interpreter->AllocateTensors(); - - // Load the input frames. - Frames input_frames; - const string input_file_path = - StrCat(TestDataPath(), "/", "speech_endpointer_model_in.csv"); - ReadFrames(input_file_path, &input_frames); - - // Load the golden output results. - Frames output_frames; - const string output_file_path = - StrCat(TestDataPath(), "/", "speech_endpointer_model_out.csv"); - ReadFrames(output_file_path, &output_frames); - - const int speech_batch_size = - interpreter->tensor(kModelInputTensor)->dims->data[0]; - const int speech_input_size = - interpreter->tensor(kModelInputTensor)->dims->data[1]; - const int speech_output_size = - interpreter->tensor(kModelOutputTensor)->dims->data[1]; - - float* input_ptr = interpreter->tensor(kModelInputTensor)->data.f; - float* output_ptr = interpreter->tensor(kModelOutputTensor)->data.f; - - // Clear the LSTM state for layers. - memset(interpreter->tensor(kLstmLayer1OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer1CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1CellStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer2OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer2CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2CellStateTensor)->bytes); - - for (int i = 0; i < input_frames.size(); i++) { - // Feed the input to model. - int frame_ptr = 0; - for (int k = 0; k < speech_input_size * speech_batch_size; k++) { - input_ptr[k] = input_frames[i][frame_ptr++]; - } - // Run the model. - interpreter->Invoke(); - // Validate the output. - for (int k = 0; k < speech_output_size; k++) { - ASSERT_NEAR(output_ptr[k], output_frames[i][k], 1e-5); - } - } -} - -} // namespace models -} // namespace tflite diff --git a/tensorflow/contrib/lite/models/speech_hotword_model_test.cc b/tensorflow/contrib/lite/models/speech_hotword_model_test.cc deleted file mode 100644 index f69cae8d2c..0000000000 --- a/tensorflow/contrib/lite/models/speech_hotword_model_test.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ -// Unit test for speech Hotword model using TFLite Ops. - -#include - -#include -#include - -#include "base/logging.h" -#include "testing/base/public/googletest.h" -#include -#include "absl/strings/str_cat.h" -#include "tensorflow/contrib/lite/context.h" -#include "tensorflow/contrib/lite/interpreter.h" -#include "tensorflow/contrib/lite/kernels/register.h" -#include "tensorflow/contrib/lite/model.h" -#include "tensorflow/contrib/lite/models/test_utils.h" - -namespace tflite { -namespace models { - -void RunTest(int model_input_tensor, int svdf_layer_state_tensor, - int model_output_tensor, const string& model_name, - const string& golden_in_name, const string& golden_out_name) { - // Read the model. - string tflite_file_path = StrCat(TestDataPath(), "/", model_name); - auto model = FlatBufferModel::BuildFromFile(tflite_file_path.c_str()); - CHECK(model) << "Failed to read model from file " << tflite_file_path; - - // Initialize the interpreter. - ops::builtin::BuiltinOpResolver builtins; - std::unique_ptr interpreter; - InterpreterBuilder(*model, builtins)(&interpreter); - CHECK(interpreter != nullptr); - interpreter->AllocateTensors(); - - // Reset the SVDF layer state. - memset(interpreter->tensor(svdf_layer_state_tensor)->data.raw, 0, - interpreter->tensor(svdf_layer_state_tensor)->bytes); - - // Load the input frames. - Frames input_frames; - const string input_file_path = StrCat(TestDataPath(), "/", golden_in_name); - ReadFrames(input_file_path, &input_frames); - - // Load the golden output results. - Frames output_frames; - const string output_file_path = StrCat(TestDataPath(), "/", golden_out_name); - ReadFrames(output_file_path, &output_frames); - - const int speech_batch_size = - interpreter->tensor(model_input_tensor)->dims->data[0]; - const int speech_input_size = - interpreter->tensor(model_input_tensor)->dims->data[1]; - const int speech_output_size = - interpreter->tensor(model_output_tensor)->dims->data[1]; - const int input_sequence_size = - input_frames[0].size() / (speech_input_size * speech_batch_size); - float* input_ptr = interpreter->tensor(model_input_tensor)->data.f; - float* output_ptr = interpreter->tensor(model_output_tensor)->data.f; - - // The first layer (SVDF) input size is 40 (speech_input_size). Each speech - // input frames for this model is 1600 floats, which can be fed to input in a - // sequence of size 40 (input_sequence_size). - for (int i = 0; i < TestInputSize(input_frames); i++) { - int frame_ptr = 0; - for (int s = 0; s < input_sequence_size; s++) { - for (int k = 0; k < speech_input_size * speech_batch_size; k++) { - input_ptr[k] = input_frames[i][frame_ptr++]; - } - interpreter->Invoke(); - } - // After the whole frame (1280 floats) is fed, we can check the output frame - // matches with the golden output frame. - for (int k = 0; k < speech_output_size; k++) { - ASSERT_NEAR(output_ptr[k], output_frames[i][k], 1e-5); - } - } -} - -TEST(SpeechHotword, OkGoogleTestRank1) { - constexpr int kModelInputTensor = 0; - constexpr int kSvdfLayerStateTensor = 4; - constexpr int kModelOutputTensor = 18; - - RunTest(kModelInputTensor, kSvdfLayerStateTensor, kModelOutputTensor, - "speech_hotword_model_rank1.tflite", "speech_hotword_model_in.csv", - "speech_hotword_model_out_rank1.csv"); -} - -TEST(SpeechHotword, OkGoogleTestRank2) { - constexpr int kModelInputTensor = 17; - constexpr int kSvdfLayerStateTensor = 1; - constexpr int kModelOutputTensor = 18; - RunTest(kModelInputTensor, kSvdfLayerStateTensor, kModelOutputTensor, - "speech_hotword_model_rank2.tflite", "speech_hotword_model_in.csv", - "speech_hotword_model_out_rank2.csv"); -} - -} // namespace models -} // namespace tflite diff --git a/tensorflow/contrib/lite/models/speech_speakerid_model_test.cc b/tensorflow/contrib/lite/models/speech_speakerid_model_test.cc deleted file mode 100644 index e208fac8df..0000000000 --- a/tensorflow/contrib/lite/models/speech_speakerid_model_test.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ -// Unit test for speech SpeakerId model using TFLite Ops. - -#include - -#include -#include - -#include "base/logging.h" -#include "testing/base/public/googletest.h" -#include -#include "absl/strings/str_cat.h" -#include "tensorflow/contrib/lite/context.h" -#include "tensorflow/contrib/lite/interpreter.h" -#include "tensorflow/contrib/lite/model.h" -#include "tensorflow/contrib/lite/models/test_utils.h" -#include "tensorflow/contrib/lite/tools/mutable_op_resolver.h" - -void RegisterSelectedOps(::tflite::MutableOpResolver* resolver); - -namespace tflite { -namespace models { - -constexpr int kModelInputTensor = 0; -constexpr int kLstmLayer1OutputStateTensor = 19; -constexpr int kLstmLayer1CellStateTensor = 20; -constexpr int kLstmLayer2OutputStateTensor = 40; -constexpr int kLstmLayer2CellStateTensor = 41; -constexpr int kLstmLayer3OutputStateTensor = 61; -constexpr int kLstmLayer3CellStateTensor = 62; -constexpr int kModelOutputTensor = 66; - -void SpeakerIdTest(bool useNNAPI) { - // Read the model. - string tflite_file_path = - StrCat(TestDataPath(), "/", "speech_speakerid_model.tflite"); - auto model = FlatBufferModel::BuildFromFile(tflite_file_path.c_str()); - CHECK(model) << "Failed to read model from file " << tflite_file_path; - - // Initialize the interpreter. - ::tflite::MutableOpResolver resolver; - RegisterSelectedOps(&resolver); - std::unique_ptr interpreter; - InterpreterBuilder(*model, resolver)(&interpreter); - CHECK(interpreter != nullptr); - - interpreter->UseNNAPI(useNNAPI); - - interpreter->AllocateTensors(); - - // Load the input frames. - Frames input_frames; - const string input_file_path = - StrCat(TestDataPath(), "/", "speech_speakerid_model_in.csv"); - ReadFrames(input_file_path, &input_frames); - - // Load the golden output results. - Frames output_frames; - const string output_file_path = - StrCat(TestDataPath(), "/", "speech_speakerid_model_out.csv"); - ReadFrames(output_file_path, &output_frames); - - const int speech_batch_size = - interpreter->tensor(kModelInputTensor)->dims->data[0]; - const int speech_input_size = - interpreter->tensor(kModelInputTensor)->dims->data[1]; - const int speech_output_size = - interpreter->tensor(kModelOutputTensor)->dims->data[1]; - - float* input_ptr = interpreter->tensor(kModelInputTensor)->data.f; - float* output_ptr = interpreter->tensor(kModelOutputTensor)->data.f; - - // Clear the LSTM state for layers. - memset(interpreter->tensor(kLstmLayer1OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer1CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer2OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer2CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer3OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer3OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer3CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer3CellStateTensor)->bytes); - for (int i = 0; i < input_frames.size(); i++) { - // Feed the input to model. - int frame_ptr = 0; - for (int k = 0; k < speech_input_size * speech_batch_size; k++) { - input_ptr[k] = input_frames[i][frame_ptr++]; - } - // Run the model. - interpreter->Invoke(); - // Validate the output. - for (int k = 0; k < speech_output_size; k++) { - ASSERT_NEAR(output_ptr[k], output_frames[i][k], 1e-5); - } - } -} - -TEST(SpeechSpeakerId, OkGoogleTest) { SpeakerIdTest(false); } - -TEST(SpeechSpeakerId, OkGoogleTestUsingNNAPI) { SpeakerIdTest(true); } - -} // namespace models -} // namespace tflite diff --git a/tensorflow/contrib/lite/models/speech_tts_model_test.cc b/tensorflow/contrib/lite/models/speech_tts_model_test.cc deleted file mode 100644 index 8829177689..0000000000 --- a/tensorflow/contrib/lite/models/speech_tts_model_test.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ -// Unit test for speech TTS model using TFLite Ops. - -#include - -#include -#include - -#include "base/logging.h" -#include "testing/base/public/googletest.h" -#include -#include "absl/strings/str_cat.h" -#include "tensorflow/contrib/lite/context.h" -#include "tensorflow/contrib/lite/interpreter.h" -#include "tensorflow/contrib/lite/kernels/register.h" -#include "tensorflow/contrib/lite/model.h" -#include "tensorflow/contrib/lite/models/test_utils.h" - -namespace tflite { -namespace models { - -constexpr int kModelInputTensor = 0; -constexpr int kLstmLayer1OutputStateTensor = 25; -constexpr int kLstmLayer1CellStateTensor = 26; -constexpr int kLstmLayer2OutputStateTensor = 46; -constexpr int kLstmLayer2CellStateTensor = 47; -constexpr int kLstmLayer3OutputStateTensor = 67; -constexpr int kLstmLayer3CellStateTensor = 68; -constexpr int kRnnLayerHiddenStateTensor = 73; -constexpr int kModelOutputTensor = 74; - -TEST(SpeechTTS, RandomIOTest) { - // Read the model. - string tflite_file_path = - StrCat(TestDataPath(), "/", "speech_tts_model.tflite"); - auto model = FlatBufferModel::BuildFromFile(tflite_file_path.c_str()); - CHECK(model) << "Failed to mmap model " << tflite_file_path; - - // Initialize the interpreter. - ops::builtin::BuiltinOpResolver builtins; - std::unique_ptr interpreter; - InterpreterBuilder(*model, builtins)(&interpreter); - CHECK(interpreter != nullptr); - interpreter->AllocateTensors(); - - // Load the input frames. - Frames input_frames; - const string input_file_path = - StrCat(TestDataPath(), "/", "speech_tts_model_in.csv"); - ReadFrames(input_file_path, &input_frames); - - // Load the golden output results. - Frames output_frames; - const string output_file_path = - StrCat(TestDataPath(), "/", "speech_tts_model_out.csv"); - ReadFrames(output_file_path, &output_frames); - - const int speech_batch_size = - interpreter->tensor(kModelInputTensor)->dims->data[0]; - const int speech_input_size = - interpreter->tensor(kModelInputTensor)->dims->data[1]; - const int speech_output_size = - interpreter->tensor(kModelOutputTensor)->dims->data[1]; - - float* input_ptr = interpreter->tensor(kModelInputTensor)->data.f; - float* output_ptr = interpreter->tensor(kModelOutputTensor)->data.f; - - // Clear the LSTM state for layers. - memset(interpreter->tensor(kLstmLayer1OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer1CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer1CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer2OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer2CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer2CellStateTensor)->bytes); - - memset(interpreter->tensor(kLstmLayer3OutputStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer3OutputStateTensor)->bytes); - memset(interpreter->tensor(kLstmLayer3CellStateTensor)->data.raw, 0, - interpreter->tensor(kLstmLayer3CellStateTensor)->bytes); - - memset(interpreter->tensor(kRnnLayerHiddenStateTensor)->data.raw, 0, - interpreter->tensor(kRnnLayerHiddenStateTensor)->bytes); - - for (int i = 0; i < input_frames.size(); i++) { - // Feed the input to model. - int frame_ptr = 0; - for (int k = 0; k < speech_input_size * speech_batch_size; k++) { - input_ptr[k] = input_frames[i][frame_ptr++]; - } - // Run the model. - interpreter->Invoke(); - // Validate the output. - for (int k = 0; k < speech_output_size; k++) { - ASSERT_NEAR(output_ptr[k], output_frames[i][k], 1e-5); - } - } -} - -} // namespace models -} // namespace tflite diff --git a/tensorflow/contrib/lite/models/test_utils.h b/tensorflow/contrib/lite/models/test_utils.h deleted file mode 100644 index 1e14c26a35..0000000000 --- a/tensorflow/contrib/lite/models/test_utils.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODELS_TEST_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODELS_TEST_UTILS_H_ - -#include -#include - -#include -#include -#include -#include - -namespace tflite { -namespace models { -using Frames = std::vector>; -} // namespace models -} // namespace tflite - -#ifndef __ANDROID__ -#include "absl/strings/str_cat.h" -#include "tensorflow/core/platform/test.h" - -inline string TestDataPath() { - return string(StrCat(tensorflow::testing::TensorFlowSrcRoot(), "/", - "contrib/lite/models/testdata/")); -} -inline int TestInputSize(const tflite::models::Frames& input_frames) { - return input_frames.size(); -} -#else -inline string TestDataPath() { - return string("third_party/tensorflow/contrib/lite/models/testdata/"); -} - -inline int TestInputSize(const tflite::models::Frames& input_frames) { - // Android TAP is very slow, we only test the first 20 frames. - return 20; -} -#endif - -namespace tflite { -namespace models { - -// Read float data from a comma-separated file: -// Each line will be read into a float vector. -// The return result will be a vector of float vectors. -void ReadFrames(const string& csv_file_path, Frames* frames) { - std::ifstream csv_file(csv_file_path); - string line; - while (std::getline(csv_file, line, '\n')) { - std::vector fields; - // Used by strtok_r internaly for successive calls on the same string. - char* save_ptr = nullptr; - - // Tokenize the line. - char* next_token = - strtok_r(const_cast(line.c_str()), ",", &save_ptr); - while (next_token != nullptr) { - float f = strtod(next_token, nullptr); - fields.push_back(f); - next_token = strtok_r(nullptr, ",", &save_ptr); - } - frames->push_back(fields); - } - csv_file.close(); -} - -} // namespace models -} // namespace tflite - -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODELS_TEST_UTILS_H_ -- GitLab From a68bf328ff6d4261203f2aa723d77174a771a0ec Mon Sep 17 00:00:00 2001 From: brett koonce Date: Wed, 24 Jan 2018 10:45:52 -0800 Subject: [PATCH 187/258] minor spelling tweaks for eager execution docs (#16355) --- tensorflow/contrib/eager/python/evaluator.py | 2 +- .../contrib/eager/python/examples/resnet50/README.md | 2 +- .../contrib/eager/python/examples/resnet50/resnet50.py | 2 +- .../contrib/eager/python/examples/rnn_ptb/README.md | 2 +- .../contrib/eager/python/examples/rnn_ptb/rnn_ptb.py | 4 ++-- tensorflow/contrib/eager/python/examples/spinn/data.py | 10 +++++----- tensorflow/contrib/eager/python/network_test.py | 2 +- tensorflow/contrib/eager/python/saver.py | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tensorflow/contrib/eager/python/evaluator.py b/tensorflow/contrib/eager/python/evaluator.py index 3faaeef590..68e7b5421f 100644 --- a/tensorflow/contrib/eager/python/evaluator.py +++ b/tensorflow/contrib/eager/python/evaluator.py @@ -178,7 +178,7 @@ class Evaluator(object): call_op: An op that updates evaluation state on a mini-batch of examples. Must generate an tf.errors.OutOfRangeError when done. results_op: A dictionary of tensors that compute the final evaluation - results from the evaulation state. + results from the evaluation state. sess: The Session to run the evaluation in. Defaults to the default Session. diff --git a/tensorflow/contrib/eager/python/examples/resnet50/README.md b/tensorflow/contrib/eager/python/examples/resnet50/README.md index db023e6c97..79e4600529 100644 --- a/tensorflow/contrib/eager/python/examples/resnet50/README.md +++ b/tensorflow/contrib/eager/python/examples/resnet50/README.md @@ -34,7 +34,7 @@ bazel run -c opt --config=cuda :resnet50_graph_test -- --benchmarks=. (Or remove the `--config=cuda` flag for running on CPU instead of GPU). -On October 31, 2017, the benchmarks demostrated comparable performance +On October 31, 2017, the benchmarks demonstrated comparable performance for eager and graph execution of this particular model when using a single NVIDIA Titan X (Pascal) GPU on a host with an Intel Xeon E5-1650 CPU @ 3.50GHz and a batch size of 32. diff --git a/tensorflow/contrib/eager/python/examples/resnet50/resnet50.py b/tensorflow/contrib/eager/python/examples/resnet50/resnet50.py index b302a87e0e..9982fdb07e 100644 --- a/tensorflow/contrib/eager/python/examples/resnet50/resnet50.py +++ b/tensorflow/contrib/eager/python/examples/resnet50/resnet50.py @@ -97,7 +97,7 @@ class _ConvBlock(tfe.Network): Args: kernel_size: the kernel size of middle conv layer at main path - filters: list of integers, the filterss of 3 conv layer at main path + filters: list of integers, the filters of 3 conv layer at main path stage: integer, current stage label, used for generating layer names block: 'a','b'..., current block label, used for generating layer names data_format: data_format for the input ('channels_first' or diff --git a/tensorflow/contrib/eager/python/examples/rnn_ptb/README.md b/tensorflow/contrib/eager/python/examples/rnn_ptb/README.md index 743ebb68ee..966177e91c 100644 --- a/tensorflow/contrib/eager/python/examples/rnn_ptb/README.md +++ b/tensorflow/contrib/eager/python/examples/rnn_ptb/README.md @@ -40,7 +40,7 @@ bazel run -c opt --config=cuda :rnn_ptb_graph_test -- --benchmarks=. (Or remove the `--config=cuda` flag for running on CPU instead of GPU). -On October 31, 2017, the benchmarks demostrated slightly better performance +On October 31, 2017, the benchmarks demonstrated slightly better performance (3-6%) for graph execution over eager execution for this particular model when using a single NVIDIA Titan X (Pascal) GPU on a host with an Intel Xeon E5-1650 CPU @ 3.50GHz and a batch size of 32. diff --git a/tensorflow/contrib/eager/python/examples/rnn_ptb/rnn_ptb.py b/tensorflow/contrib/eager/python/examples/rnn_ptb/rnn_ptb.py index 7b9637a9d5..d34e9ea68b 100644 --- a/tensorflow/contrib/eager/python/examples/rnn_ptb/rnn_ptb.py +++ b/tensorflow/contrib/eager/python/examples/rnn_ptb/rnn_ptb.py @@ -88,7 +88,7 @@ class Embedding(tf.layers.Layer): class PTBModel(tfe.Network): - """LSTM for word language modelling. + """LSTM for word language modeling. Model described in: (Zaremba, et. al.) Recurrent Neural Network Regularization @@ -340,7 +340,7 @@ if __name__ == "__main__": parser.add_argument( "--logdir", type=str, default="", help="Directory for checkpoint.") parser.add_argument( - "--epoch", type=int, default=20, help="Number of epoches.") + "--epoch", type=int, default=20, help="Number of epochs.") parser.add_argument("--batch-size", type=int, default=20, help="Batch size.") parser.add_argument( "--seq-len", type=int, default=35, help="Sequence length.") diff --git a/tensorflow/contrib/eager/python/examples/spinn/data.py b/tensorflow/contrib/eager/python/examples/spinn/data.py index a6e046320f..fcaae0a4f8 100644 --- a/tensorflow/contrib/eager/python/examples/spinn/data.py +++ b/tensorflow/contrib/eager/python/examples/spinn/data.py @@ -51,11 +51,11 @@ def get_non_parenthesis_words(items): """Get the non-parenthesis items from a SNLI parsed sentence. Args: - items: Data items from a parsed SNLI setence, with parentheses. E.g., + items: Data items from a parsed SNLI sentence, with parentheses. E.g., ["(", "Man", "(", "(", "(", "(", "(", "wearing", "pass", ")", ... Returns: - A list of non-parenthis word items, all converted to lower case. E.g., + A list of non-parentheses word items, all converted to lower case. E.g., ["man", "wearing", "pass", ... """ return [x.lower() for x in items if x not in PARENTHESES and x] @@ -201,7 +201,7 @@ def load_word_vectors(data_root, vocab): def calculate_bins(length2count, min_bin_size): - """Cacluate bin boundaries given a histogram of lengths and mininum bin size. + """Calculate bin boundaries given a histogram of lengths and minimum bin size. Args: length2count: A `dict` mapping length to sentence count. @@ -335,9 +335,9 @@ class SnliData(object): # The sorting above and the batching here makes sure that sentences of # similar max lengths are batched together, minimizing the inefficiency # due to uneven max lengths. The sentences are batched differently in - # each call to get_generator() due to the shuffling before sotring + # each call to get_generator() due to the shuffling before sorting # above. The pad_and_reverse_word_ids() and pad_transitions() functions - # take care of any remaning unevenness of the max sentence lengths. + # take care of any remaining unevenness of the max sentence lengths. end = min(begin + batch_size, len(labels)) # Transpose, because the SPINN model requires time-major, instead of # batch-major. diff --git a/tensorflow/contrib/eager/python/network_test.py b/tensorflow/contrib/eager/python/network_test.py index 8e6b947e5c..81c77e41ac 100644 --- a/tensorflow/contrib/eager/python/network_test.py +++ b/tensorflow/contrib/eager/python/network_test.py @@ -688,7 +688,7 @@ class NetworkTest(test.TestCase): net2(one) # Layer names typically are globally unique rather than being unique within # the scope of their first use. However, within a Network they must be named - # locally so that previous Layer consutrciton does not interfere with + # locally so that previous Layer construction does not interfere with # variable naming (e.g. add a Layer construction before the Network, # suddenly your previously saved checkpoint is incompatible). self.assertEqual("dense", net1.l1.name) diff --git a/tensorflow/contrib/eager/python/saver.py b/tensorflow/contrib/eager/python/saver.py index 57b070ec6e..62421849c7 100644 --- a/tensorflow/contrib/eager/python/saver.py +++ b/tensorflow/contrib/eager/python/saver.py @@ -82,7 +82,7 @@ def restore_variables_on_create(save_path, map_func=None): map_func_wrapper = lambda self, x: x else: if not callable(map_func): - raise ValueError("map_func must be callaled.") + raise ValueError("map_func must be callable.") map_func_wrapper = lambda self, x: map_func(x) ckpt_var_cache = dict() -- GitLab From 44a4674d196b27b1e1f998de910af945a25b2c52 Mon Sep 17 00:00:00 2001 From: Yifei Feng Date: Wed, 24 Jan 2018 10:56:37 -0800 Subject: [PATCH 188/258] Revert #15967. Make pip package size too large. --- tensorflow/tools/graph_transforms/BUILD | 12 ------ .../graph_transforms_wrapper.py | 39 ------------------- tensorflow/tools/pip_package/BUILD | 2 - .../tools/pip_package/build_pip_package.sh | 2 - tensorflow/tools/pip_package/setup.py | 1 - 5 files changed, 56 deletions(-) delete mode 100644 tensorflow/tools/graph_transforms/graph_transforms_wrapper.py diff --git a/tensorflow/tools/graph_transforms/BUILD b/tensorflow/tools/graph_transforms/BUILD index 31c4349431..b5465b7fb3 100644 --- a/tensorflow/tools/graph_transforms/BUILD +++ b/tensorflow/tools/graph_transforms/BUILD @@ -317,18 +317,6 @@ tf_py_test( main = "python/transform_graph_test.py", ) -py_binary( - name = "graph_transforms_wrapper", - srcs = ["graph_transforms_wrapper.py"], - srcs_version = "PY2AND3", - data = [ - ":transform_graph", - ], - deps = [ - "//tensorflow:tensorflow_py", - ], -) - filegroup( name = "all_files", srcs = glob( diff --git a/tensorflow/tools/graph_transforms/graph_transforms_wrapper.py b/tensorflow/tools/graph_transforms/graph_transforms_wrapper.py deleted file mode 100644 index e12feddba2..0000000000 --- a/tensorflow/tools/graph_transforms/graph_transforms_wrapper.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2017 The TensorFlow Authors. 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. -# ============================================================================== -"""Wrapper for runninmg graph_transform binary embedded in pip site-package. -NOTE: this mainly exists since PIP setup.py cannot install binaries to bin/. -It can only install Python "console-scripts." This will work as a console -script. See tools/pip_package/setup.py (search for CONSOLE_SCRIPTS). -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import os -import sys -import tensorflow as tf - - -def main(): - # Pip installs the binary in aux-bin off of main site-package install. - # Just find it and exec, passing all arguments in the process. - pip_binary = os.path.join(tf.__path__[0], 'aux-bin/transform_graph') - bazel_binary = ('bazel-bin/tensorflow/tools/graph_transforms/' - 'graph_transforms_wrapper.runfiles/org_tensorflow/' - 'tensorflow/tools/graph_transforms/transform_graph') - binary = bazel_binary if os.path.isfile(bazel_binary) else pip_binary - os.execvp(binary, sys.argv) - -main() diff --git a/tensorflow/tools/pip_package/BUILD b/tensorflow/tools/pip_package/BUILD index d61ddb889c..c789e2ba0c 100644 --- a/tensorflow/tools/pip_package/BUILD +++ b/tensorflow/tools/pip_package/BUILD @@ -179,8 +179,6 @@ sh_binary( "//tensorflow/python/tools:tools_pip", "//tensorflow/python:test_ops", "//tensorflow/tools/dist_test/server:grpc_tensorflow_server", - "//tensorflow/tools/graph_transforms:graph_transforms_wrapper", - "//tensorflow/tools/graph_transforms:transform_graph", ], }) + if_mkl(["//third_party/mkl:intel_binary_blob"]), ) diff --git a/tensorflow/tools/pip_package/build_pip_package.sh b/tensorflow/tools/pip_package/build_pip_package.sh index 32b8c54a56..dc31e4c5f7 100755 --- a/tensorflow/tools/pip_package/build_pip_package.sh +++ b/tensorflow/tools/pip_package/build_pip_package.sh @@ -140,8 +140,6 @@ function main() { mkdir "${TMPDIR}/tensorflow/aux-bin" # Install toco as a binary in aux-bin. cp bazel-bin/tensorflow/contrib/lite/toco/toco ${TMPDIR}/tensorflow/aux-bin/ - # Install graph transform tool as a bianry in aux-bin - cp bazel-bin/tensorflow/tools/graph_transforms/transform_graph ${TMPDIR}/tensorflow/aux-bin/ fi # protobuf pip package doesn't ship with header files. Copy the headers diff --git a/tensorflow/tools/pip_package/setup.py b/tensorflow/tools/pip_package/setup.py index 0034fe447c..62df6453fb 100644 --- a/tensorflow/tools/pip_package/setup.py +++ b/tensorflow/tools/pip_package/setup.py @@ -74,7 +74,6 @@ CONSOLE_SCRIPTS = [ 'freeze_graph = tensorflow.python.tools.freeze_graph:main', 'toco_from_protos = tensorflow.contrib.lite.toco.python.toco_from_protos:main', 'toco = tensorflow.contrib.lite.toco.python.toco_wrapper:main', - 'transform_graph = tensorflow.tools.graph_transforms.graph_transforms_wrapper:main', 'saved_model_cli = tensorflow.python.tools.saved_model_cli:main', # We need to keep the TensorBoard command, even though the console script # is now declared by the tensorboard pip package. If we remove the -- GitLab From 5031e9f169a488eebd00eb7602e27ba6516f2486 Mon Sep 17 00:00:00 2001 From: Anna R Date: Wed, 24 Jan 2018 10:55:55 -0800 Subject: [PATCH 189/258] Fix update_api_def.sh script to output ApiDefs instead of ApiDef proto. PiperOrigin-RevId: 183109303 --- tensorflow/core/api_def/update_api_def.cc | 8 ++--- tensorflow/core/api_def/update_api_def.h | 2 +- .../core/api_def/update_api_def_test.cc | 32 ++++++++++--------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/tensorflow/core/api_def/update_api_def.cc b/tensorflow/core/api_def/update_api_def.cc index 1a6d15ec68..ea9a148260 100644 --- a/tensorflow/core/api_def/update_api_def.cc +++ b/tensorflow/core/api_def/update_api_def.cc @@ -224,14 +224,14 @@ void RemoveDocs(const std::vector& ops, } } // namespace -// Returns ApiDef text representation in multi-line format +// Returns ApiDefs text representation in multi-line format // constructed based on the given op. string CreateApiDef(const OpDef& op) { - ApiDef api_def; - FillBaseApiDef(&api_def, op); + ApiDefs api_defs; + FillBaseApiDef(api_defs.add_op(), op); const std::vector multi_line_fields = {"description"}; - string new_api_defs_str = api_def.DebugString(); + string new_api_defs_str = api_defs.DebugString(); return PBTxtToMultiline(new_api_defs_str, multi_line_fields); } diff --git a/tensorflow/core/api_def/update_api_def.h b/tensorflow/core/api_def/update_api_def.h index 5eae7e528e..5d6c15010d 100644 --- a/tensorflow/core/api_def/update_api_def.h +++ b/tensorflow/core/api_def/update_api_def.h @@ -21,7 +21,7 @@ limitations under the License. namespace tensorflow { -// Returns ApiDef text representation in multi-line format +// Returns ApiDefs text representation in multi-line format // constructed based on the given op. string CreateApiDef(const OpDef& op); diff --git a/tensorflow/core/api_def/update_api_def_test.cc b/tensorflow/core/api_def/update_api_def_test.cc index 8948f2c1d5..4200c9da23 100644 --- a/tensorflow/core/api_def/update_api_def_test.cc +++ b/tensorflow/core/api_def/update_api_def_test.cc @@ -173,30 +173,32 @@ description: "Description\nfor Op1." OpDef op; protobuf::TextFormat::ParseFromString(op_text, &op); // NOLINT - const string expected_api_def = R"(graph_op_name: "Op1" -in_arg { - name: "a" - description: < Date: Wed, 24 Jan 2018 10:57:28 -0800 Subject: [PATCH 190/258] Introduce experimental quantize training and eval apis. These APIs will include options that may have undefined behavior, still being researched. The non experimental APIs will have better hardware support and will be more suitable for users aiming to rewrite graphs to provide to backends (e.g. TFLite). PiperOrigin-RevId: 183109634 --- tensorflow/contrib/quantize/__init__.py | 2 + .../contrib/quantize/python/quantize_graph.py | 64 +++++++++++++++++++ .../quantize/python/quantize_graph_test.py | 56 +++++++--------- 3 files changed, 88 insertions(+), 34 deletions(-) diff --git a/tensorflow/contrib/quantize/__init__.py b/tensorflow/contrib/quantize/__init__.py index 5d4e4575c9..933200e607 100644 --- a/tensorflow/contrib/quantize/__init__.py +++ b/tensorflow/contrib/quantize/__init__.py @@ -27,6 +27,8 @@ from tensorflow.python.util.all_util import remove_undocumented _allowed_symbols = [ "create_eval_graph", "create_training_graph", + "experimental_create_eval_graph", + "experimental_create_training_graph", ] remove_undocumented(__name__, _allowed_symbols) diff --git a/tensorflow/contrib/quantize/python/quantize_graph.py b/tensorflow/contrib/quantize/python/quantize_graph.py index d647bb94e8..bbd9743d80 100644 --- a/tensorflow/contrib/quantize/python/quantize_graph.py +++ b/tensorflow/contrib/quantize/python/quantize_graph.py @@ -128,3 +128,67 @@ def create_eval_graph(input_graph, elements=None, device_name_or_function=None): is_training=False, elements=elements, device_name_or_function=device_name_or_function) + + +def experimental_create_training_graph(input_graph, + elements=None, + device_name_or_function=None): + """Returns a transformed training input_graph for simulated quantization. + + This function has additional experimental options not (yet) available to + create_training_graph. The resulting behavior may be undefined. + The forward pass has fake quantization ops inserted to simulate the error + introduced by quantization. + + Args: + input_graph: The tf.Graph to be transformed. + elements: (Optional) List of Tensors and Operations in input_graph whose + corresponding elements in the new graph will be returned. + device_name_or_function: (Optional) The device name or function to use. + + Returns: + g is new tf.Graph that is rewritten for simulated quantization. + l is a list of Tensors/Operations in g corresponding to the provided input + elements, if elements is not None. + + Raises: + ValueError: If elements contains an element that isn't a tf.Tensor or + tf.Operation. + """ + return _create_graph( + input_graph=input_graph, + is_training=True, + elements=elements, + device_name_or_function=device_name_or_function) + + +def experimental_create_eval_graph(input_graph, + elements=None, + device_name_or_function=None): + """Returns a transformed eval input_graph for simulated quantization. + + This function has additional experimental options not (yet) available to + create_eval_graph. The resulting behavior may be undefined. + The forward pass has fake quantization ops inserted to simulate the error + introduced by quantization. + + Args: + input_graph: The tf.Graph to be transformed. + elements: (Optional) List of Tensors and Operations in input_graph whose + corresponding elements in the new graph will be returned. + device_name_or_function: (Optional) The device name or function to use. + + Returns: + g is new tf.Graph that is rewritten for simulated quantization. + l is a list of Tensors/Operations in g corresponding to the provided input + elements, if elements is not None. + + Raises: + ValueError: If elements contains an element that isn't a tf.Tensor or + tf.Operation. + """ + return _create_graph( + input_graph=input_graph, + is_training=False, + elements=elements, + device_name_or_function=device_name_or_function) diff --git a/tensorflow/contrib/quantize/python/quantize_graph_test.py b/tensorflow/contrib/quantize/python/quantize_graph_test.py index 3407ace391..514862a0ab 100644 --- a/tensorflow/contrib/quantize/python/quantize_graph_test.py +++ b/tensorflow/contrib/quantize/python/quantize_graph_test.py @@ -31,28 +31,30 @@ from tensorflow.python.platform import googletest class QuantizeGraphTest(test_util.TensorFlowTestCase): - # We have a lot of other tests that test the details of the rewrite, here we # just the specific features of the quantize_graph API. - def testReturnedElementsTraining(self): - self._TestReturnElements(True) - def testReturnedElementsEval(self): - self._TestReturnElements(False) + def _RunTestOverParameters(self, test_fn): + rewrite_fns = [ + quantize_graph.create_training_graph, + quantize_graph.create_eval_graph, + quantize_graph.experimental_create_training_graph, + quantize_graph.experimental_create_eval_graph, + ] + for fn in rewrite_fns: + test_fn(fn) + + def testReturnedElements(self): + self._RunTestOverParameters(self._TestReturnElements) - def _TestReturnElements(self, is_training): + def _TestReturnElements(self, fn): graph = ops.Graph() with graph.as_default(): a = constant_op.constant(1.0) b = variables.Variable(2.0) c = a + b elements = [a, b, c.op] - if is_training: - q_graph, returned_elements = quantize_graph.create_training_graph( - graph, elements=elements) - else: - q_graph, returned_elements = quantize_graph.create_eval_graph( - graph, elements=elements) + q_graph, returned_elements = fn(graph, elements=elements) # Make sure q_graph is different from graph. self.assertTrue(graph != q_graph) # Check that the returned elements are part of the new graph. @@ -62,35 +64,26 @@ class QuantizeGraphTest(test_util.TensorFlowTestCase): for element, returned_element in zip(elements, returned_elements): self.assertEqual(element.name, returned_element.name) - def testNoReturnElementsTraining(self): - self._TestNoReturnElements(True) + def testNoReturnElements(self): + self._RunTestOverParameters(self._TestNoReturnElements) - def testNoReturnElementsEval(self): - self._TestNoReturnElements(False) - - def _TestNoReturnElements(self, is_training): + def _TestNoReturnElements(self, fn): graph = ops.Graph() with graph.as_default(): a = constant_op.constant(1.0) b = variables.Variable(2.0) _ = a + b - if is_training: - q_graph = quantize_graph.create_training_graph(graph) - else: - q_graph = quantize_graph.create_eval_graph(graph) + q_graph = fn(graph) # Check that quantize_graph didn't return a tuple when elements isn't # provided. self.assertTrue(isinstance(q_graph, ops.Graph)) # Make sure q_graph is different from graph. self.assertTrue(graph != q_graph) - def testDeviceNameTraining(self): - self._TestDeviceName(True) - - def testDeviceNameEval(self): - self._TestDeviceName(False) + def testDeviceName(self): + self._RunTestOverParameters(self._TestDeviceName) - def _TestDeviceName(self, is_training): + def _TestDeviceName(self, fn): graph = ops.Graph() with graph.as_default(): batch_size, height, width, depth = 5, 128, 128, 3 @@ -106,12 +99,7 @@ class QuantizeGraphTest(test_util.TensorFlowTestCase): _ = nn_ops.relu6(conv) device_name = '/job:oink/task:0/device:CPU:0' - if is_training: - q_graph = quantize_graph.create_training_graph( - graph, device_name_or_function=device_name) - else: - q_graph = quantize_graph.create_eval_graph( - graph, device_name_or_function=device_name) + q_graph = fn(graph, device_name_or_function=device_name) orig_variable_names = set( [v.name for v in graph.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) -- GitLab From 94276a1e7c6f718eada8dbdfa23a3751669e2247 Mon Sep 17 00:00:00 2001 From: Renat Idrisov Date: Wed, 24 Jan 2018 20:24:01 +0100 Subject: [PATCH 191/258] Setting proper sonames on Linux (#15307) * Setting proper sonames on Linux * Revert "Setting proper sonames on Linux" This reverts commit 141d796dcd3cb6b7a96a1b0841952daf60f72f1c. * Adding soname to tf_cc_shared_object rule definition --- tensorflow/tensorflow.bzl | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/tensorflow.bzl b/tensorflow/tensorflow.bzl index cbb64a3489..f32d456155 100644 --- a/tensorflow/tensorflow.bzl +++ b/tensorflow/tensorflow.bzl @@ -291,6 +291,7 @@ def tf_cc_shared_object( "-Wl,-install_name,@rpath/" + name.split("/")[-1], ], "//conditions:default": [ + "-Wl,-soname," + name.split("/")[-1], ], }), **kwargs) -- GitLab From 127146d8d68f607d68699931030cdaa0044c58fa Mon Sep 17 00:00:00 2001 From: Rajendra arora Date: Thu, 25 Jan 2018 00:54:31 +0530 Subject: [PATCH 192/258] Making string values in legacy constant (#16326) --- tensorflow/contrib/session_bundle/bundle_shim.py | 8 ++++---- tensorflow/contrib/session_bundle/constants.py | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/session_bundle/bundle_shim.py b/tensorflow/contrib/session_bundle/bundle_shim.py index 062c9cc680..3149875e41 100644 --- a/tensorflow/contrib/session_bundle/bundle_shim.py +++ b/tensorflow/contrib/session_bundle/bundle_shim.py @@ -82,7 +82,7 @@ def _convert_default_signature_to_signature_def(signatures): """ default_signature = signatures.default_signature signature_def = meta_graph_pb2.SignatureDef() - if default_signature.WhichOneof("type") == "regression_signature": + if default_signature.WhichOneof("type") == legacy_constants.REGRESSION_SIGNATURE: regression_signature = default_signature.regression_signature signature_def.method_name = signature_constants.REGRESS_METHOD_NAME _add_input_to_signature_def(regression_signature.input.tensor_name, @@ -91,7 +91,7 @@ def _convert_default_signature_to_signature_def(signatures): _add_output_to_signature_def(regression_signature.output.tensor_name, signature_constants.REGRESS_OUTPUTS, signature_def) - elif default_signature.WhichOneof("type") == "classification_signature": + elif default_signature.WhichOneof("type") == legacy_constants.CLASSIFICATION_SIGNATURE: classification_signature = default_signature.classification_signature signature_def.method_name = signature_constants.CLASSIFY_METHOD_NAME _add_input_to_signature_def(classification_signature.input.tensor_name, @@ -132,8 +132,8 @@ def _convert_named_signatures_to_signature_def(signatures): signature_constants.PREDICT_OUTPUTS] # TODO(pdudnik): what if there are other signatures? Mimic cr/140900781 once # it is submitted. - if (input_signature.WhichOneof("type") != "generic_signature" or - output_signature.WhichOneof("type") != "generic_signature"): + if (input_signature.WhichOneof("type") != legacy_constants.GENERIC_SIGNATURE or + output_signature.WhichOneof("type") != legacy_constants.GENERIC_SIGNATURE): raise RuntimeError("Named input and output signatures can only be " "up-converted if they are generic signature. " "Input signature type is %s, output signature type is " diff --git a/tensorflow/contrib/session_bundle/constants.py b/tensorflow/contrib/session_bundle/constants.py index 6ced73241a..e833baee79 100644 --- a/tensorflow/contrib/session_bundle/constants.py +++ b/tensorflow/contrib/session_bundle/constants.py @@ -32,3 +32,6 @@ INIT_OP_KEY = "serving_init_op" SIGNATURES_KEY = "serving_signatures" ASSETS_KEY = "serving_assets" GRAPH_KEY = "serving_graph" +REGRESSION_SIGNATURE = "regression_signature" +CLASSIFICATION_SIGNATURE = "classification_signature" +GENERIC_SIGNATURE = "generic_signature" -- GitLab From 7f8e600bfb4ff5973bd1ec178b65538e2446fb69 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 11:29:08 -0800 Subject: [PATCH 193/258] fix typos in schema.fbs comments. PiperOrigin-RevId: 183114994 --- tensorflow/contrib/lite/schema/schema.fbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/lite/schema/schema.fbs b/tensorflow/contrib/lite/schema/schema.fbs index da7db9bcf4..2172135f49 100644 --- a/tensorflow/contrib/lite/schema/schema.fbs +++ b/tensorflow/contrib/lite/schema/schema.fbs @@ -53,12 +53,12 @@ table Tensor { type:TensorType; // An index that refers to the buffers table at the root of the model. Or, // if there is no data buffer associated (i.e. intermediate results), then - // this is 0 (which refers to an always existant empty buffer). + // this is 0 (which refers to an always existent empty buffer). // // The data_buffer itself is an opaque container, with the assumption that the // target device is little-endian. In addition, all builtin operators assume // the memory is ordered such that if `shape` is [4, 3, 2], then index - // [i, j, k] maps to data_buffer[i*3*2 + j*3 + k]. + // [i, j, k] maps to data_buffer[i*3*2 + j*2 + k]. buffer:uint; name:string; // For debugging and importing back into tensorflow. quantization:QuantizationParameters; // Optional. -- GitLab From ad07a86d75ab06bbcfd6f8f6a24debd9036a52d0 Mon Sep 17 00:00:00 2001 From: Jianwei Xie Date: Wed, 24 Jan 2018 11:31:06 -0800 Subject: [PATCH 194/258] Fixed linter errors. PiperOrigin-RevId: 183115307 --- .../contrib/cmake/python_sanity_test.py | 18 +- .../contrib/layers/python/layers/layers.py | 661 +++++++------- .../training/model_average_optimizer.py | 119 +-- .../training/model_average_optimizer_test.py | 103 ++- .../kernel_tests/periodic_resample_op_test.py | 39 +- .../rnn/python/kernel_tests/rnn_cell_test.py | 852 +++++++++--------- tensorflow/contrib/rnn/python/ops/rnn_cell.py | 597 ++++++------ .../kernel_tests/beam_search_decoder_test.py | 79 +- .../seq2seq/python/ops/beam_search_decoder.py | 99 +- tensorflow/contrib/verbs/rdma.cc | 109 ++- tensorflow/contrib/verbs/rdma.h | 11 +- tensorflow/contrib/verbs/rdma_mgr.cc | 29 +- tensorflow/core/kernels/mkl_aggregate_ops.cc | 188 ++-- tensorflow/core/kernels/mkl_softmax_op.cc | 33 +- .../core/kernels/spectrogram_test_utils.cc | 4 +- .../core/kernels/transpose_functor_cpu.cc | 16 +- .../tutorials/word2vec/word2vec_basic.py | 81 +- .../kernel_tests/batch_dataset_op_test.py | 103 ++- tensorflow/python/ops/histogram_ops.py | 13 +- tensorflow/python/ops/histogram_ops_test.py | 10 +- tensorflow/python/ops/image_ops_impl.py | 235 ++--- tensorflow/python/ops/metrics_impl.py | 530 ++++++----- tensorflow/python/ops/nn_impl.py | 26 +- tensorflow/python/ops/nn_test.py | 19 +- tensorflow/python/util/compat.py | 5 +- .../tools/pip_package/pip_smoke_test.py | 29 +- 26 files changed, 2119 insertions(+), 1889 deletions(-) diff --git a/tensorflow/contrib/cmake/python_sanity_test.py b/tensorflow/contrib/cmake/python_sanity_test.py index 3be5bd1b23..e0056823a8 100644 --- a/tensorflow/contrib/cmake/python_sanity_test.py +++ b/tensorflow/contrib/cmake/python_sanity_test.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -""" -Complain about invalid or missing entries in python_*.txt files. +"""Complain about invalid or missing entries in python_*.txt files. + Problematic entries can be commented for temporary whitelisting. """ @@ -35,6 +35,7 @@ def abs_path(path): path = os.path.abspath(path) return path + def read_entries(test): with open(abs_path(test.entries_file), "r") as f: lines = f.readlines() @@ -47,25 +48,28 @@ def read_entries(test): for line in lines: # line is comment - if line.startswith('#'): + if line.startswith("#"): line = line[1:].strip() # whitelist entry - if line.startswith('tensorflow/'): + if line.startswith("tensorflow/"): test.whitelist.append(line) # line has comment -> strip comment - elif line.find('#') != -1: - line = line[:line.find('#')].strip() + elif line.find("#") != -1: + line = line[:line.find("#")].strip() test.entries.append(line) else: test.entries.append(line) + def test_invalid_directories(test): for entry in test.entries: if not os.path.isdir(abs_path(entry)): problem = "'" + test.entries_file + "' contains invalid '" + entry + "'" - solution = "Please remove the invalid entry (or add the missing directory)." + solution = ("Please remove the invalid entry (or add the missing " + "directory).") raise AssertionError(problem + "\n" + solution) + def test_missing_directory(test, path): if path in test.whitelist: return diff --git a/tensorflow/contrib/layers/python/layers/layers.py b/tensorflow/contrib/layers/python/layers/layers.py index ef2b673074..7c52da7b49 100644 --- a/tensorflow/contrib/layers/python/layers/layers.py +++ b/tensorflow/contrib/layers/python/layers/layers.py @@ -54,47 +54,17 @@ from tensorflow.python.layers.maxout import maxout # TODO(b/28426988): Replace legacy_* fns migrated from slim. # TODO(b/28426988): Remove legacy_* when all uses have migrated to new API. -__all__ = ['avg_pool2d', - 'avg_pool3d', - 'batch_norm', - 'bias_add', - 'conv2d', - 'conv3d', - 'conv2d_in_plane', - 'conv2d_transpose', - 'conv3d_transpose', - 'convolution', - 'convolution2d', - 'convolution2d_in_plane', - 'convolution2d_transpose', - 'convolution3d', - 'convolution3d_transpose', - 'dropout', - 'elu', - 'flatten', - 'fully_connected', - 'GDN', - 'gdn', - 'layer_norm', - 'linear', - 'pool', - 'max_pool2d', - 'max_pool3d', - 'one_hot_encoding', - 'relu', - 'relu6', - 'repeat', - 'scale_gradient', - 'separable_conv2d', - 'separable_convolution2d', - 'softmax', - 'spatial_softmax', - 'stack', - 'unit_norm', - 'legacy_fully_connected', - 'legacy_linear', - 'legacy_relu', - 'maxout'] +__all__ = [ + 'avg_pool2d', 'avg_pool3d', 'batch_norm', 'bias_add', 'conv2d', 'conv3d', + 'conv2d_in_plane', 'conv2d_transpose', 'conv3d_transpose', 'convolution', + 'convolution2d', 'convolution2d_in_plane', 'convolution2d_transpose', + 'convolution3d', 'convolution3d_transpose', 'dropout', 'elu', 'flatten', + 'fully_connected', 'GDN', 'gdn', 'layer_norm', 'linear', 'pool', + 'max_pool2d', 'max_pool3d', 'one_hot_encoding', 'relu', 'relu6', 'repeat', + 'scale_gradient', 'separable_conv2d', 'separable_convolution2d', 'softmax', + 'spatial_softmax', 'stack', 'unit_norm', 'legacy_fully_connected', + 'legacy_linear', 'legacy_relu', 'maxout' +] DATA_FORMAT_NCHW = 'NCHW' DATA_FORMAT_NHWC = 'NHWC' @@ -139,13 +109,14 @@ def avg_pool2d(inputs, raise ValueError('data_format has to be either NCHW or NHWC.') with ops.name_scope(scope, 'AvgPool2D', [inputs]) as sc: inputs = ops.convert_to_tensor(inputs) - df = ('channels_first' if data_format and data_format.startswith('NC') - else 'channels_last') - layer = pooling_layers.AveragePooling2D(pool_size=kernel_size, - strides=stride, - padding=padding, - data_format=df, - _scope=sc) + df = ('channels_first' + if data_format and data_format.startswith('NC') else 'channels_last') + layer = pooling_layers.AveragePooling2D( + pool_size=kernel_size, + strides=stride, + padding=padding, + data_format=df, + _scope=sc) outputs = layer.apply(inputs) return utils.collect_named_outputs(outputs_collections, sc, outputs) @@ -187,13 +158,14 @@ def avg_pool3d(inputs, raise ValueError('data_format has to be either NCDHW or NDHWC.') with ops.name_scope(scope, 'AvgPool3D', [inputs]) as sc: inputs = ops.convert_to_tensor(inputs) - df = ('channels_first' if data_format and data_format.startswith('NC') - else 'channels_last') - layer = pooling_layers.AveragePooling3D(pool_size=kernel_size, - strides=stride, - padding=padding, - data_format=df, - _scope=sc) + df = ('channels_first' + if data_format and data_format.startswith('NC') else 'channels_last') + layer = pooling_layers.AveragePooling3D( + pool_size=kernel_size, + strides=stride, + padding=padding, + data_format=df, + _scope=sc) outputs = layer.apply(inputs) return utils.collect_named_outputs(outputs_collections, sc, outputs) @@ -298,8 +270,8 @@ def _fused_batch_norm(inputs, raise ValueError('Inputs %s has undefined rank' % inputs.name) elif original_rank not in [2, 4]: raise ValueError('Inputs %s has unsupported rank.' - ' Expected 2 or 4 but got %d' % ( - inputs.name, original_rank)) + ' Expected 2 or 4 but got %d' % (inputs.name, + original_rank)) if original_rank == 2: channels = inputs.get_shape()[-1].value if channels is None: @@ -393,6 +365,7 @@ def _fused_batch_norm(inputs, def _fused_batch_norm_training(): return nn.fused_batch_norm( inputs, gamma, beta, epsilon=epsilon, data_format=data_format) + def _fused_batch_norm_inference(): return nn.fused_batch_norm( inputs, @@ -403,9 +376,9 @@ def _fused_batch_norm(inputs, epsilon=epsilon, is_training=False, data_format=data_format) - outputs, mean, variance = utils.smart_cond(is_training, - _fused_batch_norm_training, - _fused_batch_norm_inference) + + outputs, mean, variance = utils.smart_cond( + is_training, _fused_batch_norm_training, _fused_batch_norm_inference) # If `is_training` doesn't have a constant value, because it is a `Tensor`, # a `Variable` or `Placeholder` then is_training_value will be None and @@ -415,6 +388,7 @@ def _fused_batch_norm(inputs, if need_updates: if updates_collections is None: no_updates = lambda: outputs + def _force_updates(): """Internal function forces updates moving_vars if is_training.""" update_moving_mean = moving_averages.assign_moving_average( @@ -424,9 +398,11 @@ def _fused_batch_norm(inputs, with ops.control_dependencies( [update_moving_mean, update_moving_variance]): return array_ops.identity(outputs) + outputs = utils.smart_cond(is_training, _force_updates, no_updates) else: moving_vars_fn = lambda: (moving_mean, moving_variance) + def _delay_updates(): """Internal function that delay updates moving_vars if is_training.""" update_moving_mean = moving_averages.assign_moving_average( @@ -434,9 +410,9 @@ def _fused_batch_norm(inputs, update_moving_variance = moving_averages.assign_moving_average( moving_variance, variance, decay, zero_debias=False) return update_moving_mean, update_moving_variance - update_mean, update_variance = utils.smart_cond(is_training, - _delay_updates, - moving_vars_fn) + + update_mean, update_variance = utils.smart_cond( + is_training, _delay_updates, moving_vars_fn) ops.add_to_collections(updates_collections, update_mean) ops.add_to_collections(updates_collections, update_variance) @@ -482,9 +458,10 @@ def batch_norm(inputs, Can be used as a normalizer function for conv2d and fully_connected. The normalization is over all but the last dimension if `data_format` is `NHWC` and all but the second dimension if `data_format` is `NCHW`. In case of a 2D - tensor this corresponds to the batch dimension, while in case of a 4D tensor this + tensor this corresponds to the batch dimension, while in case of a 4D tensor + this corresponds to the batch and space dimensions. - + Note: when training, the moving_mean and moving_variance need to be updated. By default the update ops are placed in `tf.GraphKeys.UPDATE_OPS`, so they need to be added as a dependency to the `train_op`. For example: @@ -592,10 +569,9 @@ def batch_norm(inputs, # implementation in normalization_layers.BatchNormalization. inputs = ops.convert_to_tensor(inputs) rank = inputs.get_shape().ndims - possible_to_fuse = (batch_weights is None and - not renorm and - rank in [2, 4] and - adjustment is None) + possible_to_fuse = ( + batch_weights is None and not renorm and rank in [2, 4] and + adjustment is None) if fused and possible_to_fuse and ( zero_debias_moving_mean or rank == 2 or updates_collections is not ops.GraphKeys.UPDATE_OPS): @@ -623,7 +599,9 @@ def batch_norm(inputs, layer_variable_getter = _build_variable_getter() with variable_scope.variable_scope( - scope, 'BatchNorm', [inputs], reuse=reuse, + scope, + 'BatchNorm', [inputs], + reuse=reuse, custom_getter=layer_variable_getter) as sc: inputs = ops.convert_to_tensor(inputs) @@ -671,15 +649,15 @@ def batch_norm(inputs, outputs = layer.apply(inputs, training=is_training) # Add variables to collections. - _add_variable_to_collections( - layer.moving_mean, variables_collections, 'moving_mean') - _add_variable_to_collections( - layer.moving_variance, variables_collections, 'moving_variance') + _add_variable_to_collections(layer.moving_mean, variables_collections, + 'moving_mean') + _add_variable_to_collections(layer.moving_variance, variables_collections, + 'moving_variance') if layer.beta is not None: _add_variable_to_collections(layer.beta, variables_collections, 'beta') if layer.gamma is not None: - _add_variable_to_collections( - layer.gamma, variables_collections, 'gamma') + _add_variable_to_collections(layer.gamma, variables_collections, + 'gamma') if activation_fn is not None: outputs = activation_fn(outputs) @@ -719,8 +697,8 @@ def batch_norm(inputs, params_shape = inputs_shape[-1:] params_shape_broadcast = None if not params_shape.is_fully_defined(): - raise ValueError('Inputs %s has undefined channels dimension %s.' % ( - inputs.name, params_shape)) + raise ValueError('Inputs %s has undefined channels dimension %s.' % + (inputs.name, params_shape)) # Allocate parameters for the beta and gamma of the normalization. beta, gamma = None, None @@ -731,23 +709,25 @@ def batch_norm(inputs, 'beta') beta_initializer = param_initializers.get('beta', init_ops.zeros_initializer()) - beta = variables.model_variable('beta', - shape=params_shape, - dtype=dtype, - initializer=beta_initializer, - collections=beta_collections, - trainable=trainable) + beta = variables.model_variable( + 'beta', + shape=params_shape, + dtype=dtype, + initializer=beta_initializer, + collections=beta_collections, + trainable=trainable) if scale: - gamma_collections = utils.get_variable_collections(variables_collections, - 'gamma') + gamma_collections = utils.get_variable_collections( + variables_collections, 'gamma') gamma_initializer = param_initializers.get('gamma', init_ops.ones_initializer()) - gamma = variables.model_variable('gamma', - shape=params_shape, - dtype=dtype, - initializer=gamma_initializer, - collections=gamma_collections, - trainable=trainable) + gamma = variables.model_variable( + 'gamma', + shape=params_shape, + dtype=dtype, + initializer=gamma_initializer, + collections=gamma_collections, + trainable=trainable) # Create moving_mean and moving_variance variables and add them to the # appropriate collections. We disable variable partitioning while creating @@ -796,8 +776,8 @@ def batch_norm(inputs, mean, variance = nn.moments(inputs, moments_axes) else: if data_format == DATA_FORMAT_NCHW: - mean, variance = nn.weighted_moments(inputs, moments_axes, - batch_weights, keep_dims=True) + mean, variance = nn.weighted_moments( + inputs, moments_axes, batch_weights, keep_dims=True) mean = array_ops.reshape(mean, [-1]) variance = array_ops.reshape(variance, [-1]) else: @@ -806,19 +786,21 @@ def batch_norm(inputs, moving_vars_fn = lambda: (moving_mean, moving_variance) if updates_collections is None: + def _force_updates(): """Internal function forces updates moving_vars if is_training.""" update_moving_mean = moving_averages.assign_moving_average( moving_mean, mean, decay, zero_debias=zero_debias_moving_mean) update_moving_variance = moving_averages.assign_moving_average( moving_variance, variance, decay, zero_debias=False) - with ops.control_dependencies([update_moving_mean, - update_moving_variance]): + with ops.control_dependencies( + [update_moving_mean, update_moving_variance]): return array_ops.identity(mean), array_ops.identity(variance) - mean, variance = utils.smart_cond(is_training, - _force_updates, + + mean, variance = utils.smart_cond(is_training, _force_updates, moving_vars_fn) else: + def _delay_updates(): """Internal function that delay updates moving_vars if is_training.""" update_moving_mean = moving_averages.assign_moving_average( @@ -827,9 +809,8 @@ def batch_norm(inputs, moving_variance, variance, decay, zero_debias=False) return update_moving_mean, update_moving_variance - update_mean, update_variance = utils.smart_cond(is_training, - _delay_updates, - moving_vars_fn) + update_mean, update_variance = utils.smart_cond( + is_training, _delay_updates, moving_vars_fn) ops.add_to_collections(updates_collections, update_mean) ops.add_to_collections(updates_collections, update_variance) # Use computed moments during training and moving_vars otherwise. @@ -897,8 +878,8 @@ def bias_add(inputs, """ if data_format not in (DATA_FORMAT_NCHW, DATA_FORMAT_NHWC): raise ValueError('data_format has to be either NCHW or NHWC.') - with variable_scope.variable_scope(scope, 'BiasAdd', [inputs], - reuse=reuse) as sc: + with variable_scope.variable_scope( + scope, 'BiasAdd', [inputs], reuse=reuse) as sc: inputs = ops.convert_to_tensor(inputs) dtype = inputs.dtype.base_dtype inputs_shape = inputs.get_shape() @@ -913,13 +894,16 @@ def bias_add(inputs, raise ValueError('`C` dimension must be known but is None') biases_collections = utils.get_variable_collections(variables_collections, 'biases') - biases = variables.model_variable('biases', - shape=[num_features,], - dtype=dtype, - initializer=initializer, - regularizer=regularizer, - collections=biases_collections, - trainable=trainable) + biases = variables.model_variable( + 'biases', + shape=[ + num_features, + ], + dtype=dtype, + initializer=initializer, + regularizer=regularizer, + collections=biases_collections, + trainable=trainable) outputs = nn.bias_add(inputs, biases, data_format=data_format) if activation_fn is not None: outputs = activation_fn(outputs) @@ -1019,8 +1003,10 @@ def convolution(inputs, if data_format not in [None, 'NWC', 'NCW', 'NHWC', 'NCHW', 'NDHWC', 'NCDHW']: raise ValueError('Invalid data_format: %r' % (data_format,)) - layer_variable_getter = _build_variable_getter( - {'bias': 'biases', 'kernel': 'weights'}) + layer_variable_getter = _build_variable_getter({ + 'bias': 'biases', + 'kernel': 'weights' + }) with variable_scope.variable_scope( scope, 'Conv', [inputs], reuse=reuse, @@ -1038,26 +1024,27 @@ def convolution(inputs, raise ValueError('Convolution not supported for input with rank', input_rank) - df = ('channels_first' if data_format and data_format.startswith('NC') - else 'channels_last') - layer = layer_class(filters=num_outputs, - kernel_size=kernel_size, - strides=stride, - padding=padding, - data_format=df, - dilation_rate=rate, - activation=None, - use_bias=not normalizer_fn and biases_initializer, - kernel_initializer=weights_initializer, - bias_initializer=biases_initializer, - kernel_regularizer=weights_regularizer, - bias_regularizer=biases_regularizer, - activity_regularizer=None, - trainable=trainable, - name=sc.name, - dtype=inputs.dtype.base_dtype, - _scope=sc, - _reuse=reuse) + df = ('channels_first' + if data_format and data_format.startswith('NC') else 'channels_last') + layer = layer_class( + filters=num_outputs, + kernel_size=kernel_size, + strides=stride, + padding=padding, + data_format=df, + dilation_rate=rate, + activation=None, + use_bias=not normalizer_fn and biases_initializer, + kernel_initializer=weights_initializer, + bias_initializer=biases_initializer, + kernel_regularizer=weights_regularizer, + bias_regularizer=biases_regularizer, + activity_regularizer=None, + trainable=trainable, + name=sc.name, + dtype=inputs.dtype.base_dtype, + _scope=sc, + _reuse=reuse) outputs = layer.apply(inputs) # Add variables to collections. @@ -1073,6 +1060,7 @@ def convolution(inputs, outputs = activation_fn(outputs) return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + convolution2d = convolution convolution3d = convolution @@ -1148,13 +1136,14 @@ def convolution2d_in_plane( weights_shape = [kernel_h, kernel_w, 1, 1] weights_collections = utils.get_variable_collections( variables_collections, 'weights') - weights = variables.model_variable('weights', - shape=weights_shape, - dtype=dtype, - initializer=weights_initializer, - regularizer=weights_regularizer, - collections=weights_collections, - trainable=trainable) + weights = variables.model_variable( + 'weights', + shape=weights_shape, + dtype=dtype, + initializer=weights_initializer, + regularizer=weights_regularizer, + collections=weights_collections, + trainable=trainable) depthwise_weights = array_ops.tile(weights, [1, 1, num_filters_in, 1]) outputs = nn.depthwise_conv2d(inputs, depthwise_weights, [1, stride_h, stride_w, 1], padding) @@ -1165,13 +1154,16 @@ def convolution2d_in_plane( if biases_initializer is not None: biases_collections = utils.get_variable_collections( variables_collections, 'biases') - biases = variables.model_variable('biases', - shape=[num_filters_in,], - dtype=dtype, - initializer=biases_initializer, - regularizer=biases_regularizer, - collections=biases_collections, - trainable=trainable) + biases = variables.model_variable( + 'biases', + shape=[ + num_filters_in, + ], + dtype=dtype, + initializer=biases_initializer, + regularizer=biases_regularizer, + collections=biases_collections, + trainable=trainable) outputs = nn.bias_add(outputs, biases) if activation_fn is not None: @@ -1244,19 +1236,23 @@ def convolution2d_transpose( ValueError: If `data_format` is neither `NHWC` nor `NCHW`. ValueError: If `C` dimension of `inputs` is None. """ - layer_variable_getter = _build_variable_getter( - {'bias': 'biases', 'kernel': 'weights'}) + layer_variable_getter = _build_variable_getter({ + 'bias': 'biases', + 'kernel': 'weights' + }) with variable_scope.variable_scope( - scope, 'Conv2d_transpose', [inputs], reuse=reuse, + scope, + 'Conv2d_transpose', [inputs], + reuse=reuse, custom_getter=layer_variable_getter) as sc: if data_format not in (DATA_FORMAT_NCHW, DATA_FORMAT_NHWC): raise ValueError('data_format has to be either NCHW or NHWC.') inputs = ops.convert_to_tensor(inputs) - df = ('channels_first' if data_format and data_format.startswith('NC') - else 'channels_last') + df = ('channels_first' + if data_format and data_format.startswith('NC') else 'channels_last') layer = convolutional_layers.Convolution2DTranspose( filters=num_outputs, kernel_size=kernel_size, @@ -1353,19 +1349,23 @@ def convolution3d_transpose( ValueError: If `data_format` is neither `NDHWC` nor `NCDHW`. ValueError: If `C` dimension of `inputs` is None. """ - layer_variable_getter = _build_variable_getter( - {'bias': 'biases', 'kernel': 'weights'}) + layer_variable_getter = _build_variable_getter({ + 'bias': 'biases', + 'kernel': 'weights' + }) with variable_scope.variable_scope( - scope, 'Conv3d_transpose', [inputs], reuse=reuse, + scope, + 'Conv3d_transpose', [inputs], + reuse=reuse, custom_getter=layer_variable_getter) as sc: if data_format not in (DATA_FORMAT_NCDHW, DATA_FORMAT_NDHWC): raise ValueError('data_format has to be either NCDHW or NDHWC.') inputs = ops.convert_to_tensor(inputs) - df = ('channels_first' if data_format and data_format.startswith('NC') - else 'channels_last') + df = ('channels_first' + if data_format and data_format.startswith('NC') else 'channels_last') layer = convolutional_layers.Convolution3DTranspose( filters=num_outputs, kernel_size=kernel_size, @@ -1434,19 +1434,18 @@ def dropout(inputs, with variable_scope.variable_scope( scope, 'Dropout', [inputs], custom_getter=_model_variable_getter) as sc: inputs = ops.convert_to_tensor(inputs) - layer = core_layers.Dropout(rate=1 - keep_prob, - noise_shape=noise_shape, - seed=seed, - name=sc.name, - _scope=sc) + layer = core_layers.Dropout( + rate=1 - keep_prob, + noise_shape=noise_shape, + seed=seed, + name=sc.name, + _scope=sc) outputs = layer.apply(inputs, training=is_training) return utils.collect_named_outputs(outputs_collections, sc.name, outputs) @add_arg_scope -def flatten(inputs, - outputs_collections=None, - scope=None): +def flatten(inputs, outputs_collections=None, scope=None): """Flattens the input while maintaining the batch_size. Assumes that the first dimension represents the batch. @@ -1478,8 +1477,8 @@ def _sparse_inner_flatten(inputs, new_rank): outer_dimensions = inputs.dense_shape[:new_rank - 1] inner_dimensions = inputs.dense_shape[new_rank - 1:] - new_shape = array_ops.concat((outer_dimensions, - [math_ops.reduce_prod(inner_dimensions)]), 0) + new_shape = array_ops.concat( + (outer_dimensions, [math_ops.reduce_prod(inner_dimensions)]), 0) flattened = sparse_ops.sparse_reshape(inputs, new_shape) return flattened @@ -1545,10 +1544,18 @@ def _inner_flatten(inputs, new_rank, output_collections=None, scope=None): return utils.collect_named_outputs(output_collections, sc, flattened) -def _model_variable_getter(getter, name, shape=None, dtype=None, - initializer=None, regularizer=None, trainable=True, - collections=None, caching_device=None, - partitioner=None, rename=None, use_resource=None, +def _model_variable_getter(getter, + name, + shape=None, + dtype=None, + initializer=None, + regularizer=None, + trainable=True, + collections=None, + caching_device=None, + partitioner=None, + rename=None, + use_resource=None, **_): """Getter that uses model_variable for compatibility with core layers.""" short_name = name.split('/')[-1] @@ -1557,25 +1564,34 @@ def _model_variable_getter(getter, name, shape=None, dtype=None, name_components[-1] = rename[short_name] name = '/'.join(name_components) return variables.model_variable( - name, shape=shape, dtype=dtype, initializer=initializer, - regularizer=regularizer, collections=collections, trainable=trainable, - caching_device=caching_device, partitioner=partitioner, - custom_getter=getter, use_resource=use_resource) + name, + shape=shape, + dtype=dtype, + initializer=initializer, + regularizer=regularizer, + collections=collections, + trainable=trainable, + caching_device=caching_device, + partitioner=partitioner, + custom_getter=getter, + use_resource=use_resource) def _build_variable_getter(rename=None): """Build a model variable getter that respects scope getter and renames.""" + # VariableScope will nest the getters def layer_variable_getter(getter, *args, **kwargs): kwargs['rename'] = rename return _model_variable_getter(getter, *args, **kwargs) + return layer_variable_getter def _add_variable_to_collections(variable, collections_set, collections_name): """Adds variable (or all its parts) to all collections with that name.""" - collections = utils.get_variable_collections( - collections_set, collections_name) or [] + collections = utils.get_variable_collections(collections_set, + collections_name) or [] variables_list = [variable] if isinstance(variable, tf_variables.PartitionedVariable): variables_list = [v for v in variable] @@ -1644,15 +1660,19 @@ def fully_connected(inputs, ValueError: If x has rank less than 2 or if its last dimension is not set. """ if not isinstance(num_outputs, six.integer_types): - raise ValueError( - 'num_outputs should be int or long, got %s.' % (num_outputs,)) + raise ValueError('num_outputs should be int or long, got %s.' % + (num_outputs,)) - layer_variable_getter = _build_variable_getter({'bias': 'biases', - 'kernel': 'weights'}) + layer_variable_getter = _build_variable_getter({ + 'bias': 'biases', + 'kernel': 'weights' + }) with variable_scope.variable_scope( - scope, 'fully_connected', [inputs], - reuse=reuse, custom_getter=layer_variable_getter) as sc: + scope, + 'fully_connected', [inputs], + reuse=reuse, + custom_getter=layer_variable_getter) as sc: inputs = ops.convert_to_tensor(inputs) layer = core_layers.Dense( units=num_outputs, @@ -1758,15 +1778,17 @@ class GDN(base.Layer): inverse=False, beta_min=1e-6, gamma_init=.1, - reparam_offset=2 ** -18, + reparam_offset=2**-18, data_format='channels_last', activity_regularizer=None, trainable=True, name=None, **kwargs): - super(GDN, self).__init__(trainable=trainable, name=name, - activity_regularizer=activity_regularizer, - **kwargs) + super(GDN, self).__init__( + trainable=trainable, + name=name, + activity_regularizer=activity_regularizer, + **kwargs) self.inverse = inverse self._beta_min = beta_min self._gamma_init = gamma_init @@ -1801,8 +1823,9 @@ class GDN(base.Layer): with ops.name_scope(name, 'GDNLowerBound', [inputs, bound]) as scope: inputs = ops.convert_to_tensor(inputs, name='inputs') bound = ops.convert_to_tensor(bound, name='bound') - with ops.get_default_graph().gradient_override_map( - {'Maximum': 'GDNLowerBound'}): + with ops.get_default_graph().gradient_override_map({ + 'Maximum': 'GDNLowerBound' + }): return math_ops.maximum(inputs, bound, name=scope) @staticmethod @@ -1829,12 +1852,14 @@ class GDN(base.Layer): raise ValueError('The channel dimension of the inputs to `GDN` ' 'must be defined.') self._input_rank = input_shape.ndims - self.input_spec = base.InputSpec(ndim=input_shape.ndims, - axes={channel_axis: num_channels}) + self.input_spec = base.InputSpec( + ndim=input_shape.ndims, axes={ + channel_axis: num_channels + }) - pedestal = array_ops.constant(self._reparam_offset ** 2, dtype=self.dtype) + pedestal = array_ops.constant(self._reparam_offset**2, dtype=self.dtype) beta_bound = array_ops.constant( - (self._beta_min + self._reparam_offset ** 2) ** .5, dtype=self.dtype) + (self._beta_min + self._reparam_offset**2)**.5, dtype=self.dtype) gamma_bound = array_ops.constant(self._reparam_offset, dtype=self.dtype) def beta_initializer(shape, dtype=None, partition_info=None): @@ -1848,19 +1873,21 @@ class GDN(base.Layer): eye = linalg_ops.eye(shape[0], dtype=dtype) return math_ops.sqrt(self._gamma_init * eye + pedestal) - beta = self.add_variable('reparam_beta', - shape=[num_channels], - initializer=beta_initializer, - dtype=self.dtype, - trainable=True) + beta = self.add_variable( + 'reparam_beta', + shape=[num_channels], + initializer=beta_initializer, + dtype=self.dtype, + trainable=True) beta = self._lower_bound(beta, beta_bound) self.beta = math_ops.square(beta) - pedestal - gamma = self.add_variable('reparam_gamma', - shape=[num_channels, num_channels], - initializer=gamma_initializer, - dtype=self.dtype, - trainable=True) + gamma = self.add_variable( + 'reparam_gamma', + shape=[num_channels, num_channels], + initializer=gamma_initializer, + dtype=self.dtype, + trainable=True) gamma = self._lower_bound(gamma, gamma_bound) self.gamma = math_ops.square(gamma) - pedestal @@ -1875,8 +1902,11 @@ class GDN(base.Layer): # Compute normalization pool. if self.data_format == 'channels_first': - norm_pool = nn.convolution(math_ops.square(inputs), gamma, 'VALID', - data_format='NC' + 'DHW'[-(ndim - 2):]) + norm_pool = nn.convolution( + math_ops.square(inputs), + gamma, + 'VALID', + data_format='NC' + 'DHW' [-(ndim - 2):]) if ndim == 3: norm_pool = array_ops.expand_dims(norm_pool, 2) norm_pool = nn.bias_add(norm_pool, self.beta, data_format='NCHW') @@ -1918,7 +1948,7 @@ def gdn(inputs, inverse=False, beta_min=1e-6, gamma_init=.1, - reparam_offset=2 ** -18, + reparam_offset=2**-18, data_format='channels_last', activity_regularizer=None, trainable=True, @@ -1984,17 +2014,18 @@ def gdn(inputs, Returns: Output tensor. """ - layer = GDN(inverse=inverse, - beta_min=beta_min, - gamma_init=gamma_init, - reparam_offset=reparam_offset, - data_format=data_format, - activity_regularizer=activity_regularizer, - trainable=trainable, - name=name, - dtype=inputs.dtype.base_dtype, - _scope=name, - _reuse=reuse) + layer = GDN( + inverse=inverse, + beta_min=beta_min, + gamma_init=gamma_init, + reparam_offset=reparam_offset, + data_format=data_format, + activity_regularizer=activity_regularizer, + trainable=trainable, + name=name, + dtype=inputs.dtype.base_dtype, + _scope=name, + _reuse=reuse) return layer.apply(inputs) @@ -2070,8 +2101,8 @@ def layer_norm(inputs, or if `inputs.shape[begin_params_axis:]` is not fully defined at graph build time. """ - with variable_scope.variable_scope(scope, 'LayerNorm', [inputs], - reuse=reuse) as sc: + with variable_scope.variable_scope( + scope, 'LayerNorm', [inputs], reuse=reuse) as sc: inputs = ops.convert_to_tensor(inputs) inputs_shape = inputs.shape inputs_rank = inputs_shape.ndims @@ -2081,15 +2112,14 @@ def layer_norm(inputs, if begin_norm_axis < 0: begin_norm_axis = inputs_rank + begin_norm_axis if begin_params_axis >= inputs_rank or begin_norm_axis >= inputs_rank: - raise ValueError( - 'begin_params_axis (%d) and begin_norm_axis (%d) ' - 'must be < rank(inputs) (%d)' - % (begin_params_axis, begin_norm_axis, inputs_rank)) + raise ValueError('begin_params_axis (%d) and begin_norm_axis (%d) ' + 'must be < rank(inputs) (%d)' % + (begin_params_axis, begin_norm_axis, inputs_rank)) params_shape = inputs_shape[begin_params_axis:] if not params_shape.is_fully_defined(): raise ValueError( - 'Inputs %s: shape(inputs)[%s:] is not fully defined: %s' % ( - inputs.name, begin_params_axis, inputs_shape)) + 'Inputs %s: shape(inputs)[%s:] is not fully defined: %s' % + (inputs.name, begin_params_axis, inputs_shape)) # Allocate parameters for the beta and gamma of the normalization. beta, gamma = None, None if center: @@ -2103,8 +2133,8 @@ def layer_norm(inputs, collections=beta_collections, trainable=trainable) if scale: - gamma_collections = utils.get_variable_collections(variables_collections, - 'gamma') + gamma_collections = utils.get_variable_collections( + variables_collections, 'gamma') gamma = variables.model_variable( 'gamma', shape=params_shape, @@ -2118,7 +2148,11 @@ def layer_norm(inputs, # Compute layer normalization using the batch_normalization function. variance_epsilon = 1e-12 outputs = nn.batch_normalization( - inputs, mean, variance, offset=beta, scale=gamma, + inputs, + mean, + variance, + offset=beta, + scale=gamma, variance_epsilon=variance_epsilon) outputs.set_shape(inputs_shape) if activation_fn is not None: @@ -2164,13 +2198,14 @@ def max_pool2d(inputs, raise ValueError('data_format has to be either NCHW or NHWC.') with ops.name_scope(scope, 'MaxPool2D', [inputs]) as sc: inputs = ops.convert_to_tensor(inputs) - df = ('channels_first' if data_format and data_format.startswith('NC') - else 'channels_last') - layer = pooling_layers.MaxPooling2D(pool_size=kernel_size, - strides=stride, - padding=padding, - data_format=df, - _scope=sc) + df = ('channels_first' + if data_format and data_format.startswith('NC') else 'channels_last') + layer = pooling_layers.MaxPooling2D( + pool_size=kernel_size, + strides=stride, + padding=padding, + data_format=df, + _scope=sc) outputs = layer.apply(inputs) return utils.collect_named_outputs(outputs_collections, sc, outputs) @@ -2213,13 +2248,14 @@ def max_pool3d(inputs, raise ValueError('data_format has to be either NCDHW or NDHWC.') with ops.name_scope(scope, 'MaxPool3D', [inputs]) as sc: inputs = ops.convert_to_tensor(inputs) - df = ('channels_first' if data_format and data_format.startswith('NC') - else 'channels_last') - layer = pooling_layers.MaxPooling3D(pool_size=kernel_size, - strides=stride, - padding=padding, - data_format=df, - _scope=sc) + df = ('channels_first' + if data_format and data_format.startswith('NC') else 'channels_last') + layer = pooling_layers.MaxPooling3D( + pool_size=kernel_size, + strides=stride, + padding=padding, + data_format=df, + _scope=sc) outputs = layer.apply(inputs) return utils.collect_named_outputs(outputs_collections, sc, outputs) @@ -2272,8 +2308,8 @@ def pool(inputs, """ # pylint: enable=line-too-long - with ops.name_scope(scope, '%s_pool' % - (pooling_type.lower()), [inputs]) as sc: + with ops.name_scope(scope, '%s_pool' % (pooling_type.lower()), + [inputs]) as sc: inputs = ops.convert_to_tensor(inputs) input_rank = inputs.get_shape().ndims if input_rank is None: @@ -2318,18 +2354,16 @@ def one_hot_encoding(labels, labels = ops.convert_to_tensor(labels) if labels.dtype == dtypes.int32: labels = standard_ops.to_int64(labels) - outputs = standard_ops.one_hot(labels, - num_classes, - on_value=on_value, - off_value=off_value) + outputs = standard_ops.one_hot( + labels, num_classes, on_value=on_value, off_value=off_value) return utils.collect_named_outputs(outputs_collections, sc, outputs) def _apply_activation(y, activation_fn, output_collections): if activation_fn is not None: y = activation_fn(y) - ops.add_to_collections(list(output_collections or []) + - [ops.GraphKeys.ACTIVATIONS], y) + ops.add_to_collections( + list(output_collections or []) + [ops.GraphKeys.ACTIVATIONS], y) return y @@ -2374,7 +2408,7 @@ def repeat(inputs, repetitions, layer, *args, **kwargs): scope = 'repeat' outputs = inputs for i in range(repetitions): - kwargs['scope'] = scope + '_' + str(i+1) + kwargs['scope'] = scope + '_' + str(i + 1) outputs = layer(outputs, *args, **kwargs) return outputs @@ -2389,8 +2423,8 @@ def _scale_gradient_grad(op, grad): return [grad * op.inputs[1], None] -@function.Defun(python_grad_func=_scale_gradient_grad, - shape_func=_scale_gradient_shape) +@function.Defun( + python_grad_func=_scale_gradient_grad, shape_func=_scale_gradient_shape) def scale_gradient(inputs, gradient_multiplier): """Identity operation, but with the gradient multiplied by a tensor. @@ -2495,18 +2529,21 @@ def separable_convolution2d( """ if data_format not in (DATA_FORMAT_NCHW, DATA_FORMAT_NHWC): raise ValueError('data_format has to be either NCHW or NHWC.') - layer_variable_getter = _build_variable_getter( - {'bias': 'biases', - 'depthwise_kernel': 'depthwise_weights', - 'pointwise_kernel': 'pointwise_weights'}) + layer_variable_getter = _build_variable_getter({ + 'bias': 'biases', + 'depthwise_kernel': 'depthwise_weights', + 'pointwise_kernel': 'pointwise_weights' + }) with variable_scope.variable_scope( - scope, 'SeparableConv2d', [inputs], reuse=reuse, + scope, + 'SeparableConv2d', [inputs], + reuse=reuse, custom_getter=layer_variable_getter) as sc: inputs = ops.convert_to_tensor(inputs) - df = ('channels_first' if data_format and data_format.startswith('NC') - else 'channels_last') + df = ('channels_first' + if data_format and data_format.startswith('NC') else 'channels_last') if num_outputs is not None: # Apply separable conv using the SeparableConvolution2D layer. layer = convolutional_layers.SeparableConvolution2D( @@ -2539,8 +2576,8 @@ def separable_convolution2d( _add_variable_to_collections(layer.pointwise_kernel, variables_collections, 'weights') if layer.bias is not None: - _add_variable_to_collections(layer.bias, - variables_collections, 'biases') + _add_variable_to_collections(layer.bias, variables_collections, + 'biases') if normalizer_fn is not None: normalizer_params = normalizer_params or {} @@ -2555,8 +2592,7 @@ def separable_convolution2d( weights_collections = utils.get_variable_collections( variables_collections, 'weights') - depthwise_shape = [kernel_h, kernel_w, - num_filters_in, depth_multiplier] + depthwise_shape = [kernel_h, kernel_w, num_filters_in, depth_multiplier] depthwise_weights = variables.model_variable( 'depthwise_weights', shape=depthwise_shape, @@ -2570,9 +2606,13 @@ def separable_convolution2d( 1, stride_h, stride_w, 1 ] - outputs = nn.depthwise_conv2d(inputs, depthwise_weights, strides, padding, - rate=utils.two_element_tuple(rate), - data_format=data_format) + outputs = nn.depthwise_conv2d( + inputs, + depthwise_weights, + strides, + padding, + rate=utils.two_element_tuple(rate), + data_format=data_format) num_outputs = depth_multiplier * num_filters_in if normalizer_fn is not None: @@ -2582,13 +2622,16 @@ def separable_convolution2d( if biases_initializer is not None: biases_collections = utils.get_variable_collections( variables_collections, 'biases') - biases = variables.model_variable('biases', - shape=[num_outputs,], - dtype=dtype, - initializer=biases_initializer, - regularizer=biases_regularizer, - trainable=trainable, - collections=biases_collections) + biases = variables.model_variable( + 'biases', + shape=[ + num_outputs, + ], + dtype=dtype, + initializer=biases_initializer, + regularizer=biases_regularizer, + trainable=trainable, + collections=biases_collections) outputs = nn.bias_add(outputs, biases, data_format=data_format) if activation_fn is not None: @@ -2673,23 +2716,24 @@ def spatial_softmax(features, with ops.name_scope('spatial_softmax_op', 'spatial_softmax_op', [features]): # Create tensors for x and y coordinate values, scaled to range [-1, 1]. - pos_x, pos_y = array_ops.meshgrid(math_ops.lin_space(-1., 1., num=height), - math_ops.lin_space(-1., 1., num=width), - indexing='ij') + pos_x, pos_y = array_ops.meshgrid( + math_ops.lin_space(-1., 1., num=height), + math_ops.lin_space(-1., 1., num=width), + indexing='ij') pos_x = array_ops.reshape(pos_x, [height * width]) pos_y = array_ops.reshape(pos_y, [height * width]) - + if temperature is None: temp_initializer = init_ops.ones_initializer() else: temp_initializer = init_ops.constant_initializer(temperature) - + if not trainable: temp_collections = None else: temp_collections = utils.get_variable_collections( - variables_collections, 'temperature') - + variables_collections, 'temperature') + temperature = variables.model_variable( 'temperature', shape=(), @@ -2703,14 +2747,14 @@ def spatial_softmax(features, features = array_ops.reshape( array_ops.transpose(features, [0, 3, 1, 2]), [-1, height * width]) - softmax_attention = nn.softmax(features/temperature) + softmax_attention = nn.softmax(features / temperature) expected_x = math_ops.reduce_sum( pos_x * softmax_attention, [1], keep_dims=True) expected_y = math_ops.reduce_sum( pos_y * softmax_attention, [1], keep_dims=True) expected_xy = array_ops.concat([expected_x, expected_y], 1) - feature_keypoints = array_ops.reshape( - expected_xy, [-1, num_channels.value * 2]) + feature_keypoints = array_ops.reshape(expected_xy, + [-1, num_channels.value * 2]) feature_keypoints.set_shape([None, num_channels.value * 2]) return feature_keypoints @@ -2762,7 +2806,7 @@ def stack(inputs, layer, stack_args, **kwargs): scope = 'stack' outputs = inputs for i in range(len(stack_args)): - kwargs['scope'] = scope + '_' + str(i+1) + kwargs['scope'] = scope + '_' + str(i + 1) layer_args = stack_args[i] if not isinstance(layer_args, (list, tuple)): layer_args = [layer_args] @@ -2793,11 +2837,10 @@ def unit_norm(inputs, dim, epsilon=1e-7, scope=None): raise ValueError('The input rank must be known.') input_rank = len(inputs.get_shape().as_list()) if dim < 0 or dim >= input_rank: - raise ValueError( - 'dim must be positive but smaller than the input rank.') + raise ValueError('dim must be positive but smaller than the input rank.') - lengths = math_ops.sqrt(epsilon + math_ops.reduce_sum( - math_ops.square(inputs), dim, True)) + lengths = math_ops.sqrt( + epsilon + math_ops.reduce_sum(math_ops.square(inputs), dim, True)) multiples = [] if dim > 0: multiples.append(array_ops.ones([dim], dtypes.int32)) @@ -2938,29 +2981,31 @@ def legacy_fully_connected(x, raise ValueError('last dimension of x must be known but is None') dtype = x.dtype.base_dtype - weight_collections = set(list(weight_collections or []) + - [ops.GraphKeys.GLOBAL_VARIABLES]) - w = variable_scope.get_variable('weights', - shape=[num_input_units, num_output_units], - dtype=dtype, - initializer=weight_init, - collections=weight_collections, - regularizer=weight_regularizer, - trainable=trainable) - x_2_dim = x if len(dims) <= 2 else array_ops.reshape(x, - [-1, num_input_units]) + weight_collections = set( + list(weight_collections or []) + [ops.GraphKeys.GLOBAL_VARIABLES]) + w = variable_scope.get_variable( + 'weights', + shape=[num_input_units, num_output_units], + dtype=dtype, + initializer=weight_init, + collections=weight_collections, + regularizer=weight_regularizer, + trainable=trainable) + x_2_dim = x if len(dims) <= 2 else array_ops.reshape( + x, [-1, num_input_units]) y = standard_ops.matmul(x_2_dim, w) if bias_init is not None: - bias_collections = set(list(bias_collections or []) + - [ops.GraphKeys.GLOBAL_VARIABLES]) - b = variable_scope.get_variable('bias', - shape=[num_output_units], - dtype=dtype, - initializer=bias_init, - collections=bias_collections, - regularizer=bias_regularizer, - trainable=trainable) + bias_collections = set( + list(bias_collections or []) + [ops.GraphKeys.GLOBAL_VARIABLES]) + b = variable_scope.get_variable( + 'bias', + shape=[num_output_units], + dtype=dtype, + initializer=bias_init, + collections=bias_collections, + regularizer=bias_regularizer, + trainable=trainable) y = nn.bias_add(y, b) diff --git a/tensorflow/contrib/opt/python/training/model_average_optimizer.py b/tensorflow/contrib/opt/python/training/model_average_optimizer.py index 47509ecca6..a7c97a1da2 100644 --- a/tensorflow/contrib/opt/python/training/model_average_optimizer.py +++ b/tensorflow/contrib/opt/python/training/model_average_optimizer.py @@ -12,30 +12,30 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== - -"""Wrapper optimizer for Model Average """ +"""Wrapper optimizer for Model Average.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.python.framework import ops -from tensorflow.python.framework import dtypes from tensorflow.python.framework import constant_op -from tensorflow.python.training import optimizer -from tensorflow.python.training import session_run_hook -from tensorflow.python.ops import math_ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import data_flow_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import state_ops from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables -from tensorflow.python.ops import state_ops -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import data_flow_ops +from tensorflow.python.training import optimizer +from tensorflow.python.training import session_run_hook -GLOBAL_VARIABLE_NAME = 'global_center_variable' +GLOBAL_VARIABLE_NAME = "global_center_variable" class ModelAverageCustomGetter(object): - """Custom_getter class is used to do: + """Custom_getter class is used to do. + 1. Change trainable variables to local collection and place them at worker device 2. Generate global variables @@ -73,15 +73,18 @@ class ModelAverageCustomGetter(object): def __call__(self, getter, name, trainable, collections, *args, **kwargs): if trainable: with ops.device(self._worker_device): - local_var = getter(name, trainable=True, - collections=[ops.GraphKeys.LOCAL_VARIABLES], - *args, **kwargs) + local_var = getter( + name, + trainable=True, + collections=[ops.GraphKeys.LOCAL_VARIABLES], + *args, + **kwargs) global_variable = variable_scope.variable( - name='%s/%s' % (GLOBAL_VARIABLE_NAME, name), - initial_value=local_var.initialized_value(), - trainable=False, - collections=[ops.GraphKeys.GLOBAL_VARIABLES]) + name="%s/%s" % (GLOBAL_VARIABLE_NAME, name), + initial_value=local_var.initialized_value(), + trainable=False, + collections=[ops.GraphKeys.GLOBAL_VARIABLES]) self._local_2_global[local_var] = global_variable return local_var @@ -91,6 +94,7 @@ class ModelAverageCustomGetter(object): class ModelAverageOptimizer(optimizer.Optimizer): """Wrapper optimizer that implements the Model Average algorithm. + This is a sync optimizer. During the training, each worker will update the local variables and maintains its own local_step, which starts from 0 and is incremented by 1 after each update of local variables. Whenever the @@ -99,15 +103,14 @@ class ModelAverageOptimizer(optimizer.Optimizer): local variables will be assigned by global center variables. """ - def __init__( - self, - opt, - num_worker, - is_chief, - ma_custom_getter, - interval_steps=100, - use_locking=True, - name="ModelAverageOptimizer"): + def __init__(self, + opt, + num_worker, + is_chief, + ma_custom_getter, + interval_steps=100, + use_locking=True, + name="ModelAverageOptimizer"): """Construct a new model average optimizer. Args: @@ -124,18 +127,18 @@ class ModelAverageOptimizer(optimizer.Optimizer): self._opt = opt self._num_worker = num_worker self._is_chief = is_chief - self._local_2_global = ma_custom_getter._local_2_global + self._local_2_global = ma_custom_getter._local_2_global # pylint:disable=protected-access self._interval_steps = interval_steps self._accumulator_list = [] self._chief_init_op = None self._local_step = variable_scope.get_variable( - initializer=0, - trainable=False, - collections=[ops.GraphKeys.LOCAL_VARIABLES], - name="local_step") + initializer=0, + trainable=False, + collections=[ops.GraphKeys.LOCAL_VARIABLES], + name="local_step") - self._opt._prepare() + self._opt._prepare() # pylint:disable=protected-access def compute_gradients(self, *args, **kwargs): """Compute gradients of "loss" for the variables in "var_list". @@ -159,10 +162,12 @@ class ModelAverageOptimizer(optimizer.Optimizer): Returns: An update op + + Raises: + ValueError: if var_list is empty. """ if not var_list: - raise ValueError( - 'The list of local_variables should not be empty') + raise ValueError("The list of local_variables should not be empty") update_ops = [] global_center_vars = [self._local_2_global[var] for var in var_list] for lvar, gvar in zip(var_list, global_center_vars): @@ -204,28 +209,29 @@ class ModelAverageOptimizer(optimizer.Optimizer): apply_updates = self._opt.apply_gradients(grads_and_vars) with ops.control_dependencies([apply_updates]): local_update = state_ops.assign_add( - self._local_step, 1, name='local_step_update').op + self._local_step, 1, name="local_step_update").op # update global variables. - def _Update_global_variables(): + def _update_global_variables(): # pylint: disable=missing-docstring local_vars = [v for g, v in grads_and_vars if g is not None] global_vars = [self._local_2_global[v] for v in local_vars] # sync queue with ops.colocate_with(global_step): - sync_queue = data_flow_ops.FIFOQueue(-1, [dtypes.bool], shapes=[[]], - shared_name='sync_queue') + sync_queue = data_flow_ops.FIFOQueue( + -1, [dtypes.bool], shapes=[[]], shared_name="sync_queue") train_ops = [] aggregated_vars = [] - with ops.name_scope(None, self._name + '/global'): + with ops.name_scope(None, self._name + "/global"): for var, gvar in zip(local_vars, global_vars): + # pylint: disable=protected-access with ops.device(gvar.device): if isinstance(var._ref(), ops.Tensor): var_accum = data_flow_ops.ConditionalAccumulator( - var.dtype, - shape=var.get_shape(), - shared_name=gvar.name + "/var_accum") + var.dtype, + shape=var.get_shape(), + shared_name=gvar.name + "/var_accum") train_ops.append( - var_accum.apply_grad(var._ref(), local_step=global_step)) + var_accum.apply_grad(var._ref(), local_step=global_step)) aggregated_vars.append(var_accum.take_grad(self._num_worker)) else: raise ValueError("Unknown local variable type!") @@ -254,24 +260,26 @@ class ModelAverageOptimizer(optimizer.Optimizer): return local_update_op with ops.control_dependencies([local_update]): - condition = math_ops.equal(math_ops.mod( - self._local_step, self._interval_steps), 0) + condition = math_ops.equal( + math_ops.mod(self._local_step, self._interval_steps), 0) conditional_update = control_flow_ops.cond( - condition, _Update_global_variables, control_flow_ops.no_op) + condition, _update_global_variables, control_flow_ops.no_op) chief_init_ops = [] for accum, dev in self._accumulator_list: with ops.device(dev): chief_init_ops.append( - accum.set_global_step( - global_step, name="SetGlobalStep")) + accum.set_global_step(global_step, name="SetGlobalStep")) self._chief_init_op = control_flow_ops.group(*(chief_init_ops)) return conditional_update def get_init_op(self): - """Returns the op to let all the local variables equal to the global - variables before the training begins""" + """Returns the op. + + This method lets all the local variables equal to the global + variables before the training begins. + """ return self._local_vars_update(variables.trainable_variables()) def make_session_run_hook(self): @@ -279,12 +287,13 @@ class ModelAverageOptimizer(optimizer.Optimizer): return _ModelAverageOptimizerHook(self, self._is_chief) -class _ModelAverageOptimizerHook(session_run_hook.SessionRunHook): +class _ModelAverageOptimizerHook(session_run_hook.SessionRunHook): # pylint: disable=missing-docstring + def __init__(self, ma_optimizer, is_chief): """Creates hook to handle ModelAverageOptimizer initialization ops. Args: - ea_optimizer: `ModelAverageOptimizer` which this hook will initialize. + ma_optimizer: `ModelAverageOptimizer` which this hook will initialize. is_chief: `Bool`, whether is this a chief replica or not. """ self._ma_optimizer = ma_optimizer @@ -295,5 +304,5 @@ class _ModelAverageOptimizerHook(session_run_hook.SessionRunHook): self._global_init_op = None if self._is_chief: self._global_init_op = variables.global_variables_initializer() - self._chief_init_op = self._ma_optimizer._chief_init_op + self._chief_init_op = self._ma_optimizer._chief_init_op # pylint: disable=protected-access self._variable_init_op = self._ma_optimizer.get_init_op() diff --git a/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py b/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py index a73aa772bb..29ecd22839 100644 --- a/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py +++ b/tensorflow/contrib/opt/python/training/model_average_optimizer_test.py @@ -18,18 +18,18 @@ from __future__ import division from __future__ import print_function import portpicker + +from tensorflow.contrib.opt.python.training import model_average_optimizer from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables from tensorflow.python.platform import test +from tensorflow.python.training import device_setter from tensorflow.python.training import gradient_descent from tensorflow.python.training import server_lib from tensorflow.python.training import training from tensorflow.python.training import training_util -from tensorflow.python.ops import variable_scope -from tensorflow.python.training import device_setter -from tensorflow.contrib.opt.python.training.model_average_optimizer import \ - ModelAverageOptimizer, ModelAverageCustomGetter, GLOBAL_VARIABLE_NAME def create_local_cluster(num_workers, num_ps, protocol="grpc"): @@ -37,20 +37,20 @@ def create_local_cluster(num_workers, num_ps, protocol="grpc"): worker_ports = [portpicker.pick_unused_port() for _ in range(num_workers)] ps_ports = [portpicker.pick_unused_port() for _ in range(num_ps)] cluster_dict = { - "worker": ["localhost:%s" % port for port in worker_ports], - "ps": ["localhost:%s" % port for port in ps_ports] + "worker": ["localhost:%s" % port for port in worker_ports], + "ps": ["localhost:%s" % port for port in ps_ports] } cs = server_lib.ClusterSpec(cluster_dict) workers = [ - server_lib.Server( - cs, job_name="worker", protocol=protocol, task_index=ix, start=True) - for ix in range(num_workers) + server_lib.Server( + cs, job_name="worker", protocol=protocol, task_index=ix, start=True) + for ix in range(num_workers) ] ps_servers = [ - server_lib.Server( - cs, job_name="ps", protocol=protocol, task_index=ix, start=True) - for ix in range(num_ps) + server_lib.Server( + cs, job_name="ps", protocol=protocol, task_index=ix, start=True) + for ix in range(num_ps) ] return cluster_dict, workers, ps_servers @@ -67,16 +67,16 @@ def _get_workers(num_workers, steps, workers): is_chief = (worker_id == 0) with graph.as_default(): worker_device = "/job:worker/task:%d/cpu:0" % (worker_id) - ma_coustom = ModelAverageCustomGetter( - worker_device=worker_device) - with variable_scope.variable_scope('', - custom_getter=ma_coustom), ops.device( - device_setter.replica_device_setter(worker_device=worker_device, - ps_device="/job:ps/task:0/cpu:0", - ps_tasks=1)): - - global_step = variables.Variable(0, name='global_step', - trainable=False) + ma_coustom = model_average_optimizer.ModelAverageCustomGetter( + worker_device=worker_device) + with variable_scope.variable_scope( + "", custom_getter=ma_coustom), ops.device( + device_setter.replica_device_setter( + worker_device=worker_device, + ps_device="/job:ps/task:0/cpu:0", + ps_tasks=1)): + + global_step = variables.Variable(0, name="global_step", trainable=False) var_0 = variable_scope.get_variable(initializer=0.0, name="v0") var_1 = variable_scope.get_variable(initializer=1.0, name="v1") @@ -88,22 +88,20 @@ def _get_workers(num_workers, steps, workers): grads_0 = constant_op.constant(-2.0) grads_1 = constant_op.constant(-2.0) sgd_opt = gradient_descent.GradientDescentOptimizer(1.0) - opt = ModelAverageOptimizer( - opt=sgd_opt, - num_worker=num_workers, - ma_custom_getter=ma_coustom, - is_chief=is_chief, - interval_steps=steps - ) + opt = model_average_optimizer.ModelAverageOptimizer( + opt=sgd_opt, + num_worker=num_workers, + ma_custom_getter=ma_coustom, + is_chief=is_chief, + interval_steps=steps) train_op = [ - opt.apply_gradients( - [[grads_0, var_0], - [grads_1, var_1]], global_step) + opt.apply_gradients([[grads_0, var_0], [grads_1, var_1]], + global_step) ] easgd_hook = opt.make_session_run_hook() # Creates MonitoredSession - sess = training.MonitoredTrainingSession(workers[worker_id].target, - hooks=[easgd_hook]) + sess = training.MonitoredTrainingSession( + workers[worker_id].target, hooks=[easgd_hook]) sessions.append(sess) graphs.append(graph) @@ -112,6 +110,7 @@ def _get_workers(num_workers, steps, workers): class ModelAverageOptimizerTest(test.TestCase): + def _run(self, train_op, sess): sess.run(train_op) @@ -119,18 +118,18 @@ class ModelAverageOptimizerTest(test.TestCase): num_workers = 2 steps = 2 num_ps = 1 - cluster, workers, _ = create_local_cluster(num_workers=num_workers, - num_ps=num_ps) + _, workers, _ = create_local_cluster( + num_workers=num_workers, num_ps=num_ps) - sessions, graphs, train_ops = _get_workers(num_workers, - steps, - workers) + sessions, graphs, train_ops = _get_workers(num_workers, steps, workers) - var_0 = graphs[0].get_tensor_by_name('v0:0') - var_1 = graphs[0].get_tensor_by_name('v1:0') + var_0 = graphs[0].get_tensor_by_name("v0:0") + var_1 = graphs[0].get_tensor_by_name("v1:0") global_step = training_util.get_global_step(graphs[0]) - global_var_0 = graphs[0].get_tensor_by_name(GLOBAL_VARIABLE_NAME + "/v0:0") - global_var_1 = graphs[0].get_tensor_by_name(GLOBAL_VARIABLE_NAME + "/v1:0") + global_var_0 = graphs[0].get_tensor_by_name( + model_average_optimizer.GLOBAL_VARIABLE_NAME + "/v0:0") + global_var_1 = graphs[0].get_tensor_by_name( + model_average_optimizer.GLOBAL_VARIABLE_NAME + "/v1:0") # Verify the initialized value. self.assertAllEqual(0.0, sessions[0].run(var_0)) @@ -150,9 +149,9 @@ class ModelAverageOptimizerTest(test.TestCase): # iteration 2, global varibale update thread_0 = self.checkedThread( - target=self._run, args=(train_ops[0], sessions[0])) + target=self._run, args=(train_ops[0], sessions[0])) thread_1 = self.checkedThread( - target=self._run, args=(train_ops[1], sessions[1])) + target=self._run, args=(train_ops[1], sessions[1])) thread_0.start() thread_1.start() thread_0.join() @@ -175,20 +174,20 @@ class ModelAverageOptimizerTest(test.TestCase): def testPS2TasksWithClusterSpecClass(self): cluster_spec = server_lib.ClusterSpec({ - "ps": ["ps0:2222", "ps1:2222"], - "worker": ["worker0:2222", "worker1:2222", "worker2:2222"] + "ps": ["ps0:2222", "ps1:2222"], + "worker": ["worker0:2222", "worker1:2222", "worker2:2222"] }) worker_device = "/job:worker/task:0" - ma_coustom = ModelAverageCustomGetter( - worker_device=worker_device) + ma_coustom = model_average_optimizer.ModelAverageCustomGetter( + worker_device=worker_device) from tensorflow.python.training import device_setter with ops.device( device_setter.replica_device_setter(cluster=cluster_spec, worker_device=worker_device, ps_device="/job:ps")), \ - variable_scope.variable_scope('', custom_getter=ma_coustom): + variable_scope.variable_scope("", custom_getter=ma_coustom): v = variable_scope.get_variable(initializer=[1, 2], name="v") - w = variable_scope.get_variable(initializer=[2, 1], name='w') + w = variable_scope.get_variable(initializer=[2, 1], name="w") v_g, w_g = ma_coustom._local_2_global[v], ma_coustom._local_2_global[w] self.assertDeviceEqual("/job:worker/task:0", v.device) self.assertDeviceEqual("job:ps/task:0", v_g.device) @@ -196,5 +195,5 @@ class ModelAverageOptimizerTest(test.TestCase): self.assertDeviceEqual("job:ps/task:1", w_g.device) -if __name__ == '__main__': +if __name__ == "__main__": test.main() diff --git a/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py b/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py index 30a2077570..a25de55e18 100644 --- a/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py +++ b/tensorflow/contrib/periodic_resample/python/kernel_tests/periodic_resample_op_test.py @@ -53,12 +53,11 @@ class PeriodicResampleTest(test_util.TensorFlowTestCase): def testPeriodicResampleBasic3D(self): - input_tensor = numpy.arange(2*2*4).reshape((2, 2, 4)) + input_tensor = numpy.arange(2 * 2 * 4).reshape((2, 2, 4)) desired_shape = numpy.array([4, 4, None]) - output_tensor = numpy.array([[[0], [2], [4], [6]], - [[1], [3], [5], [7]], - [[8], [10], [12], [14]], - [[9], [11], [13], [15]]]) + output_tensor = numpy.array([[[0], [2], [4], [6]], [[1], [3], [5], [7]], + [[8], [10], [12], [14]], [[9], [11], [13], + [15]]]) # NOTE: output_tensor != input_tensor.reshape((4, 4, -1)) with self.test_session(): @@ -72,24 +71,18 @@ class PeriodicResampleTest(test_util.TensorFlowTestCase): def testPeriodicResampleBasic4D(self): - input_tensor = numpy.arange(2*2*2*8).reshape((2, 2, 2, 8)) + input_tensor = numpy.arange(2 * 2 * 2 * 8).reshape((2, 2, 2, 8)) desired_shape = numpy.array([4, 4, 4, None]) - output_tensor = numpy.array([[[[0], [4], [8], [12]], - [[2], [6], [10], [14]], - [[16], [20], [24], [28]], - [[18], [22], [26], [30]]], - [[[1], [5], [9], [13]], - [[3], [7], [11], [15]], - [[17], [21], [25], [29]], - [[19], [23], [27], [31]]], - [[[32], [36], [40], [44]], - [[34], [38], [42], [46]], - [[48], [52], [56], [60]], - [[50], [54], [58], [62]]], - [[[33], [37], [41], [45]], - [[35], [39], [43], [47]], - [[49], [53], [57], [61]], - [[51], [55], [59], [63]]]]) + output_tensor = numpy.array( + [[[[0], [4], [8], [12]], [[2], [6], [10], [14]], + [[16], [20], [24], [28]], [[18], [22], [26], [30]]], + [[[1], [5], [9], [13]], [[3], [7], [11], [15]], [[17], [21], [25], + [29]], + [[19], [23], [27], + [31]]], [[[32], [36], [40], [44]], [[34], [38], [42], [46]], + [[48], [52], [56], [60]], [[50], [54], [58], [62]]], + [[[33], [37], [41], [45]], [[35], [39], [43], [47]], + [[49], [53], [57], [61]], [[51], [55], [59], [63]]]]) # NOTE: output_tensor != input_tensor.reshape((4, 4, 4, -1)) with self.test_session(): @@ -111,5 +104,5 @@ class PeriodicResampleTest(test_util.TensorFlowTestCase): periodic_resample(input_tensor, [None, 4, 4]).eval() -if __name__ == "__main__": +if __name__ == '__main__': googletest.main() diff --git a/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py b/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py index 70aaba1728..c780e85d72 100644 --- a/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py +++ b/tensorflow/contrib/rnn/python/kernel_tests/rnn_cell_test.py @@ -53,14 +53,12 @@ class RNNCellTest(test.TestCase): batch_size = 3 input_size = 4 expected_output = np.array( - [[0.121753, 0.121753], - [0.103349, 0.103349], - [0.100178, 0.100178]], + [[0.121753, 0.121753], [0.103349, 0.103349], [0.100178, 0.100178]], dtype=np.float32) expected_state = np.array( - [[0.137523, 0.137523, 0.121753, 0.121753], - [0.105450, 0.105450, 0.103349, 0.103349], - [0.100742, 0.100742, 0.100178, 0.100178]], + [[0.137523, 0.137523, 0.121753, 0.121753], [ + 0.105450, 0.105450, 0.103349, 0.103349 + ], [0.100742, 0.100742, 0.100178, 0.100178]], dtype=np.float32) with variable_scope.variable_scope( "root", initializer=init_ops.constant_initializer(0.5)): @@ -69,14 +67,14 @@ class RNNCellTest(test.TestCase): output, state = contrib_rnn_cell.CoupledInputForgetGateLSTMCell( num_units=num_units, forget_bias=1.0, state_is_tuple=False)(x, m) sess.run([variables.global_variables_initializer()]) - res = sess.run([output, state], { - x.name: - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]]), - m.name: - 0.1 * np.ones((batch_size, state_size)) - }) + res = sess.run( + [output, state], { + x.name: + np.array([[1., 1., 1., 1.], [2., 2., 2., 2.], + [3., 3., 3., 3.]]), + m.name: + 0.1 * np.ones((batch_size, state_size)) + }) # This is a smoke test: Only making sure expected values didn't change. self.assertEqual(len(res), 2) self.assertAllClose(res[0], expected_output) @@ -101,14 +99,14 @@ class RNNCellTest(test.TestCase): frequency_skip=frequency_skip, forget_bias=1.0)(x, m) sess.run([variables.global_variables_initializer()]) - res = sess.run([output, state], { - x.name: - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]]), - m.name: - 0.1 * np.ones((batch_size, int(state_size * (num_shifts)))) - }) + res = sess.run( + [output, state], { + x.name: + np.array([[1., 1., 1., 1.], [2., 2., 2., 2.], + [3., 3., 3., 3.]]), + m.name: + 0.1 * np.ones((batch_size, int(state_size * (num_shifts)))) + }) self.assertEqual(len(res), 2) # The numbers in results were not calculated, this is mostly just a # smoke test. @@ -141,17 +139,14 @@ class RNNCellTest(test.TestCase): state_is_tuple=True) inputs = constant_op.constant( np.array( - [[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]], + [[1., 1., 1., 1.], [2., 2., 2., 2.], [3., 3., 3., 3.]], dtype=np.float32), dtype=dtypes.float32) state_value = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) - init_state = cell.state_tuple_type( - *([state_value, state_value] * num_shifts)) + init_state = cell.state_tuple_type(*( + [state_value, state_value] * num_shifts)) output, state = cell(inputs, init_state) sess.run([variables.global_variables_initializer()]) res = sess.run([output, state]) @@ -198,11 +193,10 @@ class RNNCellTest(test.TestCase): dtype=np.float32), dtype=dtypes.float32) state_value = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) - init_state = cell.state_tuple_type( - *([state_value, state_value] * total_blocks)) + init_state = cell.state_tuple_type(*( + [state_value, state_value] * total_blocks)) output, state = cell(inputs, init_state) sess.run([variables.global_variables_initializer()]) res = sess.run([output, state]) @@ -230,20 +224,28 @@ class RNNCellTest(test.TestCase): frequency_skip = 1 num_shifts = int((input_size - feature_size) / frequency_skip + 1) expected_output = np.array( - [[0.416383, 0.416383, 0.403238, 0.403238, 0.524020, 0.524020, - 0.565425, 0.565425, 0.557865, 0.557865, 0.609699, 0.609699], - [0.627331, 0.627331, 0.622393, 0.622393, 0.688342, 0.688342, - 0.708078, 0.708078, 0.694245, 0.694245, 0.715171, 0.715171], - [0.711050, 0.711050, 0.709197, 0.709197, 0.736533, 0.736533, - 0.744264, 0.744264, 0.737390, 0.737390, 0.745250, 0.745250]], + [[ + 0.416383, 0.416383, 0.403238, 0.403238, 0.524020, 0.524020, + 0.565425, 0.565425, 0.557865, 0.557865, 0.609699, 0.609699 + ], [ + 0.627331, 0.627331, 0.622393, 0.622393, 0.688342, 0.688342, + 0.708078, 0.708078, 0.694245, 0.694245, 0.715171, 0.715171 + ], [ + 0.711050, 0.711050, 0.709197, 0.709197, 0.736533, 0.736533, + 0.744264, 0.744264, 0.737390, 0.737390, 0.745250, 0.745250 + ]], dtype=np.float32) expected_state = np.array( - [[0.625556, 0.625556, 0.416383, 0.416383, 0.759134, 0.759134, - 0.524020, 0.524020, 0.798795, 0.798795, 0.557865, 0.557865], - [0.875488, 0.875488, 0.627331, 0.627331, 0.936432, 0.936432, - 0.688342, 0.688342, 0.941961, 0.941961, 0.694245, 0.694245], - [0.957327, 0.957327, 0.711050, 0.711050, 0.979522, 0.979522, - 0.736533, 0.736533, 0.980245, 0.980245, 0.737390, 0.737390]], + [[ + 0.625556, 0.625556, 0.416383, 0.416383, 0.759134, 0.759134, + 0.524020, 0.524020, 0.798795, 0.798795, 0.557865, 0.557865 + ], [ + 0.875488, 0.875488, 0.627331, 0.627331, 0.936432, 0.936432, + 0.688342, 0.688342, 0.941961, 0.941961, 0.694245, 0.694245 + ], [ + 0.957327, 0.957327, 0.711050, 0.711050, 0.979522, 0.979522, + 0.736533, 0.736533, 0.980245, 0.980245, 0.737390, 0.737390 + ]], dtype=np.float32) for state_is_tuple in [False, True]: with self.test_session() as sess: @@ -259,18 +261,16 @@ class RNNCellTest(test.TestCase): couple_input_forget_gates=True, state_is_tuple=state_is_tuple) inputs = constant_op.constant( - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]], - dtype=np.float32), + np.array( + [[1., 1., 1., 1.], [2., 2., 2., 2.], [3., 3., 3., 3.]], + dtype=np.float32), dtype=dtypes.float32) if state_is_tuple: state_value = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) - init_state = cell.state_tuple_type( - *([state_value, state_value] * num_shifts)) + init_state = cell.state_tuple_type(*( + [state_value, state_value] * num_shifts)) else: init_state = constant_op.constant( 0.1 * np.ones( @@ -302,32 +302,40 @@ class RNNCellTest(test.TestCase): frequency_skip = 1 num_shifts = int((input_size - feature_size) / frequency_skip + 1) expected_output = np.array( - [[0.464130, 0.464130, 0.419165, 0.419165, 0.593283, 0.593283, - 0.738350, 0.738350, 0.661638, 0.661638, 0.866774, 0.866774, - 0.520789, 0.520789, 0.476968, 0.476968, 0.604341, 0.604341, - 0.760207, 0.760207, 0.635773, 0.635773, 0.850218, 0.850218], - [0.669636, 0.669636, 0.628966, 0.628966, 0.736057, 0.736057, - 0.895927, 0.895927, 0.755559, 0.755559, 0.954359, 0.954359, - 0.692621, 0.692621, 0.652363, 0.652363, 0.737517, 0.737517, - 0.899558, 0.899558, 0.745984, 0.745984, 0.946840, 0.946840], - [0.751109, 0.751109, 0.711716, 0.711716, 0.778357, 0.778357, - 0.940779, 0.940779, 0.784530, 0.784530, 0.980604, 0.980604, - 0.759940, 0.759940, 0.720652, 0.720652, 0.778552, 0.778552, - 0.941606, 0.941606, 0.781035, 0.781035, 0.977731, 0.977731]], + [[ + 0.464130, 0.464130, 0.419165, 0.419165, 0.593283, 0.593283, + 0.738350, 0.738350, 0.661638, 0.661638, 0.866774, 0.866774, + 0.520789, 0.520789, 0.476968, 0.476968, 0.604341, 0.604341, + 0.760207, 0.760207, 0.635773, 0.635773, 0.850218, 0.850218 + ], [ + 0.669636, 0.669636, 0.628966, 0.628966, 0.736057, 0.736057, + 0.895927, 0.895927, 0.755559, 0.755559, 0.954359, 0.954359, + 0.692621, 0.692621, 0.652363, 0.652363, 0.737517, 0.737517, + 0.899558, 0.899558, 0.745984, 0.745984, 0.946840, 0.946840 + ], [ + 0.751109, 0.751109, 0.711716, 0.711716, 0.778357, 0.778357, + 0.940779, 0.940779, 0.784530, 0.784530, 0.980604, 0.980604, + 0.759940, 0.759940, 0.720652, 0.720652, 0.778552, 0.778552, + 0.941606, 0.941606, 0.781035, 0.781035, 0.977731, 0.977731 + ]], dtype=np.float32) expected_state = np.array( - [[0.710660, 0.710660, 0.464130, 0.464130, 0.877293, 0.877293, - 0.593283, 0.593283, 0.958505, 0.958505, 0.661638, 0.661638, - 0.785405, 0.785405, 0.520789, 0.520789, 0.890836, 0.890836, - 0.604341, 0.604341, 0.928512, 0.928512, 0.635773, 0.635773], - [0.967579, 0.967579, 0.669636, 0.669636, 1.038811, 1.038811, - 0.736057, 0.736057, 1.058201, 1.058201, 0.755559, 0.755559, - 0.993088, 0.993088, 0.692621, 0.692621, 1.040288, 1.040288, - 0.737517, 0.737517, 1.048773, 1.048773, 0.745984, 0.745984], - [1.053842, 1.053842, 0.751109, 0.751109, 1.079919, 1.079919, - 0.778357, 0.778357, 1.085620, 1.085620, 0.784530, 0.784530, - 1.062455, 1.062455, 0.759940, 0.759940, 1.080101, 1.080101, - 0.778552, 0.778552, 1.082402, 1.082402, 0.781035, 0.781035]], + [[ + 0.710660, 0.710660, 0.464130, 0.464130, 0.877293, 0.877293, + 0.593283, 0.593283, 0.958505, 0.958505, 0.661638, 0.661638, + 0.785405, 0.785405, 0.520789, 0.520789, 0.890836, 0.890836, + 0.604341, 0.604341, 0.928512, 0.928512, 0.635773, 0.635773 + ], [ + 0.967579, 0.967579, 0.669636, 0.669636, 1.038811, 1.038811, + 0.736057, 0.736057, 1.058201, 1.058201, 0.755559, 0.755559, + 0.993088, 0.993088, 0.692621, 0.692621, 1.040288, 1.040288, + 0.737517, 0.737517, 1.048773, 1.048773, 0.745984, 0.745984 + ], [ + 1.053842, 1.053842, 0.751109, 0.751109, 1.079919, 1.079919, + 0.778357, 0.778357, 1.085620, 1.085620, 0.784530, 0.784530, + 1.062455, 1.062455, 0.759940, 0.759940, 1.080101, 1.080101, + 0.778552, 0.778552, 1.082402, 1.082402, 0.781035, 0.781035 + ]], dtype=np.float32) with variable_scope.variable_scope( "root", initializer=init_ops.constant_initializer(0.5)): @@ -339,17 +347,16 @@ class RNNCellTest(test.TestCase): forget_bias=1.0, num_frequency_blocks=[num_shifts]) inputs = constant_op.constant( - np.array([[1.0, 1.1, 1.2, 1.3], - [2.0, 2.1, 2.2, 2.3], - [3.0, 3.1, 3.2, 3.3]], - dtype=np.float32), + np.array( + [[1.0, 1.1, 1.2, 1.3], [2.0, 2.1, 2.2, 2.3], + [3.0, 3.1, 3.2, 3.3]], + dtype=np.float32), dtype=dtypes.float32) state_value = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) - init_state = cell.state_tuple_type( - *([state_value, state_value] * num_shifts * 2)) + init_state = cell.state_tuple_type(*( + [state_value, state_value] * num_shifts * 2)) output, state = cell(inputs, init_state) sess.run([variables.global_variables_initializer()]) res = sess.run([output, state]) @@ -375,32 +382,40 @@ class RNNCellTest(test.TestCase): frequency_skip = 1 num_shifts = int((input_size - feature_size) / frequency_skip + 1) expected_output = np.array( - [[0.464130, 0.464130, 0.419165, 0.419165, 0.593283, 0.593283, - 0.738350, 0.738350, 0.661638, 0.661638, 0.866774, 0.866774, - 0.322645, 0.322645, 0.276068, 0.276068, 0.584654, 0.584654, - 0.690292, 0.690292, 0.640446, 0.640446, 0.840071, 0.840071], - [0.669636, 0.669636, 0.628966, 0.628966, 0.736057, 0.736057, - 0.895927, 0.895927, 0.755559, 0.755559, 0.954359, 0.954359, - 0.493625, 0.493625, 0.449236, 0.449236, 0.730828, 0.730828, - 0.865996, 0.865996, 0.749429, 0.749429, 0.944958, 0.944958], - [0.751109, 0.751109, 0.711716, 0.711716, 0.778357, 0.778357, - 0.940779, 0.940779, 0.784530, 0.784530, 0.980604, 0.980604, - 0.608587, 0.608587, 0.566683, 0.566683, 0.777345, 0.777345, - 0.925820, 0.925820, 0.782597, 0.782597, 0.976858, 0.976858]], + [[ + 0.464130, 0.464130, 0.419165, 0.419165, 0.593283, 0.593283, + 0.738350, 0.738350, 0.661638, 0.661638, 0.866774, 0.866774, + 0.322645, 0.322645, 0.276068, 0.276068, 0.584654, 0.584654, + 0.690292, 0.690292, 0.640446, 0.640446, 0.840071, 0.840071 + ], [ + 0.669636, 0.669636, 0.628966, 0.628966, 0.736057, 0.736057, + 0.895927, 0.895927, 0.755559, 0.755559, 0.954359, 0.954359, + 0.493625, 0.493625, 0.449236, 0.449236, 0.730828, 0.730828, + 0.865996, 0.865996, 0.749429, 0.749429, 0.944958, 0.944958 + ], [ + 0.751109, 0.751109, 0.711716, 0.711716, 0.778357, 0.778357, + 0.940779, 0.940779, 0.784530, 0.784530, 0.980604, 0.980604, + 0.608587, 0.608587, 0.566683, 0.566683, 0.777345, 0.777345, + 0.925820, 0.925820, 0.782597, 0.782597, 0.976858, 0.976858 + ]], dtype=np.float32) expected_state = np.array( - [[0.710660, 0.710660, 0.464130, 0.464130, 0.877293, 0.877293, - 0.593283, 0.593283, 0.958505, 0.958505, 0.661638, 0.661638, - 0.516575, 0.516575, 0.322645, 0.322645, 0.866628, 0.866628, - 0.584654, 0.584654, 0.934002, 0.934002, 0.640446, 0.640446], - [0.967579, 0.967579, 0.669636, 0.669636, 1.038811, 1.038811, - 0.736057, 0.736057, 1.058201, 1.058201, 0.755559, 0.755559, - 0.749836, 0.749836, 0.493625, 0.493625, 1.033488, 1.033488, - 0.730828, 0.730828, 1.052186, 1.052186, 0.749429, 0.749429], - [1.053842, 1.053842, 0.751109, 0.751109, 1.079919, 1.079919, - 0.778357, 0.778357, 1.085620, 1.085620, 0.784530, 0.784530, - 0.895999, 0.895999, 0.608587, 0.608587, 1.078978, 1.078978, - 0.777345, 0.777345, 1.083843, 1.083843, 0.782597, 0.782597]], + [[ + 0.710660, 0.710660, 0.464130, 0.464130, 0.877293, 0.877293, + 0.593283, 0.593283, 0.958505, 0.958505, 0.661638, 0.661638, + 0.516575, 0.516575, 0.322645, 0.322645, 0.866628, 0.866628, + 0.584654, 0.584654, 0.934002, 0.934002, 0.640446, 0.640446 + ], [ + 0.967579, 0.967579, 0.669636, 0.669636, 1.038811, 1.038811, + 0.736057, 0.736057, 1.058201, 1.058201, 0.755559, 0.755559, + 0.749836, 0.749836, 0.493625, 0.493625, 1.033488, 1.033488, + 0.730828, 0.730828, 1.052186, 1.052186, 0.749429, 0.749429 + ], [ + 1.053842, 1.053842, 0.751109, 0.751109, 1.079919, 1.079919, + 0.778357, 0.778357, 1.085620, 1.085620, 0.784530, 0.784530, + 0.895999, 0.895999, 0.608587, 0.608587, 1.078978, 1.078978, + 0.777345, 0.777345, 1.083843, 1.083843, 0.782597, 0.782597 + ]], dtype=np.float32) with variable_scope.variable_scope( "root", initializer=init_ops.constant_initializer(0.5)): @@ -413,17 +428,16 @@ class RNNCellTest(test.TestCase): num_frequency_blocks=[num_shifts], backward_slice_offset=1) inputs = constant_op.constant( - np.array([[1.0, 1.1, 1.2, 1.3], - [2.0, 2.1, 2.2, 2.3], - [3.0, 3.1, 3.2, 3.3]], - dtype=np.float32), + np.array( + [[1.0, 1.1, 1.2, 1.3], [2.0, 2.1, 2.2, 2.3], + [3.0, 3.1, 3.2, 3.3]], + dtype=np.float32), dtype=dtypes.float32) state_value = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) - init_state = cell.state_tuple_type( - *([state_value, state_value] * num_shifts * 2)) + init_state = cell.state_tuple_type(*( + [state_value, state_value] * num_shifts * 2)) output, state = cell(inputs, init_state) sess.run([variables.global_variables_initializer()]) res = sess.run([output, state]) @@ -474,8 +488,8 @@ class RNNCellTest(test.TestCase): for state_is_tuple in [False, True]: with ops.Graph().as_default(): with self.test_session() as sess: - with variable_scope.variable_scope("state_is_tuple_" + str( - state_is_tuple)): + with variable_scope.variable_scope( + "state_is_tuple_" + str(state_is_tuple)): lstm_cell = rnn_cell.BasicLSTMCell( num_units, state_is_tuple=state_is_tuple) cell = contrib_rnn_cell.AttentionCellWrapper( @@ -525,16 +539,15 @@ class RNNCellTest(test.TestCase): for state_is_tuple in [False, True]: with ops.Graph().as_default(): with self.test_session() as sess: - with variable_scope.variable_scope("state_is_tuple_" + str( - state_is_tuple)): + with variable_scope.variable_scope( + "state_is_tuple_" + str(state_is_tuple)): lstm_cell = rnn_cell.BasicLSTMCell( num_units, state_is_tuple=state_is_tuple) cell = contrib_rnn_cell.AttentionCellWrapper( lstm_cell, attn_length, state_is_tuple=state_is_tuple) if state_is_tuple: zeros = constant_op.constant( - 0.1 * np.ones( - [batch_size, num_units], dtype=np.float32), + 0.1 * np.ones([batch_size, num_units], dtype=np.float32), dtype=dtypes.float32) attn_state_zeros = constant_op.constant( 0.1 * np.ones( @@ -579,22 +592,25 @@ class RNNCellTest(test.TestCase): [1.018088, 0.378983, -0.572179, 0.268591]], dtype=np.float32) expected_state = np.array( - [[0.74946702, 0.34681597, 0.26474735, 1.06485605, 0.38465962, - 0.11420801, 0.10272158, 0.30925757, 0.63899988, 0.7181077, - 0.47534478, 0.33715725, 0.58086717, 0.49446869, 0.7641536, - 0.12814975, 0.92231739, 0.89857256, 0.21889746, 0.38442063, - 0.53481543, 0.8876909, 0.45823169, 0.5905602, 0.78038228, - 0.56501579, 0.03971386, 0.09870267, 0.8074435, 0.66821432, - 0.99211812, 0.12295902, 1.14606023, 0.34370938, -0.79251152, - 0.51843399], - [0.5179342, 0.48682183, -0.25426468, 0.96810579, 0.28809637, - 0.13607743, -0.11446252, 0.26792109, 0.78047138, 0.63460857, - 0.49122369, 0.52007174, 0.73000264, 0.66986895, 0.73576689, - 0.86301267, 0.87887371, 0.35185754, 0.93417215, 0.64732957, - 0.63173044, 0.66627824, 0.53644657, 0.20477486, 0.98458421, - 0.38277245, 0.03746676, 0.92510188, 0.57714164, 0.84932971, - 0.36127412, 0.12125921, 1.1362772, 0.34361625, -0.78150457, - 0.70582712]], + [[ + 0.74946702, 0.34681597, 0.26474735, 1.06485605, 0.38465962, + 0.11420801, 0.10272158, 0.30925757, 0.63899988, 0.7181077, + 0.47534478, 0.33715725, 0.58086717, 0.49446869, 0.7641536, + 0.12814975, 0.92231739, 0.89857256, 0.21889746, 0.38442063, + 0.53481543, 0.8876909, 0.45823169, 0.5905602, 0.78038228, + 0.56501579, 0.03971386, 0.09870267, 0.8074435, 0.66821432, + 0.99211812, 0.12295902, 1.14606023, 0.34370938, -0.79251152, + 0.51843399 + ], [ + 0.5179342, 0.48682183, -0.25426468, 0.96810579, 0.28809637, + 0.13607743, -0.11446252, 0.26792109, 0.78047138, 0.63460857, + 0.49122369, 0.52007174, 0.73000264, 0.66986895, 0.73576689, + 0.86301267, 0.87887371, 0.35185754, 0.93417215, 0.64732957, + 0.63173044, 0.66627824, 0.53644657, 0.20477486, 0.98458421, + 0.38277245, 0.03746676, 0.92510188, 0.57714164, 0.84932971, + 0.36127412, 0.12125921, 1.1362772, 0.34361625, -0.78150457, + 0.70582712 + ]], dtype=np.float32) seed = 12345 random_seed.set_random_seed(seed) @@ -602,7 +618,8 @@ class RNNCellTest(test.TestCase): for state_is_tuple in [False, True]: with session.Session() as sess: with variable_scope.variable_scope( - "state_is_tuple", reuse=state_is_tuple, + "state_is_tuple", + reuse=state_is_tuple, initializer=init_ops.glorot_uniform_initializer()): lstm_cell = rnn_cell.BasicLSTMCell( num_units, state_is_tuple=state_is_tuple) @@ -646,36 +663,31 @@ class RNNCellTest(test.TestCase): def testNASCell(self): num_units = 6 batch_size = 3 - expected_output = np.array([[0.576751, 0.576751, 0.576751, 0.576751, - 0.576751, 0.576751], - [0.618936, 0.618936, 0.618936, 0.618936, - 0.618936, 0.618936], - [0.627393, 0.627393, 0.627393, 0.627393, - 0.627393, 0.627393]]) - expected_state = np.array([[0.71579772, 0.71579772, 0.71579772, 0.71579772, - 0.71579772, 0.71579772, 0.57675087, 0.57675087, - 0.57675087, 0.57675087, 0.57675087, 0.57675087], - [0.78041625, 0.78041625, 0.78041625, 0.78041625, - 0.78041625, 0.78041625, 0.6189357, 0.6189357, - 0.61893570, 0.6189357, 0.6189357, 0.6189357], - [0.79457647, 0.79457647, 0.79457647, 0.79457647, - 0.79457653, 0.79457653, 0.62739348, 0.62739348, - 0.62739348, 0.62739348, 0.62739348, 0.62739348] - ]) + expected_output = np.array( + [[0.576751, 0.576751, 0.576751, 0.576751, 0.576751, 0.576751], + [0.618936, 0.618936, 0.618936, 0.618936, 0.618936, 0.618936], + [0.627393, 0.627393, 0.627393, 0.627393, 0.627393, 0.627393]]) + expected_state = np.array([[ + 0.71579772, 0.71579772, 0.71579772, 0.71579772, 0.71579772, 0.71579772, + 0.57675087, 0.57675087, 0.57675087, 0.57675087, 0.57675087, 0.57675087 + ], [ + 0.78041625, 0.78041625, 0.78041625, 0.78041625, 0.78041625, 0.78041625, + 0.6189357, 0.6189357, 0.61893570, 0.6189357, 0.6189357, 0.6189357 + ], [ + 0.79457647, 0.79457647, 0.79457647, 0.79457647, 0.79457653, 0.79457653, + 0.62739348, 0.62739348, 0.62739348, 0.62739348, 0.62739348, 0.62739348 + ]]) with self.test_session() as sess: with variable_scope.variable_scope( - "nas_test", - initializer=init_ops.constant_initializer(0.5)): + "nas_test", initializer=init_ops.constant_initializer(0.5)): cell = contrib_rnn_cell.NASCell(num_units=num_units) inputs = constant_op.constant( - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]], - dtype=np.float32), + np.array( + [[1., 1., 1., 1.], [2., 2., 2., 2.], [3., 3., 3., 3.]], + dtype=np.float32), dtype=dtypes.float32) state_value = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) init_state = rnn_cell.LSTMStateTuple(state_value, state_value) output, state = cell(inputs, init_state) @@ -699,39 +711,34 @@ class RNNCellTest(test.TestCase): num_units = 6 batch_size = 3 num_proj = 5 - expected_output = np.array([[1.697418, 1.697418, 1.697418, 1.697418, - 1.697418], - [1.840037, 1.840037, 1.840037, 1.840037, - 1.840037], - [1.873985, 1.873985, 1.873985, 1.873985, - 1.873985]]) - expected_state = np.array([[0.69855207, 0.69855207, 0.69855207, 0.69855207, - 0.69855207, 0.69855207, 1.69741797, 1.69741797, - 1.69741797, 1.69741797, 1.69741797], - [0.77073824, 0.77073824, 0.77073824, 0.77073824, - 0.77073824, 0.77073824, 1.84003687, 1.84003687, - 1.84003687, 1.84003687, 1.84003687], - [0.78973997, 0.78973997, 0.78973997, 0.78973997, - 0.78973997, 0.78973997, 1.87398517, 1.87398517, - 1.87398517, 1.87398517, 1.87398517]]) + expected_output = np.array( + [[1.697418, 1.697418, 1.697418, 1.697418, + 1.697418], [1.840037, 1.840037, 1.840037, 1.840037, 1.840037], + [1.873985, 1.873985, 1.873985, 1.873985, 1.873985]]) + expected_state = np.array([[ + 0.69855207, 0.69855207, 0.69855207, 0.69855207, 0.69855207, 0.69855207, + 1.69741797, 1.69741797, 1.69741797, 1.69741797, 1.69741797 + ], [ + 0.77073824, 0.77073824, 0.77073824, 0.77073824, 0.77073824, 0.77073824, + 1.84003687, 1.84003687, 1.84003687, 1.84003687, 1.84003687 + ], [ + 0.78973997, 0.78973997, 0.78973997, 0.78973997, 0.78973997, 0.78973997, + 1.87398517, 1.87398517, 1.87398517, 1.87398517, 1.87398517 + ]]) with self.test_session() as sess: with variable_scope.variable_scope( - "nas_proj_test", - initializer=init_ops.constant_initializer(0.5)): + "nas_proj_test", initializer=init_ops.constant_initializer(0.5)): cell = contrib_rnn_cell.NASCell(num_units=num_units, num_proj=num_proj) inputs = constant_op.constant( - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]], - dtype=np.float32), + np.array( + [[1., 1., 1., 1.], [2., 2., 2., 2.], [3., 3., 3., 3.]], + dtype=np.float32), dtype=dtypes.float32) state_value_c = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) state_value_h = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_proj), dtype=np.float32), + 0.1 * np.ones((batch_size, num_proj), dtype=np.float32), dtype=dtypes.float32) init_state = rnn_cell.LSTMStateTuple(state_value_c, state_value_h) output, state = cell(inputs, init_state) @@ -755,24 +762,20 @@ class RNNCellTest(test.TestCase): num_units = 2 batch_size = 3 expected_state_and_output = np.array( - [[0.13752282, 0.13752282], - [0.10545051, 0.10545051], + [[0.13752282, 0.13752282], [0.10545051, 0.10545051], [0.10074195, 0.10074195]], dtype=np.float32) with self.test_session() as sess: with variable_scope.variable_scope( - "ugrnn_cell_test", - initializer=init_ops.constant_initializer(0.5)): + "ugrnn_cell_test", initializer=init_ops.constant_initializer(0.5)): cell = contrib_rnn_cell.UGRNNCell(num_units=num_units) inputs = constant_op.constant( - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]], - dtype=np.float32), + np.array( + [[1., 1., 1., 1.], [2., 2., 2., 2.], [3., 3., 3., 3.]], + dtype=np.float32), dtype=dtypes.float32) init_state = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) output, state = cell(inputs, init_state) sess.run([variables.global_variables_initializer()]) @@ -786,13 +789,11 @@ class RNNCellTest(test.TestCase): num_units = 2 batch_size = 3 expected_state = np.array( - [[0.13752282, 0.13752282], - [0.10545051, 0.10545051], + [[0.13752282, 0.13752282], [0.10545051, 0.10545051], [0.10074195, 0.10074195]], dtype=np.float32) expected_output = np.array( - [[2.00431061, 2.00431061], - [4.00060606, 4.00060606], + [[2.00431061, 2.00431061], [4.00060606, 4.00060606], [6.00008249, 6.00008249]], dtype=np.float32) with self.test_session() as sess: @@ -802,14 +803,12 @@ class RNNCellTest(test.TestCase): cell = contrib_rnn_cell.IntersectionRNNCell( num_units=num_units, num_in_proj=num_units) inputs = constant_op.constant( - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]], - dtype=np.float32), + np.array( + [[1., 1., 1., 1.], [2., 2., 2., 2.], [3., 3., 3., 3.]], + dtype=np.float32), dtype=dtypes.float32) init_state = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) output, state = cell(inputs, init_state) sess.run([variables.global_variables_initializer()]) @@ -824,19 +823,17 @@ class RNNCellTest(test.TestCase): batch_size = 3 cell = contrib_rnn_cell.IntersectionRNNCell(num_units=num_units) inputs = constant_op.constant( - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]], - dtype=np.float32), + np.array( + [[1., 1., 1., 1.], [2., 2., 2., 2.], [3., 3., 3., 3.]], + dtype=np.float32), dtype=dtypes.float32) init_state = constant_op.constant( - 0.1 * np.ones( - (batch_size, num_units), dtype=np.float32), + 0.1 * np.ones((batch_size, num_units), dtype=np.float32), dtype=dtypes.float32) - with self.assertRaisesRegexp( - ValueError, "Must have input size == output size for " - "Intersection RNN. To fix, num_in_proj should " - "be set to num_units at cell init."): + with self.assertRaisesRegexp(ValueError, + "Must have input size == output size for " + "Intersection RNN. To fix, num_in_proj should " + "be set to num_units at cell init."): cell(inputs, init_state) def testPhasedLSTMCell(self): @@ -845,13 +842,11 @@ class RNNCellTest(test.TestCase): batch_size = 3 input_size = 4 expected_state_c = np.array( - [[6.450831e-04, 4.697885e-04], - [9.862894e-05, 7.212213e-04], + [[6.450831e-04, 4.697885e-04], [9.862894e-05, 7.212213e-04], [4.401947e-04, 9.143004e-04]], dtype=np.float32) expected_state_h = np.array( - [[4.621217e-04, 3.365449e-04], - [7.438179e-05, 5.439147e-04], + [[4.621217e-04, 3.365449e-04], [7.438179e-05, 5.439147e-04], [3.347936e-04, 6.953785e-04]], dtype=np.float32) with variable_scope.variable_scope( @@ -864,14 +859,14 @@ class RNNCellTest(test.TestCase): output, state = contrib_rnn_cell.PhasedLSTMCell(num_units=num_units)( (t, x), state0) sess.run([variables.global_variables_initializer()]) - res = sess.run([output, state], { - t.name: - np.array([[1.], [2.], [3.]]), - x.name: - np.array([[1., 1., 1., 1.], - [2., 2., 2., 2.], - [3., 3., 3., 3.]]), - }) + res = sess.run( + [output, state], { + t.name: + np.array([[1.], [2.], [3.]]), + x.name: + np.array([[1., 1., 1., 1.], [2., 2., 2., 2.], + [3., 3., 3., 3.]]), + }) # This is a smoke test, making sure expected values are unchanged. self.assertEqual(len(res), 2) self.assertAllClose(res[0], res[1].h) @@ -880,36 +875,32 @@ class RNNCellTest(test.TestCase): def testConv1DLSTMCell(self): with self.test_session() as sess: - shape = [2,1] + shape = [2, 1] filter_size = [3] num_features = 1 batch_size = 2 expected_state_c = np.array( - [[[1.4375670191], [1.4375670191]], - [[2.7542609292], [2.7542609292]]], + [[[1.4375670191], [1.4375670191]], [[2.7542609292], [2.7542609292]]], dtype=np.float32) expected_state_h = np.array( - [[[0.6529865603], [0.6529865603]], - [[0.8736877431], [0.8736877431]]], + [[[0.6529865603], [0.6529865603]], [[0.8736877431], [0.8736877431]]], dtype=np.float32) with variable_scope.variable_scope( - "root", initializer=init_ops.constant_initializer(1.0/2.0)): + "root", initializer=init_ops.constant_initializer(1.0 / 2.0)): x = array_ops.placeholder(dtypes.float32, [None, None, 1]) - cell = contrib_rnn_cell.Conv1DLSTMCell(input_shape=shape, - kernel_shape=filter_size, - output_channels=num_features) + cell = contrib_rnn_cell.Conv1DLSTMCell( + input_shape=shape, + kernel_shape=filter_size, + output_channels=num_features) hidden = cell.zero_state(array_ops.shape(x)[0], dtypes.float32) output, state = cell(x, hidden) sess.run([variables.global_variables_initializer()]) - res = sess.run([output, state], { - hidden[0].name: - np.array([[[1.],[1.]], - [[2.],[2.]]]), - x.name: - np.array([[[1.],[1.]], - [[2.],[2.]]]), - }) + res = sess.run( + [output, state], { + hidden[0].name: np.array([[[1.], [1.]], [[2.], [2.]]]), + x.name: np.array([[[1.], [1.]], [[2.], [2.]]]), + }) # This is a smoke test, making sure expected values are unchanged. self.assertEqual(len(res), 2) self.assertAllClose(res[0], res[1].h) @@ -918,44 +909,40 @@ class RNNCellTest(test.TestCase): def testConv2DLSTMCell(self): with self.test_session() as sess: - shape = [2,2,1] - filter_size = [3,3] + shape = [2, 2, 1] + filter_size = [3, 3] num_features = 1 batch_size = 2 expected_state_c = np.array( - [[[[1.4375670191], [1.4375670191]], - [[1.4375670191], [1.4375670191]]], - [[[2.7542609292], [2.7542609292]], - [[2.7542609292], [2.7542609292]]]], + [[[[1.4375670191], [1.4375670191]], [[1.4375670191], [1.4375670191]]], + [[[2.7542609292], [2.7542609292]], [[2.7542609292], [2.7542609292]] + ]], dtype=np.float32) expected_state_h = np.array( - [[[[0.6529865603], [0.6529865603]], - [[0.6529865603], [0.6529865603]]], - [[[0.8736877431], [0.8736877431]], - [[0.8736877431], [0.8736877431]]]], + [[[[0.6529865603], [0.6529865603]], [[0.6529865603], [0.6529865603]]], + [[[0.8736877431], [0.8736877431]], [[0.8736877431], [0.8736877431]] + ]], dtype=np.float32) with variable_scope.variable_scope( - "root", initializer=init_ops.constant_initializer(1.0/4.0)): + "root", initializer=init_ops.constant_initializer(1.0 / 4.0)): x = array_ops.placeholder(dtypes.float32, [None, None, None, 1]) - cell = contrib_rnn_cell.Conv2DLSTMCell(input_shape=shape, - kernel_shape=filter_size, - output_channels=num_features) + cell = contrib_rnn_cell.Conv2DLSTMCell( + input_shape=shape, + kernel_shape=filter_size, + output_channels=num_features) hidden = cell.zero_state(array_ops.shape(x)[0], dtypes.float32) output, state = cell(x, hidden) sess.run([variables.global_variables_initializer()]) - res = sess.run([output, state], { - hidden[0].name: - np.array([[[[1.],[1.]], - [[1.],[1.]]], - [[[2.],[2.]], - [[2.],[2.]]]]), - x.name: - np.array([[[[1.],[1.]], - [[1.],[1.]]], - [[[2.],[2.]], - [[2.],[2.]]]]), - }) + res = sess.run( + [output, state], { + hidden[0].name: + np.array([[[[1.], [1.]], [[1.], [1.]]], [[[2.], [2.]], + [[2.], [2.]]]]), + x.name: + np.array([[[[1.], [1.]], [[1.], [1.]]], [[[2.], [2.]], + [[2.], [2.]]]]), + }) # This is a smoke test, making sure expected values are unchanged. self.assertEqual(len(res), 2) self.assertAllClose(res[0], res[1].h) @@ -964,36 +951,33 @@ class RNNCellTest(test.TestCase): def testConv3DLSTMCell(self): with self.test_session() as sess: - shape = [2,2,2,1] - filter_size = [3,3,3] + shape = [2, 2, 2, 1] + filter_size = [3, 3, 3] num_features = 1 batch_size = 2 expected_state_c = np.array( - [[[[[1.4375670191], [1.4375670191]], - [[1.4375670191], [1.4375670191]]], - [[[1.4375670191], [1.4375670191]], - [[1.4375670191], [1.4375670191]]]], - [[[[2.7542609292], [2.7542609292]], - [[2.7542609292], [2.7542609292]]], - [[[2.7542609292], [2.7542609292]], - [[2.7542609292], [2.7542609292]]]]], + [[[[[1.4375670191], [1.4375670191]], [[1.4375670191], [1.4375670191]] + ], [[[1.4375670191], [1.4375670191]], [[1.4375670191], + [1.4375670191]]]], + [[[[2.7542609292], [2.7542609292]], [[2.7542609292], [2.7542609292]] + ], [[[2.7542609292], [2.7542609292]], [[2.7542609292], + [2.7542609292]]]]], dtype=np.float32) expected_state_h = np.array( - [[[[[0.6529865603], [0.6529865603]], - [[0.6529865603], [0.6529865603]]], - [[[0.6529865603], [0.6529865603]], - [[0.6529865603], [0.6529865603]]]], - [[[[0.8736877431], [0.8736877431]], - [[0.8736877431], [0.8736877431]]], - [[[0.8736877431], [0.8736877431]], - [[0.8736877431], [0.8736877431]]]]], + [[[[[0.6529865603], [0.6529865603]], [[0.6529865603], [0.6529865603]] + ], [[[0.6529865603], [0.6529865603]], [[0.6529865603], + [0.6529865603]]]], + [[[[0.8736877431], [0.8736877431]], [[0.8736877431], [0.8736877431]] + ], [[[0.8736877431], [0.8736877431]], [[0.8736877431], + [0.8736877431]]]]], dtype=np.float32) with variable_scope.variable_scope( - "root", initializer=init_ops.constant_initializer(1.0/8.0)): + "root", initializer=init_ops.constant_initializer(1.0 / 8.0)): x = array_ops.placeholder(dtypes.float32, [None, None, None, None, 1]) - cell = contrib_rnn_cell.Conv3DLSTMCell(input_shape=shape, - kernel_shape=filter_size, - output_channels=num_features) + cell = contrib_rnn_cell.Conv3DLSTMCell( + input_shape=shape, + kernel_shape=filter_size, + output_channels=num_features) hidden = cell.zero_state(array_ops.shape(x)[0], dtypes.float32) output, state = cell(x, hidden) @@ -1056,8 +1040,8 @@ class RNNCellTest(test.TestCase): num_units=num_units, number_of_groups=number_of_groups) cell = rnn_cell.LSTMCell(num_units=num_units) self.assertTrue(isinstance(gcell.state_size, tuple)) - zero_state = gcell.zero_state(batch_size=batch_size, - dtype=dtypes.float32) + zero_state = gcell.zero_state( + batch_size=batch_size, dtype=dtypes.float32) gh, gs = gcell(x, zero_state) h, g = cell(x, zero_state) @@ -1080,16 +1064,16 @@ class RNNCellTest(test.TestCase): glstm_input = array_ops.ones([batch_size, num_units]) gcell = contrib_rnn_cell.GLSTMCell( num_units=num_units, number_of_groups=number_of_groups) - gcell_zero_state = gcell.zero_state(batch_size=batch_size, - dtype=dtypes.float32) + gcell_zero_state = gcell.zero_state( + batch_size=batch_size, dtype=dtypes.float32) gh, gs = gcell(glstm_input, gcell_zero_state) # input for LSTM cell simulating single G-LSTM group lstm_input = array_ops.ones([batch_size, num_units / number_of_groups]) # note division by number_of_groups. This cell one simulates G-LSTM group cell = rnn_cell.LSTMCell(num_units=int(num_units / number_of_groups)) - cell_zero_state = cell.zero_state(batch_size=batch_size, - dtype=dtypes.float32) + cell_zero_state = cell.zero_state( + batch_size=batch_size, dtype=dtypes.float32) h, g = cell(lstm_input, cell_zero_state) sess.run([variables.global_variables_initializer()]) @@ -1099,6 +1083,7 @@ class RNNCellTest(test.TestCase): self.assertAllClose(gh_res[:, int(num_units / number_of_groups):], h_res, 1e-5) + class LayerNormBasicLSTMCellTest(test.TestCase): # NOTE: all the values in the current test case have been calculated. @@ -1119,13 +1104,14 @@ class LayerNormBasicLSTMCellTest(test.TestCase): cell = rnn_cell.MultiRNNCell([single_cell() for _ in range(2)]) g, out_m = cell(x, state) sess.run([variables.global_variables_initializer()]) - res = sess.run([g, out_m], { - x.name: np.array([[1., 1.]]), - c0.name: 0.1 * np.asarray([[0, 1]]), - h0.name: 0.1 * np.asarray([[2, 3]]), - c1.name: 0.1 * np.asarray([[4, 5]]), - h1.name: 0.1 * np.asarray([[6, 7]]), - }) + res = sess.run( + [g, out_m], { + x.name: np.array([[1., 1.]]), + c0.name: 0.1 * np.asarray([[0, 1]]), + h0.name: 0.1 * np.asarray([[2, 3]]), + c1.name: 0.1 * np.asarray([[4, 5]]), + h1.name: 0.1 * np.asarray([[6, 7]]), + }) expected_h = np.array([[-0.38079708, 0.38079708]]) expected_state0_c = np.array([[-1.0, 1.0]]) @@ -1155,11 +1141,12 @@ class LayerNormBasicLSTMCellTest(test.TestCase): cell = contrib_rnn_cell.LayerNormBasicLSTMCell(2) g, out_m = cell(x, state) sess.run([variables.global_variables_initializer()]) - res = sess.run([g, out_m], { - x.name: np.array([[1., 1., 1.]]), - c.name: 0.1 * np.asarray([[0, 1]]), - h.name: 0.1 * np.asarray([[2, 3]]), - }) + res = sess.run( + [g, out_m], { + x.name: np.array([[1., 1., 1.]]), + c.name: 0.1 * np.asarray([[0, 1]]), + h.name: 0.1 * np.asarray([[2, 3]]), + }) expected_h = np.array([[-0.38079708, 0.38079708]]) expected_c = np.array([[-1.0, 1.0]]) @@ -1168,7 +1155,6 @@ class LayerNormBasicLSTMCellTest(test.TestCase): self.assertAllClose(res[1].c, expected_c, 1e-5) self.assertAllClose(res[1].h, expected_h, 1e-5) - def testBasicLSTMCellWithoutNorm(self): """Tests that BasicLSTMCell with layer_norm=False.""" with self.test_session() as sess: @@ -1186,19 +1172,20 @@ class LayerNormBasicLSTMCellTest(test.TestCase): cell = rnn_cell.MultiRNNCell([single_cell() for _ in range(2)]) g, out_m = cell(x, state) sess.run([variables.global_variables_initializer()]) - res = sess.run([g, out_m], { - x.name: np.array([[1., 1.]]), - c0.name: 0.1 * np.asarray([[0, 1]]), - h0.name: 0.1 * np.asarray([[2, 3]]), - c1.name: 0.1 * np.asarray([[4, 5]]), - h1.name: 0.1 * np.asarray([[6, 7]]), - }) - - expected_h = np.array([[ 0.70230919, 0.72581059]]) - expected_state0_c = np.array([[ 0.8020075, 0.89599884]]) - expected_state0_h = np.array([[ 0.56668288, 0.60858738]]) - expected_state1_c = np.array([[ 1.17500675, 1.26892781]]) - expected_state1_h = np.array([[ 0.70230919, 0.72581059]]) + res = sess.run( + [g, out_m], { + x.name: np.array([[1., 1.]]), + c0.name: 0.1 * np.asarray([[0, 1]]), + h0.name: 0.1 * np.asarray([[2, 3]]), + c1.name: 0.1 * np.asarray([[4, 5]]), + h1.name: 0.1 * np.asarray([[6, 7]]), + }) + + expected_h = np.array([[0.70230919, 0.72581059]]) + expected_state0_c = np.array([[0.8020075, 0.89599884]]) + expected_state0_h = np.array([[0.56668288, 0.60858738]]) + expected_state1_c = np.array([[1.17500675, 1.26892781]]) + expected_state1_h = np.array([[0.70230919, 0.72581059]]) actual_h = res[0] actual_state0_c = res[1][0].c @@ -1215,21 +1202,22 @@ class LayerNormBasicLSTMCellTest(test.TestCase): with variable_scope.variable_scope( "other", initializer=init_ops.constant_initializer(0.5)) as vs: x = array_ops.zeros( - [1, 3]) # Test BasicLSTMCell with input_size != num_units. + [1, 3]) # Test BasicLSTMCell with input_size != num_units. c = array_ops.zeros([1, 2]) h = array_ops.zeros([1, 2]) state = rnn_cell.LSTMStateTuple(c, h) cell = contrib_rnn_cell.LayerNormBasicLSTMCell(2, layer_norm=False) g, out_m = cell(x, state) sess.run([variables.global_variables_initializer()]) - res = sess.run([g, out_m], { - x.name: np.array([[1., 1., 1.]]), - c.name: 0.1 * np.asarray([[0, 1]]), - h.name: 0.1 * np.asarray([[2, 3]]), - }) - - expected_h = np.array([[ 0.64121795, 0.68166804]]) - expected_c = np.array([[ 0.88477188, 0.98103917]]) + res = sess.run( + [g, out_m], { + x.name: np.array([[1., 1., 1.]]), + c.name: 0.1 * np.asarray([[0, 1]]), + h.name: 0.1 * np.asarray([[2, 3]]), + }) + + expected_h = np.array([[0.64121795, 0.68166804]]) + expected_c = np.array([[0.88477188, 0.98103917]]) self.assertEqual(len(res), 2) self.assertAllClose(res[0], expected_h, 1e-5) self.assertAllClose(res[1].c, expected_c, 1e-5) @@ -1250,13 +1238,14 @@ class LayerNormBasicLSTMCellTest(test.TestCase): [contrib_rnn_cell.LayerNormBasicLSTMCell(2) for _ in range(2)]) h, (s0, s1) = cell(x, (state0, state1)) sess.run([variables.global_variables_initializer()]) - res = sess.run([h, s0, s1], { - x.name: np.array([[1., 1.]]), - c0.name: 0.1 * np.asarray([[0, 1]]), - h0.name: 0.1 * np.asarray([[2, 3]]), - c1.name: 0.1 * np.asarray([[4, 5]]), - h1.name: 0.1 * np.asarray([[6, 7]]), - }) + res = sess.run( + [h, s0, s1], { + x.name: np.array([[1., 1.]]), + c0.name: 0.1 * np.asarray([[0, 1]]), + h0.name: 0.1 * np.asarray([[2, 3]]), + c1.name: 0.1 * np.asarray([[4, 5]]), + h1.name: 0.1 * np.asarray([[6, 7]]), + }) expected_h = np.array([[-0.38079708, 0.38079708]]) expected_h0 = np.array([[-0.38079708, 0.38079708]]) @@ -1344,11 +1333,12 @@ class LayerNormBasicLSTMCellTest(test.TestCase): g, s = cell(x, state) sess.run([variables.global_variables_initializer()]) - res = sess.run([g, s], { - x.name: np.ones([1, 5]), - c.name: np.ones([1, 5]), - h.name: np.ones([1, 5]), - }) + res = sess.run( + [g, s], { + x.name: np.ones([1, 5]), + c.name: np.ones([1, 5]), + h.name: np.ones([1, 5]), + }) # Since the returned tensors are of size [1,n] # get the first component right now. @@ -1374,35 +1364,35 @@ class LayerNormBasicLSTMCellTest(test.TestCase): self.assertIn(dropped_count, allowed_low) -def _create_multi_lstm_cell_ops(batch_size, num_units, input_depth, - num_layers, max_time, compiled): +def _create_multi_lstm_cell_ops(batch_size, num_units, input_depth, num_layers, + max_time, compiled): with variable_scope.variable_scope( "root", initializer=init_ops.random_uniform_initializer(-0.1, 0.1, seed=2)): inputs = variable_scope.get_variable( - "inputs", initializer=random_ops.random_uniform( + "inputs", + initializer=random_ops.random_uniform( (max_time, batch_size, input_depth), seed=1)) maybe_xla = lambda c: contrib_rnn_cell.CompiledWrapper(c) if compiled else c cell = rnn_cell.MultiRNNCell( [maybe_xla(rnn_cell.LSTMCell(num_units)) for _ in range(num_layers)]) - initial_state = cell.zero_state( - batch_size=batch_size, dtype=dtypes.float32) + initial_state = cell.zero_state(batch_size=batch_size, dtype=dtypes.float32) outputs, final_state = rnn.dynamic_rnn( - cell=cell, inputs=inputs, initial_state=initial_state, - time_major=True) + cell=cell, inputs=inputs, initial_state=initial_state, time_major=True) flat_final_state = nest.flatten(final_state) trainable_variables = variables.trainable_variables() outputs_grad = gradients_impl.gradients( - [outputs], - trainable_variables + [inputs] + nest.flatten(initial_state)) + [outputs], trainable_variables + [inputs] + nest.flatten(initial_state)) final_state_grad = gradients_impl.gradients( flat_final_state, trainable_variables + [inputs] + nest.flatten(initial_state)) - return {"outputs": outputs, - "final_state": flat_final_state, - "outputs_grad": outputs_grad, - "final_state_grad": final_state_grad} + return { + "outputs": outputs, + "final_state": flat_final_state, + "outputs_grad": outputs_grad, + "final_state_grad": final_state_grad + } class CompiledWrapperTest(test.TestCase): @@ -1420,8 +1410,10 @@ class CompiledWrapperTest(test.TestCase): random_seed.set_random_seed(1234) with self.test_session(graph=ops.Graph()) as sess: xla_ops = _create_multi_lstm_cell_ops( - batch_size=batch_size, num_units=num_units, - input_depth=input_depth, num_layers=num_layers, + batch_size=batch_size, + num_units=num_units, + input_depth=input_depth, + num_layers=num_layers, max_time=max_time, compiled=True) sess.run([variables.global_variables_initializer()]) @@ -1430,8 +1422,10 @@ class CompiledWrapperTest(test.TestCase): random_seed.set_random_seed(1234) with self.test_session(graph=ops.Graph()) as sess: non_xla_ops = _create_multi_lstm_cell_ops( - batch_size=batch_size, num_units=num_units, - input_depth=input_depth, num_layers=num_layers, + batch_size=batch_size, + num_units=num_units, + input_depth=input_depth, + num_layers=num_layers, max_time=max_time, compiled=False) sess.run([variables.global_variables_initializer()]) @@ -1440,16 +1434,16 @@ class CompiledWrapperTest(test.TestCase): self.assertAllClose( non_xla_results["outputs"], xla_results["outputs"], atol=atol) - for xla_value, non_xla_value in zip( - xla_results["final_state"], non_xla_results["final_state"]): + for xla_value, non_xla_value in zip(xla_results["final_state"], + non_xla_results["final_state"]): self.assertAllClose(xla_value, non_xla_value, atol=atol) - for xla_g, non_xla_g in zip( - xla_results["outputs_grad"], non_xla_results["outputs_grad"]): + for xla_g, non_xla_g in zip(xla_results["outputs_grad"], + non_xla_results["outputs_grad"]): self.assertAllClose(xla_g, non_xla_g, atol=atol) - for xla_g, non_xla_g in zip( - xla_results["final_state_grad"], non_xla_results["final_state_grad"]): + for xla_g, non_xla_g in zip(xla_results["final_state_grad"], + non_xla_results["final_state_grad"]): self.assertAllClose(xla_g, non_xla_g, atol=atol) def testMultiRNNCellWithStateTuple(self): @@ -1463,19 +1457,20 @@ class CompiledWrapperTest(test.TestCase): # Test incorrectness of state with self.assertRaisesRegexp(ValueError, "Expected state .* a tuple"): rnn_cell.MultiRNNCell( - [rnn_cell.GRUCell(2) - for _ in range(2)], state_is_tuple=True)(x, m_bad) + [rnn_cell.GRUCell(2) for _ in range(2)], + state_is_tuple=True)(x, m_bad) _, ml = rnn_cell.MultiRNNCell( - [rnn_cell.GRUCell(2) - for _ in range(2)], state_is_tuple=True)(x, m_good) + [rnn_cell.GRUCell(2) for _ in range(2)], + state_is_tuple=True)(x, m_good) sess.run([variables.global_variables_initializer()]) - res = sess.run(ml, { - x.name: np.array([[1., 1.]]), - m_good[0].name: np.array([[0.1, 0.1]]), - m_good[1].name: np.array([[0.1, 0.1]]) - }) + res = sess.run( + ml, { + x.name: np.array([[1., 1.]]), + m_good[0].name: np.array([[0.1, 0.1]]), + m_good[1].name: np.array([[0.1, 0.1]]) + }) # The numbers in results were not calculated, this is just a # smoke test. However, these numbers should match those of @@ -1490,24 +1485,20 @@ class BenchmarkLSTMCellXLA(test.Benchmark): num_layers = 3 max_time = 50 print("benchmarkDynamicRNNWithMultiLSTMCell") - print("\t" + - "\t".join(["inter_th", "intra_th", - "batch_size", "num_units", "input_depth", "device", - "compiled", "wall_time"])) + print("\t" + "\t".join([ + "inter_th", "intra_th", "batch_size", "num_units", "input_depth", + "device", "compiled", "wall_time" + ])) warmup_run = True - for (threads, - device, - num_units, - batch_size, - input_depth, - compiled) in itertools.product( - [{"inter": 0, "intra": 0}, {"inter": 1, "intra": 4}], - ["cpu", "gpu"], - [32, 512], - [1, 32, 256], - [32, 512], - [False, True]): + for (threads, device, num_units, batch_size, input_depth, + compiled) in itertools.product([{ + "inter": 0, + "intra": 0 + }, { + "inter": 1, + "intra": 4 + }], ["cpu", "gpu"], [32, 512], [1, 32, 256], [32, 512], [False, True]): if threads["inter"] != 0: # We only care about testing inter/intra op limitations on # CPU with small batch size, to mimic embedded devices. @@ -1523,30 +1514,35 @@ class BenchmarkLSTMCellXLA(test.Benchmark): with session.Session(config=config, graph=ops.Graph()) as sess: with ops.device("/%s:0" % device): ops_dict = _create_multi_lstm_cell_ops( - batch_size=batch_size, num_units=num_units, - input_depth=input_depth, num_layers=num_layers, + batch_size=batch_size, + num_units=num_units, + input_depth=input_depth, + num_layers=num_layers, max_time=max_time, compiled=compiled) sess.run([variables.global_variables_initializer()]) all_ops = nest.flatten(ops_dict.values()) all_ops_group = control_flow_ops.group(*all_ops) - name_suffix = ( - "inter_th_%d_intra_th_%d_bs_%d_units_%d_inputdepth_%d" - "_device_%s_xla_%s" % ( - threads["inter"], threads["intra"], - batch_size, num_units, input_depth, device, compiled)) + name_suffix = ("inter_th_%d_intra_th_%d_bs_%d_units_%d_inputdepth_%d" + "_device_%s_xla_%s" % + (threads["inter"], threads["intra"], batch_size, + num_units, input_depth, device, compiled)) if warmup_run: self.run_op_benchmark( sess, all_ops_group, min_iters=30, name="ignore_warmup") warmup_run = False benchmark_results = self.run_op_benchmark( - sess, all_ops_group, min_iters=50, + sess, + all_ops_group, + min_iters=50, name="benchmarkDynamicRNNWithMultiLSTMCell_%s" % name_suffix) - print("\t" + - "\t".join(["%s" % x for x in [ - threads["inter"], threads["intra"], - batch_size, num_units, input_depth, device, compiled, - benchmark_results["wall_time"]]])) + print("\t" + "\t".join([ + "%s" % x + for x in [ + threads["inter"], threads["intra"], batch_size, num_units, + input_depth, device, compiled, benchmark_results["wall_time"] + ] + ])) class WeightNormLSTMCellTest(test.TestCase): @@ -1557,8 +1553,7 @@ class WeightNormLSTMCellTest(test.TestCase): with self.test_session() as sess: init = init_ops.constant_initializer(0.5) - with variable_scope.variable_scope("root", - initializer=init): + with variable_scope.variable_scope("root", initializer=init): x = array_ops.zeros([1, 2]) c0 = array_ops.zeros([1, 2]) h0 = array_ops.zeros([1, 2]) @@ -1568,11 +1563,12 @@ class WeightNormLSTMCellTest(test.TestCase): xout, sout = cell()(x, state0) sess.run([variables.global_variables_initializer()]) - res = sess.run([xout, sout], { - x.name: np.array([[1., 1.]]), - c0.name: 0.1 * np.asarray([[0, 1]]), - h0.name: 0.1 * np.asarray([[2, 3]]), - }) + res = sess.run( + [xout, sout], { + x.name: np.array([[1., 1.]]), + c0.name: 0.1 * np.asarray([[0, 1]]), + h0.name: 0.1 * np.asarray([[2, 3]]), + }) actual_state_c = res[1].c actual_state_h = res[1].h @@ -1583,9 +1579,8 @@ class WeightNormLSTMCellTest(test.TestCase): """Tests cell w/o peepholes and w/o normalisation""" def cell(): - return contrib_rnn_cell.WeightNormLSTMCell(2, - norm=False, - use_peepholes=False) + return contrib_rnn_cell.WeightNormLSTMCell( + 2, norm=False, use_peepholes=False) actual_c, actual_h = self._cell_output(cell) @@ -1599,9 +1594,8 @@ class WeightNormLSTMCellTest(test.TestCase): """Tests cell with peepholes and w/o normalisation""" def cell(): - return contrib_rnn_cell.WeightNormLSTMCell(2, - norm=False, - use_peepholes=True) + return contrib_rnn_cell.WeightNormLSTMCell( + 2, norm=False, use_peepholes=True) actual_c, actual_h = self._cell_output(cell) @@ -1611,14 +1605,12 @@ class WeightNormLSTMCellTest(test.TestCase): self.assertAllClose(expected_c, actual_c, 1e-5) self.assertAllClose(expected_h, actual_h, 1e-5) - def testBasicCellWithNorm(self): """Tests cell w/o peepholes and with normalisation""" def cell(): - return contrib_rnn_cell.WeightNormLSTMCell(2, - norm=True, - use_peepholes=False) + return contrib_rnn_cell.WeightNormLSTMCell( + 2, norm=True, use_peepholes=False) actual_c, actual_h = self._cell_output(cell) @@ -1632,9 +1624,8 @@ class WeightNormLSTMCellTest(test.TestCase): """Tests cell with peepholes and with normalisation""" def cell(): - return contrib_rnn_cell.WeightNormLSTMCell(2, - norm=True, - use_peepholes=True) + return contrib_rnn_cell.WeightNormLSTMCell( + 2, norm=True, use_peepholes=True) actual_c, actual_h = self._cell_output(cell) @@ -1644,5 +1635,6 @@ class WeightNormLSTMCellTest(test.TestCase): self.assertAllClose(expected_c, actual_c, 1e-5) self.assertAllClose(expected_h, actual_h, 1e-5) + if __name__ == "__main__": test.main() diff --git a/tensorflow/contrib/rnn/python/ops/rnn_cell.py b/tensorflow/contrib/rnn/python/ops/rnn_cell.py index d7ae6621db..8adf5dce6e 100644 --- a/tensorflow/contrib/rnn/python/ops/rnn_cell.py +++ b/tensorflow/contrib/rnn/python/ops/rnn_cell.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== - """Module for constructing RNN Cells.""" from __future__ import absolute_import from __future__ import division @@ -56,16 +55,15 @@ def _get_concat_variable(name, shape, dtype, num_shards): return value concat_variable = array_ops.concat(sharded_variable, 0, name=concat_name) - ops.add_to_collection(ops.GraphKeys.CONCATENATED_VARIABLES, - concat_variable) + ops.add_to_collection(ops.GraphKeys.CONCATENATED_VARIABLES, concat_variable) return concat_variable def _get_sharded_variable(name, shape, dtype, num_shards): """Get a list of sharded variables with the given dtype.""" if num_shards > shape[0]: - raise ValueError("Too many shards: shape=%s, num_shards=%d" % - (shape, num_shards)) + raise ValueError("Too many shards: shape=%s, num_shards=%d" % (shape, + num_shards)) unit_shard_size = int(math.floor(shape[0] / num_shards)) remaining_rows = shape[0] - unit_shard_size * num_shards @@ -74,8 +72,9 @@ def _get_sharded_variable(name, shape, dtype, num_shards): current_size = unit_shard_size if i < remaining_rows: current_size += 1 - shards.append(vs.get_variable(name + "_%d" % i, [current_size] + shape[1:], - dtype=dtype)) + shards.append( + vs.get_variable( + name + "_%d" % i, [current_size] + shape[1:], dtype=dtype)) return shards @@ -177,9 +176,8 @@ class CoupledInputForgetGateLSTMCell(rnn_cell_impl.RNNCell): """ super(CoupledInputForgetGateLSTMCell, self).__init__(_reuse=reuse) if not state_is_tuple: - logging.warn( - "%s: Using a concatenated state is slower and will soon be " - "deprecated. Use state_is_tuple=True.", self) + logging.warn("%s: Using a concatenated state is slower and will soon be " + "deprecated. Use state_is_tuple=True.", self) self._num_units = num_units self._use_peepholes = use_peepholes self._initializer = initializer @@ -196,12 +194,14 @@ class CoupledInputForgetGateLSTMCell(rnn_cell_impl.RNNCell): self._norm_shift = norm_shift if num_proj: - self._state_size = (rnn_cell_impl.LSTMStateTuple(num_units, num_proj) - if state_is_tuple else num_units + num_proj) + self._state_size = ( + rnn_cell_impl.LSTMStateTuple(num_units, num_proj) + if state_is_tuple else num_units + num_proj) self._output_size = num_proj else: - self._state_size = (rnn_cell_impl.LSTMStateTuple(num_units, num_units) - if state_is_tuple else 2 * num_units) + self._state_size = ( + rnn_cell_impl.LSTMStateTuple(num_units, num_units) + if state_is_tuple else 2 * num_units) self._output_size = num_units @property @@ -251,8 +251,8 @@ class CoupledInputForgetGateLSTMCell(rnn_cell_impl.RNNCell): if input_size.value is None: raise ValueError("Could not infer input size from inputs.get_shape()[-1]") concat_w = _get_concat_variable( - "W", [input_size.value + num_proj, 3 * self._num_units], - dtype, self._num_unit_shards) + "W", [input_size.value + num_proj, 3 * self._num_units], dtype, + self._num_unit_shards) b = vs.get_variable( "B", @@ -299,9 +299,9 @@ class CoupledInputForgetGateLSTMCell(rnn_cell_impl.RNNCell): m = sigmoid(o) * self._activation(c) if self._num_proj is not None: - concat_w_proj = _get_concat_variable( - "W_P", [self._num_units, self._num_proj], - dtype, self._num_proj_shards) + concat_w_proj = _get_concat_variable("W_P", + [self._num_units, self._num_proj], + dtype, self._num_proj_shards) m = math_ops.matmul(m, concat_w_proj) if self._proj_clip is not None: @@ -309,8 +309,9 @@ class CoupledInputForgetGateLSTMCell(rnn_cell_impl.RNNCell): m = clip_ops.clip_by_value(m, -self._proj_clip, self._proj_clip) # pylint: enable=invalid-unary-operand-type - new_state = (rnn_cell_impl.LSTMStateTuple(c, m) - if self._state_is_tuple else array_ops.concat([c, m], 1)) + new_state = ( + rnn_cell_impl.LSTMStateTuple(c, m) + if self._state_is_tuple else array_ops.concat([c, m], 1)) return m, new_state @@ -326,10 +327,15 @@ class TimeFreqLSTMCell(rnn_cell_impl.RNNCell): It uses peep-hole connections and optional cell clipping. """ - def __init__(self, num_units, use_peepholes=False, - cell_clip=None, initializer=None, - num_unit_shards=1, forget_bias=1.0, - feature_size=None, frequency_skip=1, + def __init__(self, + num_units, + use_peepholes=False, + cell_clip=None, + initializer=None, + num_unit_shards=1, + forget_bias=1.0, + feature_size=None, + frequency_skip=1, reuse=None): """Initialize the parameters for an LSTM cell. @@ -399,7 +405,7 @@ class TimeFreqLSTMCell(rnn_cell_impl.RNNCell): actual_input_size = freq_inputs[0].get_shape().as_list()[1] concat_w = _get_concat_variable( - "W", [actual_input_size + 2*self._num_units, 4 * self._num_units], + "W", [actual_input_size + 2 * self._num_units, 4 * self._num_units], dtype, self._num_unit_shards) b = vs.get_variable( @@ -418,23 +424,23 @@ class TimeFreqLSTMCell(rnn_cell_impl.RNNCell): "W_O_diag", shape=[self._num_units], dtype=dtype) # initialize the first freq state to be zero - m_prev_freq = array_ops.zeros([int(inputs.get_shape()[0]), - self._num_units], dtype) + m_prev_freq = array_ops.zeros([int(inputs.get_shape()[0]), self._num_units], + dtype) for fq in range(len(freq_inputs)): - c_prev = array_ops.slice(state, [0, 2*fq*self._num_units], + c_prev = array_ops.slice(state, [0, 2 * fq * self._num_units], [-1, self._num_units]) - m_prev = array_ops.slice(state, [0, (2*fq+1)*self._num_units], + m_prev = array_ops.slice(state, [0, (2 * fq + 1) * self._num_units], [-1, self._num_units]) # i = input_gate, j = new_input, f = forget_gate, o = output_gate - cell_inputs = array_ops.concat([freq_inputs[fq], m_prev, m_prev_freq], - 1) + cell_inputs = array_ops.concat([freq_inputs[fq], m_prev, m_prev_freq], 1) lstm_matrix = nn_ops.bias_add(math_ops.matmul(cell_inputs, concat_w), b) i, j, f, o = array_ops.split( value=lstm_matrix, num_or_size_splits=4, axis=1) if self._use_peepholes: - c = (sigmoid(f + self._forget_bias + w_f_diag * c_prev) * c_prev + - sigmoid(i + w_i_diag * c_prev) * tanh(j)) + c = ( + sigmoid(f + self._forget_bias + w_f_diag * c_prev) * c_prev + + sigmoid(i + w_i_diag * c_prev) * tanh(j)) else: c = (sigmoid(f + self._forget_bias) * c_prev + sigmoid(i) * tanh(j)) @@ -472,11 +478,11 @@ class TimeFreqLSTMCell(rnn_cell_impl.RNNCell): input_size = input_feat.get_shape().with_rank(2)[-1].value if input_size is None: raise ValueError("Cannot infer input_size from static shape inference.") - num_feats = int((input_size - self._feature_size) / ( - self._frequency_skip)) + 1 + num_feats = int( + (input_size - self._feature_size) / (self._frequency_skip)) + 1 freq_inputs = [] for f in range(num_feats): - cur_input = array_ops.slice(input_feat, [0, f*self._frequency_skip], + cur_input = array_ops.slice(input_feat, [0, f * self._frequency_skip], [-1, self._feature_size]) freq_inputs.append(cur_input) return freq_inputs @@ -498,11 +504,16 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): The code uses optional peephole connections, shared_weights and cell clipping. """ - def __init__(self, num_units, use_peepholes=False, + def __init__(self, + num_units, + use_peepholes=False, share_time_frequency_weights=False, - cell_clip=None, initializer=None, - num_unit_shards=1, forget_bias=1.0, - feature_size=None, frequency_skip=None, + cell_clip=None, + initializer=None, + num_unit_shards=1, + forget_bias=1.0, + feature_size=None, + frequency_skip=None, num_frequency_blocks=None, start_freqindex_list=None, end_freqindex_list=None, @@ -580,10 +591,10 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): for freq_index in range(self._num_frequency_blocks[block_index]): name_prefix = "state_f%02d_b%02d" % (freq_index, block_index) state_names += ("%s_c, %s_m," % (name_prefix, name_prefix)) - self._state_tuple_type = collections.namedtuple( - "GridLSTMStateTuple", state_names.strip(",")) - self._state_size = self._state_tuple_type( - *([num_units, num_units] * self._total_blocks)) + self._state_tuple_type = collections.namedtuple("GridLSTMStateTuple", + state_names.strip(",")) + self._state_size = self._state_tuple_type(*( + [num_units, num_units] * self._total_blocks)) else: self._state_tuple_type = None self._state_size = num_units * self._total_blocks * 2 @@ -626,7 +637,10 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): state_out_lst = [] for block in range(len(freq_inputs)): m_out_lst_current, state_out_lst_current = self._compute( - freq_inputs[block], block, state, batch_size, + freq_inputs[block], + block, + state, + batch_size, state_is_tuple=self._state_is_tuple) m_out_lst.extend(m_out_lst_current) state_out_lst.extend(state_out_lst_current) @@ -637,7 +651,11 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): m_out = array_ops.concat(m_out_lst, 1) return m_out, state_out - def _compute(self, freq_inputs, block, state, batch_size, + def _compute(self, + freq_inputs, + block, + state, + batch_size, state_prefix="state", state_is_tuple=True): """Run the actual computation of one step LSTM. @@ -666,8 +684,8 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): actual_input_size = freq_inputs[0].get_shape().as_list()[1] concat_w_f = _get_concat_variable( - "W_f_%d" % block, [actual_input_size + 2 * self._num_units, - num_gates * self._num_units], + "W_f_%d" % block, + [actual_input_size + 2 * self._num_units, num_gates * self._num_units], dtype, self._num_unit_shards) b_f = vs.get_variable( "B_f_%d" % block, @@ -675,10 +693,9 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): initializer=init_ops.zeros_initializer(), dtype=dtype) if not self._share_time_frequency_weights: - concat_w_t = _get_concat_variable( - "W_t_%d" % block, [actual_input_size + 2 * self._num_units, - num_gates * self._num_units], - dtype, self._num_unit_shards) + concat_w_t = _get_concat_variable("W_t_%d" % block, [ + actual_input_size + 2 * self._num_units, num_gates * self._num_units + ], dtype, self._num_unit_shards) b_t = vs.get_variable( "B_t_%d" % block, shape=[num_gates * self._num_units], @@ -691,7 +708,7 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): w_f_diag_freqf = vs.get_variable( "W_F_diag_freqf_%d" % block, shape=[self._num_units], dtype=dtype) w_f_diag_freqt = vs.get_variable( - "W_F_diag_freqt_%d"% block, shape=[self._num_units], dtype=dtype) + "W_F_diag_freqt_%d" % block, shape=[self._num_units], dtype=dtype) w_i_diag_freqf = vs.get_variable( "W_I_diag_freqf_%d" % block, shape=[self._num_units], dtype=dtype) w_i_diag_freqt = vs.get_variable( @@ -725,8 +742,7 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): m_prev_time = getattr(state, name_prefix + "_m") else: c_prev_time = array_ops.slice( - state, [0, 2 * freq_index * self._num_units], - [-1, self._num_units]) + state, [0, 2 * freq_index * self._num_units], [-1, self._num_units]) m_prev_time = array_ops.slice( state, [0, (2 * freq_index + 1) * self._num_units], [-1, self._num_units]) @@ -736,8 +752,8 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): [freq_inputs[freq_index], m_prev_time, m_prev_freq], 1) # F-LSTM - lstm_matrix_freq = nn_ops.bias_add(math_ops.matmul(cell_inputs, - concat_w_f), b_f) + lstm_matrix_freq = nn_ops.bias_add( + math_ops.matmul(cell_inputs, concat_w_f), b_f) if self._couple_input_forget_gates: i_freq, j_freq, o_freq = array_ops.split( value=lstm_matrix_freq, num_or_size_splits=num_gates, axis=1) @@ -752,8 +768,8 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): f_time = f_freq o_time = o_freq else: - lstm_matrix_time = nn_ops.bias_add(math_ops.matmul(cell_inputs, - concat_w_t), b_t) + lstm_matrix_time = nn_ops.bias_add( + math_ops.matmul(cell_inputs, concat_w_t), b_t) if self._couple_input_forget_gates: i_time, j_time, o_time = array_ops.split( value=lstm_matrix_time, num_or_size_splits=num_gates, axis=1) @@ -765,8 +781,7 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): # F-LSTM c_freq # input gate activations if self._use_peepholes: - i_freq_g = sigmoid(i_freq + - w_i_diag_freqf * c_prev_freq + + i_freq_g = sigmoid(i_freq + w_i_diag_freqf * c_prev_freq + w_i_diag_freqt * c_prev_time) else: i_freq_g = sigmoid(i_freq) @@ -775,9 +790,8 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): f_freq_g = 1.0 - i_freq_g else: if self._use_peepholes: - f_freq_g = sigmoid(f_freq + self._forget_bias + - w_f_diag_freqf * c_prev_freq + - w_f_diag_freqt * c_prev_time) + f_freq_g = sigmoid(f_freq + self._forget_bias + w_f_diag_freqf * + c_prev_freq + w_f_diag_freqt * c_prev_time) else: f_freq_g = sigmoid(f_freq + self._forget_bias) # cell state @@ -792,12 +806,10 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): # input gate activations if self._use_peepholes: if self._share_time_frequency_weights: - i_time_g = sigmoid(i_time + - w_i_diag_freqf * c_prev_freq + + i_time_g = sigmoid(i_time + w_i_diag_freqf * c_prev_freq + w_i_diag_freqt * c_prev_time) else: - i_time_g = sigmoid(i_time + - w_i_diag_timef * c_prev_freq + + i_time_g = sigmoid(i_time + w_i_diag_timef * c_prev_freq + w_i_diag_timet * c_prev_time) else: i_time_g = sigmoid(i_time) @@ -807,13 +819,11 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): else: if self._use_peepholes: if self._share_time_frequency_weights: - f_time_g = sigmoid(f_time + self._forget_bias + - w_f_diag_freqf * c_prev_freq + - w_f_diag_freqt * c_prev_time) + f_time_g = sigmoid(f_time + self._forget_bias + w_f_diag_freqf * + c_prev_freq + w_f_diag_freqt * c_prev_time) else: - f_time_g = sigmoid(f_time + self._forget_bias + - w_f_diag_timef * c_prev_freq + - w_f_diag_timet * c_prev_time) + f_time_g = sigmoid(f_time + self._forget_bias + w_f_diag_timef * + c_prev_freq + w_f_diag_timet * c_prev_time) else: f_time_g = sigmoid(f_time + self._forget_bias) # cell state @@ -826,8 +836,7 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): # F-LSTM m_freq if self._use_peepholes: - m_freq = sigmoid(o_freq + - w_o_diag_freqf * c_freq + + m_freq = sigmoid(o_freq + w_o_diag_freqf * c_freq + w_o_diag_freqt * c_time) * tanh(c_freq) else: m_freq = sigmoid(o_freq) * tanh(c_freq) @@ -835,12 +844,10 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): # T-LSTM m_time if self._use_peepholes: if self._share_time_frequency_weights: - m_time = sigmoid(o_time + - w_o_diag_freqf * c_freq + + m_time = sigmoid(o_time + w_o_diag_freqf * c_freq + w_o_diag_freqt * c_time) * tanh(c_time) else: - m_time = sigmoid(o_time + - w_o_diag_timef * c_freq + + m_time = sigmoid(o_time + w_o_diag_timef * c_freq + w_o_diag_timet * c_time) * tanh(c_time) else: m_time = sigmoid(o_time) * tanh(c_time) @@ -879,16 +886,18 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): raise ValueError("Cannot infer input_size from static shape inference.") if slice_offset > 0: # Padding to the end - inputs = array_ops.pad( - input_feat, array_ops.constant([0, 0, 0, slice_offset], shape=[2, 2], - dtype=dtypes.int32), - "CONSTANT") + inputs = array_ops.pad(input_feat, + array_ops.constant( + [0, 0, 0, slice_offset], + shape=[2, 2], + dtype=dtypes.int32), "CONSTANT") elif slice_offset < 0: # Padding to the front - inputs = array_ops.pad( - input_feat, array_ops.constant([0, 0, -slice_offset, 0], shape=[2, 2], - dtype=dtypes.int32), - "CONSTANT") + inputs = array_ops.pad(input_feat, + array_ops.constant( + [0, 0, -slice_offset, 0], + shape=[2, 2], + dtype=dtypes.int32), "CONSTANT") slice_offset = 0 else: inputs = input_feat @@ -898,13 +907,13 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): raise ValueError("Length of num_frequency_blocks" " is not 1, but instead is %d", len(self._num_frequency_blocks)) - num_feats = int((input_size - self._feature_size) / ( - self._frequency_skip)) + 1 + num_feats = int( + (input_size - self._feature_size) / (self._frequency_skip)) + 1 if num_feats != self._num_frequency_blocks[0]: raise ValueError( "Invalid num_frequency_blocks, requires %d but gets %d, please" - " check the input size and filter config are correct." % ( - self._num_frequency_blocks[0], num_feats)) + " check the input size and filter config are correct." % + (self._num_frequency_blocks[0], num_feats)) block_inputs = [] for f in range(num_feats): cur_input = array_ops.slice( @@ -927,18 +936,18 @@ class GridLSTMCell(rnn_cell_impl.RNNCell): start_index = self._start_freqindex_list[b] end_index = self._end_freqindex_list[b] cur_size = end_index - start_index - block_feats = int((cur_size - self._feature_size) / ( - self._frequency_skip)) + 1 + block_feats = int( + (cur_size - self._feature_size) / (self._frequency_skip)) + 1 if block_feats != self._num_frequency_blocks[b]: raise ValueError( "Invalid num_frequency_blocks, requires %d but gets %d, please" - " check the input size and filter config are correct." % ( - self._num_frequency_blocks[b], block_feats)) + " check the input size and filter config are correct." % + (self._num_frequency_blocks[b], block_feats)) block_inputs = [] for f in range(block_feats): cur_input = array_ops.slice( - inputs, [0, start_index + slice_offset + f * - self._frequency_skip], + inputs, + [0, start_index + slice_offset + f * self._frequency_skip], [-1, self._feature_size]) block_inputs.append(cur_input) freq_inputs.append(block_inputs) @@ -954,11 +963,16 @@ class BidirectionalGridLSTMCell(GridLSTMCell): The current implementation uses different weights for the two directions. """ - def __init__(self, num_units, use_peepholes=False, + def __init__(self, + num_units, + use_peepholes=False, share_time_frequency_weights=False, - cell_clip=None, initializer=None, - num_unit_shards=1, forget_bias=1.0, - feature_size=None, frequency_skip=None, + cell_clip=None, + initializer=None, + num_unit_shards=1, + forget_bias=1.0, + feature_size=None, + frequency_skip=None, num_frequency_blocks=None, start_freqindex_list=None, end_freqindex_list=None, @@ -1017,8 +1031,8 @@ class BidirectionalGridLSTMCell(GridLSTMCell): state_names += ("%s_c, %s_m," % (name_prefix, name_prefix)) self._state_tuple_type = collections.namedtuple( "BidirectionalGridLSTMStateTuple", state_names.strip(",")) - self._state_size = self._state_tuple_type( - *([num_units, num_units] * self._total_blocks * 2)) + self._state_size = self._state_tuple_type(*( + [num_units, num_units] * self._total_blocks * 2)) self._output_size = 2 * num_units * self._total_blocks * 2 def call(self, inputs, state): @@ -1052,8 +1066,12 @@ class BidirectionalGridLSTMCell(GridLSTMCell): fwd_state_out_lst = [] for block in range(len(fwd_inputs)): fwd_m_out_lst_current, fwd_state_out_lst_current = self._compute( - fwd_inputs[block], block, state, batch_size, - state_prefix="fwd_state", state_is_tuple=True) + fwd_inputs[block], + block, + state, + batch_size, + state_prefix="fwd_state", + state_is_tuple=True) fwd_m_out_lst.extend(fwd_m_out_lst_current) fwd_state_out_lst.extend(fwd_state_out_lst_current) # Backward processing @@ -1064,8 +1082,12 @@ class BidirectionalGridLSTMCell(GridLSTMCell): # Reverse the blocks bwd_inputs_reverse = bwd_inputs[block][::-1] bwd_m_out_lst_current, bwd_state_out_lst_current = self._compute( - bwd_inputs_reverse, block, state, batch_size, - state_prefix="bwd_state", state_is_tuple=True) + bwd_inputs_reverse, + block, + state, + batch_size, + state_prefix="bwd_state", + state_is_tuple=True) bwd_m_out_lst.extend(bwd_m_out_lst_current) bwd_state_out_lst.extend(bwd_state_out_lst_current) state_out = self._state_tuple_type(*(fwd_state_out_lst + bwd_state_out_lst)) @@ -1076,6 +1098,7 @@ class BidirectionalGridLSTMCell(GridLSTMCell): # pylint: disable=protected-access _Linear = core_rnn_cell._Linear # pylint: disable=invalid-name + # pylint: enable=protected-access @@ -1085,8 +1108,14 @@ class AttentionCellWrapper(rnn_cell_impl.RNNCell): Implementation based on https://arxiv.org/abs/1409.0473. """ - def __init__(self, cell, attn_length, attn_size=None, attn_vec_size=None, - input_size=None, state_is_tuple=True, reuse=None): + def __init__(self, + cell, + attn_length, + attn_size=None, + attn_vec_size=None, + input_size=None, + state_is_tuple=True, + reuse=None): """Create a cell with attention. Args: @@ -1116,16 +1145,15 @@ class AttentionCellWrapper(rnn_cell_impl.RNNCell): if not rnn_cell_impl._like_rnncell(cell): # pylint: disable=protected-access raise TypeError("The parameter cell is not RNNCell.") if nest.is_sequence(cell.state_size) and not state_is_tuple: - raise ValueError("Cell returns tuple of states, but the flag " - "state_is_tuple is not set. State size is: %s" - % str(cell.state_size)) + raise ValueError( + "Cell returns tuple of states, but the flag " + "state_is_tuple is not set. State size is: %s" % str(cell.state_size)) if attn_length <= 0: - raise ValueError("attn_length should be greater than zero, got %s" - % str(attn_length)) + raise ValueError( + "attn_length should be greater than zero, got %s" % str(attn_length)) if not state_is_tuple: - logging.warn( - "%s: Using a concatenated state is slower and will soon be " - "deprecated. Use state_is_tuple=True.", self) + logging.warn("%s: Using a concatenated state is slower and will soon be " + "deprecated. Use state_is_tuple=True.", self) if attn_size is None: attn_size = cell.output_size if attn_vec_size is None: @@ -1161,8 +1189,8 @@ class AttentionCellWrapper(rnn_cell_impl.RNNCell): else: states = state state = array_ops.slice(states, [0, 0], [-1, self._cell.state_size]) - attns = array_ops.slice( - states, [0, self._cell.state_size], [-1, self._attn_size]) + attns = array_ops.slice(states, [0, self._cell.state_size], + [-1, self._attn_size]) attn_states = array_ops.slice( states, [0, self._cell.state_size + self._attn_size], [-1, self._attn_size * self._attn_length]) @@ -1200,8 +1228,8 @@ class AttentionCellWrapper(rnn_cell_impl.RNNCell): tanh = math_ops.tanh with vs.variable_scope("attention"): - k = vs.get_variable( - "attn_w", [1, 1, self._attn_size, self._attn_vec_size]) + k = vs.get_variable("attn_w", + [1, 1, self._attn_size, self._attn_vec_size]) v = vs.get_variable("attn_v", [self._attn_vec_size]) hidden = array_ops.reshape(attn_states, [-1, self._attn_length, 1, self._attn_size]) @@ -1228,7 +1256,8 @@ class HighwayWrapper(rnn_cell_impl.RNNCell): https://arxiv.org/abs/1505.00387 """ - def __init__(self, cell, + def __init__(self, + cell, couple_carry_transform_gates=True, carry_bias_init=1.0): """Constructs a `HighwayWrapper` for `cell`. @@ -1260,8 +1289,7 @@ class HighwayWrapper(rnn_cell_impl.RNNCell): carry_weight = vs.get_variable("carry_w", [input_size, input_size]) carry_bias = vs.get_variable( "carry_b", [input_size], - initializer=init_ops.constant_initializer( - self._carry_bias_init)) + initializer=init_ops.constant_initializer(self._carry_bias_init)) carry = math_ops.sigmoid(nn_ops.xw_plus_b(inp, carry_weight, carry_bias)) if self._couple_carry_transform_gates: transform = 1 - carry @@ -1270,11 +1298,9 @@ class HighwayWrapper(rnn_cell_impl.RNNCell): [input_size, input_size]) transform_bias = vs.get_variable( "transform_b", [input_size], - initializer=init_ops.constant_initializer( - -self._carry_bias_init)) - transform = math_ops.sigmoid(nn_ops.xw_plus_b(inp, - transform_weight, - transform_bias)) + initializer=init_ops.constant_initializer(-self._carry_bias_init)) + transform = math_ops.sigmoid( + nn_ops.xw_plus_b(inp, transform_weight, transform_bias)) return inp * carry + out * transform def __call__(self, inputs, state, scope=None): @@ -1294,9 +1320,11 @@ class HighwayWrapper(rnn_cell_impl.RNNCell): """ outputs, new_state = self._cell(inputs, state, scope=scope) nest.assert_same_structure(inputs, outputs) + # Ensure shapes match def assert_shape_match(inp, out): inp.get_shape().assert_is_compatible_with(out.get_shape()) + nest.map_structure(assert_shape_match, inputs, outputs) res_outputs = nest.map_structure(self._highway, inputs, outputs) return (res_outputs, new_state) @@ -1322,10 +1350,16 @@ class LayerNormBasicLSTMCell(rnn_cell_impl.RNNCell): Stanislau Semeniuta, Aliaksei Severyn, Erhardt Barth. """ - def __init__(self, num_units, forget_bias=1.0, - input_size=None, activation=math_ops.tanh, - layer_norm=True, norm_gain=1.0, norm_shift=0.0, - dropout_keep_prob=1.0, dropout_prob_seed=None, + def __init__(self, + num_units, + forget_bias=1.0, + input_size=None, + activation=math_ops.tanh, + layer_norm=True, + norm_gain=1.0, + norm_shift=0.0, + dropout_keep_prob=1.0, + dropout_prob_seed=None, reuse=None): """Initializes the basic LSTM cell. @@ -1410,8 +1444,8 @@ class LayerNormBasicLSTMCell(rnn_cell_impl.RNNCell): if (not isinstance(self._keep_prob, float)) or self._keep_prob < 1: g = nn_ops.dropout(g, self._keep_prob, seed=self._seed) - new_c = (c * math_ops.sigmoid(f + self._forget_bias) - + math_ops.sigmoid(i) * g) + new_c = ( + c * math_ops.sigmoid(f + self._forget_bias) + math_ops.sigmoid(i) * g) if self._layer_norm: new_c = self._norm(new_c, "state", dtype=dtype) new_h = self._activation(new_c) * math_ops.sigmoid(o) @@ -1433,8 +1467,7 @@ class NASCell(rnn_cell_impl.RNNCell): The class uses an optional projection layer. """ - def __init__(self, num_units, num_proj=None, - use_biases=False, reuse=None): + def __init__(self, num_units, num_proj=None, use_biases=False, reuse=None): """Initialize the parameters for a NAS cell. Args: @@ -1504,12 +1537,10 @@ class NASCell(rnn_cell_impl.RNNCell): raise ValueError("Could not infer input size from inputs.get_shape()[-1]") # Variables for the NAS cell. W_m is all matrices multiplying the # hiddenstate and W_inputs is all matrices multiplying the inputs. - concat_w_m = vs.get_variable( - "recurrent_kernel", [num_proj, 8 * self._num_units], - dtype) + concat_w_m = vs.get_variable("recurrent_kernel", + [num_proj, 8 * self._num_units], dtype) concat_w_inputs = vs.get_variable( - "kernel", [input_size.value, 8 * self._num_units], - dtype) + "kernel", [input_size.value, 8 * self._num_units], dtype) m_matrix = math_ops.matmul(m_prev, concat_w_m) inputs_matrix = math_ops.matmul(inputs, concat_w_inputs) @@ -1524,10 +1555,10 @@ class NASCell(rnn_cell_impl.RNNCell): # The NAS cell branches into 8 different splits for both the hiddenstate # and the input - m_matrix_splits = array_ops.split(axis=1, num_or_size_splits=8, - value=m_matrix) - inputs_matrix_splits = array_ops.split(axis=1, num_or_size_splits=8, - value=inputs_matrix) + m_matrix_splits = array_ops.split( + axis=1, num_or_size_splits=8, value=m_matrix) + inputs_matrix_splits = array_ops.split( + axis=1, num_or_size_splits=8, value=inputs_matrix) # First layer layer1_0 = sigmoid(inputs_matrix_splits[0] + m_matrix_splits[0]) @@ -1559,9 +1590,8 @@ class NASCell(rnn_cell_impl.RNNCell): # Projection layer if specified if self._num_proj is not None: - concat_w_proj = vs.get_variable( - "projection_weights", [self._num_units, self._num_proj], - dtype) + concat_w_proj = vs.get_variable("projection_weights", + [self._num_units, self._num_proj], dtype) new_m = math_ops.matmul(new_m, concat_w_proj) new_state = rnn_cell_impl.LSTMStateTuple(new_c, new_m) @@ -1584,8 +1614,12 @@ class UGRNNCell(rnn_cell_impl.RNNCell): "Capacity and Trainability in Recurrent Neural Networks" Proc. ICLR 2017. """ - def __init__(self, num_units, initializer=None, forget_bias=1.0, - activation=math_ops.tanh, reuse=None): + def __init__(self, + num_units, + initializer=None, + forget_bias=1.0, + activation=math_ops.tanh, + reuse=None): """Initialize the parameters for an UGRNN cell. Args: @@ -1640,8 +1674,8 @@ class UGRNNCell(rnn_cell_impl.RNNCell): if input_size.value is None: raise ValueError("Could not infer input size from inputs.get_shape()[-1]") - with vs.variable_scope(vs.get_variable_scope(), - initializer=self._initializer): + with vs.variable_scope( + vs.get_variable_scope(), initializer=self._initializer): cell_inputs = array_ops.concat([inputs, state], 1) if self._linear is None: self._linear = _Linear(cell_inputs, 2 * self._num_units, True) @@ -1681,9 +1715,13 @@ class IntersectionRNNCell(rnn_cell_impl.RNNCell): RNNs so it may not achieve best performance with depth 1. """ - def __init__(self, num_units, num_in_proj=None, - initializer=None, forget_bias=1.0, - y_activation=nn_ops.relu, reuse=None): + def __init__(self, + num_units, + num_in_proj=None, + initializer=None, + forget_bias=1.0, + y_activation=nn_ops.relu, + reuse=None): """Initialize the parameters for an +RNN cell. Args: @@ -1747,8 +1785,8 @@ class IntersectionRNNCell(rnn_cell_impl.RNNCell): if input_size.value is None: raise ValueError("Could not infer input size from inputs.get_shape()[-1]") - with vs.variable_scope(vs.get_variable_scope(), - initializer=self._initializer): + with vs.variable_scope( + vs.get_variable_scope(), initializer=self._initializer): # read-in projections (should be used for first layer in deep +RNN # to transform size of inputs from I --> N) if input_size.value != self._num_units: @@ -1765,13 +1803,13 @@ class IntersectionRNNCell(rnn_cell_impl.RNNCell): n_dim = i_dim = self._num_units cell_inputs = array_ops.concat([inputs, state], 1) if self._linear2 is None: - self._linear2 = _Linear(cell_inputs, 2*n_dim + 2*i_dim, True) + self._linear2 = _Linear(cell_inputs, 2 * n_dim + 2 * i_dim, True) rnn_matrix = self._linear2(cell_inputs) - gh_act = rnn_matrix[:, :n_dim] # b x n - h_act = rnn_matrix[:, n_dim:2*n_dim] # b x n - gy_act = rnn_matrix[:, 2*n_dim:2*n_dim+i_dim] # b x i - y_act = rnn_matrix[:, 2*n_dim+i_dim:2*n_dim+2*i_dim] # b x i + gh_act = rnn_matrix[:, :n_dim] # b x n + h_act = rnn_matrix[:, n_dim:2 * n_dim] # b x n + gy_act = rnn_matrix[:, 2 * n_dim:2 * n_dim + i_dim] # b x i + y_act = rnn_matrix[:, 2 * n_dim + i_dim:2 * n_dim + 2 * i_dim] # b x i h = tanh(h_act) y = self._y_activation(y_act) @@ -1817,6 +1855,7 @@ class CompiledWrapper(rnn_cell_impl.RNNCell): if self._compile_stateful: compile_ops = True else: + def compile_ops(node_def): global _REGISTERED_OPS if _REGISTERED_OPS is None: @@ -1827,10 +1866,7 @@ class CompiledWrapper(rnn_cell_impl.RNNCell): return self._cell(inputs, state, scope=scope) -def _random_exp_initializer(minval, - maxval, - seed=None, - dtype=dtypes.float32): +def _random_exp_initializer(minval, maxval, seed=None, dtype=dtypes.float32): """Returns an exponential distribution initializer. Args: @@ -1849,10 +1885,7 @@ def _random_exp_initializer(minval, del partition_info # Unused. return math_ops.exp( random_ops.random_uniform( - shape, - math_ops.log(minval), - math_ops.log(maxval), - dtype, + shape, math_ops.log(minval), math_ops.log(maxval), dtype, seed=seed)) return _initializer @@ -1956,8 +1989,7 @@ class PhasedLSTMCell(rnn_cell_impl.RNNCell): if self._linear1 is None: self._linear1 = _Linear(in_mask_gates, 2 * self._num_units, True) - mask_gates = math_ops.sigmoid( - self._linear1(in_mask_gates)) + mask_gates = math_ops.sigmoid(self._linear1(in_mask_gates)) [input_gate, forget_gate] = array_ops.split( axis=1, num_or_size_splits=2, value=mask_gates) @@ -1981,12 +2013,12 @@ class PhasedLSTMCell(rnn_cell_impl.RNNCell): period = vs.get_variable( "period", [self._num_units], - initializer=_random_exp_initializer( - self._period_init_min, self._period_init_max)) + initializer=_random_exp_initializer(self._period_init_min, + self._period_init_max)) phase = vs.get_variable( "phase", [self._num_units], - initializer=init_ops.random_uniform_initializer( - 0., period.initial_value)) + initializer=init_ops.random_uniform_initializer(0., + period.initial_value)) ratio_on = vs.get_variable( "ratio_on", [self._num_units], initializer=init_ops.constant_initializer(self._ratio_on), @@ -2008,6 +2040,7 @@ class PhasedLSTMCell(rnn_cell_impl.RNNCell): return new_h, new_state + class ConvLSTMCell(rnn_cell_impl.RNNCell): """Convolutional LSTM recurrent network cell. @@ -2041,7 +2074,7 @@ class ConvLSTMCell(rnn_cell_impl.RNNCell): """ super(ConvLSTMCell, self).__init__(name=name) - if conv_ndims != len(input_shape)-1: + if conv_ndims != len(input_shape) - 1: raise ValueError("Invalid input_shape {} for conv_ndims={}.".format( input_shape, conv_ndims)) @@ -2060,8 +2093,8 @@ class ConvLSTMCell(rnn_cell_impl.RNNCell): state_size = tensor_shape.TensorShape( self._input_shape[:-1] + [self._output_channels]) self._state_size = rnn_cell_impl.LSTMStateTuple(state_size, state_size) - self._output_size = tensor_shape.TensorShape(self._input_shape[:-1] - + [self._total_output_channels]) + self._output_size = tensor_shape.TensorShape( + self._input_shape[:-1] + [self._total_output_channels]) @property def output_size(self): @@ -2073,13 +2106,10 @@ class ConvLSTMCell(rnn_cell_impl.RNNCell): def call(self, inputs, state, scope=None): cell, hidden = state - new_hidden = _conv([inputs, hidden], - self._kernel_shape, - 4*self._output_channels, - self._use_bias) - gates = array_ops.split(value=new_hidden, - num_or_size_splits=4, - axis=self._conv_ndims+1) + new_hidden = _conv([inputs, hidden], self._kernel_shape, + 4 * self._output_channels, self._use_bias) + gates = array_ops.split( + value=new_hidden, num_or_size_splits=4, axis=self._conv_ndims + 1) input_gate, new_input, forget_gate, output_gate = gates new_cell = math_ops.sigmoid(forget_gate + self._forget_bias) * cell @@ -2091,29 +2121,35 @@ class ConvLSTMCell(rnn_cell_impl.RNNCell): new_state = rnn_cell_impl.LSTMStateTuple(new_cell, output) return output, new_state + class Conv1DLSTMCell(ConvLSTMCell): """1D Convolutional LSTM recurrent network cell. https://arxiv.org/pdf/1506.04214v1.pdf """ + def __init__(self, name="conv_1d_lstm_cell", **kwargs): """Construct Conv1DLSTM. See `ConvLSTMCell` for more details.""" super(Conv1DLSTMCell, self).__init__(conv_ndims=1, **kwargs) + class Conv2DLSTMCell(ConvLSTMCell): """2D Convolutional LSTM recurrent network cell. https://arxiv.org/pdf/1506.04214v1.pdf """ + def __init__(self, name="conv_2d_lstm_cell", **kwargs): """Construct Conv2DLSTM. See `ConvLSTMCell` for more details.""" super(Conv2DLSTMCell, self).__init__(conv_ndims=2, **kwargs) + class Conv3DLSTMCell(ConvLSTMCell): """3D Convolutional LSTM recurrent network cell. https://arxiv.org/pdf/1506.04214v1.pdf """ + def __init__(self, name="conv_3d_lstm_cell", **kwargs): """Construct Conv3DLSTM. See `ConvLSTMCell` for more details.""" super(Conv3DLSTMCell, self).__init__(conv_ndims=3, **kwargs) @@ -2138,7 +2174,7 @@ def _conv(args, filter_size, num_features, bias, bias_start=0.0): shapes = [a.get_shape().as_list() for a in args] shape_length = len(shapes[0]) for shape in shapes: - if len(shape) not in [3,4,5]: + if len(shape) not in [3, 4, 5]: raise ValueError("Conv Linear expects 3D, 4D " "or 5D arguments: %s" % str(shapes)) if len(shape) != len(shapes[0]): @@ -2149,40 +2185,36 @@ def _conv(args, filter_size, num_features, bias, bias_start=0.0): dtype = [a.dtype for a in args][0] # determine correct conv operation - if shape_length == 3: + if shape_length == 3: conv_op = nn_ops.conv1d strides = 1 elif shape_length == 4: conv_op = nn_ops.conv2d - strides = shape_length*[1] + strides = shape_length * [1] elif shape_length == 5: conv_op = nn_ops.conv3d - strides = shape_length*[1] + strides = shape_length * [1] # Now the computation. kernel = vs.get_variable( - "kernel", - filter_size + [total_arg_size_depth, num_features], - dtype=dtype) + "kernel", filter_size + [total_arg_size_depth, num_features], dtype=dtype) if len(args) == 1: - res = conv_op(args[0], - kernel, - strides, - padding='SAME') + res = conv_op(args[0], kernel, strides, padding="SAME") else: - res = conv_op(array_ops.concat(axis=shape_length-1, values=args), - kernel, - strides, - padding='SAME') + res = conv_op( + array_ops.concat(axis=shape_length - 1, values=args), + kernel, + strides, + padding="SAME") if not bias: return res bias_term = vs.get_variable( "biases", [num_features], dtype=dtype, - initializer=init_ops.constant_initializer( - bias_start, dtype=dtype)) + initializer=init_ops.constant_initializer(bias_start, dtype=dtype)) return res + bias_term + class GLSTMCell(rnn_cell_impl.RNNCell): """Group LSTM cell (G-LSTM). @@ -2194,8 +2226,13 @@ class GLSTMCell(rnn_cell_impl.RNNCell): "Factorization Tricks for LSTM Networks", ICLR 2017 workshop. """ - def __init__(self, num_units, initializer=None, num_proj=None, - number_of_groups=1, forget_bias=1.0, activation=math_ops.tanh, + def __init__(self, + num_units, + initializer=None, + num_proj=None, + number_of_groups=1, + forget_bias=1.0, + activation=math_ops.tanh, reuse=None): """Initialize the parameters of G-LSTM cell. @@ -2232,11 +2269,15 @@ class GLSTMCell(rnn_cell_impl.RNNCell): if self._num_proj: if self._num_proj % self._number_of_groups != 0: raise ValueError("num_proj must be divisible by number_of_groups") - self._group_shape = [int(self._num_proj / self._number_of_groups), - int(self._num_units / self._number_of_groups)] + self._group_shape = [ + int(self._num_proj / self._number_of_groups), + int(self._num_units / self._number_of_groups) + ] else: - self._group_shape = [int(self._num_units / self._number_of_groups), - int(self._num_units / self._number_of_groups)] + self._group_shape = [ + int(self._num_units / self._number_of_groups), + int(self._num_units / self._number_of_groups) + ] if num_proj: self._state_size = rnn_cell_impl.LSTMStateTuple(num_units, num_proj) @@ -2268,10 +2309,11 @@ class GLSTMCell(rnn_cell_impl.RNNCell): subset of inputs corresponding to group "group_id", a Tensor, 2D, [batch x num_units/number_of_groups] """ - return array_ops.slice(input_=inputs, - begin=[0, group_id * group_size], - size=[self._batch_size, group_size], - name=("GLSTM_group%d_input_generation" % group_id)) + return array_ops.slice( + input_=inputs, + begin=[0, group_id * group_size], + size=[self._batch_size, group_size], + name=("GLSTM_group%d_input_generation" % group_id)) def call(self, inputs, state): """Run one step of G-LSTM. @@ -2310,10 +2352,13 @@ class GLSTMCell(rnn_cell_impl.RNNCell): for group_id in range(self._number_of_groups): with vs.variable_scope("group%d" % group_id): x_g_id = array_ops.concat( - [self._get_input_for_group(inputs, group_id, - self._group_shape[0]), - self._get_input_for_group(m_prev, group_id, - self._group_shape[0])], axis=1) + [ + self._get_input_for_group(inputs, group_id, + self._group_shape[0]), + self._get_input_for_group(m_prev, group_id, + self._group_shape[0]) + ], + axis=1) if self._linear1 is None: self._linear1 = _Linear(x_g_id, 4 * self._group_shape[1], False) R_k = self._linear1(x_g_id) # pylint: disable=invalid-name @@ -2324,34 +2369,35 @@ class GLSTMCell(rnn_cell_impl.RNNCell): f_parts.append(f_k) o_parts.append(o_k) - bi = vs.get_variable(name="bias_i", - shape=[self._num_units], - dtype=dtype, - initializer= - init_ops.constant_initializer(0.0, dtype=dtype)) - bj = vs.get_variable(name="bias_j", - shape=[self._num_units], - dtype=dtype, - initializer= - init_ops.constant_initializer(0.0, dtype=dtype)) - bf = vs.get_variable(name="bias_f", - shape=[self._num_units], - dtype=dtype, - initializer= - init_ops.constant_initializer(0.0, dtype=dtype)) - bo = vs.get_variable(name="bias_o", - shape=[self._num_units], - dtype=dtype, - initializer= - init_ops.constant_initializer(0.0, dtype=dtype)) + bi = vs.get_variable( + name="bias_i", + shape=[self._num_units], + dtype=dtype, + initializer=init_ops.constant_initializer(0.0, dtype=dtype)) + bj = vs.get_variable( + name="bias_j", + shape=[self._num_units], + dtype=dtype, + initializer=init_ops.constant_initializer(0.0, dtype=dtype)) + bf = vs.get_variable( + name="bias_f", + shape=[self._num_units], + dtype=dtype, + initializer=init_ops.constant_initializer(0.0, dtype=dtype)) + bo = vs.get_variable( + name="bias_o", + shape=[self._num_units], + dtype=dtype, + initializer=init_ops.constant_initializer(0.0, dtype=dtype)) i = nn_ops.bias_add(array_ops.concat(i_parts, axis=1), bi) j = nn_ops.bias_add(array_ops.concat(j_parts, axis=1), bj) f = nn_ops.bias_add(array_ops.concat(f_parts, axis=1), bf) o = nn_ops.bias_add(array_ops.concat(o_parts, axis=1), bo) - c = (math_ops.sigmoid(f + self._forget_bias) * c_prev + - math_ops.sigmoid(i) * math_ops.tanh(j)) + c = ( + math_ops.sigmoid(f + self._forget_bias) * c_prev + + math_ops.sigmoid(i) * math_ops.tanh(j)) m = math_ops.sigmoid(o) * self._activation(c) if self._num_proj is not None: @@ -2636,10 +2682,12 @@ class LayerNormLSTMCell(rnn_cell_impl.RNNCell): class SRUCell(rnn_cell_impl._LayerRNNCell): """SRU, Simple Recurrent Unit + Implementation based on Training RNNs as Fast as CNNs (cf. https://arxiv.org/abs/1709.02755). - This variation of RNN cell is characterized by the simplified data dependence + This variation of RNN cell is characterized by the simplified data + dependence between hidden states of two consecutive time steps. Traditionally, hidden states from a cell at time step t-1 needs to be multiplied with a matrix W_hh before being fed into the ensuing cell at time step t. @@ -2657,8 +2705,8 @@ class SRUCell(rnn_cell_impl._LayerRNNCell): will share weights, but to avoid mistakes we require reuse=True in such cases. """ - def __init__(self, num_units, - activation=None, reuse=None, name=None): + + def __init__(self, num_units, activation=None, reuse=None, name=None): super(SRUCell, self).__init__(_reuse=reuse, name=name) self._num_units = num_units self._activation = activation or math_ops.tanh @@ -2676,8 +2724,8 @@ class SRUCell(rnn_cell_impl._LayerRNNCell): def build(self, inputs_shape): if inputs_shape[1].value is None: - raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s" - % inputs_shape) + raise ValueError( + "Expected inputs.shape[-1] to be known, saw shape: %s" % inputs_shape) input_depth = inputs_shape[1].value @@ -2712,12 +2760,12 @@ class SRUCell(rnn_cell_impl._LayerRNNCell): """Simple recurrent unit (SRU) with num_units cells.""" U = math_ops.matmul(inputs, self._kernel) - x_bar, f_intermediate, r_intermediate = array_ops.split(value=U, - num_or_size_splits=3, - axis=1) + x_bar, f_intermediate, r_intermediate = array_ops.split( + value=U, num_or_size_splits=3, axis=1) - f_r = math_ops.sigmoid(nn_ops.bias_add(array_ops.concat( - [f_intermediate, r_intermediate], 1), self._bias)) + f_r = math_ops.sigmoid( + nn_ops.bias_add( + array_ops.concat([f_intermediate, r_intermediate], 1), self._bias)) f, r = array_ops.split(value=f_r, num_or_size_splits=2, axis=1) c = f * state + (1.0 - f) * x_bar @@ -2750,9 +2798,16 @@ class WeightNormLSTMCell(rnn_cell_impl.RNNCell): large scale acoustic modeling." INTERSPEECH, 2014. """ - def __init__(self, num_units, norm=True, use_peepholes=False, - cell_clip=None, initializer=None, num_proj=None, - proj_clip=None, forget_bias=1, activation=None, + def __init__(self, + num_units, + norm=True, + use_peepholes=False, + cell_clip=None, + initializer=None, + num_proj=None, + proj_clip=None, + forget_bias=1, + activation=None, reuse=None): """Initialize the parameters of a weight-normalized LSTM cell. @@ -2779,7 +2834,7 @@ class WeightNormLSTMCell(rnn_cell_impl.RNNCell): """ super(WeightNormLSTMCell, self).__init__(_reuse=reuse) - self._scope = 'wn_lstm_cell' + self._scope = "wn_lstm_cell" self._num_units = num_units self._norm = norm self._initializer = initializer @@ -2822,7 +2877,8 @@ class WeightNormLSTMCell(rnn_cell_impl.RNNCell): g = vs.get_variable(name, [output_size], dtype=weight.dtype) return nn_impl.l2_normalize(weight, dim=0) * g - def _linear(self, args, + def _linear(self, + args, output_size, norm, bias, @@ -2877,8 +2933,8 @@ class WeightNormLSTMCell(rnn_cell_impl.RNNCell): with ops.control_dependencies(None): for i in range(len(args)): en = st + shapes[i][1].value - wn.append(self._normalize(weights[st:en, :], - name='norm_{}'.format(i))) + wn.append( + self._normalize(weights[st:en, :], name="norm_{}".format(i))) st = en weights = array_ops.concat(wn, axis=0) @@ -2936,8 +2992,8 @@ class WeightNormLSTMCell(rnn_cell_impl.RNNCell): with vs.variable_scope(self._scope, initializer=self._initializer): - concat = self._linear([inputs, h], 4 * num_units, - norm=self._norm, bias=True) + concat = self._linear( + [inputs, h], 4 * num_units, norm=self._norm, bias=True) # i = input_gate, j = new_input, f = forget_gate, o = output_gate i, j, f, o = array_ops.split(value=concat, num_or_size_splits=4, axis=1) @@ -2947,11 +3003,13 @@ class WeightNormLSTMCell(rnn_cell_impl.RNNCell): w_i_diag = vs.get_variable("w_i_diag", shape=[num_units], dtype=dtype) w_o_diag = vs.get_variable("w_o_diag", shape=[num_units], dtype=dtype) - new_c = (c * sigmoid(f + self._forget_bias + w_f_diag * c) - + sigmoid(i + w_i_diag * c) * self._activation(j)) + new_c = ( + c * sigmoid(f + self._forget_bias + w_f_diag * c) + + sigmoid(i + w_i_diag * c) * self._activation(j)) else: - new_c = (c * sigmoid(f + self._forget_bias) - + sigmoid(i) * self._activation(j)) + new_c = ( + c * sigmoid(f + self._forget_bias) + + sigmoid(i) * self._activation(j)) if self._cell_clip is not None: # pylint: disable=invalid-unary-operand-type @@ -2964,15 +3022,12 @@ class WeightNormLSTMCell(rnn_cell_impl.RNNCell): if self._num_proj is not None: with vs.variable_scope("projection"): - new_h = self._linear(new_h, - self._num_proj, - norm=self._norm, - bias=False) + new_h = self._linear( + new_h, self._num_proj, norm=self._norm, bias=False) if self._proj_clip is not None: # pylint: disable=invalid-unary-operand-type - new_h = clip_ops.clip_by_value(new_h, - -self._proj_clip, + new_h = clip_ops.clip_by_value(new_h, -self._proj_clip, self._proj_clip) # pylint: enable=invalid-unary-operand-type diff --git a/tensorflow/contrib/seq2seq/python/kernel_tests/beam_search_decoder_test.py b/tensorflow/contrib/seq2seq/python/kernel_tests/beam_search_decoder_test.py index f498b2bb57..9265540317 100644 --- a/tensorflow/contrib/seq2seq/python/kernel_tests/beam_search_decoder_test.py +++ b/tensorflow/contrib/seq2seq/python/kernel_tests/beam_search_decoder_test.py @@ -46,20 +46,18 @@ class TestGatherTree(test.TestCase): # create (batch_size, max_time, beam_width) matrix and transpose it predicted_ids = np.array( - [[[1, 2, 3], [4, 5, 6], [7, 8, 9]], - [[2, 3, 4], [5, 6, 7], [8, 9, 10]]], + [[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[2, 3, 4], [5, 6, 7], [8, 9, 10]]], dtype=np.int32).transpose([1, 0, 2]) parent_ids = np.array( - [[[0, 0, 0], [0, 1, 1], [2, 1, 2]], - [[0, 0, 0], [1, 2, 0], [2, 1, 1]]], + [[[0, 0, 0], [0, 1, 1], [2, 1, 2]], [[0, 0, 0], [1, 2, 0], [2, 1, 1]]], dtype=np.int32).transpose([1, 0, 2]) # sequence_lengths is shaped (batch_size = 3) max_sequence_lengths = [3, 3] - expected_result = np.array( - [[[2, 2, 2], [6, 5, 6], [7, 8, 9]], - [[2, 4, 4], [7, 6, 6], [8, 9, 10]]]).transpose([1, 0, 2]) + expected_result = np.array([[[2, 2, 2], [6, 5, 6], [7, 8, 9]], + [[2, 4, 4], [7, 6, 6], + [8, 9, 10]]]).transpose([1, 0, 2]) res = beam_search_ops.gather_tree( predicted_ids, @@ -157,8 +155,8 @@ class TestBeamStep(test.TestCase): self.assertAllEqual(outputs_.predicted_ids, [[3, 3, 2], [2, 2, 1]]) self.assertAllEqual(outputs_.parent_ids, [[1, 0, 0], [2, 1, 0]]) self.assertAllEqual(next_state_.lengths, [[3, 3, 3], [3, 3, 3]]) - self.assertAllEqual(next_state_.finished, [[False, False, False], - [False, False, False]]) + self.assertAllEqual(next_state_.finished, + [[False, False, False], [False, False, False]]) expected_log_probs = [] expected_log_probs.append(state_.log_probs[0][[1, 0, 0]]) @@ -212,8 +210,8 @@ class TestBeamStep(test.TestCase): self.assertAllEqual(outputs_.parent_ids, [[1, 0, 0], [1, 2, 0]]) self.assertAllEqual(outputs_.predicted_ids, [[0, 3, 2], [2, 0, 1]]) self.assertAllEqual(next_state_.lengths, [[1, 3, 3], [3, 1, 3]]) - self.assertAllEqual(next_state_.finished, [[True, False, False], - [False, True, False]]) + self.assertAllEqual(next_state_.finished, + [[True, False, False], [False, True, False]]) expected_log_probs = [] expected_log_probs.append(state_.log_probs[0][[1, 0, 0]]) @@ -226,9 +224,10 @@ class TestBeamStep(test.TestCase): class TestLargeBeamStep(test.TestCase): - """ - Tests a single step of beam search in such - case that beam size is larger than vocabulary size. + """Tests large beam step. + + Tests a single step of beam search in such case that beam size is larger than + vocabulary size. """ def setUp(self): @@ -239,19 +238,21 @@ class TestLargeBeamStep(test.TestCase): self.end_token = 0 self.length_penalty_weight = 0.6 - def test_step(self): - def get_probs(): - """this simulates the initialize method in BeamSearchDecoder""" - log_prob_mask = array_ops.one_hot(array_ops.zeros([self.batch_size], - dtype=dtypes.int32), - depth=self.beam_width, on_value=True, - off_value=False, dtype=dtypes.bool) - log_prob_zeros = array_ops.zeros([self.batch_size, self.beam_width], - dtype=dtypes.float32) - log_prob_neg_inf = array_ops.ones([self.batch_size, self.beam_width], - dtype=dtypes.float32) * -np.Inf + def get_probs(): + """this simulates the initialize method in BeamSearchDecoder.""" + log_prob_mask = array_ops.one_hot( + array_ops.zeros([self.batch_size], dtype=dtypes.int32), + depth=self.beam_width, + on_value=True, + off_value=False, + dtype=dtypes.bool) + + log_prob_zeros = array_ops.zeros( + [self.batch_size, self.beam_width], dtype=dtypes.float32) + log_prob_neg_inf = array_ops.ones( + [self.batch_size, self.beam_width], dtype=dtypes.float32) * -np.Inf log_probs = array_ops.where(log_prob_mask, log_prob_zeros, log_prob_neg_inf) @@ -260,12 +261,15 @@ class TestLargeBeamStep(test.TestCase): log_probs = get_probs() dummy_cell_state = array_ops.zeros([self.batch_size, self.beam_width]) + # pylint: disable=invalid-name _finished = array_ops.one_hot( array_ops.zeros([self.batch_size], dtype=dtypes.int32), - depth=self.beam_width, on_value=False, - off_value=True, dtype=dtypes.bool) + depth=self.beam_width, + on_value=False, + off_value=True, + dtype=dtypes.bool) _lengths = np.zeros([self.batch_size, self.beam_width], dtype=np.int64) - _lengths[:, 0]=2 + _lengths[:, 0] = 2 _lengths = constant_op.constant(_lengths, dtype=dtypes.int64) beam_state = beam_search_decoder.BeamSearchDecoderState( @@ -298,20 +302,20 @@ class TestLargeBeamStep(test.TestCase): length_penalty_weight=self.length_penalty_weight) with self.test_session() as sess: - outputs_, next_state_, state_, log_probs_ = sess.run( + outputs_, next_state_, _, _ = sess.run( [outputs, next_beam_state, beam_state, log_probs]) self.assertEqual(outputs_.predicted_ids[0, 0], 3) self.assertEqual(outputs_.predicted_ids[0, 1], 2) self.assertEqual(outputs_.predicted_ids[1, 0], 1) neg_inf = -np.Inf - self.assertAllEqual(next_state_.log_probs[:, -3:], - [[neg_inf, neg_inf, neg_inf], - [neg_inf, neg_inf, neg_inf]]) + self.assertAllEqual( + next_state_.log_probs[:, -3:], + [[neg_inf, neg_inf, neg_inf], [neg_inf, neg_inf, neg_inf]]) self.assertEqual((next_state_.log_probs[:, :-3] > neg_inf).all(), True) self.assertEqual((next_state_.lengths[:, :-3] > 0).all(), True) - self.assertAllEqual(next_state_.lengths[:, -3:], [[0, 0, 0], - [0, 0, 0]]) + self.assertAllEqual(next_state_.lengths[:, -3:], [[0, 0, 0], [0, 0, 0]]) + class BeamSearchDecoderTest(test.TestCase): @@ -338,8 +342,8 @@ class BeamSearchDecoderTest(test.TestCase): initial_state = cell.zero_state(batch_size, dtypes.float32) if has_attention: inputs = array_ops.placeholder_with_default( - np.random.randn(batch_size, decoder_max_time, - input_depth).astype(np.float32), + np.random.randn(batch_size, decoder_max_time, input_depth).astype( + np.float32), shape=(None, None, input_depth)) tiled_inputs = beam_search_decoder.tile_batch( inputs, multiplier=beam_width) @@ -359,8 +363,7 @@ class BeamSearchDecoderTest(test.TestCase): cell_state = cell.zero_state( dtype=dtypes.float32, batch_size=batch_size_tensor * beam_width) if has_attention: - cell_state = cell_state.clone( - cell_state=initial_state) + cell_state = cell_state.clone(cell_state=initial_state) bsd = beam_search_decoder.BeamSearchDecoder( cell=cell, embedding=embedding, diff --git a/tensorflow/contrib/seq2seq/python/ops/beam_search_decoder.py b/tensorflow/contrib/seq2seq/python/ops/beam_search_decoder.py index a5f7169c31..d6184d6109 100644 --- a/tensorflow/contrib/seq2seq/python/ops/beam_search_decoder.py +++ b/tensorflow/contrib/seq2seq/python/ops/beam_search_decoder.py @@ -37,7 +37,6 @@ from tensorflow.python.ops import rnn_cell_impl from tensorflow.python.ops import tensor_array_ops from tensorflow.python.util import nest - __all__ = [ "BeamSearchDecoderOutput", "BeamSearchDecoderState", @@ -48,8 +47,8 @@ __all__ = [ class BeamSearchDecoderState( - collections.namedtuple("BeamSearchDecoderState", ("cell_state", "log_probs", - "finished", "lengths"))): + collections.namedtuple("BeamSearchDecoderState", + ("cell_state", "log_probs", "finished", "lengths"))): pass @@ -85,11 +84,12 @@ def _tile_batch(t, multiplier): tiled_static_batch_size = ( t.shape[0].value * multiplier if t.shape[0].value is not None else None) tiled = array_ops.tile(array_ops.expand_dims(t, 1), tiling) - tiled = array_ops.reshape( - tiled, array_ops.concat(([shape_t[0] * multiplier], shape_t[1:]), 0)) + tiled = array_ops.reshape(tiled, + array_ops.concat( + ([shape_t[0] * multiplier], shape_t[1:]), 0)) tiled.set_shape( - tensor_shape.TensorShape( - [tiled_static_batch_size]).concatenate(t.shape[1:])) + tensor_shape.TensorShape([tiled_static_batch_size]).concatenate( + t.shape[1:])) return tiled @@ -197,8 +197,8 @@ class BeamSearchDecoder(decoder.Decoder): """ if not rnn_cell_impl._like_rnncell(cell): # pylint: disable=protected-access raise TypeError("cell must be an RNNCell, received: %s" % type(cell)) - if (output_layer is not None - and not isinstance(output_layer, layers_base.Layer)): + if (output_layer is not None and + not isinstance(output_layer, layers_base.Layer)): raise TypeError( "output_layer must be a Layer, received: %s" % type(output_layer)) self._cell = cell @@ -223,16 +223,17 @@ class BeamSearchDecoder(decoder.Decoder): self._beam_width = beam_width self._length_penalty_weight = length_penalty_weight self._initial_cell_state = nest.map_structure( - self._maybe_split_batch_beams, - initial_state, self._cell.state_size) + self._maybe_split_batch_beams, initial_state, self._cell.state_size) self._start_tokens = array_ops.tile( array_ops.expand_dims(self._start_tokens, 1), [1, self._beam_width]) self._start_inputs = self._embedding_fn(self._start_tokens) - + self._finished = array_ops.one_hot( array_ops.zeros([self._batch_size], dtype=dtypes.int32), - depth=self._beam_width, on_value=False, - off_value=True, dtype=dtypes.bool) + depth=self._beam_width, + on_value=False, + off_value=True, + dtype=dtypes.bool) @property def batch_size(self): @@ -250,8 +251,7 @@ class BeamSearchDecoder(decoder.Decoder): # dimensions to get the output size of the rnn with the layer # applied to the top. output_shape_with_unknown_batch = nest.map_structure( - lambda s: tensor_shape.TensorShape([None]).concatenate(s), - size) + lambda s: tensor_shape.TensorShape([None]).concatenate(s), size) layer_output_shape = self._output_layer.compute_output_shape( output_shape_with_unknown_batch) return nest.map_structure(lambda s: s[1:], layer_output_shape) @@ -302,10 +302,11 @@ class BeamSearchDecoder(decoder.Decoder): log_probs = array_ops.one_hot( # shape(batch_sz, beam_sz) array_ops.zeros([self._batch_size], dtype=dtypes.int32), - depth=self._beam_width, on_value=0.0, off_value=-np.Inf, + depth=self._beam_width, + on_value=0.0, + off_value=-np.Inf, dtype=nest.flatten(self._initial_cell_state)[0].dtype) - initial_state = BeamSearchDecoderState( cell_state=self._initial_cell_state, log_probs=log_probs, @@ -365,11 +366,12 @@ class BeamSearchDecoder(decoder.Decoder): t_shape = array_ops.shape(t) static_batch_size = tensor_util.constant_value(self._batch_size) batch_size_beam_width = ( - None if static_batch_size is None - else static_batch_size * self._beam_width) + None + if static_batch_size is None else static_batch_size * self._beam_width) reshaped_t = array_ops.reshape( - t, array_ops.concat( - ([self._batch_size * self._beam_width], t_shape[2:]), 0)) + t, + array_ops.concat(([self._batch_size * self._beam_width], t_shape[2:]), + 0)) reshaped_t.set_shape( (tensor_shape.TensorShape([batch_size_beam_width]).concatenate(s))) return reshaped_t @@ -398,8 +400,9 @@ class BeamSearchDecoder(decoder.Decoder): s = tensor_shape.TensorShape(s) t_shape = array_ops.shape(t) reshaped_t = array_ops.reshape( - t, array_ops.concat( - ([self._batch_size, self._beam_width], t_shape[1:]), 0)) + t, + array_ops.concat(([self._batch_size, self._beam_width], t_shape[1:]), + 0)) static_batch_size = tensor_util.constant_value(self._batch_size) expected_reshaped_shape = tensor_shape.TensorShape( [static_batch_size, self._beam_width]).concatenate(s) @@ -409,8 +412,8 @@ class BeamSearchDecoder(decoder.Decoder): "We expected it to have shape " "(batch_size, beam_width, depth) == %s. Perhaps you " "forgot to create a zero_state with " - "batch_size=encoder_batch_size * beam_width?" - % (reshaped_t.shape, expected_reshaped_shape)) + "batch_size=encoder_batch_size * beam_width?" % + (reshaped_t.shape, expected_reshaped_shape)) reshaped_t.set_shape(expected_reshaped_shape) return reshaped_t @@ -482,15 +485,13 @@ class BeamSearchDecoder(decoder.Decoder): cell_state = state.cell_state inputs = nest.map_structure( lambda inp: self._merge_batch_beams(inp, s=inp.shape[2:]), inputs) - cell_state = nest.map_structure( - self._maybe_merge_batch_beams, - cell_state, self._cell.state_size) + cell_state = nest.map_structure(self._maybe_merge_batch_beams, cell_state, + self._cell.state_size) cell_outputs, next_cell_state = self._cell(inputs, cell_state) cell_outputs = nest.map_structure( lambda out: self._split_batch_beams(out, out.shape[1:]), cell_outputs) next_cell_state = nest.map_structure( - self._maybe_split_batch_beams, - next_cell_state, self._cell.state_size) + self._maybe_split_batch_beams, next_cell_state, self._cell.state_size) if self._output_layer is not None: cell_outputs = self._output_layer(cell_outputs) @@ -553,7 +554,8 @@ def _beam_search_step(time, logits, next_cell_state, beam_state, batch_size, lengths_to_add = array_ops.one_hot( indices=array_ops.fill([batch_size, beam_width], end_token), depth=vocab_size, - on_value=np.int64(0), off_value=np.int64(1), + on_value=np.int64(0), + off_value=np.int64(1), dtype=dtypes.int64) add_mask = math_ops.to_int64(math_ops.logical_not(previously_finished)) lengths_to_add *= array_ops.expand_dims(add_mask, 2) @@ -572,8 +574,8 @@ def _beam_search_step(time, logits, next_cell_state, beam_state, batch_size, scores_flat = array_ops.reshape(scores, [batch_size, -1]) # Pick the next beams according to the specified successors function - next_beam_size = ops.convert_to_tensor(beam_width, dtype=dtypes.int32, - name="beam_width") + next_beam_size = ops.convert_to_tensor( + beam_width, dtype=dtypes.int32, name="beam_width") next_beam_scores, word_indices = nn_ops.top_k(scores_flat, k=next_beam_size) next_beam_scores.set_shape([static_batch_size, beam_width]) @@ -592,11 +594,11 @@ def _beam_search_step(time, logits, next_cell_state, beam_state, batch_size, # name="next_beam_word_ids") # would be a lot cleaner but for reasons unclear, that hides the results of # the op which prevents capturing it with tfdbg debug ops. - raw_next_word_ids = math_ops.mod(word_indices, vocab_size, - name="next_beam_word_ids") + raw_next_word_ids = math_ops.mod( + word_indices, vocab_size, name="next_beam_word_ids") next_word_ids = math_ops.to_int32(raw_next_word_ids) - next_beam_ids = math_ops.to_int32(word_indices / vocab_size, - name="next_beam_parent_ids") + next_beam_ids = math_ops.to_int32( + word_indices / vocab_size, name="next_beam_parent_ids") # Append new ids to current predictions previously_finished = _tensor_gather_helper( @@ -605,9 +607,10 @@ def _beam_search_step(time, logits, next_cell_state, beam_state, batch_size, batch_size=batch_size, range_size=beam_width, gather_shape=[-1]) - next_finished = math_ops.logical_or(previously_finished, - math_ops.equal(next_word_ids, end_token), - name="next_beam_finished") + next_finished = math_ops.logical_or( + previously_finished, + math_ops.equal(next_word_ids, end_token), + name="next_beam_finished") # Calculate the length of the next predictions. # 1. Finished beams remain unchanged. @@ -768,8 +771,12 @@ def _maybe_tensor_gather_helper(gather_indices, gather_from, batch_size, return gather_from -def _tensor_gather_helper(gather_indices, gather_from, batch_size, - range_size, gather_shape, name=None): +def _tensor_gather_helper(gather_indices, + gather_from, + batch_size, + range_size, + gather_shape, + name=None): """Helper for gathering the right indices from the tensor. This works by reshaping gather_from to gather_shape (e.g. [-1]) and then @@ -800,9 +807,9 @@ def _tensor_gather_helper(gather_indices, gather_from, batch_size, array_ops.reshape(gather_from, gather_shape), gather_indices) final_shape = array_ops.shape(gather_from)[:1 + len(gather_shape)] static_batch_size = tensor_util.constant_value(batch_size) - final_static_shape = (tensor_shape.TensorShape([static_batch_size]) - .concatenate( - gather_from.shape[1:1 + len(gather_shape)])) + final_static_shape = ( + tensor_shape.TensorShape([static_batch_size]).concatenate( + gather_from.shape[1:1 + len(gather_shape)])) output = array_ops.reshape(output, final_shape, name="output") output.set_shape(final_static_shape) return output diff --git a/tensorflow/contrib/verbs/rdma.cc b/tensorflow/contrib/verbs/rdma.cc index ec5271abe0..7d95b6522c 100644 --- a/tensorflow/contrib/verbs/rdma.cc +++ b/tensorflow/contrib/verbs/rdma.cc @@ -15,10 +15,11 @@ limitations under the License. #ifdef TENSORFLOW_USE_VERBS +#include +#include + #include "tensorflow/contrib/verbs/rdma.h" #include "tensorflow/contrib/verbs/verbs_service.pb.h" -#include -#include #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/common_runtime/dma_helper.h" #include "tensorflow/core/common_runtime/process_util.h" @@ -27,15 +28,15 @@ limitations under the License. #include "tensorflow/core/common_runtime/gpu/process_state.h" #endif #include "tensorflow/core/distributed_runtime/rendezvous_mgr_interface.h" -#include "tensorflow/core/distributed_runtime/session_mgr.h" #include "tensorflow/core/distributed_runtime/rpc/grpc_util.h" +#include "tensorflow/core/distributed_runtime/session_mgr.h" #include "tensorflow/core/framework/rendezvous.h" #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/core/stringpiece.h" +#include "tensorflow/core/lib/core/threadpool.h" #include "tensorflow/core/lib/hash/hash.h" #include "tensorflow/core/lib/random/random.h" -#include "tensorflow/core/lib/core/threadpool.h" namespace tensorflow { @@ -447,9 +448,9 @@ void RdmaAdapter::Process_CQ() { CHECK_GE(ne, 0); for (int i = 0; i < ne; ++i) { CHECK(wc_[i].status == IBV_WC_SUCCESS) - << "Failed status \n" << ibv_wc_status_str(wc_[i].status) << " " - << wc_[i].status << " " << static_cast(wc_[i].wr_id) << " " - << wc_[i].vendor_err; + << "Failed status \n" + << ibv_wc_status_str(wc_[i].status) << " " << wc_[i].status << " " + << static_cast(wc_[i].wr_id) << " " << wc_[i].vendor_err; if (wc_[i].opcode == IBV_WC_RECV_RDMA_WITH_IMM) { RdmaChannel* rc = reinterpret_cast(wc_[i].wr_id); // put back a recv wr. @@ -538,7 +539,7 @@ int RdmaChannel::PingPostRecv() { int RdmaChannel::PingPostSend() { struct ibv_send_wr wr, *bad_wr; memset(&wr, 0, sizeof(wr)); - wr.wr_id = (uint64_t) this; + wr.wr_id = (uint64_t)this; wr.sg_list = &ping_sge_list_; wr.num_sge = 1; wr.opcode = IBV_WR_SEND; @@ -658,7 +659,7 @@ void RdmaChannel::SetRemoteAddress(const RdmaAddress& ra, bool override) { void RdmaChannel::Recv() { struct ibv_recv_wr wr; memset(&wr, 0, sizeof(wr)); - wr.wr_id = (uint64_t) this; + wr.wr_id = (uint64_t)this; struct ibv_recv_wr* bad_wr; CHECK(!ibv_post_recv(qp_, &wr, &bad_wr)) << "Failed to post recv"; } @@ -729,11 +730,11 @@ void RdmaChannel::Connect(const RdmaAddress& remoteAddr) { attr.ah_attr.grh.traffic_class = adapter_->params_.traffic_class; int r; - CHECK(!(r = ibv_modify_qp(qp_, &attr, IBV_QP_STATE | IBV_QP_AV | - IBV_QP_PATH_MTU | - IBV_QP_DEST_QPN | IBV_QP_RQ_PSN | - IBV_QP_MAX_DEST_RD_ATOMIC | - IBV_QP_MIN_RNR_TIMER))) + CHECK(!(r = ibv_modify_qp(qp_, &attr, + IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | IBV_QP_RQ_PSN | + IBV_QP_MAX_DEST_RD_ATOMIC | + IBV_QP_MIN_RNR_TIMER))) << "QP to Ready to Receive " << r; memset(&attr, 0, sizeof(ibv_qp_attr)); @@ -744,10 +745,10 @@ void RdmaChannel::Connect(const RdmaAddress& remoteAddr) { attr.rnr_retry = 7; /* infinite */ attr.max_rd_atomic = 1; - CHECK(!(r = ibv_modify_qp(qp_, &attr, IBV_QP_STATE | IBV_QP_TIMEOUT | - IBV_QP_RETRY_CNT | - IBV_QP_RNR_RETRY | IBV_QP_SQ_PSN | - IBV_QP_MAX_QP_RD_ATOMIC))) + CHECK(!(r = ibv_modify_qp(qp_, &attr, + IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | IBV_QP_SQ_PSN | + IBV_QP_MAX_QP_RD_ATOMIC))) << "QP to Ready to Send " << r; connected_ = true; @@ -897,16 +898,16 @@ static void CountCopies(const std::string& key, void* src_addr, void* dst_addr, } if ((++numTotalCopies % 0x400) == 0) { RDMA_LOG(0) << "Tensor copies:" - << " GPU to CPU: " << numGPUToCPUCopies - << " (" << numGPUToCPUCopiedBytes << " Bytes)" - << " CPU to GPU: " << numCPUToGPUCopies - << " (" << numCPUToGPUCopiedBytes << " Bytes)"; + << " GPU to CPU: " << numGPUToCPUCopies << " (" + << numGPUToCPUCopiedBytes << " Bytes)" + << " CPU to GPU: " << numCPUToGPUCopies << " (" + << numCPUToGPUCopiedBytes << " Bytes)"; } - RDMA_LOG(2) << "Copying tensor " << key - << " From: " << src_addr << " To: " << dst_addr; -#endif // RDMA_COUNT_COPIES + RDMA_LOG(2) << "Copying tensor " << key << " From: " << src_addr + << " To: " << dst_addr; +#endif // RDMA_COUNT_COPIES } -#endif // GOOGLE_CUDA +#endif // GOOGLE_CUDA #ifdef RDMA_DATA_VALIDATION static uint64_t Checksum(Device* device, const DeviceContext* device_context, @@ -920,7 +921,7 @@ static uint64_t Checksum(Device* device, const DeviceContext* device_context, checksum = (device_context != nullptr) ? GPUUtil::Checksum(device, device_context, in) : GPUUtil::Checksum(in); -#endif // GOOGLE_CUDA +#endif // GOOGLE_CUDA } else { string s = in.SummarizeValue(999999); checksum = Hash64(s.c_str(), s.size(), 0); @@ -955,17 +956,16 @@ static void ValidateChecksum(uint64_t expected, uint64_t actual, } } } -#endif // RDMA_DATA_VALIDATION +#endif // RDMA_DATA_VALIDATION #if GOOGLE_CUDA // Sync the 'done' operation on the GPU stream, but without all the data // copying. -static void StreamGPUOp(Device* gpu_device, - const DeviceContext* device_context, +static void StreamGPUOp(Device* gpu_device, const DeviceContext* device_context, StatusCallback done) { Tensor dummy1, dummy2; - GPUUtil::CopyGPUTensorToCPU( - gpu_device, device_context, &dummy1, &dummy2, done); + GPUUtil::CopyGPUTensorToCPU(gpu_device, device_context, &dummy1, &dummy2, + done); } #endif // GOOGLE_CUDA @@ -1072,7 +1072,7 @@ void RdmaTensorResponse::RecvHandler(Rendezvous::ParsedKey parsed, // skip the copy here as well. if ((in.TotalBytes() > 0) && !meta_data_changed_ && (RdmaMemoryMgr::Singleton().FindMemoryRegion( - (void*)DMAHelper::base(&in), in.TotalBytes()) != nullptr)) { + (void*)DMAHelper::base(&in), in.TotalBytes()) != nullptr)) { StreamGPUOp(src_dev_, send_dev_context, [this, in, proto, is_dead](const Status& s) { Send(in, proto, is_dead, s); @@ -1118,8 +1118,8 @@ void RdmaTensorResponse::Send(const Tensor& in, const TensorProto& proto, return; } bool can_memcpy = DataTypeCanUseMemcpy(in.dtype()); - bool proto_size_changed = (!can_memcpy) && - (proto.ByteSize() != rm_.tensor_bytes_); + bool proto_size_changed = + (!can_memcpy) && (proto.ByteSize() != rm_.tensor_bytes_); if (meta_data_changed_ || proto_size_changed) { Clone(in, proto, is_dead); SendMetaData(in, proto, is_dead); @@ -1238,9 +1238,8 @@ void RdmaTensorResponse::SendErrorStatus(const Status& status) { rm.request_index_ = rm_.request_index_; rm.status_ = status; LOG(ERROR) << "Step 0x" << std::hex << rm.step_id_ << std::dec - << ": Sending RDMA_MESSAGE_ERROR_STATUS #" - << rm.request_index_ << ": " << rm.name_ - << ". Status: " << status.ToString(); + << ": Sending RDMA_MESSAGE_ERROR_STATUS #" << rm.request_index_ + << ": " << rm.name_ << ". Status: " << status.ToString(); string message = RdmaMessage::CreateMessage(rm); channel_->tx_message_buffer_->EnqueueItem(message); @@ -1336,14 +1335,13 @@ string RdmaMessage::CreateMessage(const RdmaMessage& rm) { uint32_t gsProtoSize = gsProto.ByteSize(); if (gsProtoSize + 4 > kErrorStatusMaxSize) { LOG(ERROR) << "Error status (" << gsProtoSize + 4 << " bytes) " - << "is too big to fit in RDMA message (" - << kErrorStatusMaxSize << " bytes). Truncated."; + << "is too big to fit in RDMA message (" << kErrorStatusMaxSize + << " bytes). Truncated."; gsProtoSize = kErrorStatusMaxSize - 4; } uint32_t* proto_size = (uint32_t*)&message[kErrorStatusStartIndex]; *proto_size = gsProtoSize; - gsProto.SerializeToArray(&message[kErrorStatusStartIndex + 4], - gsProtoSize); + gsProto.SerializeToArray(&message[kErrorStatusStartIndex + 4], gsProtoSize); message_size += gsProtoSize + 4; } return string(message, message_size); @@ -1393,8 +1391,8 @@ void RdmaMessage::ParseMessage(RdmaMessage& rm, void* buffer) { if (rm.type_ == RDMA_MESSAGE_ERROR_STATUS) { ErrorStatusProto gsProto; uint32_t gsProtoSize = *(uint32_t*)&message[kErrorStatusStartIndex]; - CHECK(ParseProtoUnlimited( - &gsProto, &message[kErrorStatusStartIndex + 4], gsProtoSize)) + CHECK(ParseProtoUnlimited(&gsProto, &message[kErrorStatusStartIndex + 4], + gsProtoSize)) << "Failed to parse error status proto from message. Aborting."; ::grpc::Status gs((::grpc::StatusCode)gsProto.error_code(), gsProto.error_message(), gsProto.error_details()); @@ -1566,8 +1564,8 @@ void RdmaTensorRequest::AllocateTensorsAsync(StatusCallback done) { if (dst_dev_->tensorflow_gpu_device_info() && !on_host && (proxy_tensor_ == nullptr)) { #if GOOGLE_CUDA - // We need to sync the memory allocation on the GPU: - StreamGPUOp(dst_dev_, recv_args_.device_context, done); + // We need to sync the memory allocation on the GPU: + StreamGPUOp(dst_dev_, recv_args_.device_context, done); #endif } else { done(Status::OK()); @@ -1594,9 +1592,8 @@ void RdmaTensorRequest::Send(RdmaMessageType message_type) { rm.rkey_ = (mr_ == nullptr) ? 0 : mr_->rkey; RDMA_LOG(1) << "Step 0x" << std::hex << rm.step_id_ << std::dec - << ": Sending " << MessageTypeToString(message_type) - << " #" << index_ << ": " - << rm.name_ << " on " << rdma_addr_ + << ": Sending " << MessageTypeToString(message_type) << " #" + << index_ << ": " << rm.name_ << " on " << rdma_addr_ << " (rkey: 0x" << std::hex << rm.rkey_ << ")"; string message = RdmaMessage::CreateMessage(rm); @@ -1610,9 +1607,8 @@ void RdmaTensorRequest::RecvTensorMetaData(DataType dtype, TensorShape shape, key_, dtype, shape, is_dead, proto_size); DeallocateTensors(); - AllocateTensorsAsync([this](const Status& s) { - Send(RDMA_MESSAGE_TENSOR_RE_REQUEST); - }); + AllocateTensorsAsync( + [this](const Status& s) { Send(RDMA_MESSAGE_TENSOR_RE_REQUEST); }); } void RdmaTensorRequest::RecvTensorContent() { @@ -1620,8 +1616,8 @@ void RdmaTensorRequest::RecvTensorContent() { size_t message_size = can_memcpy ? result_tensor_->TotalBytes() : meta_data_->proto_size_; RDMA_LOG(1) << "Step 0x" << std::hex << step_id_ << std::dec - << ": Received tensor content #" << index_ << ": " - << key_ << " (Size: 0x" << std::hex << message_size << ")"; + << ": Received tensor content #" << index_ << ": " << key_ + << " (Size: 0x" << std::hex << message_size << ")"; Tensor val; @@ -1667,9 +1663,8 @@ void RdmaTensorRequest::RecvErrorStatus(const Status& status) { void RdmaTensorRequest::Start() { meta_data_ = RdmaMemoryMgr::Singleton().GetTensorMetaData(key_); if (meta_data_ != nullptr) { - AllocateTensorsAsync([this](const Status& s) { - Send(RDMA_MESSAGE_TENSOR_REQUEST); - }); + AllocateTensorsAsync( + [this](const Status& s) { Send(RDMA_MESSAGE_TENSOR_REQUEST); }); } else { Send(RDMA_MESSAGE_TENSOR_REQUEST); } diff --git a/tensorflow/contrib/verbs/rdma.h b/tensorflow/contrib/verbs/rdma.h index 68b3d59f56..b6c41de6ee 100644 --- a/tensorflow/contrib/verbs/rdma.h +++ b/tensorflow/contrib/verbs/rdma.h @@ -73,15 +73,8 @@ struct RemoteMR { uint64_t remote_addr; uint32_t rkey; }; -enum BufferStatus { - none, - idle, - busy -}; -enum Location { - local, - remote -}; +enum BufferStatus { none, idle, busy }; +enum Location { local, remote }; enum RdmaMessageType { RDMA_MESSAGE_META_DATA_UPDATE, diff --git a/tensorflow/contrib/verbs/rdma_mgr.cc b/tensorflow/contrib/verbs/rdma_mgr.cc index f3644af0b4..369bd986df 100644 --- a/tensorflow/contrib/verbs/rdma_mgr.cc +++ b/tensorflow/contrib/verbs/rdma_mgr.cc @@ -116,9 +116,9 @@ void RdmaMgr::SetupChannels() { } CHECK(i == RdmaChannel::kNumMessageBuffers); } else { - LOG(ERROR) << "Connecting to " << worker_name - << ": Got " << s.error_message() << ". Retrying (" - << (attempts + 1) << "/" << max_num_attempts << ")..." ; + LOG(ERROR) << "Connecting to " << worker_name << ": Got " + << s.error_message() << ". Retrying (" << (attempts + 1) + << "/" << max_num_attempts << ")..."; if (++attempts == max_num_attempts) { break; } @@ -159,19 +159,17 @@ bool RdmaMgr::ConnectivityCheck() { ibv_wc_status s = rdma_adapter_->wc_[i].status; // recv complete if ((int)rdma_adapter_->wc_[i].wr_id == RdmaChannel::kPingRecvWrid) { - CHECK(s == IBV_WC_SUCCESS) << ": " << ibv_wc_status_str( - rdma_adapter_->wc_[i].status) - << "(" << rdma_adapter_->wc_[i].status - << ") for PING_RECV_WRID"; + CHECK(s == IBV_WC_SUCCESS) + << ": " << ibv_wc_status_str(rdma_adapter_->wc_[i].status) << "(" + << rdma_adapter_->wc_[i].status << ") for PING_RECV_WRID"; ++rcnt; // send complete } else { RdmaChannel* rc = reinterpret_cast(rdma_adapter_->wc_[i].wr_id); - CHECK(s == IBV_WC_SUCCESS) << ": " << ibv_wc_status_str( - rdma_adapter_->wc_[i].status) - << "(" << rdma_adapter_->wc_[i].status - << ") to " << rc->remote_name_; + CHECK(s == IBV_WC_SUCCESS) + << ": " << ibv_wc_status_str(rdma_adapter_->wc_[i].status) << "(" + << rdma_adapter_->wc_[i].status << ") to " << rc->remote_name_; ++scnt; } } // for @@ -238,8 +236,9 @@ int TryToReadNumaNode(ibv_device* device) { if (strings::safe_strto32(content, &value)) { if (value < 0) { LOG(INFO) << "Successful NUMA node read from SysFS had negative value (" - << value << "), but there must be at least one NUMA node" - ", so returning NUMA node zero"; + << value + << "), but there must be at least one NUMA node" + ", so returning NUMA node zero"; return 0; } LOG(INFO) << "NUMA node for device: " << device->name << " is " << value; @@ -302,8 +301,8 @@ void RdmaMgr::InitAllocators() { &RdmaMemoryMgr::EvictMemoryRegion, &RdmaMemoryMgr::Singleton(), _1, _2); auto* visitable_allocator = dynamic_cast(allocator); - CHECK(visitable_allocator) << "is not visitable for instrumentation" - << allocator->Name(); + CHECK(visitable_allocator) + << "is not visitable for instrumentation" << allocator->Name(); // Make sure we don't instrument the same allocator twice if (instrumented_.find(allocator) == std::end(instrumented_)) { visitable_allocator->AddAllocVisitor(alloc_visitor); diff --git a/tensorflow/core/kernels/mkl_aggregate_ops.cc b/tensorflow/core/kernels/mkl_aggregate_ops.cc index bb5eceab27..89d37d2f87 100644 --- a/tensorflow/core/kernels/mkl_aggregate_ops.cc +++ b/tensorflow/core/kernels/mkl_aggregate_ops.cc @@ -65,13 +65,11 @@ class MklAddNOp : public OpKernel { TensorShape src1_shape, src2_shape; src1_shape = input0.shape(); src2_shape = input1.shape(); - if (!src1_shape.IsSameSize(src2_shape) ){ - ctx->SetStatus( - errors::InvalidArgument( - "Inputs to operation ", this->name(), " of type ", this->type_string(), - " must have the same size and shape. Input 0: ", - src1_shape.DebugString(), " != input 1: ", - src2_shape.DebugString())); + if (!src1_shape.IsSameSize(src2_shape)) { + ctx->SetStatus(errors::InvalidArgument( + "Inputs to operation ", this->name(), " of type ", + this->type_string(), " must have the same size and shape. Input 0: ", + src1_shape.DebugString(), " != input 1: ", src2_shape.DebugString())); } // handle the case of a scalar if (!input1_in_mkl_format && input0.dims() == 0) { @@ -82,17 +80,16 @@ class MklAddNOp : public OpKernel { mkl_context.output_shape); float user_i1 = (input0.scalar()()); float user_i2 = (input1.scalar()()); - out_tensor->scalar()() = - std::plus{}(user_i1, user_i2); + out_tensor->scalar()() = std::plus{}(user_i1, user_i2); return; } mkl_context.in_dims = input1_in_mkl_format - ? mkl_context.input1_shape.GetDimension() - : input0.dims(); + ? mkl_context.input1_shape.GetDimension() + : input0.dims(); mkl_context.in_dims = input2_in_mkl_format - ? mkl_context.input2_shape.GetDimension() - : input1.dims(); + ? mkl_context.input2_shape.GetDimension() + : input1.dims(); // If there is nothing to compute, return. if (!input1_in_mkl_format && !input2_in_mkl_format) { @@ -101,7 +98,7 @@ class MklAddNOp : public OpKernel { Tensor* out_tensor = nullptr; mkl_context.output_shape.SetMklTensor(false); AllocateOutputSetMklShape(ctx, src1_idx, &out_tensor, o_shape, - mkl_context.output_shape); + mkl_context.output_shape); return; } } @@ -110,9 +107,9 @@ class MklAddNOp : public OpKernel { mkl_context.in_strides = new size_t[mkl_context.in_dims]; // Generate size, stride for input if input is in MKL format. if (input1_in_mkl_format || input2_in_mkl_format) { - const MklShape* tmp_mkl_shape = - (input1_in_mkl_format) ? &mkl_context.input1_shape : - &mkl_context.input2_shape; + const MklShape* tmp_mkl_shape = (input1_in_mkl_format) + ? &mkl_context.input1_shape + : &mkl_context.input2_shape; for (int i = 0; i < mkl_context.in_dims; i++) { mkl_context.in_sizes[i] = tmp_mkl_shape->GetSizes()[i]; mkl_context.in_strides[i] = tmp_mkl_shape->GetStrides()[i]; @@ -136,32 +133,33 @@ class MklAddNOp : public OpKernel { Tensor mkl_tmp_input1_buf_tensor, mkl_tmp_input2_buf_tensor; mkl_context.MklPrepareAddNInputs(ctx, &mkl_tmp_input1_buf_tensor, - &mkl_tmp_input2_buf_tensor); + &mkl_tmp_input2_buf_tensor); Tensor* output = nullptr; if (input1_in_mkl_format || input2_in_mkl_format) { - TensorShape tf_shape; - mkl_context.output_shape.SetMklTensor(true); - mkl_context.output_shape.SetMklLayout(mkl_context.Eltwise, dnnResourceDst); - - mkl_context.output_shape.SetTfLayout( - mkl_context.in_dims, mkl_context.in_sizes, mkl_context.in_strides); - if (input1_in_mkl_format == true) { - mkl_context.output_shape.SetTfDimOrder(mkl_context.in_dims, - mkl_context.input1_shape.GetTfToMklDimMap()); - } else { - mkl_context.output_shape.SetTfDimOrder(mkl_context.in_dims, - mkl_context.input2_shape.GetTfToMklDimMap()); - } - tf_shape.AddDim(dnnLayoutGetMemorySize_F32(static_cast( - mkl_context.output_shape.GetMklLayout())) / - sizeof(T)); - - AllocateOutputSetMklShape(ctx, src1_idx, &output, tf_shape, - mkl_context.output_shape); + TensorShape tf_shape; + mkl_context.output_shape.SetMklTensor(true); + mkl_context.output_shape.SetMklLayout(mkl_context.Eltwise, + dnnResourceDst); + + mkl_context.output_shape.SetTfLayout( + mkl_context.in_dims, mkl_context.in_sizes, mkl_context.in_strides); + if (input1_in_mkl_format == true) { + mkl_context.output_shape.SetTfDimOrder( + mkl_context.in_dims, mkl_context.input1_shape.GetTfToMklDimMap()); + } else { + mkl_context.output_shape.SetTfDimOrder( + mkl_context.in_dims, mkl_context.input2_shape.GetTfToMklDimMap()); + } + tf_shape.AddDim(dnnLayoutGetMemorySize_F32(static_cast( + mkl_context.output_shape.GetMklLayout())) / + sizeof(T)); + + AllocateOutputSetMklShape(ctx, src1_idx, &output, tf_shape, + mkl_context.output_shape); } else { - const TensorShape& o_shape = input1.shape(); - mkl_context.output_shape.SetMklTensor(false); - AllocateOutputSetMklShape(ctx, src1_idx, &output, o_shape, + const TensorShape& o_shape = input1.shape(); + mkl_context.output_shape.SetMklTensor(false); + AllocateOutputSetMklShape(ctx, src1_idx, &output, o_shape, mkl_context.output_shape); } @@ -189,18 +187,16 @@ class MklAddNOp : public OpKernel { void MklCreateInputLayouts(OpKernelContext* context) { bool input1_in_mkl_format = input1_shape.IsMklTensor(); if (!input1_in_mkl_format) { - CHECK_EQ( - dnnLayoutCreate_F32(<_input1, in_dims, in_sizes, in_strides), - E_SUCCESS); + CHECK_EQ(dnnLayoutCreate_F32(<_input1, in_dims, in_sizes, in_strides), + E_SUCCESS); } else { lt_input1 = static_cast(input1_shape.GetCurLayout()); } bool input2_in_mkl_format = input2_shape.IsMklTensor(); if (!input2_in_mkl_format) { - CHECK_EQ( - dnnLayoutCreate_F32(<_input2, in_dims, in_sizes, in_strides), - E_SUCCESS); + CHECK_EQ(dnnLayoutCreate_F32(<_input2, in_dims, in_sizes, in_strides), + E_SUCCESS); } else { lt_input2 = static_cast(input2_shape.GetCurLayout()); } @@ -276,14 +272,14 @@ class MklAddNOp : public OpKernel { bool input2_in_mkl_format = input2_shape.IsMklTensor(); dnnDelete_F32(Eltwise); if (!input1_in_mkl_format || !input2_in_mkl_format) { - delete [] in_sizes; - delete [] in_strides; + delete[] in_sizes; + delete[] in_strides; } if (!input1_in_mkl_format) { - dnnLayoutDelete_F32(lt_input1); + dnnLayoutDelete_F32(lt_input1); } if (!input2_in_mkl_format) { - dnnLayoutDelete_F32(lt_input2); + dnnLayoutDelete_F32(lt_input2); } } } MklAddNOpContext; @@ -315,45 +311,44 @@ class MklAddNOp : public OpKernel { GetMklShape(ctx, src2_idx, &src2_mkl_shape); bool input1_in_mkl_format = src1_mkl_shape.IsMklTensor(); bool input2_in_mkl_format = src2_mkl_shape.IsMklTensor(); - int src1_dims_size = input1_in_mkl_format? - src1_mkl_shape.GetDimension(): src1_tensor.dims(); - int src2_dims_size = input2_in_mkl_format? - src2_mkl_shape.GetDimension(): src2_tensor.dims(); + int src1_dims_size = input1_in_mkl_format ? src1_mkl_shape.GetDimension() + : src1_tensor.dims(); + int src2_dims_size = input2_in_mkl_format ? src2_mkl_shape.GetDimension() + : src2_tensor.dims(); // if the shapes of two tensors are not same raise op error TensorShape src1_shape, src2_shape; src1_shape = src1_tensor.shape(); src2_shape = src2_tensor.shape(); - if (!src1_shape.IsSameSize(src2_shape) ){ - ctx->SetStatus( - errors::InvalidArgument( - "Inputs to operation ", this->name(), " of type ", this->type_string(), + if (!src1_shape.IsSameSize(src2_shape)) { + ctx->SetStatus(errors::InvalidArgument( + "Inputs to operation ", this->name(), " of type ", + this->type_string(), " must have the same size and shape. Input 0: ", - src1_shape.DebugString(), " != input 1: ", - src2_shape.DebugString())); + src1_shape.DebugString(), + " != input 1: ", src2_shape.DebugString())); } if (!input1_in_mkl_format && src1_dims_size == 0) { - Tensor* dst_tensor = nullptr; - MklShape mkl_shape_dst; - mkl_shape_dst.SetMklTensor(false); - AllocateOutputSetMklShape(ctx, output_idx, &dst_tensor, - src1_tensor.shape(), mkl_shape_dst); - float user_i1 = (src1_tensor.scalar()()); - float user_i2 = (src2_tensor.scalar()()); - dst_tensor->scalar()() = - std::plus{}(user_i1, user_i2); - return; - } + Tensor* dst_tensor = nullptr; + MklShape mkl_shape_dst; + mkl_shape_dst.SetMklTensor(false); + AllocateOutputSetMklShape(ctx, output_idx, &dst_tensor, + src1_tensor.shape(), mkl_shape_dst); + float user_i1 = (src1_tensor.scalar()()); + float user_i2 = (src2_tensor.scalar()()); + dst_tensor->scalar()() = std::plus{}(user_i1, user_i2); + return; + } // If there is nothing to compute, return. if (!input1_in_mkl_format && !input2_in_mkl_format) { if (src1_tensor.shape().num_elements() == 0) { - Tensor* dst_tensor = nullptr; - MklShape mkl_shape_dst; - mkl_shape_dst.SetMklTensor(false); - AllocateOutputSetMklShape(ctx, output_idx, &dst_tensor, - src1_tensor.shape(), mkl_shape_dst); - return; + Tensor* dst_tensor = nullptr; + MklShape mkl_shape_dst; + mkl_shape_dst.SetMklTensor(false); + AllocateOutputSetMklShape(ctx, output_idx, &dst_tensor, + src1_tensor.shape(), mkl_shape_dst); + return; } } @@ -362,7 +357,7 @@ class MklAddNOp : public OpKernel { MklDnnData src2(&cpu_engine); MklDnnData dst(&cpu_engine); - int tmp_size = input1_in_mkl_format ? src2_dims_size: src1_dims_size; + int tmp_size = input1_in_mkl_format ? src2_dims_size : src1_dims_size; memory::dims dims(tmp_size); memory::dims strides(tmp_size); memory::desc md1({}, memory::data_undef, memory::format_undef); @@ -392,21 +387,19 @@ class MklAddNOp : public OpKernel { md1 = src1_mkl_shape.GetMklLayout(); memory::format src1_mkl_data_format = src1_mkl_shape.GetTfDataFormat(); - auto src1_tf_data_format = MklDnnDataFormatToTFDataFormat( - src1_mkl_data_format); - auto src2_dims = TFShapeToMklDnnDimsInNCHW(src2_tensor.shape(), - src1_tf_data_format); - md2 = memory::desc(src2_dims, MklDnnType(), - src1_mkl_data_format); + auto src1_tf_data_format = + MklDnnDataFormatToTFDataFormat(src1_mkl_data_format); + auto src2_dims = + TFShapeToMklDnnDimsInNCHW(src2_tensor.shape(), src1_tf_data_format); + md2 = memory::desc(src2_dims, MklDnnType(), src1_mkl_data_format); } else if (input2_in_mkl_format && !input1_in_mkl_format) { // Same comment as above. memory::format src2_mkl_data_format = src2_mkl_shape.GetTfDataFormat(); - auto src2_tf_data_format = MklDnnDataFormatToTFDataFormat( - src2_mkl_data_format); - auto src1_dims = TFShapeToMklDnnDimsInNCHW(src1_tensor.shape(), - src2_tf_data_format); - md1 = memory::desc(src1_dims, MklDnnType(), - src2_mkl_data_format); + auto src2_tf_data_format = + MklDnnDataFormatToTFDataFormat(src2_mkl_data_format); + auto src1_dims = + TFShapeToMklDnnDimsInNCHW(src1_tensor.shape(), src2_tf_data_format); + md1 = memory::desc(src1_dims, MklDnnType(), src2_mkl_data_format); md2 = src2_mkl_shape.GetMklLayout(); } else { @@ -480,20 +473,19 @@ class MklAddNOp : public OpKernel { output_mkl_shape.SetMklTensor(false); output_tf_shape = src1_tensor.shape(); } - AllocateOutputSetMklShape(ctx, output_idx, &dst_tensor, - output_tf_shape, output_mkl_shape); + AllocateOutputSetMklShape(ctx, output_idx, &dst_tensor, output_tf_shape, + output_mkl_shape); dst.SetUsrMemDataHandle(dst_tensor); // Create Sum op, and submit net for execution. net.push_back(sum(sum_pd, inputs, dst.GetOpMem())); stream(stream::kind::eager).submit(net).wait(); - } catch (mkldnn::error &e) { + } catch (mkldnn::error& e) { string error_msg = "Status: " + std::to_string(e.status) + - ", message: " + string(e.message) + - ", in file " + string(__FILE__) + ":" + - std::to_string(__LINE__); - OP_REQUIRES_OK(ctx, errors::Aborted("Operation received an exception:", - error_msg)); + ", message: " + string(e.message) + ", in file " + + string(__FILE__) + ":" + std::to_string(__LINE__); + OP_REQUIRES_OK( + ctx, errors::Aborted("Operation received an exception:", error_msg)); } } }; diff --git a/tensorflow/core/kernels/mkl_softmax_op.cc b/tensorflow/core/kernels/mkl_softmax_op.cc index 896d562933..c46eabdde1 100644 --- a/tensorflow/core/kernels/mkl_softmax_op.cc +++ b/tensorflow/core/kernels/mkl_softmax_op.cc @@ -17,13 +17,13 @@ limitations under the License. #ifdef INTEL_MKL #ifdef INTEL_MKL_DNN +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/framework/numeric_op.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/register_types.h" #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/util/tensor_format.h" -#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "mkldnn.h" #include "mkldnn_types.h" @@ -31,16 +31,14 @@ limitations under the License. #include "tensorflow/core/util/mkl_util.h" #include "mkldnn.hpp" -using mkldnn::stream; using mkldnn::prop_kind; using mkldnn::softmax_forward; +using mkldnn::stream; namespace tensorflow { typedef Eigen::ThreadPoolDevice CPUDevice; - - template class MklSoftmaxOp : public OpKernel { public: @@ -60,11 +58,11 @@ class MklSoftmaxOp : public OpKernel { MklDnnShape src_mkl_shape; GetMklShape(context, src_idx, &src_mkl_shape); - // src_dims is the dimenstion of src_tensor // dim of the dst will also be same as src_dims - auto src_tf_shape = src_mkl_shape.IsMklTensor() ? - src_mkl_shape.GetTfShape() : src_tensor.shape(); + auto src_tf_shape = src_mkl_shape.IsMklTensor() + ? src_mkl_shape.GetTfShape() + : src_tensor.shape(); auto src_dims = TFShapeToMklDnnDims(src_tf_shape); auto output_dims = src_dims; @@ -77,10 +75,10 @@ class MklSoftmaxOp : public OpKernel { // construct input Tf layout. For TF layout, although input shape // (src_dims) required is in MKL-DNN order, the layout is Tensorflow's // layout - auto src_md = src_mkl_shape.IsMklTensor() - ? src_mkl_shape.GetMklLayout() - : memory::desc(src_dims, MklDnnType(), - memory::format::nc); + auto src_md = + src_mkl_shape.IsMklTensor() + ? src_mkl_shape.GetMklLayout() + : memory::desc(src_dims, MklDnnType(), memory::format::nc); // src: setting memory descriptor and op memory descriptor // Basically following two functions maps the TF "src_tensor" to mkl @@ -95,8 +93,8 @@ class MklSoftmaxOp : public OpKernel { int axis = 1; // axis to which softmax will be applied auto softmax_fwd_desc = softmax_forward::desc(prop_kind::forward_scoring, src.GetOpMemDesc(), axis); - auto softmax_fwd_pd = softmax_forward::primitive_desc(softmax_fwd_desc, - cpu_engine); + auto softmax_fwd_pd = + softmax_forward::primitive_desc(softmax_fwd_desc, cpu_engine); // add: output Tensor* output_tensor = nullptr; @@ -136,9 +134,9 @@ class MklSoftmaxOp : public OpKernel { net.push_back(softmax_fwd); stream(stream::kind::eager).submit(net).wait(); } catch (mkldnn::error& e) { - string error_msg = "Status: " + std::to_string(e.status) + ", message: " + - string(e.message) + ", in file " + string(__FILE__) + - ":" + std::to_string(__LINE__); + string error_msg = "Status: " + std::to_string(e.status) + + ", message: " + string(e.message) + ", in file " + + string(__FILE__) + ":" + std::to_string(__LINE__); OP_REQUIRES_OK( context, errors::Aborted("Operation received an exception:", error_msg)); @@ -148,7 +146,7 @@ class MklSoftmaxOp : public OpKernel { /* Register DNN kernels for supported operations and supported types - right now * it is only Softmax and f32 */ -#define REGISTER_SOFTMAX_MKL_SUPPORTED_KERNELS_TYPES(type) \ +#define REGISTER_SOFTMAX_MKL_SUPPORTED_KERNELS_TYPES(type) \ REGISTER_KERNEL_BUILDER(Name("_MklSoftmax") \ .Device(DEVICE_CPU) \ .TypeConstraint("T") \ @@ -156,7 +154,6 @@ class MklSoftmaxOp : public OpKernel { MklSoftmaxOp); TF_CALL_float(REGISTER_SOFTMAX_MKL_SUPPORTED_KERNELS_TYPES); - } // namespace tensorflow #endif // INTEL_MKL_DNN diff --git a/tensorflow/core/kernels/spectrogram_test_utils.cc b/tensorflow/core/kernels/spectrogram_test_utils.cc index bc30330d61..872a6e9d1b 100644 --- a/tensorflow/core/kernels/spectrogram_test_utils.cc +++ b/tensorflow/core/kernels/spectrogram_test_utils.cc @@ -72,12 +72,12 @@ bool ReadRawFloatFileToComplexVector( while (offset < end) { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ char arr[4]; - for (int i = 0; i < kBytesPerValue; ++i ) { + for (int i = 0; i < kBytesPerValue; ++i) { arr[3 - i] = *(data_string.data() + offset + i); } memcpy(&real_out, arr, kBytesPerValue); offset += kBytesPerValue; - for (int i = 0; i < kBytesPerValue; ++i ) { + for (int i = 0; i < kBytesPerValue; ++i) { arr[3 - i] = *(data_string.data() + offset + i); } memcpy(&imag_out, arr, kBytesPerValue); diff --git a/tensorflow/core/kernels/transpose_functor_cpu.cc b/tensorflow/core/kernels/transpose_functor_cpu.cc index 6594f7ee7b..5198df7e16 100644 --- a/tensorflow/core/kernels/transpose_functor_cpu.cc +++ b/tensorflow/core/kernels/transpose_functor_cpu.cc @@ -89,17 +89,17 @@ struct Transpose { out); break; case 6: - internal::TransposeUsingEigen(d, in, perm, conjugate, - out); - break; + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + break; case 7: - internal::TransposeUsingEigen(d, in, perm, conjugate, - out); - break; + internal::TransposeUsingEigen(d, in, perm, conjugate, + out); + break; case 8: internal::TransposeUsingEigen(d, in, perm, conjugate, - out); - break; + out); + break; default: TransposeSimple(d, in, perm, out); break; diff --git a/tensorflow/examples/tutorials/word2vec/word2vec_basic.py b/tensorflow/examples/tutorials/word2vec/word2vec_basic.py index 7d1650f05e..f6906b0f79 100644 --- a/tensorflow/examples/tutorials/word2vec/word2vec_basic.py +++ b/tensorflow/examples/tutorials/word2vec/word2vec_basic.py @@ -40,10 +40,10 @@ current_path = os.path.dirname(os.path.realpath(sys.argv[0])) parser = argparse.ArgumentParser() parser.add_argument( - '--log_dir', - type=str, - default=os.path.join(current_path, 'log'), - help='The log directory for TensorBoard summaries.') + '--log_dir', + type=str, + default=os.path.join(current_path, 'log'), + help='The log directory for TensorBoard summaries.') FLAGS, unparsed = parser.parse_known_args() # Create the directory for TensorBoard variables if there is not. @@ -81,6 +81,7 @@ def read_data(filename): data = tf.compat.as_str(f.read(f.namelist()[0])).split() return data + vocabulary = read_data(filename) print('Data size', len(vocabulary)) @@ -106,20 +107,22 @@ def build_dataset(words, n_words): reversed_dictionary = dict(zip(dictionary.values(), dictionary.keys())) return data, count, dictionary, reversed_dictionary + # Filling 4 global variables: # data - list of codes (integers from 0 to vocabulary_size-1). # This is the original text but words are replaced by their codes # count - map of words(strings) to count of occurrences # dictionary - map of words(strings) to their codes(integers) # reverse_dictionary - maps codes(integers) to words(strings) -data, count, dictionary, reverse_dictionary = build_dataset(vocabulary, - vocabulary_size) +data, count, dictionary, reverse_dictionary = build_dataset( + vocabulary, vocabulary_size) del vocabulary # Hint to reduce memory. print('Most common words (+UNK)', count[:5]) print('Sample data', data[:10], [reverse_dictionary[i] for i in data[:10]]) data_index = 0 + # Step 3: Function to generate a training batch for the skip-gram model. def generate_batch(batch_size, num_skips, skip_window): global data_index @@ -149,28 +152,28 @@ def generate_batch(batch_size, num_skips, skip_window): data_index = (data_index + len(data) - span) % len(data) return batch, labels + batch, labels = generate_batch(batch_size=8, num_skips=2, skip_window=1) for i in range(8): - print(batch[i], reverse_dictionary[batch[i]], - '->', labels[i, 0], reverse_dictionary[labels[i, 0]]) + print(batch[i], reverse_dictionary[batch[i]], '->', labels[i, 0], + reverse_dictionary[labels[i, 0]]) # Step 4: Build and train a skip-gram model. batch_size = 128 embedding_size = 128 # Dimension of the embedding vector. -skip_window = 1 # How many words to consider left and right. -num_skips = 2 # How many times to reuse an input to generate a label. -num_sampled = 64 # Number of negative examples to sample. +skip_window = 1 # How many words to consider left and right. +num_skips = 2 # How many times to reuse an input to generate a label. +num_sampled = 64 # Number of negative examples to sample. # We pick a random validation set to sample nearest neighbors. Here we limit the # validation samples to the words that have a low numeric ID, which by # construction are also the most frequent. These 3 variables are used only for # displaying model accuracy, they don't affect calculation. -valid_size = 16 # Random set of words to evaluate similarity on. +valid_size = 16 # Random set of words to evaluate similarity on. valid_window = 100 # Only pick dev samples in the head of the distribution. valid_examples = np.random.choice(valid_window, valid_size, replace=False) - graph = tf.Graph() with graph.as_default(): @@ -192,8 +195,9 @@ with graph.as_default(): # Construct the variables for the NCE loss with tf.name_scope('weights'): nce_weights = tf.Variable( - tf.truncated_normal([vocabulary_size, embedding_size], - stddev=1.0 / math.sqrt(embedding_size))) + tf.truncated_normal( + [vocabulary_size, embedding_size], + stddev=1.0 / math.sqrt(embedding_size))) with tf.name_scope('biases'): nce_biases = tf.Variable(tf.zeros([vocabulary_size])) @@ -204,12 +208,13 @@ with graph.as_default(): # http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/ with tf.name_scope('loss'): loss = tf.reduce_mean( - tf.nn.nce_loss(weights=nce_weights, - biases=nce_biases, - labels=train_labels, - inputs=embed, - num_sampled=num_sampled, - num_classes=vocabulary_size)) + tf.nn.nce_loss( + weights=nce_weights, + biases=nce_biases, + labels=train_labels, + inputs=embed, + num_sampled=num_sampled, + num_classes=vocabulary_size)) # Add the loss value as a scalar to summary. tf.summary.scalar('loss', loss) @@ -221,8 +226,8 @@ with graph.as_default(): # Compute the cosine similarity between minibatch examples and all embeddings. norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True)) normalized_embeddings = embeddings / norm - valid_embeddings = tf.nn.embedding_lookup( - normalized_embeddings, valid_dataset) + valid_embeddings = tf.nn.embedding_lookup(normalized_embeddings, + valid_dataset) similarity = tf.matmul( valid_embeddings, normalized_embeddings, transpose_b=True) @@ -248,8 +253,8 @@ with tf.Session(graph=graph) as session: average_loss = 0 for step in xrange(num_steps): - batch_inputs, batch_labels = generate_batch( - batch_size, num_skips, skip_window) + batch_inputs, batch_labels = generate_batch(batch_size, num_skips, + skip_window) feed_dict = {train_inputs: batch_inputs, train_labels: batch_labels} # Define metadata variable. @@ -259,9 +264,12 @@ with tf.Session(graph=graph) as session: # in the list of returned values for session.run() # Also, evaluate the merged op to get all summaries from the returned "summary" variable. # Feed metadata variable to session for visualizing the graph in TensorBoard. - _, summary, loss_val = session.run([optimizer, merged, loss], feed_dict=feed_dict, run_metadata=run_metadata) + _, summary, loss_val = session.run( + [optimizer, merged, loss], + feed_dict=feed_dict, + run_metadata=run_metadata) average_loss += loss_val - + # Add returned summaries to writer in each step. writer.add_summary(summary, step) # Add metadata to visualize the graph for the last run. @@ -295,7 +303,7 @@ with tf.Session(graph=graph) as session: f.write(reverse_dictionary[i] + '\n') # Save the model for checkpoints. - saver.save(session, os.path.join(FLAGS.log_dir, "model.ckpt")) + saver.save(session, os.path.join(FLAGS.log_dir, 'model.ckpt')) # Create a configuration for visualizing embeddings with the labels in TensorBoard. config = projector.ProjectorConfig() @@ -317,21 +325,24 @@ def plot_with_labels(low_dim_embs, labels, filename): for i, label in enumerate(labels): x, y = low_dim_embs[i, :] plt.scatter(x, y) - plt.annotate(label, - xy=(x, y), - xytext=(5, 2), - textcoords='offset points', - ha='right', - va='bottom') + plt.annotate( + label, + xy=(x, y), + xytext=(5, 2), + textcoords='offset points', + ha='right', + va='bottom') plt.savefig(filename) + try: # pylint: disable=g-import-not-at-top from sklearn.manifold import TSNE import matplotlib.pyplot as plt - tsne = TSNE(perplexity=30, n_components=2, init='pca', n_iter=5000, method='exact') + tsne = TSNE( + perplexity=30, n_components=2, init='pca', n_iter=5000, method='exact') plot_only = 500 low_dim_embs = tsne.fit_transform(final_embeddings[:plot_only, :]) labels = [reverse_dictionary[i] for i in xrange(plot_only)] diff --git a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py index eac1c1960d..bd80b9dbf5 100644 --- a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py @@ -51,8 +51,9 @@ class BatchDatasetTest(test.TestCase): def _map_fn(x, y, z): return math_ops.square(x), math_ops.square(y), math_ops.square(z) - iterator = (dataset_ops.Dataset.from_tensor_slices(components).map(_map_fn) - .repeat(count).batch(batch_size).make_initializable_iterator()) + iterator = ( + dataset_ops.Dataset.from_tensor_slices(components).map(_map_fn) + .repeat(count).batch(batch_size).make_initializable_iterator()) init_op = iterator.initializer get_next = iterator.get_next() @@ -68,7 +69,7 @@ class BatchDatasetTest(test.TestCase): result = sess.run(get_next) for component, result_component in zip(components, result): for j in range(14): - self.assertAllEqual(component[(i*14 + j) % 7]**2, + self.assertAllEqual(component[(i * 14 + j) % 7]**2, result_component[j]) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -83,12 +84,12 @@ class BatchDatasetTest(test.TestCase): result = sess.run(get_next) for component, result_component in zip(components, result): for j in range(8): - self.assertAllEqual(component[(i*8 + j) % 7]**2, + self.assertAllEqual(component[(i * 8 + j) % 7]**2, result_component[j]) result = sess.run(get_next) for component, result_component in zip(components, result): for j in range((14 * 7) % 8): - self.assertAllEqual(component[((num_batches - 1)*8 + j) % 7]**2, + self.assertAllEqual(component[((num_batches - 1) * 8 + j) % 7]**2, result_component[j]) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -189,33 +190,34 @@ class BatchDatasetTest(test.TestCase): sess.run(get_next) def testBatchShapeError(self): + def generator(): yield [1.0, 2.0, 3.0] yield [4.0, 5.0, 6.0] yield [7.0, 8.0, 9.0, 10.0] - iterator = (dataset_ops.Dataset.from_generator(generator, dtypes.float32, - output_shapes=[None]) - .batch(3) - .make_initializable_iterator()) + iterator = ( + dataset_ops.Dataset.from_generator( + generator, dtypes.float32, output_shapes=[None]).batch(3) + .make_initializable_iterator()) next_element = iterator.get_next() with self.test_session() as sess: sess.run(iterator.initializer) with self.assertRaisesRegexp( errors.InvalidArgumentError, - r"Cannot batch tensors with different shapes in component 0. " - r"First element had shape \[3\] and element 2 had shape \[4\]."): + r'Cannot batch tensors with different shapes in component 0. ' + r'First element had shape \[3\] and element 2 had shape \[4\].'): sess.run(next_element) def testPaddedBatchDataset(self): seq_lens = array_ops.placeholder(dtypes.int32, shape=[None]) padded_shape = array_ops.placeholder(dtypes.int64, shape=[1]) - iterator = (dataset_ops.Dataset.from_tensor_slices(seq_lens) - .map(lambda x: array_ops.fill([x], x)).padded_batch( - 4, - padded_shapes=padded_shape).make_initializable_iterator()) + iterator = ( + dataset_ops.Dataset.from_tensor_slices(seq_lens) + .map(lambda x: array_ops.fill([x], x)).padded_batch( + 4, padded_shapes=padded_shape).make_initializable_iterator()) init_op = iterator.initializer get_next = iterator.get_next() @@ -223,35 +225,40 @@ class BatchDatasetTest(test.TestCase): with self.test_session() as sess: # Test with random sequence lengths, and max padding. random_seq_lens = np.random.randint(20, size=(32,)).astype(np.int32) - sess.run(init_op, feed_dict={padded_shape: [-1], - seq_lens: random_seq_lens}) + sess.run( + init_op, feed_dict={ + padded_shape: [-1], + seq_lens: random_seq_lens + }) for i in range(8): result = sess.run(get_next) padded_len = np.max(result) self.assertEqual((4, padded_len), result.shape) for j in range(4): - seq_len = random_seq_lens[(i*4)+j] + seq_len = random_seq_lens[(i * 4) + j] self.assertAllEqual(result[j, :seq_len], [seq_len] * seq_len) self.assertAllEqual(result[j, seq_len:], [0] * (padded_len - seq_len)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) # Test with random sequence lengths, and constant padding. - sess.run(init_op, feed_dict={padded_shape: [25], - seq_lens: random_seq_lens}) + sess.run( + init_op, feed_dict={ + padded_shape: [25], + seq_lens: random_seq_lens + }) for i in range(8): result = sess.run(get_next) self.assertEqual((4, 25), result.shape) for j in range(4): - seq_len = random_seq_lens[(i*4)+j] + seq_len = random_seq_lens[(i * 4) + j] self.assertAllEqual(result[j, :seq_len], [seq_len] * seq_len) self.assertAllEqual(result[j, seq_len:], [0] * (25 - seq_len)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) # Test correct handling of empty tensors. - sess.run(init_op, feed_dict={padded_shape: [-1], - seq_lens: [0, 0, 0, 0]}) + sess.run(init_op, feed_dict={padded_shape: [-1], seq_lens: [0, 0, 0, 0]}) result = sess.run(get_next) self.assertAllEqual([[], [], [], []], result) with self.assertRaises(errors.OutOfRangeError): @@ -259,8 +266,7 @@ class BatchDatasetTest(test.TestCase): # Test error handling with constant sequence lengths, and # too-short padding. - sess.run(init_op, feed_dict={padded_shape: [5], - seq_lens: [6, 5, 5, 5]}) + sess.run(init_op, feed_dict={padded_shape: [5], seq_lens: [6, 5, 5, 5]}) with self.assertRaises(errors.DataLossError): result = sess.run(get_next) @@ -271,11 +277,13 @@ class BatchDatasetTest(test.TestCase): def fill_tuple(x): filled = array_ops.fill([x], x) return (filled, string_ops.as_string(filled)) - iterator = (dataset_ops.Dataset.from_tensor_slices(seq_lens).map(fill_tuple) - .padded_batch( - 4, - padded_shapes=(padded_shape, padded_shape), - padding_values=(-1, "")).make_initializable_iterator()) + + iterator = ( + dataset_ops.Dataset.from_tensor_slices(seq_lens).map(fill_tuple) + .padded_batch( + 4, + padded_shapes=(padded_shape, padded_shape), + padding_values=(-1, '')).make_initializable_iterator()) init_op = iterator.initializer get_next = iterator.get_next() @@ -283,46 +291,46 @@ class BatchDatasetTest(test.TestCase): with self.test_session() as sess: # Test with random sequence lengths, and max padding. random_seq_lens = np.random.randint(20, size=(32,)).astype(np.int32) - sess.run(init_op, feed_dict={padded_shape: [-1], - seq_lens: random_seq_lens}) + sess.run( + init_op, feed_dict={ + padded_shape: [-1], + seq_lens: random_seq_lens + }) for i in range(8): result = sess.run(get_next) padded_len = np.max(result[0]) self.assertEqual((4, padded_len), result[0].shape) self.assertEqual((4, padded_len), result[1].shape) for j in range(4): - seq_len = random_seq_lens[(i*4)+j] + seq_len = random_seq_lens[(i * 4) + j] self.assertAllEqual(result[0][j, :seq_len], [seq_len] * seq_len) self.assertAllEqual(result[0][j, seq_len:], [-1] * (padded_len - seq_len)) self.assertAllEqual(result[1][j, :seq_len], [compat.as_bytes(str(seq_len))] * seq_len) self.assertAllEqual(result[1][j, seq_len:], - [b""] * (padded_len - seq_len)) + [b''] * (padded_len - seq_len)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) def testPaddedBatchDatasetUnicode(self): # See GitHub issue 16149 def generator(): - data = [ - [u'Простой', u'тест', u'юникода'], - [u'никогда', u'не', u'бывает', u'простым']] + data = [[u'Простой', u'тест', u'юникода'], + [u'никогда', u'не', u'бывает', u'простым']] for seq in data: yield seq, [0, 1, 2, 3] dataset = dataset_ops.Dataset.from_generator( - generator, - (dtypes.string, dtypes.int32), + generator, (dtypes.string, dtypes.int32), (tensor_shape.TensorShape([None]), tensor_shape.TensorShape([None]))) - padded_dataset = dataset.padded_batch(2, padded_shapes=([None], [None]), - padding_values=('', 0)) + padded_dataset = dataset.padded_batch( + 2, padded_shapes=([None], [None]), padding_values=('', 0)) with self.test_session() as sess: next_element = padded_dataset.make_one_shot_iterator().get_next() sess.run(next_element) - def testPaddedBatchDatasetShapeSpecifications(self): int_placeholder = array_ops.placeholder(dtypes.int32) float_placeholder = array_ops.placeholder(dtypes.float32) @@ -346,15 +354,16 @@ class BatchDatasetTest(test.TestCase): constant_op.constant([-1, -1], dtype=dtypes.int64), constant_op.constant([37], dtype=dtypes.int64))) - for dataset in [dynamic_padding_from_tensor_shapes, - dynamic_padding_from_lists, - dynamic_padding_from_lists_with_minus_one, - dynamic_padding_from_tensors]: + for dataset in [ + dynamic_padding_from_tensor_shapes, dynamic_padding_from_lists, + dynamic_padding_from_lists_with_minus_one, dynamic_padding_from_tensors + ]: self.assertEqual([None, None], dataset.output_shapes[0].as_list()) self.assertEqual([None, None, None], dataset.output_shapes[1].as_list()) self.assertEqual([None, 37], dataset.output_shapes[2].as_list()) def testPaddedBatchSparseError(self): + def _map_fn(i): return sparse_tensor.SparseTensorValue( indices=[[0, 0]], values=(i * [1]), dense_shape=[1, 1]), i @@ -363,5 +372,5 @@ class BatchDatasetTest(test.TestCase): _ = dataset_ops.Dataset.range(10).map(_map_fn).padded_batch(10) -if __name__ == "__main__": +if __name__ == '__main__': test.main() diff --git a/tensorflow/python/ops/histogram_ops.py b/tensorflow/python/ops/histogram_ops.py index b2de2e5015..f079e56b10 100644 --- a/tensorflow/python/ops/histogram_ops.py +++ b/tensorflow/python/ops/histogram_ops.py @@ -74,7 +74,7 @@ def histogram_fixed_width_bins(values, ``` """ with ops.name_scope(name, 'histogram_fixed_width_bins', - [values, value_range, nbins]) as scope: + [values, value_range, nbins]): values = ops.convert_to_tensor(values, name='values') shape = array_ops.shape(values) @@ -84,9 +84,10 @@ def histogram_fixed_width_bins(values, nbins_float = math_ops.cast(nbins, values.dtype) # Map tensor values that fall within value_range to [0, 1]. - scaled_values = math_ops.truediv(values - value_range[0], - value_range[1] - value_range[0], - name='scaled_values') + scaled_values = math_ops.truediv( + values - value_range[0], + value_range[1] - value_range[0], + name='scaled_values') # map tensor values within the open interval value_range to {0,.., nbins-1}, # values outside the open interval will be zero or less, or nbins or more. @@ -138,5 +139,5 @@ def histogram_fixed_width(values, """ with ops.name_scope(name, 'histogram_fixed_width', [values, value_range, nbins]) as name: - return gen_math_ops._histogram_fixed_width(values, value_range, nbins, - dtype=dtype, name=name) + return gen_math_ops._histogram_fixed_width( # pylint: disable=protected-access + values, value_range, nbins, dtype=dtype, name=name) diff --git a/tensorflow/python/ops/histogram_ops_test.py b/tensorflow/python/ops/histogram_ops_test.py index 80ee090575..a226ac81bb 100644 --- a/tensorflow/python/ops/histogram_ops_test.py +++ b/tensorflow/python/ops/histogram_ops_test.py @@ -36,7 +36,8 @@ class BinValuesFixedWidth(test.TestCase): values = [] expected_bins = [] with self.test_session(): - bins = histogram_ops.histogram_fixed_width_bins(values, value_range, nbins=5) + bins = histogram_ops.histogram_fixed_width_bins( + values, value_range, nbins=5) self.assertEqual(dtypes.int32, bins.dtype) self.assertAllClose(expected_bins, bins.eval()) @@ -69,8 +70,7 @@ class BinValuesFixedWidth(test.TestCase): # (-inf, 1), [1, 2), [2, 3), [3, 4), [4, inf) value_range = [0.0, 5.0] values = constant_op.constant( - [[-1.0, 0.0, 1.5], [2.0, 5.0, 15]], - shape=(2, 3)) + [[-1.0, 0.0, 1.5], [2.0, 5.0, 15]], shape=(2, 3)) expected_bins = [[0, 0, 1], [2, 4, 4]] with self.test_session(): bins = histogram_ops.histogram_fixed_width_bins( @@ -140,8 +140,8 @@ class HistogramFixedWidthTest(test.TestCase): self.assertEqual(dtypes.int32, hist.dtype) self.assertAllClose(expected_bin_counts, hist.eval()) - hist = histogram_ops.histogram_fixed_width(values, value_range, - nbins=placeholder) + hist = histogram_ops.histogram_fixed_width( + values, value_range, nbins=placeholder) self.assertEquals(hist.shape.ndims, 1) self.assertIs(hist.shape[0].value, None) self.assertEqual(dtypes.int32, hist.dtype) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index b713c44717..76da3bed31 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -12,15 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== - """Implementation of image ops.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import os - from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops @@ -28,7 +25,6 @@ from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops -from tensorflow.python.ops import clip_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_image_ops from tensorflow.python.ops import gen_nn_ops @@ -38,7 +34,6 @@ from tensorflow.python.ops import string_ops from tensorflow.python.ops import variables from tensorflow.python.util.tf_export import tf_export - ops.NotDifferentiable('RandomCrop') # TODO(b/31222613): This op may be differentiable, and there may be # latent bugs here. @@ -110,8 +105,9 @@ def _ImageDimensions(image, rank): else: static_shape = image.get_shape().with_rank(rank).as_list() dynamic_shape = array_ops.unstack(array_ops.shape(image), rank) - return [s if s is not None else d - for s, d in zip(static_shape, dynamic_shape)] + return [ + s if s is not None else d for s, d in zip(static_shape, dynamic_shape) + ] def _Check3DImage(image, require_static=True): @@ -132,18 +128,19 @@ def _Check3DImage(image, require_static=True): try: image_shape = image.get_shape().with_rank(3) except ValueError: - raise ValueError("'image' (shape %s) must be three-dimensional." % - image.shape) + raise ValueError( + "'image' (shape %s) must be three-dimensional." % image.shape) if require_static and not image_shape.is_fully_defined(): - raise ValueError("'image' (shape %s) must be fully defined." % - image_shape) + raise ValueError("'image' (shape %s) must be fully defined." % image_shape) if any(x == 0 for x in image_shape): - raise ValueError("all dims of 'image.shape' must be > 0: %s" % - image_shape) + raise ValueError("all dims of 'image.shape' must be > 0: %s" % image_shape) if not image_shape.is_fully_defined(): - return [check_ops.assert_positive(array_ops.shape(image), - ["all dims of 'image.shape' " - "must be > 0."])] + return [ + check_ops.assert_positive( + array_ops.shape(image), + ["all dims of 'image.shape' " + 'must be > 0.']) + ] else: return [] @@ -167,7 +164,7 @@ def _Assert3DImage(image): added that asserts the correct dynamic shape. """ return control_flow_ops.with_dependencies( - _Check3DImage(image, require_static=False), image) + _Check3DImage(image, require_static=False), image) def _CheckAtLeast3DImage(image, require_static=True): @@ -195,12 +192,15 @@ def _CheckAtLeast3DImage(image, require_static=True): if require_static and not image_shape.is_fully_defined(): raise ValueError('\'image\' must be fully defined.') if any(x == 0 for x in image_shape): - raise ValueError('all dims of \'image.shape\' must be > 0: %s' % - image_shape) + raise ValueError( + 'all dims of \'image.shape\' must be > 0: %s' % image_shape) if not image_shape.is_fully_defined(): - return [check_ops.assert_positive(array_ops.shape(image), - ["all dims of 'image.shape' " - "must be > 0."])] + return [ + check_ops.assert_positive( + array_ops.shape(image), + ["all dims of 'image.shape' " + 'must be > 0.']) + ] else: return [] @@ -248,10 +248,11 @@ def random_flip_up_down(image, seed=None): image = _Assert3DImage(image) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) - result = control_flow_ops.cond(mirror_cond, - lambda: array_ops.reverse(image, [0]), - lambda: image, - name=scope) + result = control_flow_ops.cond( + mirror_cond, + lambda: array_ops.reverse(image, [0]), + lambda: image, + name=scope) return fix_image_flip_shape(image, result) @@ -279,10 +280,11 @@ def random_flip_left_right(image, seed=None): image = _Assert3DImage(image) uniform_random = random_ops.random_uniform([], 0, 1.0, seed=seed) mirror_cond = math_ops.less(uniform_random, .5) - result = control_flow_ops.cond(mirror_cond, - lambda: array_ops.reverse(image, [1]), - lambda: image, - name=scope) + result = control_flow_ops.cond( + mirror_cond, + lambda: array_ops.reverse(image, [1]), + lambda: image, + name=scope) return fix_image_flip_shape(image, result) @@ -307,8 +309,8 @@ def flip_left_right(image): with ops.name_scope(None, 'flip_left_right', [image]) as scope: image = ops.convert_to_tensor(image, name='image') image = _Assert3DImage(image) - return fix_image_flip_shape(image, - array_ops.reverse(image, [1], name=scope)) + return fix_image_flip_shape(image, array_ops.reverse( + image, [1], name=scope)) @tf_export('image.flip_up_down') @@ -332,8 +334,8 @@ def flip_up_down(image): with ops.name_scope(None, 'flip_up_down', [image]) as scope: image = ops.convert_to_tensor(image, name='image') image = _Assert3DImage(image) - return fix_image_flip_shape(image, - array_ops.reverse(image, [0], name=scope)) + return fix_image_flip_shape(image, array_ops.reverse( + image, [0], name=scope)) @tf_export('image.rot90') @@ -356,19 +358,19 @@ def rot90(image, k=1, name=None): k = math_ops.mod(k, 4) def _rot90(): - return array_ops.transpose(array_ops.reverse_v2(image, [1]), - [1, 0, 2]) + return array_ops.transpose(array_ops.reverse_v2(image, [1]), [1, 0, 2]) + def _rot180(): return array_ops.reverse_v2(image, [0, 1]) + def _rot270(): - return array_ops.reverse_v2(array_ops.transpose(image, [1, 0, 2]), - [1]) - cases = [(math_ops.equal(k, 1), _rot90), - (math_ops.equal(k, 2), _rot180), + return array_ops.reverse_v2(array_ops.transpose(image, [1, 0, 2]), [1]) + + cases = [(math_ops.equal(k, 1), _rot90), (math_ops.equal(k, 2), _rot180), (math_ops.equal(k, 3), _rot270)] - ret = control_flow_ops.case(cases, default=lambda: image, exclusive=True, - name=scope) + ret = control_flow_ops.case( + cases, default=lambda: image, exclusive=True, name=scope) ret.set_shape([None, None, image.get_shape()[2]]) return ret @@ -518,8 +520,10 @@ def pad_to_bounding_box(image, offset_height, offset_width, target_height, ]), [4, 2]) padded = array_ops.pad(image, paddings) - padded_shape = [None if _is_tensor(i) else i - for i in [batch, target_height, target_width, depth]] + padded_shape = [ + None if _is_tensor(i) else i + for i in [batch, target_height, target_width, depth] + ] padded.set_shape(padded_shape) if not is_batch: @@ -593,12 +597,13 @@ def crop_to_bounding_box(image, offset_height, offset_width, target_height, image = control_flow_ops.with_dependencies(assert_ops, image) cropped = array_ops.slice( - image, - array_ops.stack([0, offset_height, offset_width, 0]), + image, array_ops.stack([0, offset_height, offset_width, 0]), array_ops.stack([-1, target_height, target_width, -1])) - cropped_shape = [None if _is_tensor(i) else i - for i in [batch, target_height, target_width, depth]] + cropped_shape = [ + None if _is_tensor(i) else i + for i in [batch, target_height, target_width, depth] + ] cropped.set_shape(cropped_shape) if not is_batch: @@ -663,8 +668,8 @@ def resize_image_with_crop_or_pad(image, target_height, target_width): target_height = control_flow_ops.with_dependencies( assert_ops, target_height) if _is_tensor(target_width): - target_width = control_flow_ops.with_dependencies( - assert_ops, target_width) + target_width = control_flow_ops.with_dependencies(assert_ops, + target_width) def max_(x, y): if _is_tensor(x) or _is_tensor(y): @@ -709,10 +714,12 @@ def resize_image_with_crop_or_pad(image, target_height, target_width): _, resized_height, resized_width, _ = _ImageDimensions(resized, rank=4) assert_ops = [] - assert_ops += _assert(equal_(resized_height, target_height), ValueError, - 'resized height is not correct.') - assert_ops += _assert(equal_(resized_width, target_width), ValueError, - 'resized width is not correct.') + assert_ops += _assert( + equal_(resized_height, target_height), ValueError, + 'resized height is not correct.') + assert_ops += _assert( + equal_(resized_width, target_width), ValueError, + 'resized width is not correct.') resized = control_flow_ops.with_dependencies(assert_ops, resized) @@ -813,22 +820,17 @@ def resize_images(images, return images if method == ResizeMethod.BILINEAR: - images = gen_image_ops.resize_bilinear(images, - size, - align_corners=align_corners) + images = gen_image_ops.resize_bilinear( + images, size, align_corners=align_corners) elif method == ResizeMethod.NEAREST_NEIGHBOR: - images = gen_image_ops.resize_nearest_neighbor(images, - size, - align_corners= - align_corners) + images = gen_image_ops.resize_nearest_neighbor( + images, size, align_corners=align_corners) elif method == ResizeMethod.BICUBIC: - images = gen_image_ops.resize_bicubic(images, - size, - align_corners=align_corners) + images = gen_image_ops.resize_bicubic( + images, size, align_corners=align_corners) elif method == ResizeMethod.AREA: - images = gen_image_ops.resize_area(images, - size, - align_corners=align_corners) + images = gen_image_ops.resize_area( + images, size, align_corners=align_corners) else: raise ValueError('Resize method is not implemented.') @@ -869,8 +871,9 @@ def per_image_standardization(image): image = math_ops.cast(image, dtype=dtypes.float32) image_mean = math_ops.reduce_mean(image) - variance = (math_ops.reduce_mean(math_ops.square(image)) - - math_ops.square(image_mean)) + variance = ( + math_ops.reduce_mean(math_ops.square(image)) - + math_ops.square(image_mean)) variance = gen_nn_ops.relu(variance) stddev = math_ops.sqrt(variance) @@ -971,9 +974,8 @@ def adjust_brightness(image, delta): orig_dtype = image.dtype flt_image = convert_image_dtype(image, dtypes.float32) - adjusted = math_ops.add(flt_image, - math_ops.cast(delta, dtypes.float32), - name=name) + adjusted = math_ops.add( + flt_image, math_ops.cast(delta, dtypes.float32), name=name) return convert_image_dtype(adjusted, orig_dtype, saturate=True) @@ -1012,9 +1014,8 @@ def adjust_contrast(images, contrast_factor): flt_images = convert_image_dtype(images, dtypes.float32) # pylint: disable=protected-access - adjusted = gen_image_ops._adjust_contrastv2(flt_images, - contrast_factor=contrast_factor, - name=name) + adjusted = gen_image_ops._adjust_contrastv2( + flt_images, contrast_factor=contrast_factor, name=name) # pylint: enable=protected-access return convert_image_dtype(adjusted, orig_dtype, saturate=True) @@ -1061,10 +1062,10 @@ def adjust_gamma(image, gamma=1, gain=1): gamma = control_flow_ops.with_dependencies(assert_op, gamma) # scale = max(dtype) - min(dtype). - scale = constant_op.constant(image.dtype.limits[1] - image.dtype.limits[0], - dtype=dtypes.float32) + scale = constant_op.constant( + image.dtype.limits[1] - image.dtype.limits[0], dtype=dtypes.float32) # According to the definition of gamma correction. - adjusted_img = (img / scale) ** gamma * scale * gain + adjusted_img = (img / scale)**gamma * scale * gain return adjusted_img @@ -1195,9 +1196,8 @@ def grayscale_to_rgb(images, name=None): with ops.name_scope(name, 'grayscale_to_rgb', [images]) as name: images = ops.convert_to_tensor(images, name='images') rank_1 = array_ops.expand_dims(array_ops.rank(images) - 1, 0) - shape_list = ( - [array_ops.ones(rank_1, - dtype=dtypes.int32)] + [array_ops.expand_dims(3, 0)]) + shape_list = ([array_ops.ones(rank_1, dtype=dtypes.int32)] + + [array_ops.expand_dims(3, 0)]) multiples = array_ops.concat(shape_list, 0) rgb = array_ops.tile(images, multiples, name=name) rgb.set_shape(images.get_shape()[:-1].concatenate([3])) @@ -1393,8 +1393,7 @@ def decode_image(contents, channels=None, name=None): gif_channels = 0 if channels is None else channels good_channels = math_ops.logical_and( math_ops.not_equal(gif_channels, 1, name='check_gif_channels'), - math_ops.not_equal(gif_channels, 4, name='check_gif_channels') - ) + math_ops.not_equal(gif_channels, 4, name='check_gif_channels')) channels_msg = 'Channels must be in (None, 0, 3) when decoding GIF images' assert_channels = control_flow_ops.Assert(good_channels, [channels_msg]) with ops.control_dependencies([assert_channels]): @@ -1417,8 +1416,8 @@ def decode_image(contents, channels=None, name=None): def _jpeg(): """Decodes a jpeg image.""" jpeg_channels = 0 if channels is None else channels - good_channels = math_ops.not_equal(jpeg_channels, 4, - name='check_jpeg_channels') + good_channels = math_ops.not_equal( + jpeg_channels, 4, name='check_jpeg_channels') channels_msg = ('Channels must be in (None, 0, 1, 3) when decoding JPEG ' 'images') assert_channels = control_flow_ops.Assert(good_channels, [channels_msg]) @@ -1496,16 +1495,21 @@ def total_variation(images, name=None): # Calculate the total variation by taking the absolute value of the # pixel-differences and summing over the appropriate axis. - tot_var = (math_ops.reduce_sum(math_ops.abs(pixel_dif1), axis=sum_axis) + - math_ops.reduce_sum(math_ops.abs(pixel_dif2), axis=sum_axis)) + tot_var = ( + math_ops.reduce_sum(math_ops.abs(pixel_dif1), axis=sum_axis) + + math_ops.reduce_sum(math_ops.abs(pixel_dif2), axis=sum_axis)) return tot_var @tf_export('image.sample_distorted_bounding_box') -def sample_distorted_bounding_box(image_size, bounding_boxes, seed=None, - seed2=None, min_object_covered=None, - aspect_ratio_range=None, area_range=None, +def sample_distorted_bounding_box(image_size, + bounding_boxes, + seed=None, + seed2=None, + min_object_covered=None, + aspect_ratio_range=None, + area_range=None, max_attempts=None, use_image_if_no_bounding_boxes=None, name=None): @@ -1521,10 +1525,12 @@ def sample_distorted_bounding_box(image_size, bounding_boxes, seed=None, The output of this Op is a single bounding box that may be used to crop the original image. The output is returned as 3 tensors: `begin`, `size` and `bboxes`. The first 2 tensors can be fed directly into `tf.slice` to crop the - image. The latter may be supplied to `tf.image.draw_bounding_boxes` to visualize + image. The latter may be supplied to `tf.image.draw_bounding_boxes` to + visualize what the bounding box looks like. - Bounding boxes are supplied and returned as `[y_min, x_min, y_max, x_max]`. The + Bounding boxes are supplied and returned as `[y_min, x_min, y_max, x_max]`. + The bounding box coordinates are floats in `[0.0, 1.0]` relative to the width and height of the underlying image. @@ -1552,23 +1558,27 @@ def sample_distorted_bounding_box(image_size, bounding_boxes, seed=None, false and no bounding boxes are supplied, an error is raised. Args: - image_size: A `Tensor`. Must be one of the following types: `uint8`, `int8`, `int16`, `int32`, `int64`. + image_size: A `Tensor`. Must be one of the following types: `uint8`, `int8`, + `int16`, `int32`, `int64`. 1-D, containing `[height, width, channels]`. bounding_boxes: A `Tensor` of type `float32`. 3-D with shape `[batch, N, 4]` describing the N bounding boxes associated with the image. seed: An optional `int`. Defaults to `0`. If either `seed` or `seed2` are set to non-zero, the random number - generator is seeded by the given `seed`. Otherwise, it is seeded by a random + generator is seeded by the given `seed`. Otherwise, it is seeded by a + random seed. seed2: An optional `int`. Defaults to `0`. A second seed to avoid seed collision. min_object_covered: A Tensor of type `float32`. Defaults to `0.1`. The cropped area of the image must contain at least this - fraction of any bounding box supplied. The value of this parameter should be + fraction of any bounding box supplied. The value of this parameter should + be non-negative. In the case of 0, the cropped area does not need to overlap any of the bounding boxes supplied. - aspect_ratio_range: An optional list of `floats`. Defaults to `[0.75, 1.33]`. + aspect_ratio_range: An optional list of `floats`. Defaults to `[0.75, + 1.33]`. The cropped area of the image must have an aspect ratio = width / height within this range. area_range: An optional list of `floats`. Defaults to `[0.05, 1]`. @@ -1576,32 +1586,41 @@ def sample_distorted_bounding_box(image_size, bounding_boxes, seed=None, supplied image within in this range. max_attempts: An optional `int`. Defaults to `100`. Number of attempts at generating a cropped region of the image - of the specified constraints. After `max_attempts` failures, return the entire + of the specified constraints. After `max_attempts` failures, return the + entire image. use_image_if_no_bounding_boxes: An optional `bool`. Defaults to `False`. Controls behavior if no bounding boxes supplied. - If true, assume an implicit bounding box covering the whole input. If false, + If true, assume an implicit bounding box covering the whole input. If + false, raise an error. name: A name for the operation (optional). Returns: A tuple of `Tensor` objects (begin, size, bboxes). - begin: A `Tensor`. Has the same type as `image_size`. 1-D, containing `[offset_height, offset_width, 0]`. Provide as input to + begin: A `Tensor`. Has the same type as `image_size`. 1-D, containing + `[offset_height, offset_width, 0]`. Provide as input to `tf.slice`. - size: A `Tensor`. Has the same type as `image_size`. 1-D, containing `[target_height, target_width, -1]`. Provide as input to + size: A `Tensor`. Has the same type as `image_size`. 1-D, containing + `[target_height, target_width, -1]`. Provide as input to `tf.slice`. - bboxes: A `Tensor` of type `float32`. 3-D with shape `[1, 1, 4]` containing the distorted bounding box. + bboxes: A `Tensor` of type `float32`. 3-D with shape `[1, 1, 4]` containing + the distorted bounding box. Provide as input to `tf.image.draw_bounding_boxes`. """ with ops.name_scope(name, 'sample_distorted_bounding_box'): - return gen_image_ops._sample_distorted_bounding_box_v2(image_size, - bounding_boxes, seed=seed, - seed2=seed2, min_object_covered=min_object_covered, - aspect_ratio_range=aspect_ratio_range, area_range=area_range, - max_attempts=max_attempts, - use_image_if_no_bounding_boxes=use_image_if_no_bounding_boxes, - name=name) + return gen_image_ops._sample_distorted_bounding_box_v2( # pylint: disable=protected-access + image_size, + bounding_boxes, + seed=seed, + seed2=seed2, + min_object_covered=min_object_covered, + aspect_ratio_range=aspect_ratio_range, + area_range=area_range, + max_attempts=max_attempts, + use_image_if_no_bounding_boxes=use_image_if_no_bounding_boxes, + name=name) @tf_export('image.non_max_suppression') diff --git a/tensorflow/python/ops/metrics_impl.py b/tensorflow/python/ops/metrics_impl.py index 2d77e26081..7776ff08c4 100644 --- a/tensorflow/python/ops/metrics_impl.py +++ b/tensorflow/python/ops/metrics_impl.py @@ -100,27 +100,29 @@ def _remove_squeezable_dimensions(predictions, labels, weights): # Use dynamic rank. weights_rank_tensor = array_ops.rank(weights) rank_diff = weights_rank_tensor - array_ops.rank(predictions) + def _maybe_expand_weights(): return control_flow_ops.cond( math_ops.equal(rank_diff, -1), - lambda: array_ops.expand_dims(weights, [-1]), - lambda: weights) + lambda: array_ops.expand_dims(weights, [-1]), lambda: weights) + # Don't attempt squeeze if it will fail based on static check. if ((weights_rank is not None) and (not weights_shape.dims[-1].is_compatible_with(1))): maybe_squeeze_weights = lambda: weights else: maybe_squeeze_weights = lambda: array_ops.squeeze(weights, [-1]) + def _maybe_adjust_weights(): return control_flow_ops.cond( - math_ops.equal(rank_diff, 1), - maybe_squeeze_weights, + math_ops.equal(rank_diff, 1), maybe_squeeze_weights, _maybe_expand_weights) + # If weights are scalar, do nothing. Otherwise, try to add or remove a # dimension to match predictions. weights = control_flow_ops.cond( - math_ops.equal(weights_rank_tensor, 0), - lambda: weights, _maybe_adjust_weights) + math_ops.equal(weights_rank_tensor, 0), lambda: weights, + _maybe_adjust_weights) return predictions, labels, weights @@ -165,14 +167,14 @@ def _maybe_expand_labels(labels, predictions): if predictions_rank == labels_rank + 1: return array_ops.expand_dims(labels, -1, name=scope) raise ValueError( - 'Unexpected labels shape %s for predictions shape %s.' % ( - labels.get_shape(), predictions.get_shape())) + 'Unexpected labels shape %s for predictions shape %s.' % + (labels.get_shape(), predictions.get_shape())) # Otherwise, use dynamic shape. return control_flow_ops.cond( - math_ops.equal(array_ops.rank(predictions), array_ops.rank(labels) + 1), - lambda: array_ops.expand_dims(labels, -1, name=scope), - lambda: labels) + math_ops.equal(array_ops.rank(predictions), + array_ops.rank(labels) + 1), + lambda: array_ops.expand_dims(labels, -1, name=scope), lambda: labels) def _safe_div(numerator, denominator, name): @@ -264,8 +266,11 @@ def _streaming_confusion_matrix(labels, predictions, num_classes, weights=None): @tf_export('metrics.mean') -def mean(values, weights=None, metrics_collections=None, - updates_collections=None, name=None): +def mean(values, + weights=None, + metrics_collections=None, + updates_collections=None, + name=None): """Computes the (weighted) mean of the given values. The `mean` function creates two local variables, `total` and `count` @@ -340,8 +345,12 @@ def mean(values, weights=None, metrics_collections=None, @tf_export('metrics.accuracy') -def accuracy(labels, predictions, weights=None, metrics_collections=None, - updates_collections=None, name=None): +def accuracy(labels, + predictions, + weights=None, + metrics_collections=None, + updates_collections=None, + name=None): """Calculates how often `predictions` matches `labels`. The `accuracy` function creates two local variables, `total` and @@ -395,12 +404,15 @@ def accuracy(labels, predictions, weights=None, metrics_collections=None, if labels.dtype != predictions.dtype: predictions = math_ops.cast(predictions, labels.dtype) is_correct = math_ops.to_float(math_ops.equal(predictions, labels)) - return mean(is_correct, weights, metrics_collections, - updates_collections, name or 'accuracy') + return mean(is_correct, weights, metrics_collections, updates_collections, + name or 'accuracy') -def _confusion_matrix_at_thresholds( - labels, predictions, thresholds, weights=None, includes=None): +def _confusion_matrix_at_thresholds(labels, + predictions, + thresholds, + weights=None, + includes=None): """Computes true_positives, false_negatives, true_negatives, false_positives. This function creates up to four local variables, `true_positives`, @@ -498,8 +510,8 @@ def _confusion_matrix_at_thresholds( if weights is not None: weights = weights_broadcast_ops.broadcast_weights( math_ops.to_float(weights), predictions) - weights_tiled = array_ops.tile(array_ops.reshape( - weights, [1, -1]), [num_thresholds, 1]) + weights_tiled = array_ops.tile( + array_ops.reshape(weights, [1, -1]), [num_thresholds, 1]) thresh_tiled.get_shape().assert_is_compatible_with( weights_tiled.get_shape()) else: @@ -515,8 +527,9 @@ def _confusion_matrix_at_thresholds( math_ops.logical_and(label_is_pos, pred_is_pos)) if weights_tiled is not None: is_true_positive *= weights_tiled - update_ops['tp'] = state_ops.assign_add( - true_p, math_ops.reduce_sum(is_true_positive, 1)) + update_ops['tp'] = state_ops.assign_add(true_p, + math_ops.reduce_sum( + is_true_positive, 1)) values['tp'] = true_p if 'fn' in includes: @@ -526,8 +539,9 @@ def _confusion_matrix_at_thresholds( math_ops.logical_and(label_is_pos, pred_is_neg)) if weights_tiled is not None: is_false_negative *= weights_tiled - update_ops['fn'] = state_ops.assign_add( - false_n, math_ops.reduce_sum(is_false_negative, 1)) + update_ops['fn'] = state_ops.assign_add(false_n, + math_ops.reduce_sum( + is_false_negative, 1)) values['fn'] = false_n if 'tn' in includes: @@ -537,8 +551,9 @@ def _confusion_matrix_at_thresholds( math_ops.logical_and(label_is_neg, pred_is_neg)) if weights_tiled is not None: is_true_negative *= weights_tiled - update_ops['tn'] = state_ops.assign_add( - true_n, math_ops.reduce_sum(is_true_negative, 1)) + update_ops['tn'] = state_ops.assign_add(true_n, + math_ops.reduce_sum( + is_true_negative, 1)) values['tn'] = true_n if 'fp' in includes: @@ -548,17 +563,24 @@ def _confusion_matrix_at_thresholds( math_ops.logical_and(label_is_neg, pred_is_pos)) if weights_tiled is not None: is_false_positive *= weights_tiled - update_ops['fp'] = state_ops.assign_add( - false_p, math_ops.reduce_sum(is_false_positive, 1)) + update_ops['fp'] = state_ops.assign_add(false_p, + math_ops.reduce_sum( + is_false_positive, 1)) values['fp'] = false_p return values, update_ops @tf_export('metrics.auc') -def auc(labels, predictions, weights=None, num_thresholds=200, - metrics_collections=None, updates_collections=None, - curve='ROC', name=None, summation_method='trapezoidal'): +def auc(labels, + predictions, + weights=None, + num_thresholds=200, + metrics_collections=None, + updates_collections=None, + curve='ROC', + name=None, + summation_method='trapezoidal'): """Computes the approximate AUC via a Riemann sum. The `auc` function creates four local variables, `true_positives`, @@ -626,14 +648,14 @@ def auc(labels, predictions, weights=None, num_thresholds=200, raise RuntimeError('tf.metrics.auc is not supported when eager execution ' 'is enabled.') - with variable_scope.variable_scope( - name, 'auc', (labels, predictions, weights)): + with variable_scope.variable_scope(name, 'auc', + (labels, predictions, weights)): if curve != 'ROC' and curve != 'PR': - raise ValueError('curve must be either ROC or PR, %s unknown' % - (curve)) + raise ValueError('curve must be either ROC or PR, %s unknown' % (curve)) kepsilon = 1e-7 # to account for floating point imprecisions - thresholds = [(i + 1) * 1.0 / (num_thresholds - 1) - for i in range(num_thresholds-2)] + thresholds = [ + (i + 1) * 1.0 / (num_thresholds - 1) for i in range(num_thresholds - 2) + ] thresholds = [0.0 - kepsilon] + thresholds + [1.0 + kepsilon] values, update_ops = _confusion_matrix_at_thresholds( @@ -641,6 +663,7 @@ def auc(labels, predictions, weights=None, num_thresholds=200, # Add epsilons to avoid dividing by 0. epsilon = 1.0e-6 + def compute_auc(tp, fn, tn, fp, name): """Computes the roc-auc or pr-auc based on confusion counts.""" rec = math_ops.div(tp + epsilon, tp + fn + epsilon) @@ -671,11 +694,10 @@ def auc(labels, predictions, weights=None, num_thresholds=200, raise ValueError('Invalid summation_method: %s' % summation_method) # sum up the areas of all the trapeziums - auc_value = compute_auc( - values['tp'], values['fn'], values['tn'], values['fp'], 'value') - update_op = compute_auc( - update_ops['tp'], update_ops['fn'], update_ops['tn'], update_ops['fp'], - 'update_op') + auc_value = compute_auc(values['tp'], values['fn'], values['tn'], + values['fp'], 'value') + update_op = compute_auc(update_ops['tp'], update_ops['fn'], + update_ops['tn'], update_ops['fp'], 'update_op') if metrics_collections: ops.add_to_collections(metrics_collections, auc_value) @@ -687,7 +709,9 @@ def auc(labels, predictions, weights=None, num_thresholds=200, @tf_export('metrics.mean_absolute_error') -def mean_absolute_error(labels, predictions, weights=None, +def mean_absolute_error(labels, + predictions, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -746,7 +770,10 @@ def mean_absolute_error(labels, predictions, weights=None, @tf_export('metrics.mean_cosine_distance') -def mean_cosine_distance(labels, predictions, dim, weights=None, +def mean_cosine_distance(labels, + predictions, + dim, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -802,10 +829,8 @@ def mean_cosine_distance(labels, predictions, dim, weights=None, radial_diffs, reduction_indices=[ dim, ], keepdims=True) - mean_distance, update_op = mean(radial_diffs, weights, - None, - None, - name or 'mean_cosine_distance') + mean_distance, update_op = mean(radial_diffs, weights, None, None, name or + 'mean_cosine_distance') mean_distance = math_ops.subtract(1.0, mean_distance) update_op = math_ops.subtract(1.0, update_op) @@ -906,8 +931,8 @@ def mean_per_class_accuracy(labels, per_class_accuracy = _safe_div(count, total, None) - mean_accuracy_v = math_ops.reduce_mean(per_class_accuracy, - name='mean_accuracy') + mean_accuracy_v = math_ops.reduce_mean( + per_class_accuracy, name='mean_accuracy') update_op = _safe_div(update_count_op, update_total_op, name='update_op') if metrics_collections: @@ -975,13 +1000,14 @@ def mean_iou(labels, raise RuntimeError('tf.metrics.mean_iou is not supported when ' 'eager execution is enabled.') - with variable_scope.variable_scope( - name, 'mean_iou', (predictions, labels, weights)): + with variable_scope.variable_scope(name, 'mean_iou', + (predictions, labels, weights)): # Check if shape is compatible. predictions.get_shape().assert_is_compatible_with(labels.get_shape()) total_cm, update_op = _streaming_confusion_matrix(labels, predictions, num_classes, weights) + def compute_mean_iou(name): """Compute the mean intersection-over-union via the confusion matrix.""" sum_over_row = math_ops.to_float(math_ops.reduce_sum(total_cm, 0)) @@ -992,22 +1018,21 @@ def mean_iou(labels, # The mean is only computed over classes that appear in the # label or prediction tensor. If the denominator is 0, we need to # ignore the class. - num_valid_entries = math_ops.reduce_sum(math_ops.cast( - math_ops.not_equal(denominator, 0), dtype=dtypes.float32)) + num_valid_entries = math_ops.reduce_sum( + math_ops.cast( + math_ops.not_equal(denominator, 0), dtype=dtypes.float32)) # If the value of the denominator is 0, set it to 1 to avoid # zero division. denominator = array_ops.where( - math_ops.greater(denominator, 0), - denominator, + math_ops.greater(denominator, 0), denominator, array_ops.ones_like(denominator)) iou = math_ops.div(cm_diag, denominator) # If the number of valid entries is 0 (no classes) we return 0. result = array_ops.where( math_ops.greater(num_valid_entries, 0), - math_ops.reduce_sum(iou, name=name) / num_valid_entries, - 0) + math_ops.reduce_sum(iou, name=name) / num_valid_entries, 0) return result mean_iou_v = compute_mean_iou('mean_iou') @@ -1022,7 +1047,10 @@ def mean_iou(labels, @tf_export('metrics.mean_relative_error') -def mean_relative_error(labels, predictions, normalizer, weights=None, +def mean_relative_error(labels, + predictions, + normalizer, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1081,15 +1109,16 @@ def mean_relative_error(labels, predictions, normalizer, weights=None, predictions, normalizer) predictions.get_shape().assert_is_compatible_with(normalizer.get_shape()) relative_errors = array_ops.where( - math_ops.equal(normalizer, 0.0), - array_ops.zeros_like(labels), + math_ops.equal(normalizer, 0.0), array_ops.zeros_like(labels), math_ops.div(math_ops.abs(labels - predictions), normalizer)) return mean(relative_errors, weights, metrics_collections, updates_collections, name or 'mean_relative_error') @tf_export('metrics.mean_squared_error') -def mean_squared_error(labels, predictions, weights=None, +def mean_squared_error(labels, + predictions, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1143,13 +1172,16 @@ def mean_squared_error(labels, predictions, weights=None, predictions, labels, weights = _remove_squeezable_dimensions( predictions=predictions, labels=labels, weights=weights) squared_error = math_ops.square(labels - predictions) - return mean(squared_error, weights, metrics_collections, - updates_collections, name or 'mean_squared_error') + return mean(squared_error, weights, metrics_collections, updates_collections, + name or 'mean_squared_error') @tf_export('metrics.mean_tensor') -def mean_tensor(values, weights=None, metrics_collections=None, - updates_collections=None, name=None): +def mean_tensor(values, + weights=None, + metrics_collections=None, + updates_collections=None, + name=None): """Computes the element-wise (weighted) mean of the given tensors. In contrast to the `mean` function which returns a scalar with the @@ -1216,9 +1248,8 @@ def mean_tensor(values, weights=None, metrics_collections=None, update_count_op = state_ops.assign_add(count, num_values) def compute_mean(total, count, name): - non_zero_count = math_ops.maximum(count, - array_ops.ones_like(count), - name=name) + non_zero_count = math_ops.maximum( + count, array_ops.ones_like(count), name=name) return math_ops.truediv(total, non_zero_count, name=name) mean_t = compute_mean(total, count, 'value') @@ -1234,7 +1265,9 @@ def mean_tensor(values, weights=None, metrics_collections=None, @tf_export('metrics.percentage_below') -def percentage_below(values, threshold, weights=None, +def percentage_below(values, + threshold, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1281,14 +1314,13 @@ def percentage_below(values, threshold, weights=None, 'eager execution is enabled.') is_below_threshold = math_ops.to_float(math_ops.less(values, threshold)) - return mean(is_below_threshold, - weights, - metrics_collections, - updates_collections, - name or 'percentage_below_threshold') + return mean(is_below_threshold, weights, metrics_collections, + updates_collections, name or 'percentage_below_threshold') -def _count_condition(values, weights=None, metrics_collections=None, +def _count_condition(values, + weights=None, + metrics_collections=None, updates_collections=None): """Sums the weights of cases where the given values are True. @@ -1318,8 +1350,8 @@ def _count_condition(values, weights=None, metrics_collections=None, values = math_ops.to_float(values) if weights is not None: - with ops.control_dependencies(( - check_ops.assert_rank_in(weights, (0, array_ops.rank(values))),)): + with ops.control_dependencies((check_ops.assert_rank_in( + weights, (0, array_ops.rank(values))),)): weights = math_ops.to_float(weights) values = math_ops.multiply(values, weights) @@ -1336,7 +1368,9 @@ def _count_condition(values, weights=None, metrics_collections=None, @tf_export('metrics.false_negatives') -def false_negatives(labels, predictions, weights=None, +def false_negatives(labels, + predictions, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1372,21 +1406,24 @@ def false_negatives(labels, predictions, weights=None, raise RuntimeError('tf.metrics.false_negatives is not supported when ' 'eager execution is enabled.') - with variable_scope.variable_scope( - name, 'false_negatives', (predictions, labels, weights)): + with variable_scope.variable_scope(name, 'false_negatives', + (predictions, labels, weights)): predictions, labels, weights = _remove_squeezable_dimensions( predictions=math_ops.cast(predictions, dtype=dtypes.bool), labels=math_ops.cast(labels, dtype=dtypes.bool), weights=weights) - is_false_negative = math_ops.logical_and(math_ops.equal(labels, True), - math_ops.equal(predictions, False)) + is_false_negative = math_ops.logical_and( + math_ops.equal(labels, True), math_ops.equal(predictions, False)) return _count_condition(is_false_negative, weights, metrics_collections, updates_collections) @tf_export('metrics.false_negatives_at_thresholds') -def false_negatives_at_thresholds(labels, predictions, thresholds, weights=None, +def false_negatives_at_thresholds(labels, + predictions, + thresholds, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1440,7 +1477,9 @@ def false_negatives_at_thresholds(labels, predictions, thresholds, weights=None, @tf_export('metrics.false_positives') -def false_positives(labels, predictions, weights=None, +def false_positives(labels, + predictions, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1477,21 +1516,24 @@ def false_positives(labels, predictions, weights=None, raise RuntimeError('tf.metrics.false_positives is not supported when ' 'eager execution is enabled.') - with variable_scope.variable_scope( - name, 'false_positives', (predictions, labels, weights)): + with variable_scope.variable_scope(name, 'false_positives', + (predictions, labels, weights)): predictions, labels, weights = _remove_squeezable_dimensions( predictions=math_ops.cast(predictions, dtype=dtypes.bool), labels=math_ops.cast(labels, dtype=dtypes.bool), weights=weights) - is_false_positive = math_ops.logical_and(math_ops.equal(labels, False), - math_ops.equal(predictions, True)) + is_false_positive = math_ops.logical_and( + math_ops.equal(labels, False), math_ops.equal(predictions, True)) return _count_condition(is_false_positive, weights, metrics_collections, updates_collections) @tf_export('metrics.false_positives_at_thresholds') -def false_positives_at_thresholds(labels, predictions, thresholds, weights=None, +def false_positives_at_thresholds(labels, + predictions, + thresholds, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1545,7 +1587,9 @@ def false_positives_at_thresholds(labels, predictions, thresholds, weights=None, @tf_export('metrics.true_negatives') -def true_negatives(labels, predictions, weights=None, +def true_negatives(labels, + predictions, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1582,21 +1626,24 @@ def true_negatives(labels, predictions, weights=None, raise RuntimeError('tf.metrics.true_negatives is not ' 'supported when eager execution is enabled.') - with variable_scope.variable_scope( - name, 'true_negatives', (predictions, labels, weights)): + with variable_scope.variable_scope(name, 'true_negatives', + (predictions, labels, weights)): predictions, labels, weights = _remove_squeezable_dimensions( predictions=math_ops.cast(predictions, dtype=dtypes.bool), labels=math_ops.cast(labels, dtype=dtypes.bool), weights=weights) - is_true_negative = math_ops.logical_and(math_ops.equal(labels, False), - math_ops.equal(predictions, False)) + is_true_negative = math_ops.logical_and( + math_ops.equal(labels, False), math_ops.equal(predictions, False)) return _count_condition(is_true_negative, weights, metrics_collections, updates_collections) @tf_export('metrics.true_negatives_at_thresholds') -def true_negatives_at_thresholds(labels, predictions, thresholds, weights=None, +def true_negatives_at_thresholds(labels, + predictions, + thresholds, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1650,7 +1697,9 @@ def true_negatives_at_thresholds(labels, predictions, thresholds, weights=None, @tf_export('metrics.true_positives') -def true_positives(labels, predictions, weights=None, +def true_positives(labels, + predictions, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1687,21 +1736,24 @@ def true_positives(labels, predictions, weights=None, raise RuntimeError('tf.metrics.true_positives is not ' 'supported when eager execution is enabled.') - with variable_scope.variable_scope( - name, 'true_positives', (predictions, labels, weights)): + with variable_scope.variable_scope(name, 'true_positives', + (predictions, labels, weights)): predictions, labels, weights = _remove_squeezable_dimensions( predictions=math_ops.cast(predictions, dtype=dtypes.bool), labels=math_ops.cast(labels, dtype=dtypes.bool), weights=weights) - is_true_positive = math_ops.logical_and(math_ops.equal(labels, True), - math_ops.equal(predictions, True)) + is_true_positive = math_ops.logical_and( + math_ops.equal(labels, True), math_ops.equal(predictions, True)) return _count_condition(is_true_positive, weights, metrics_collections, updates_collections) @tf_export('metrics.true_positives_at_thresholds') -def true_positives_at_thresholds(labels, predictions, thresholds, weights=None, +def true_positives_at_thresholds(labels, + predictions, + thresholds, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -1755,8 +1807,11 @@ def true_positives_at_thresholds(labels, predictions, thresholds, weights=None, @tf_export('metrics.precision') -def precision(labels, predictions, weights=None, - metrics_collections=None, updates_collections=None, +def precision(labels, + predictions, + weights=None, + metrics_collections=None, + updates_collections=None, name=None): """Computes the precision of the predictions with respect to the labels. @@ -1805,8 +1860,8 @@ def precision(labels, predictions, weights=None, raise RuntimeError('tf.metrics.precision is not ' 'supported when eager execution is enabled.') - with variable_scope.variable_scope( - name, 'precision', (predictions, labels, weights)): + with variable_scope.variable_scope(name, 'precision', + (predictions, labels, weights)): predictions, labels, weights = _remove_squeezable_dimensions( predictions=math_ops.cast(predictions, dtype=dtypes.bool), @@ -1814,22 +1869,27 @@ def precision(labels, predictions, weights=None, weights=weights) true_p, true_positives_update_op = true_positives( - labels, predictions, weights, metrics_collections=None, - updates_collections=None, name=None) + labels, + predictions, + weights, + metrics_collections=None, + updates_collections=None, + name=None) false_p, false_positives_update_op = false_positives( - labels, predictions, weights, metrics_collections=None, - updates_collections=None, name=None) + labels, + predictions, + weights, + metrics_collections=None, + updates_collections=None, + name=None) def compute_precision(tp, fp, name): return array_ops.where( - math_ops.greater(tp + fp, 0), - math_ops.div(tp, tp + fp), - 0, - name) + math_ops.greater(tp + fp, 0), math_ops.div(tp, tp + fp), 0, name) p = compute_precision(true_p, false_p, 'value') - update_op = compute_precision( - true_positives_update_op, false_positives_update_op, 'update_op') + update_op = compute_precision(true_positives_update_op, + false_positives_update_op, 'update_op') if metrics_collections: ops.add_to_collections(metrics_collections, p) @@ -1841,10 +1901,13 @@ def precision(labels, predictions, weights=None, @tf_export('metrics.precision_at_thresholds') -def precision_at_thresholds(labels, predictions, thresholds, +def precision_at_thresholds(labels, + predictions, + thresholds, weights=None, metrics_collections=None, - updates_collections=None, name=None): + updates_collections=None, + name=None): """Computes precision values for different `thresholds` on `predictions`. The `precision_at_thresholds` function creates four local variables, @@ -1900,12 +1963,13 @@ def precision_at_thresholds(labels, predictions, thresholds, # Avoid division by zero. epsilon = 1e-7 + def compute_precision(tp, fp, name): return math_ops.div(tp, epsilon + tp + fp, name='precision_' + name) prec = compute_precision(values['tp'], values['fp'], 'value') - update_op = compute_precision( - update_ops['tp'], update_ops['fp'], 'update_op') + update_op = compute_precision(update_ops['tp'], update_ops['fp'], + 'update_op') if metrics_collections: ops.add_to_collections(metrics_collections, prec) @@ -1917,8 +1981,11 @@ def precision_at_thresholds(labels, predictions, thresholds, @tf_export('metrics.recall') -def recall(labels, predictions, weights=None, - metrics_collections=None, updates_collections=None, +def recall(labels, + predictions, + weights=None, + metrics_collections=None, + updates_collections=None, name=None): """Computes the recall of the predictions with respect to the labels. @@ -1965,30 +2032,36 @@ def recall(labels, predictions, weights=None, raise RuntimeError('tf.metrics.recall is not supported is not ' 'supported when eager execution is enabled.') - with variable_scope.variable_scope( - name, 'recall', (predictions, labels, weights)): + with variable_scope.variable_scope(name, 'recall', + (predictions, labels, weights)): predictions, labels, weights = _remove_squeezable_dimensions( predictions=math_ops.cast(predictions, dtype=dtypes.bool), labels=math_ops.cast(labels, dtype=dtypes.bool), weights=weights) true_p, true_positives_update_op = true_positives( - labels, predictions, weights, metrics_collections=None, - updates_collections=None, name=None) + labels, + predictions, + weights, + metrics_collections=None, + updates_collections=None, + name=None) false_n, false_negatives_update_op = false_negatives( - labels, predictions, weights, metrics_collections=None, - updates_collections=None, name=None) + labels, + predictions, + weights, + metrics_collections=None, + updates_collections=None, + name=None) def compute_recall(true_p, false_n, name): return array_ops.where( math_ops.greater(true_p + false_n, 0), - math_ops.div(true_p, true_p + false_n), - 0, - name) + math_ops.div(true_p, true_p + false_n), 0, name) rec = compute_recall(true_p, false_n, 'value') - update_op = compute_recall( - true_positives_update_op, false_negatives_update_op, 'update_op') + update_op = compute_recall(true_positives_update_op, + false_negatives_update_op, 'update_op') if metrics_collections: ops.add_to_collections(metrics_collections, rec) @@ -2022,8 +2095,8 @@ def _select_class_id(ids, selected_id): """ ids = sparse_tensor.convert_to_tensor_or_sparse_tensor(ids) if isinstance(ids, sparse_tensor.SparseTensor): - return sparse_ops.sparse_retain( - ids, math_ops.equal(ids.values, selected_id)) + return sparse_ops.sparse_retain(ids, math_ops.equal(ids.values, + selected_id)) # TODO(ptucker): Make this more efficient, maybe add a sparse version of # tf.equal and tf.reduce_any? @@ -2031,12 +2104,13 @@ def _select_class_id(ids, selected_id): # Shape of filled IDs is the same as `ids` with the last dim collapsed to 1. ids_shape = array_ops.shape(ids, out_type=dtypes.int64) ids_last_dim = array_ops.size(ids_shape) - 1 - filled_selected_id_shape = math_ops.reduced_shape( - ids_shape, array_ops.reshape(ids_last_dim, [1])) + filled_selected_id_shape = math_ops.reduced_shape(ids_shape, + array_ops.reshape( + ids_last_dim, [1])) # Intersect `ids` with the selected ID. - filled_selected_id = array_ops.fill( - filled_selected_id_shape, math_ops.to_int64(selected_id)) + filled_selected_id = array_ops.fill(filled_selected_id_shape, + math_ops.to_int64(selected_id)) result = sets.set_intersection(filled_selected_id, ids) return sparse_tensor.SparseTensor( indices=result.indices, values=result.values, dense_shape=ids_shape) @@ -2096,15 +2170,15 @@ def _sparse_true_positive_at_k(labels, Returns: A [D1, ... DN] `Tensor` of true positive counts. """ - with ops.name_scope( - name, 'true_positives', (predictions_idx, labels, weights)): - labels, predictions_idx = _maybe_select_class_id( - labels, predictions_idx, class_id) + with ops.name_scope(name, 'true_positives', + (predictions_idx, labels, weights)): + labels, predictions_idx = _maybe_select_class_id(labels, predictions_idx, + class_id) tp = sets.set_size(sets.set_intersection(predictions_idx, labels)) tp = math_ops.to_double(tp) if weights is not None: - with ops.control_dependencies(( - weights_broadcast_ops.assert_broadcastable(weights, tp),)): + with ops.control_dependencies((weights_broadcast_ops.assert_broadcastable( + weights, tp),)): weights = math_ops.to_double(weights) tp = math_ops.multiply(tp, weights) return tp @@ -2148,11 +2222,12 @@ def _streaming_sparse_true_positive_at_k(labels, Raises: ValueError: If `weights` is not `None` and has an incompatible shape. """ - with ops.name_scope( - name, _at_k_name('true_positive', k, class_id=class_id), - (predictions_idx, labels, weights)) as scope: + with ops.name_scope(name, _at_k_name('true_positive', k, class_id=class_id), + (predictions_idx, labels, weights)) as scope: tp = _sparse_true_positive_at_k( - predictions_idx=predictions_idx, labels=labels, class_id=class_id, + predictions_idx=predictions_idx, + labels=labels, + class_id=class_id, weights=weights) batch_total_tp = math_ops.to_double(math_ops.reduce_sum(tp)) @@ -2189,18 +2264,16 @@ def _sparse_false_negative_at_k(labels, Returns: A [D1, ... DN] `Tensor` of false negative counts. """ - with ops.name_scope( - None, 'false_negatives', (predictions_idx, labels, weights)): - labels, predictions_idx = _maybe_select_class_id(labels, - predictions_idx, + with ops.name_scope(None, 'false_negatives', + (predictions_idx, labels, weights)): + labels, predictions_idx = _maybe_select_class_id(labels, predictions_idx, class_id) - fn = sets.set_size(sets.set_difference(predictions_idx, - labels, - aminusb=False)) + fn = sets.set_size( + sets.set_difference(predictions_idx, labels, aminusb=False)) fn = math_ops.to_double(fn) if weights is not None: - with ops.control_dependencies(( - weights_broadcast_ops.assert_broadcastable(weights, fn),)): + with ops.control_dependencies((weights_broadcast_ops.assert_broadcastable( + weights, fn),)): weights = math_ops.to_double(weights) fn = math_ops.multiply(fn, weights) return fn @@ -2244,11 +2317,12 @@ def _streaming_sparse_false_negative_at_k(labels, Raises: ValueError: If `weights` is not `None` and has an incompatible shape. """ - with ops.name_scope( - name, _at_k_name('false_negative', k, class_id=class_id), - (predictions_idx, labels, weights)) as scope: + with ops.name_scope(name, _at_k_name('false_negative', k, class_id=class_id), + (predictions_idx, labels, weights)) as scope: fn = _sparse_false_negative_at_k( - predictions_idx=predictions_idx, labels=labels, class_id=class_id, + predictions_idx=predictions_idx, + labels=labels, + class_id=class_id, weights=weights) batch_total_fn = math_ops.to_double(math_ops.reduce_sum(fn)) @@ -2335,9 +2409,8 @@ def recall_at_k(labels, raise RuntimeError('tf.metrics.recall_at_k is not ' 'supported when eager execution is enabled.') - with ops.name_scope( - name, _at_k_name('recall', k, class_id=class_id), - (predictions, labels, weights)) as scope: + with ops.name_scope(name, _at_k_name('recall', k, class_id=class_id), + (predictions, labels, weights)) as scope: _, top_k_idx = nn.top_k(predictions, k) return recall_at_top_k( labels=labels, @@ -2404,16 +2477,21 @@ def recall_at_top_k(labels, `predictions`, or if either `metrics_collections` or `updates_collections` are not a list or tuple. """ - with ops.name_scope(name, - _at_k_name('recall', k, class_id=class_id), + with ops.name_scope(name, _at_k_name('recall', k, class_id=class_id), (predictions_idx, labels, weights)) as scope: labels = _maybe_expand_labels(labels, predictions_idx) top_k_idx = math_ops.to_int64(predictions_idx) tp, tp_update = _streaming_sparse_true_positive_at_k( - predictions_idx=top_k_idx, labels=labels, k=k, class_id=class_id, + predictions_idx=top_k_idx, + labels=labels, + k=k, + class_id=class_id, weights=weights) fn, fn_update = _streaming_sparse_false_negative_at_k( - predictions_idx=top_k_idx, labels=labels, k=k, class_id=class_id, + predictions_idx=top_k_idx, + labels=labels, + k=k, + class_id=class_id, weights=weights) metric = math_ops.div(tp, math_ops.add(tp, fn), name=scope) @@ -2427,9 +2505,13 @@ def recall_at_top_k(labels, @tf_export('metrics.recall_at_thresholds') -def recall_at_thresholds(labels, predictions, thresholds, - weights=None, metrics_collections=None, - updates_collections=None, name=None): +def recall_at_thresholds(labels, + predictions, + thresholds, + weights=None, + metrics_collections=None, + updates_collections=None, + name=None): """Computes various recall values for different `thresholds` on `predictions`. The `recall_at_thresholds` function creates four local variables, @@ -2483,6 +2565,7 @@ def recall_at_thresholds(labels, predictions, thresholds, # Avoid division by zero. epsilon = 1e-7 + def compute_recall(tp, fn, name): return math_ops.div(tp, epsilon + tp + fn, name='recall_' + name) @@ -2499,7 +2582,9 @@ def recall_at_thresholds(labels, predictions, thresholds, @tf_export('metrics.root_mean_squared_error') -def root_mean_squared_error(labels, predictions, weights=None, +def root_mean_squared_error(labels, + predictions, + weights=None, metrics_collections=None, updates_collections=None, name=None): @@ -2552,9 +2637,9 @@ def root_mean_squared_error(labels, predictions, weights=None, predictions, labels, weights = _remove_squeezable_dimensions( predictions=predictions, labels=labels, weights=weights) - mse, update_mse_op = mean_squared_error( - labels, predictions, weights, None, None, - name or 'root_mean_squared_error') + mse, update_mse_op = mean_squared_error(labels, predictions, weights, None, + None, name or + 'root_mean_squared_error') rmse = math_ops.sqrt(mse) update_rmse_op = math_ops.sqrt(update_mse_op) @@ -2569,9 +2654,14 @@ def root_mean_squared_error(labels, predictions, weights=None, @tf_export('metrics.sensitivity_at_specificity') -def sensitivity_at_specificity( - labels, predictions, specificity, weights=None, num_thresholds=200, - metrics_collections=None, updates_collections=None, name=None): +def sensitivity_at_specificity(labels, + predictions, + specificity, + weights=None, + num_thresholds=200, + metrics_collections=None, + updates_collections=None, + name=None): """Computes the specificity at a given sensitivity. The `sensitivity_at_specificity` function creates four local @@ -2632,8 +2722,9 @@ def sensitivity_at_specificity( with variable_scope.variable_scope(name, 'sensitivity_at_specificity', (predictions, labels, weights)): kepsilon = 1e-7 # to account for floating point imprecisions - thresholds = [(i + 1) * 1.0 / (num_thresholds - 1) - for i in range(num_thresholds-2)] + thresholds = [ + (i + 1) * 1.0 / (num_thresholds - 1) for i in range(num_thresholds - 2) + ] thresholds = [0.0 - kepsilon] + thresholds + [1.0 + kepsilon] values, update_ops = _confusion_matrix_at_thresholds( @@ -2645,8 +2736,7 @@ def sensitivity_at_specificity( tf_index = math_ops.cast(tf_index, dtypes.int32) # Now, we have the implicit threshold, so compute the sensitivity: - return math_ops.div(tp[tf_index], - tp[tf_index] + fn[tf_index] + kepsilon, + return math_ops.div(tp[tf_index], tp[tf_index] + fn[tf_index] + kepsilon, name) sensitivity = compute_sensitivity_at_specificity( @@ -2685,8 +2775,8 @@ def _expand_and_tile(tensor, multiple, dim=0, name=None): """ if multiple < 1: raise ValueError('Invalid multiple %s, must be > 0.' % multiple) - with ops.name_scope( - name, 'expand_and_tile', (tensor, multiple, dim)) as scope: + with ops.name_scope(name, 'expand_and_tile', + (tensor, multiple, dim)) as scope: # Sparse. tensor = sparse_tensor.convert_to_tensor_or_sparse_tensor(tensor) if isinstance(tensor, sparse_tensor.SparseTensor): @@ -2786,8 +2876,8 @@ def _sparse_average_precision_at_top_k(labels, predictions_idx): Raises: ValueError: if the last dimension of predictions_idx is not set. """ - with ops.name_scope( - None, 'average_precision', (predictions_idx, labels)) as scope: + with ops.name_scope(None, 'average_precision', + (predictions_idx, labels)) as scope: predictions_idx = math_ops.to_int64(predictions_idx, name='predictions_idx') if predictions_idx.get_shape().ndims == 0: raise ValueError('The rank of predictions_idx must be at least 1.') @@ -2824,10 +2914,12 @@ def _sparse_average_precision_at_top_k(labels, predictions_idx): retrieved_per_k = math_ops.cumsum( array_ops.ones_like(relevant_per_k), axis=-1, name='retrieved_per_k') precision_per_k = math_ops.div( - math_ops.to_double(tp_per_k), math_ops.to_double(retrieved_per_k), + math_ops.to_double(tp_per_k), + math_ops.to_double(retrieved_per_k), name='precision_per_k') relevant_precision_per_k = math_ops.multiply( - precision_per_k, math_ops.to_double(relevant_per_k), + precision_per_k, + math_ops.to_double(relevant_per_k), name='relevant_precision_per_k') # Reduce along k dimension to get the sum, yielding a [D1, ... DN] tensor. @@ -3017,9 +3109,8 @@ def average_precision_at_k(labels, if k < 1: raise ValueError('Invalid k=%s.' % k) - with ops.name_scope( - name, _at_k_name('average_precision', k), - (predictions, labels, weights)) as scope: + with ops.name_scope(name, _at_k_name('average_precision', k), + (predictions, labels, weights)) as scope: # Calculate top k indices to produce [D1, ... DN, k] tensor. _, predictions_idx = nn.top_k(predictions, k) return _streaming_sparse_average_precision_at_top_k( @@ -3060,17 +3151,16 @@ def _sparse_false_positive_at_k(labels, Returns: A [D1, ... DN] `Tensor` of false positive counts. """ - with ops.name_scope( - None, 'false_positives', (predictions_idx, labels, weights)): - labels, predictions_idx = _maybe_select_class_id(labels, - predictions_idx, + with ops.name_scope(None, 'false_positives', + (predictions_idx, labels, weights)): + labels, predictions_idx = _maybe_select_class_id(labels, predictions_idx, class_id) - fp = sets.set_size(sets.set_difference( - predictions_idx, labels, aminusb=True)) + fp = sets.set_size( + sets.set_difference(predictions_idx, labels, aminusb=True)) fp = math_ops.to_double(fp) if weights is not None: - with ops.control_dependencies(( - weights_broadcast_ops.assert_broadcastable(weights, fp),)): + with ops.control_dependencies((weights_broadcast_ops.assert_broadcastable( + weights, fp),)): weights = math_ops.to_double(weights) fp = math_ops.multiply(fp, weights) return fp @@ -3114,11 +3204,12 @@ def _streaming_sparse_false_positive_at_k(labels, Raises: ValueError: If `weights` is not `None` and has an incompatible shape. """ - with ops.name_scope( - name, _at_k_name('false_positive', k, class_id=class_id), - (predictions_idx, labels, weights)) as scope: + with ops.name_scope(name, _at_k_name('false_positive', k, class_id=class_id), + (predictions_idx, labels, weights)) as scope: fp = _sparse_false_positive_at_k( - predictions_idx=predictions_idx, labels=labels, class_id=class_id, + predictions_idx=predictions_idx, + labels=labels, + class_id=class_id, weights=weights) batch_total_fp = math_ops.to_double(math_ops.reduce_sum(fp)) @@ -3190,10 +3281,16 @@ def precision_at_top_k(labels, labels = _maybe_expand_labels(labels, predictions_idx) top_k_idx = math_ops.to_int64(predictions_idx) tp, tp_update = _streaming_sparse_true_positive_at_k( - predictions_idx=top_k_idx, labels=labels, k=k, class_id=class_id, + predictions_idx=top_k_idx, + labels=labels, + k=k, + class_id=class_id, weights=weights) fp, fp_update = _streaming_sparse_false_positive_at_k( - predictions_idx=top_k_idx, labels=labels, k=k, class_id=class_id, + predictions_idx=top_k_idx, + labels=labels, + k=k, + class_id=class_id, weights=weights) metric = math_ops.div(tp, math_ops.add(tp, fp), name=scope) @@ -3323,9 +3420,14 @@ def precision_at_k(labels, @tf_export('metrics.specificity_at_sensitivity') -def specificity_at_sensitivity( - labels, predictions, sensitivity, weights=None, num_thresholds=200, - metrics_collections=None, updates_collections=None, name=None): +def specificity_at_sensitivity(labels, + predictions, + sensitivity, + weights=None, + num_thresholds=200, + metrics_collections=None, + updates_collections=None, + name=None): """Computes the specificity at a given sensitivity. The `specificity_at_sensitivity` function creates four local @@ -3386,8 +3488,9 @@ def specificity_at_sensitivity( with variable_scope.variable_scope(name, 'specificity_at_sensitivity', (predictions, labels, weights)): kepsilon = 1e-7 # to account for floating point imprecisions - thresholds = [(i + 1) * 1.0 / (num_thresholds - 1) - for i in range(num_thresholds-2)] + thresholds = [ + (i + 1) * 1.0 / (num_thresholds - 1) for i in range(num_thresholds - 2) + ] thresholds = [0.0 - kepsilon] + thresholds + [1.0 - kepsilon] values, update_ops = _confusion_matrix_at_thresholds( @@ -3419,8 +3522,7 @@ def specificity_at_sensitivity( tf_index = math_ops.cast(tf_index, dtypes.int32) # Now, we have the implicit threshold, so compute the specificity: - return math_ops.div(tn[tf_index], - tn[tf_index] + fp[tf_index] + kepsilon, + return math_ops.div(tn[tf_index], tn[tf_index] + fp[tf_index] + kepsilon, name) specificity = compute_specificity_at_sensitivity( diff --git a/tensorflow/python/ops/nn_impl.py b/tensorflow/python/ops/nn_impl.py index 837ee02e64..3268fd0e0a 100644 --- a/tensorflow/python/ops/nn_impl.py +++ b/tensorflow/python/ops/nn_impl.py @@ -196,9 +196,12 @@ def weighted_cross_entropy_with_logits(targets, logits, pos_weight, name=None): targets * -log(sigmoid(logits)) + (1 - targets) * -log(1 - sigmoid(logits)) - A value `pos_weights > 1` decreases the false negative count, hence increasing the recall. - Conversely setting `pos_weights < 1` decreases the false positive count and increases the precision. - This can be seen from the fact that `pos_weight` is introduced as a multiplicative coefficient for the positive targets term + A value `pos_weights > 1` decreases the false negative count, hence increasing + the recall. + Conversely setting `pos_weights < 1` decreases the false positive count and + increases the precision. + This can be seen from the fact that `pos_weight` is introduced as a + multiplicative coefficient for the positive targets term in the loss expression: targets * -log(sigmoid(logits)) * pos_weight + @@ -646,9 +649,12 @@ def normalize_moments(counts, mean_ss, variance_ss, shift, name=None): @tf_export("nn.moments") -def moments(x, axes, - shift=None, # pylint: disable=unused-argument - name=None, keep_dims=False): +def moments( + x, + axes, + shift=None, # pylint: disable=unused-argument + name=None, + keep_dims=False): """Calculate the mean and variance of `x`. The mean and variance are calculated by aggregating the contents of `x` @@ -692,8 +698,8 @@ def moments(x, axes, mean = array_ops.squeeze(mean, axes) variance = array_ops.squeeze(variance, axes) if x.dtype == dtypes.float16: - return (math_ops.cast(mean, dtypes.float16), math_ops.cast( - variance, dtypes.float16)) + return (math_ops.cast(mean, dtypes.float16), + math_ops.cast(variance, dtypes.float16)) else: return (mean, variance) @@ -824,8 +830,8 @@ def batch_normalization(x, inv = math_ops.rsqrt(variance + variance_epsilon) if scale is not None: inv *= scale - return x * inv + (offset - mean * inv - if offset is not None else -mean * inv) + return x * inv + ( + offset - mean * inv if offset is not None else -mean * inv) @tf_export("nn.fused_batch_norm") diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py index 6767564024..5a45bdc1e5 100644 --- a/tensorflow/python/ops/nn_test.py +++ b/tensorflow/python/ops/nn_test.py @@ -131,8 +131,7 @@ class LogPoissonLossTest(test_lib.TestCase): y_np = self._log_poisson_loss(x_np, z_np, compute_full_loss=False) y_np_stirling = self._log_poisson_loss(x_np, z_np, compute_full_loss=True) y_tf = nn_impl.log_poisson_loss(z_np, x_np, compute_full_loss=False) - y_tf_stirling = nn_impl.log_poisson_loss( - z_np, x_np, compute_full_loss=True) + y_tf_stirling = nn_impl.log_poisson_loss(z_np, x_np, compute_full_loss=True) y_tf_np = self.evaluate(y_tf) y_tf_np_stirling = self.evaluate(y_tf_stirling) eps = 1e-3 @@ -773,8 +772,8 @@ class ComputeSampledLogitsTest(test_lib.TestCase): def _SoftmaxCrossEntropyWithLogits(logits, targets): # logits, targets: float arrays of the same shape. assert logits.shape == targets.shape - stable_exp_logits = np.exp(logits - np.amax( - logits, axis=1, keepdims=True)) + stable_exp_logits = np.exp( + logits - np.amax(logits, axis=1, keepdims=True)) pred = stable_exp_logits / np.sum(stable_exp_logits, 1, keepdims=True) return -np.sum(targets * np.log(pred + 1.0e-20), axis=1) @@ -865,8 +864,8 @@ class LeakyReluTest(test_lib.TestCase): batch_size = 3 height, width = 4, 4 np.random.seed(1) # Make it reproducible. - inputs = np.random.uniform( - size=(batch_size, height, width, 3)).astype(np.float32) + inputs = np.random.uniform(size=(batch_size, height, width, 3)).astype( + np.float32) inputs = constant_op.constant(inputs) outputs = nn_ops.leaky_relu(inputs) @@ -884,7 +883,8 @@ class LeakyReluTest(test_lib.TestCase): with self.test_session() as sess: outputs = sess.run(outputs) tol = 2e-3 if dtype == np.float16 else 1e-6 - self.assertAllClose(outputs, [-0.4, -0.2, 0.0, 1.0, 2.0], rtol=tol, atol=tol) + self.assertAllClose( + outputs, [-0.4, -0.2, 0.0, 1.0, 2.0], rtol=tol, atol=tol) class SwishTest(test_lib.TestCase): @@ -915,7 +915,10 @@ class SwishTest(test_lib.TestCase): class MomentsTest(test_lib.TestCase): - def doOutputTest(self, input_shape, moments_axes, tol=1e-4, + def doOutputTest(self, + input_shape, + moments_axes, + tol=1e-4, check_gradients=False): for mu in [0.0, 1.0, 1e3]: for sigma in [1.0, 0.1]: diff --git a/tensorflow/python/util/compat.py b/tensorflow/python/util/compat.py index 3ab0bd16fa..270d96a3c7 100644 --- a/tensorflow/python/util/compat.py +++ b/tensorflow/python/util/compat.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== - """Functions for Python 2 vs. 3 compatibility. ## Conversion routines @@ -118,7 +117,7 @@ def path_to_str(path): Returns: A `str` object. """ - if hasattr(path, "__fspath__"): + if hasattr(path, '__fspath__'): path = as_str_any(path.__fspath__()) return path @@ -129,11 +128,9 @@ integral_types = (_numbers.Integral, _np.integer) real_types = (_numbers.Real, _np.integer, _np.floating) complex_types = (_numbers.Complex, _np.number) - # Either bytes or text. bytes_or_text_types = (bytes, _six.text_type) - _allowed_symbols = [ 'as_str', 'bytes_or_text_types', diff --git a/tensorflow/tools/pip_package/pip_smoke_test.py b/tensorflow/tools/pip_package/pip_smoke_test.py index 8eee489e2d..38a9007387 100644 --- a/tensorflow/tools/pip_package/pip_smoke_test.py +++ b/tensorflow/tools/pip_package/pip_smoke_test.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== - """This pip smoke test verifies dependency files exist in the pip package. This script runs bazel queries to see what python files are required by the @@ -26,13 +25,12 @@ from __future__ import print_function import os import subprocess +os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../.."))) -os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))) - - -PIP_PACKAGE_QUERY_EXPRESSION = \ - 'deps(//tensorflow/tools/pip_package:build_pip_package)' +PIP_PACKAGE_QUERY_EXPRESSION = ( + "deps(//tensorflow/tools/pip_package:build_pip_package)") +# pylint: disable=g-backslash-continuation PY_TEST_QUERY_EXPRESSION = 'deps(\ filter("^((?!benchmark).)*$",\ kind(py_test,\ @@ -40,6 +38,7 @@ PY_TEST_QUERY_EXPRESSION = 'deps(\ + //tensorflow/contrib/... \ - //tensorflow/contrib/tensorboard/... \ - attr(tags, "manual|no_pip", //tensorflow/...))), 1)' +# pylint: enable=g-backslash-continuation # Hard-coded blacklist of files if not included in pip package # TODO(amitpatankar): Clean up blacklist. @@ -90,15 +89,15 @@ def main(): """ # pip_package_dependencies_list is the list of included files in pip packages - pip_package_dependencies = subprocess.check_output([ - 'bazel', 'query', PIP_PACKAGE_QUERY_EXPRESSION]) + pip_package_dependencies = subprocess.check_output( + ["bazel", "query", PIP_PACKAGE_QUERY_EXPRESSION]) pip_package_dependencies_list = pip_package_dependencies.strip().split("\n") print("Pip package superset size: %d" % len(pip_package_dependencies_list)) # tf_py_test_dependencies is the list of dependencies for all python # tests in tensorflow - tf_py_test_dependencies = subprocess.check_output([ - 'bazel', 'query', PY_TEST_QUERY_EXPRESSION]) + tf_py_test_dependencies = subprocess.check_output( + ["bazel", "query", PY_TEST_QUERY_EXPRESSION]) tf_py_test_dependencies_list = tf_py_test_dependencies.strip().split("\n") print("Pytest dependency subset size: %d" % len(tf_py_test_dependencies_list)) @@ -119,8 +118,7 @@ def main(): # Check if the dependency is in the pip package, the blacklist, or # should be ignored because of its file extension - if not (ignore or - dependency in pip_package_dependencies_list or + if not (ignore or dependency in pip_package_dependencies_list or dependency in BLACKLIST): missing_dependencies.append(dependency) @@ -131,9 +129,9 @@ def main(): for missing_dependency in missing_dependencies: print("\nMissing dependency: %s " % missing_dependency) print("Affected Tests:") - rdep_query = 'rdeps(kind(py_test, \ - //tensorflow/python/...), %s)' % missing_dependency - affected_tests = subprocess.check_output(['bazel', 'query', rdep_query]) + rdep_query = ("rdeps(kind(py_test, //tensorflow/python/...), %s)" % + missing_dependency) + affected_tests = subprocess.check_output(["bazel", "query", rdep_query]) affected_tests_list = affected_tests.split("\n")[:-2] print("\n".join(affected_tests_list)) @@ -145,5 +143,6 @@ or add them to //tensorflow/tools/pip_package/BUILD.""") else: print("TEST PASSED") + if __name__ == "__main__": main() -- GitLab From e8e1f1083d2c6ba4c2fb4e7e804d36624775e971 Mon Sep 17 00:00:00 2001 From: Yunxing Dai Date: Wed, 24 Jan 2018 11:42:22 -0800 Subject: [PATCH 195/258] [BatchNorm] Remove CPU implementation We now use batchnorm rewriter (tensorflow/compiler/xla/service/batchnorm_rewriter.h) to expand batch norm into smaller ops. A specific implementation should not be needed anymore (for CPU). RELNOTES:n/a PiperOrigin-RevId: 183117252 --- .../compiler/xla/service/cpu/ir_emitter.cc | 199 ------------------ .../compiler/xla/service/cpu/ir_emitter.h | 2 - 2 files changed, 201 deletions(-) diff --git a/tensorflow/compiler/xla/service/cpu/ir_emitter.cc b/tensorflow/compiler/xla/service/cpu/ir_emitter.cc index ac8d5d33fa..b03a9f9aa5 100644 --- a/tensorflow/compiler/xla/service/cpu/ir_emitter.cc +++ b/tensorflow/compiler/xla/service/cpu/ir_emitter.cc @@ -1226,205 +1226,6 @@ static llvm_ir::IrArray::Index FillReducedDimensionIndex( return index_with_free_var; } -Status IrEmitter::HandleBatchNormTraining(HloInstruction* batch_norm_training) { - // The output of BatchNormTraining is a tuple of three element: - // - An N-dimensional array containing normalized values. - // - A 1 dimensional array containing the mean value for each feature. - // - A 1 dimensional array containing the variance value for each feature. - HloInstruction* operand = batch_norm_training->operands()[0]; - HloInstruction* scale = batch_norm_training->operands()[1]; - HloInstruction* offset = batch_norm_training->operands()[2]; - float epsilon = batch_norm_training->epsilon(); - int64 feature_index = batch_norm_training->feature_index(); - TF_RET_CHECK(ShapeUtil::IsTuple(batch_norm_training->shape()) && - ShapeUtil::TupleElementCount(batch_norm_training->shape()) == 3); - - const Shape& output_shape = - ShapeUtil::GetTupleElementShape(batch_norm_training->shape(), 0); - const Shape& feature_shape = - ShapeUtil::GetTupleElementShape(batch_norm_training->shape(), 1); - - // Reduce vector of the non-feature dimensions. - std::vector dimensions_to_reduce; - - for (int64 i = 0; i < operand->shape().dimensions_size(); ++i) { - if (i != feature_index) { - dimensions_to_reduce.push_back(i); - } - } - - // Get the second and third allocations in the output tuple, which should be - // used to store the result of mean and variance value calculation. - TF_ASSIGN_OR_RETURN( - const BufferAllocation::Slice slice_mean, - assignment_.GetUniqueSlice(batch_norm_training, /*index=*/{1})); - TF_ASSIGN_OR_RETURN( - const BufferAllocation::Slice slice_var, - assignment_.GetUniqueSlice(batch_norm_training, /*index=*/{2})); - const int feature_count = output_shape.dimensions(feature_index); - const int size_in_elements = ShapeUtil::ElementsIn(output_shape); - TF_RET_CHECK(ShapeUtil::ElementsIn(operand->shape()) == size_in_elements); - const int elements_per_feature = size_in_elements / feature_count; - - llvm::Value* mean = EmitTempBufferPointer(slice_mean, feature_shape); - llvm_ir::IrArray mean_array(mean, feature_shape); - - llvm::Value* var = EmitTempBufferPointer(slice_var, feature_shape); - llvm_ir::IrArray var_array(var, feature_shape); - - // This loop calculates mean and variance for each feature. - // - // In theory this could be swapped by multi-output fusion. We will evaluate - // this when it's ready. - // - // For variance calculation, we use a simplified formula so we can fuse the - // computation into the same loop to calculate mean: Var=E(X^2) - E(X)^2. - TF_RETURN_IF_ERROR( - llvm_ir::LoopEmitter( - [&](const llvm_ir::IrArray::Index& index) { - PrimitiveType element_type = operand->shape().element_type(); - // Used to calculate E(X). - llvm::Value* sum_address = llvm_ir::EmitAllocaAtFunctionEntry( - llvm_ir::PrimitiveTypeToIrType(element_type, module_), - "sum_address", &ir_builder_, - MinimumAlignmentForPrimitiveType(element_type)); - - // Used to calculate E(X^2). - llvm::Value* sum_square_address = - llvm_ir::EmitAllocaAtFunctionEntry( - llvm_ir::PrimitiveTypeToIrType(element_type, module_), - "sum_square_address", &ir_builder_, - MinimumAlignmentForPrimitiveType(element_type)); - - ir_builder_.CreateStore( - llvm::ConstantFP::get(ir_builder_.getFloatTy(), 0.0), - sum_address); - - ir_builder_.CreateStore( - llvm::ConstantFP::get(ir_builder_.getFloatTy(), 0.0), - sum_square_address); - - llvm_ir::ForLoopNest loops(IrName(batch_norm_training, "inner"), - &ir_builder_); - - const llvm_ir::IrArray::Index reduced_dims_index = - loops.AddLoopsForShapeOnDimensions( - operand->shape(), dimensions_to_reduce, "reduction_dim"); - - SetToFirstInsertPoint(loops.GetInnerLoopBodyBasicBlock(), - &ir_builder_); - - llvm_ir::IrArray operand_array(GetIrArrayFor(operand)); - llvm_ir::IrArray::Index input_index = - FillReducedDimensionIndex(reduced_dims_index, index); - llvm::Value* new_value = - operand_array.EmitReadArrayElement(input_index, &ir_builder_); - - llvm::Value* new_value_square = - ir_builder_.CreateFMul(new_value, new_value); - - llvm::Value* current_sum = ir_builder_.CreateLoad(sum_address); - llvm::Value* current_sum_square = - ir_builder_.CreateLoad(sum_square_address); - // Update sum. - ir_builder_.CreateStore( - ir_builder_.CreateFAdd(current_sum, new_value), sum_address); - - // Update sum square. - ir_builder_.CreateStore( - ir_builder_.CreateFAdd(current_sum_square, new_value_square), - sum_square_address); - - SetToFirstInsertPoint(loops.GetOuterLoopExitBasicBlock(), - &ir_builder_); - - llvm::Value* sum = ir_builder_.CreateLoad(sum_address); - llvm::Value* elements_per_feature_value = llvm::ConstantFP::get( - ir_builder_.getFloatTy(), elements_per_feature); - llvm::Value* mean = - ir_builder_.CreateFDiv(sum, elements_per_feature_value); - llvm::Value* mean_square = ir_builder_.CreateFMul(mean, mean); - llvm::Value* sum_square = - ir_builder_.CreateLoad(sum_square_address); - - // Var=E(X^2) - E(X)^2. - llvm::Value* var = ir_builder_.CreateFSub( - ir_builder_.CreateFDiv(sum_square, elements_per_feature_value), - mean_square); - - var_array.EmitWriteArrayElement(index, var, &ir_builder_); - return mean; - }, - mean_array, &ir_builder_) - .EmitLoop(IrName(batch_norm_training, "mean_var"))); - - TF_RETURN_IF_ERROR(EmitTargetAddressForOp(batch_norm_training)); - TF_ASSIGN_OR_RETURN( - const BufferAllocation::Slice slice, - assignment_.GetUniqueSlice(batch_norm_training, /*index=*/{0})); - - llvm::Value* normalized = EmitTempBufferPointer(slice, output_shape); - - llvm_ir::IrArray target_array(normalized, output_shape); - - AddAliasingInformationToIrArray(*batch_norm_training, &target_array); - - TF_RETURN_IF_ERROR( - llvm_ir::LoopEmitter( - [this, mean_array, var_array, epsilon, operand, dimensions_to_reduce, - feature_index, offset, scale](const llvm_ir::IrArray::Index& index) { - // The following logic normalizes the input value, scales and shifts - // it: - // - // normalized = (input - mean) / sqrt(variance + epsilon) - // result = normalized * scale + offset - - // Current index in the feature dimension. - llvm_ir::IrArray::Index feature_index_value(1, - index[feature_index]); - - llvm::Value* mean = mean_array.EmitReadArrayElement( - feature_index_value, &ir_builder_); - llvm::Value* var = var_array.EmitReadArrayElement( - feature_index_value, &ir_builder_); - - llvm_ir::IrArray operand_array(GetIrArrayFor(operand)); - llvm::Value* input = - operand_array.EmitReadArrayElement(index, &ir_builder_); - - llvm::Value* variance_with_epsilon = ir_builder_.CreateFAdd( - var, llvm::ConstantFP::get(ir_builder_.getFloatTy(), epsilon)); - llvm::Function* func_llvm_sqrt = llvm::Intrinsic::getDeclaration( - module_, llvm::Intrinsic::sqrt, {ir_builder_.getFloatTy()}); - llvm::Value* variance_sqrt = - ir_builder_.CreateCall(func_llvm_sqrt, {variance_with_epsilon}); - llvm::Value* normalized = ir_builder_.CreateFDiv( - ir_builder_.CreateFSub(input, mean), variance_sqrt); - llvm_ir::IrArray offset_array(GetIrArrayFor(offset)); - llvm::Value* offset = offset_array.EmitReadArrayElement( - feature_index_value, &ir_builder_); - llvm_ir::IrArray scale_array(GetIrArrayFor(scale)); - llvm::Value* scale = scale_array.EmitReadArrayElement( - feature_index_value, &ir_builder_); - llvm::Value* result = ir_builder_.CreateFAdd( - ir_builder_.CreateFMul(normalized, scale), offset); - - return result; - }, - target_array, &ir_builder_) - .EmitLoop(IrName(batch_norm_training, "normalize"))); - - llvm_ir::EmitTuple(GetIrArrayFor(batch_norm_training), - {normalized, mean, var}, &ir_builder_, module_); - return Status::OK(); -} - -Status IrEmitter::HandleBatchNormGrad(HloInstruction* batch_norm_grad) { - // TODO(b/62843645) Implement BatchNormGrad on CPU backend. - return Unimplemented( - "BatchNormGrad is not implemented on CPU. See b/62843645."); -} - Status IrEmitter::HandleParameter(HloInstruction* parameter) { VLOG(2) << "HandleParameter: " << parameter->ToString(); auto param_number = parameter->parameter_number(); diff --git a/tensorflow/compiler/xla/service/cpu/ir_emitter.h b/tensorflow/compiler/xla/service/cpu/ir_emitter.h index 66f2aeeab3..5094402514 100644 --- a/tensorflow/compiler/xla/service/cpu/ir_emitter.h +++ b/tensorflow/compiler/xla/service/cpu/ir_emitter.h @@ -125,8 +125,6 @@ class IrEmitter : public DfsHloVisitorWithDefault { Status HandleDot(HloInstruction* dot) override; Status HandleConvolution(HloInstruction* convolution) override; Status HandleFft(HloInstruction* fft) override; - Status HandleBatchNormTraining(HloInstruction* batch_norm_training) override; - Status HandleBatchNormGrad(HloInstruction* batch_norm_grad) override; Status HandleCrossReplicaSum(HloInstruction* crs) override; Status HandleInfeed(HloInstruction* infeed) override; Status HandleOutfeed(HloInstruction* outfeed) override; -- GitLab From 94faa1e921d647f321ca1b3204a25aa0dbede856 Mon Sep 17 00:00:00 2001 From: Anna R Date: Wed, 24 Jan 2018 11:44:55 -0800 Subject: [PATCH 196/258] Internal change. PiperOrigin-RevId: 183117665 --- tensorflow/tools/api/generator/BUILD | 3 +++ .../tools/api/generator/create_python_api.py | 22 ++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/tensorflow/tools/api/generator/BUILD b/tensorflow/tools/api/generator/BUILD index 4c47ffe07c..d110316395 100644 --- a/tensorflow/tools/api/generator/BUILD +++ b/tensorflow/tools/api/generator/BUILD @@ -86,4 +86,7 @@ py_library( name = "python_api", srcs = [":python_api_gen"], srcs_version = "PY2AND3", + deps = [ + "//tensorflow/contrib:contrib_py", # keep + ], ) diff --git a/tensorflow/tools/api/generator/create_python_api.py b/tensorflow/tools/api/generator/create_python_api.py index 2c9a2fa731..1557314939 100644 --- a/tensorflow/tools/api/generator/create_python_api.py +++ b/tensorflow/tools/api/generator/create_python_api.py @@ -31,6 +31,7 @@ from tensorflow.python.util import tf_decorator _API_CONSTANTS_ATTR = '_tf_api_constants' _API_NAMES_ATTR = '_tf_api_names' _API_DIR = '/api/' +_CONTRIB_IMPORT = 'from tensorflow import contrib' _GENERATED_FILE_HEADER = """\"\"\"Imports for Python API. This file is MACHINE GENERATED! Do not edit. @@ -50,11 +51,17 @@ def format_import(source_module_name, source_name, dest_name): Returns: An import statement string. """ - if source_name == dest_name: - return 'from %s import %s' % (source_module_name, source_name) + if source_module_name: + if source_name == dest_name: + return 'from %s import %s' % (source_module_name, source_name) + else: + return 'from %s import %s as %s' % ( + source_module_name, source_name, dest_name) else: - return 'from %s import %s as %s' % ( - source_module_name, source_name, dest_name) + if source_name == dest_name: + return 'import %s' % source_name + else: + return 'import %s as %s' % (source_name, dest_name) def get_api_imports(): @@ -74,6 +81,9 @@ def get_api_imports(): # Only look at tensorflow modules. if not module or 'tensorflow.' not in module.__name__: continue + # Do not generate __init__.py files for contrib modules for now. + if '.contrib.' in module.__name__ or module.__name__.endswith('.contrib'): + continue for module_contents_name in dir(module): attr = getattr(module, module_contents_name) @@ -151,8 +161,10 @@ def create_api_files(output_files): os.makedirs(os.path.dirname(file_path)) open(file_path, 'a').close() - # Add imports to output files. module_imports = get_api_imports() + module_imports['tf'].append(_CONTRIB_IMPORT) # Include all of contrib. + + # Add imports to output files. missing_output_files = [] for module, exports in module_imports.items(): # Make sure genrule output file list is in sync with API exports. -- GitLab From 23ed83de415b465fb5570216b8c171d63187289e Mon Sep 17 00:00:00 2001 From: ngc92 <7938269+ngc92@users.noreply.github.com> Date: Wed, 24 Jan 2018 20:58:28 +0100 Subject: [PATCH 197/258] Annotated return types for chaining dataset operations (#16359) --- tensorflow/python/data/ops/dataset_ops.py | 44 +++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index 0594c6d6a7..c1ba67e474 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -201,7 +201,7 @@ class Dataset(object): tensors: A nested structure of tensors. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return TensorDataset(tensors) @@ -214,7 +214,7 @@ class Dataset(object): 0th dimension. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return TensorSliceDataset(tensors) @@ -227,7 +227,7 @@ class Dataset(object): sparse_tensor: A `tf.SparseTensor`. Returns: - A `Dataset` of rank-(N-1) sparse tensors. + Dataset: A `Dataset` of rank-(N-1) sparse tensors. """ return SparseTensorSliceDataset(sparse_tensor) @@ -313,7 +313,7 @@ class Dataset(object): `generator`. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ if not callable(generator): raise TypeError("`generator` must be callable.") @@ -456,7 +456,7 @@ class Dataset(object): len(args) == 3 -> start = args[0], stop = args[1, stop = args[2] Returns: - A `RangeDataset`. + Dataset: A `RangeDataset`. Raises: ValueError: if len(args) == 0. @@ -500,7 +500,7 @@ class Dataset(object): datasets: A nested structure of datasets. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return ZipDataset(datasets) @@ -526,7 +526,7 @@ class Dataset(object): dataset: `Dataset` to be concatenated. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return ConcatenateDataset(self, dataset) @@ -538,7 +538,7 @@ class Dataset(object): maximum number elements that will be buffered when prefetching. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return PrefetchDataset(self, buffer_size) @@ -561,7 +561,7 @@ class Dataset(object): the filename pattern that will be matched. Returns: - A `Dataset` of strings corresponding to file names. + Dataset: A `Dataset` of strings corresponding to file names. """ return Dataset.from_tensor_slices(gen_io_ops.matching_files(file_pattern)) @@ -578,7 +578,7 @@ class Dataset(object): indefinitely. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return RepeatDataset(self, count) @@ -602,7 +602,7 @@ class Dataset(object): iterated over. (Defaults to `True`.) Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return ShuffleDataset(self, buffer_size, seed, reshuffle_each_iteration) @@ -615,7 +615,7 @@ class Dataset(object): If a filename is not provided, the dataset will be cached in memory. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return CacheDataset(self, filename) @@ -629,7 +629,7 @@ class Dataset(object): dataset, the new dataset will contain all elements of this dataset. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return TakeDataset(self, count) @@ -644,7 +644,7 @@ class Dataset(object): is -1, skips the entire dataset. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return SkipDataset(self, count) @@ -691,7 +691,7 @@ class Dataset(object): index: A `tf.int64` scalar `tf.Tensor`, representing the worker index. Returns: - A `Dataset`. + Dataset: A `Dataset`. Raises: ValueError: if `num_shards` or `index` are illegal values. Note: error @@ -735,7 +735,7 @@ class Dataset(object): consecutive elements of this dataset to combine in a single batch. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return BatchDataset(self, batch_size) @@ -764,7 +764,7 @@ class Dataset(object): the empty string for string types. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return PaddedBatchDataset(self, batch_size, padded_shapes, padding_values) @@ -780,7 +780,7 @@ class Dataset(object): specified, elements will be processed sequentially. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ if num_parallel_calls is None: return MapDataset(self, map_func) @@ -796,7 +796,7 @@ class Dataset(object): `Dataset`. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return FlatMapDataset(self, map_func) @@ -865,7 +865,7 @@ class Dataset(object): input element before cycling to another input element. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return InterleaveDataset(self, map_func, cycle_length, block_length) @@ -878,7 +878,7 @@ class Dataset(object): scalar `tf.bool` tensor. Returns: - A `Dataset`. + Dataset: A `Dataset`. """ return FilterDataset(self, predicate) @@ -902,7 +902,7 @@ class Dataset(object): returns a `Dataset`. Returns: - The `Dataset` returned by applying `transformation_func` to this dataset. + Dataset: The `Dataset` returned by applying `transformation_func` to this dataset. """ dataset = transformation_func(self) if not isinstance(dataset, Dataset): -- GitLab From 02c2214b8da916a4a9e9eb3fde2711e49e7b4703 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Wed, 24 Jan 2018 12:12:02 -0800 Subject: [PATCH 198/258] [XLA] Fix crash in HloOrdering::ToString(). HloOrdering::ToString() was crashing when given a computation containing a fusion instruction. PiperOrigin-RevId: 183121645 --- tensorflow/compiler/xla/service/BUILD | 1 + .../compiler/xla/service/hlo_ordering.cc | 2 +- .../compiler/xla/service/hlo_ordering_test.cc | 52 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/tensorflow/compiler/xla/service/BUILD b/tensorflow/compiler/xla/service/BUILD index 2e0ac256cc..d0e2dc88ea 100644 --- a/tensorflow/compiler/xla/service/BUILD +++ b/tensorflow/compiler/xla/service/BUILD @@ -908,6 +908,7 @@ tf_cc_test( "//tensorflow/compiler/xla:xla_data_proto", "//tensorflow/compiler/xla/tests:hlo_test_base", "//tensorflow/compiler/xla/tests:xla_internal_test_main", + "//tensorflow/compiler/xla/tools/parser:hlo_parser", ], ) diff --git a/tensorflow/compiler/xla/service/hlo_ordering.cc b/tensorflow/compiler/xla/service/hlo_ordering.cc index 6f6e679a21..68e3c9618c 100644 --- a/tensorflow/compiler/xla/service/hlo_ordering.cc +++ b/tensorflow/compiler/xla/service/hlo_ordering.cc @@ -249,7 +249,7 @@ bool PredecessorHloOrdering::ExecutesBeforeInSameComputation( string PredecessorHloOrdering::ToStringHelper(const string& name) const { std::vector pieces; pieces.push_back(name); - for (auto* computation : module_->computations()) { + for (auto* computation : module_->MakeNonfusionComputations()) { pieces.push_back(tensorflow::strings::Printf("computation %s:", computation->name().c_str())); const auto all = computation->MakeInstructionPostOrder(); diff --git a/tensorflow/compiler/xla/service/hlo_ordering_test.cc b/tensorflow/compiler/xla/service/hlo_ordering_test.cc index 33bafd05c1..aba66114de 100644 --- a/tensorflow/compiler/xla/service/hlo_ordering_test.cc +++ b/tensorflow/compiler/xla/service/hlo_ordering_test.cc @@ -25,6 +25,7 @@ limitations under the License. #include "tensorflow/compiler/xla/service/hlo_scheduling.h" #include "tensorflow/compiler/xla/shape_util.h" #include "tensorflow/compiler/xla/tests/hlo_test_base.h" +#include "tensorflow/compiler/xla/tools/parser/hlo_parser.h" #include "tensorflow/compiler/xla/types.h" #include "tensorflow/compiler/xla/xla_data.pb.h" @@ -310,5 +311,56 @@ TEST_F(HloOrderingTest, ValuesInWhileComputations) { *dataflow)); } +// Regression test for HloOrdering::ToString() crashing when fed a computation +// containing a fusion node. +TEST_F(HloOrderingTest, ToStringDoesNotCrash) { + const char* module_str = R"( +HloModule test_module + +body.v8 { + prev.1 = (s32[], f32[3]{0}, f32[3]{0}, f32[3]{0}) parameter(0) + get-tuple-element.4 = s32[] get-tuple-element(prev.1), index=0 + constant.1 = s32[] constant(1) + add = s32[] add(get-tuple-element.4, constant.1) + get-tuple-element.5 = f32[3]{0} get-tuple-element(prev.1), index=3 + get-tuple-element.6 = f32[3]{0} get-tuple-element(prev.1), index=1 + get-tuple-element.7 = f32[3]{0} get-tuple-element(prev.1), index=2 + ROOT tuple = (s32[], f32[3]{0}, f32[3]{0}, f32[3]{0}) tuple(add, get-tuple-element.5, get-tuple-element.6, get-tuple-element.7) +} + +condition.v4 { + constant.2 = s32[] constant(2) + prev.2 = (s32[], f32[3]{0}, f32[3]{0}, f32[3]{0}) parameter(0) + get-tuple-element.8 = s32[] get-tuple-element(prev.2), index=0 + ROOT greater-than = pred[] greater-than(constant.2, get-tuple-element.8) +} + +fused_computation { + get-tuple-element.5.param_1 = f32[3]{0} parameter(1) + get-tuple-element.6.param_2 = f32[3]{0} parameter(2) + add.4 = f32[3]{0} add(get-tuple-element.5.param_1, get-tuple-element.6.param_2) + get-tuple-element.7.param_1.1 = f32[3]{0} parameter(0) + ROOT add.5 = f32[3]{0} add(add.4, get-tuple-element.7.param_1.1) +} + +ENTRY while.v11 { + constant.5 = s32[] constant(0) + constant.6 = f32[3]{0} constant({1, 1, 1}) + constant.7 = f32[3]{0} constant({2, 2, 2}) + constant.8 = f32[3]{0} constant({3, 3, 3}) + tuple.1 = (s32[], f32[3]{0}, f32[3]{0}, f32[3]{0}) tuple(constant.5, constant.6, constant.7, constant.8) + while = (s32[], f32[3]{0}, f32[3]{0}, f32[3]{0}) while(tuple.1), condition=condition.v4, body=body.v8 + get-tuple-element.9 = f32[3]{0} get-tuple-element(while), index=3 + get-tuple-element.10 = f32[3]{0} get-tuple-element(while), index=1 + get-tuple-element.11 = f32[3]{0} get-tuple-element(while), index=2 + ROOT fusion = f32[3]{0} fusion(get-tuple-element.9, get-tuple-element.10, get-tuple-element.11), kind=kLoop, calls=fused_computation +})"; + + TF_ASSERT_OK_AND_ASSIGN(std::unique_ptr module, + tools::Parse(module_str)); + DependencyHloOrdering ordering(module.get()); + ordering.ToString(); // Shouldn't crash. +} + } // namespace } // namespace xla -- GitLab From 83d3a47d25b87c7e14ffc902489401b47bf568f1 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Wed, 24 Jan 2018 12:46:09 -0800 Subject: [PATCH 199/258] Initializes the context before setting the device policy PiperOrigin-RevId: 183126037 --- tensorflow/python/eager/context.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tensorflow/python/eager/context.py b/tensorflow/python/eager/context.py index df483b69c4..8d708b8b04 100644 --- a/tensorflow/python/eager/context.py +++ b/tensorflow/python/eager/context.py @@ -413,6 +413,8 @@ class Context(object): @contextlib.contextmanager def device_policy(self, policy): + if not self._context_handle: + self._initialize_handle_and_devices() old = pywrap_tensorflow.TFE_ContextGetDevicePlacementPolicy( self._context_handle) pywrap_tensorflow.TFE_ContextSetThreadLocalDevicePlacementPolicy( -- GitLab From a7a74f141525d6163f2ea54c5b6c2965fe1d6d35 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Wed, 24 Jan 2018 12:47:00 -0800 Subject: [PATCH 200/258] tf_contextlib forgotten oops PiperOrigin-RevId: 183126126 --- tensorflow/python/eager/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/eager/context.py b/tensorflow/python/eager/context.py index 8d708b8b04..0569791352 100644 --- a/tensorflow/python/eager/context.py +++ b/tensorflow/python/eager/context.py @@ -411,7 +411,7 @@ class Context(object): self._initialize_handle_and_devices() pywrap_tensorflow.TFE_ContextEnableRunMetadata(self._context_handle) - @contextlib.contextmanager + @tf_contextlib.contextmanager def device_policy(self, policy): if not self._context_handle: self._initialize_handle_and_devices() -- GitLab From c8f6966ec7f071e25ab8c5a8168539d18a86fad9 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 13:09:10 -0800 Subject: [PATCH 201/258] Portability fix for parse_testdata.cc PiperOrigin-RevId: 183129228 --- tensorflow/contrib/lite/testing/parse_testdata.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/lite/testing/parse_testdata.cc b/tensorflow/contrib/lite/testing/parse_testdata.cc index 7c371f2bd4..0caef0fe22 100644 --- a/tensorflow/contrib/lite/testing/parse_testdata.cc +++ b/tensorflow/contrib/lite/testing/parse_testdata.cc @@ -18,6 +18,7 @@ limitations under the License. // ASCII file. #include "tensorflow/contrib/lite/testing/parse_testdata.h" +#include #include #include #include @@ -218,8 +219,8 @@ TfLiteStatus CheckOutputs(tflite::Interpreter* interpreter, int32_t computed = data[idx]; int32_t reference = example.outputs[0].flat_data[idx]; if (std::abs(computed - reference) > 0) { - fprintf(stderr, "output[%zu][%zu] did not match %d vs reference %f\n", - i, idx, data[idx], example.outputs[0].flat_data[idx]); + fprintf(stderr, "output[%zu][%zu] did not match %d vs reference %d\n", + i, idx, computed, reference); return kTfLiteError; } } @@ -231,8 +232,9 @@ TfLiteStatus CheckOutputs(tflite::Interpreter* interpreter, int64_t reference = example.outputs[0].flat_data[idx]; if (std::abs(computed - reference) > 0) { fprintf(stderr, - "output[%zu][%zu] did not match %ld vs reference %f\n", i, - idx, data[idx], example.outputs[0].flat_data[idx]); + "output[%zu][%zu] did not match %" PRId64 + " vs reference %" PRId64 "\n", + i, idx, computed, reference); return kTfLiteError; } } -- GitLab From 68ab9a99cf07ed5216d310417873572043803a1e Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Wed, 24 Jan 2018 13:21:54 -0800 Subject: [PATCH 202/258] Make TFLite Pad op have parity with TF Pad op. PiperOrigin-RevId: 183131070 --- tensorflow/contrib/lite/builtin_op_data.h | 5 - tensorflow/contrib/lite/kernels/pad.cc | 102 ++++++++++------ tensorflow/contrib/lite/kernels/pad_test.cc | 109 +++++++++++++----- tensorflow/contrib/lite/kernels/test_util.cc | 36 ++++-- tensorflow/contrib/lite/kernels/test_util.h | 7 +- tensorflow/contrib/lite/model.cc | 19 --- tensorflow/contrib/lite/schema/schema.fbs | 2 - .../contrib/lite/schema/schema_generated.h | 62 +--------- .../contrib/lite/testing/generate_examples.py | 27 ++++- .../testing/generated_examples_zip_test.cc | 59 +++++----- .../contrib/lite/toco/tflite/operator.cc | 10 +- .../contrib/lite/toco/tflite/operator_test.cc | 10 -- 12 files changed, 237 insertions(+), 211 deletions(-) diff --git a/tensorflow/contrib/lite/builtin_op_data.h b/tensorflow/contrib/lite/builtin_op_data.h index ab07c58c92..8269de8e3f 100644 --- a/tensorflow/contrib/lite/builtin_op_data.h +++ b/tensorflow/contrib/lite/builtin_op_data.h @@ -172,11 +172,6 @@ typedef struct { } TfLiteResizeBilinearParams; typedef struct { - // TODO(ahentz): We can't have dynamic data in this struct, at least not yet. - // For now we will fix the maximum possible number of dimensions. - int before_padding[8]; - int after_padding[8]; - int num_dimensions; } TfLitePadParams; typedef struct { diff --git a/tensorflow/contrib/lite/kernels/pad.cc b/tensorflow/contrib/lite/kernels/pad.cc index 1a0d9d1505..569bf0fe8f 100644 --- a/tensorflow/contrib/lite/kernels/pad.cc +++ b/tensorflow/contrib/lite/kernels/pad.cc @@ -33,65 +33,93 @@ enum KernelType { kGenericOptimized, }; -// TODO(nupurgarg): Padding represented as a tensor is ignored. Only use the -// `left_padding` and `right_padding` specified in `params`. struct PadContext { PadContext(TfLiteContext* context, TfLiteNode* node) { - params = reinterpret_cast(node->builtin_data); input = GetInput(context, node, 0); + paddings = GetInput(context, node, 1); output = GetOutput(context, node, 0); + dims = NumDimensions(input); } - TfLitePadParams* params; TfLiteTensor* input; + TfLiteTensor* paddings; TfLiteTensor* output; + int dims; }; +// Resizes output array based on the input size and padding size. This function +// is callable from both Prepare() and Eval() as long as the caller ensures the +// paddings data is present. +TfLiteStatus ResizeOutputTensor(TfLiteContext* context, + PadContext* op_context) { + // TODO(nupurgarg): Our current implementations rely on the inputs being 4D. + TF_LITE_ENSURE_EQ(context, op_context->dims, 4); + + // Ensures the paddings array is dims x 2. + TF_LITE_ENSURE_EQ(context, SizeOfDimension(op_context->paddings, 0), + op_context->dims); + TF_LITE_ENSURE_EQ(context, SizeOfDimension(op_context->paddings, 1), 2); + + // Determines the size of the output tensor. + const TfLiteIntArray* input_size = op_context->input->dims; + TfLiteIntArray* output_size = TfLiteIntArrayCreate(op_context->dims); + const int32* paddings_data = GetTensorData(op_context->paddings); + + for (int idx = 0; idx < op_context->dims; ++idx) { + int before_padding = *paddings_data++; + int after_padding = *paddings_data++; + + TF_LITE_ENSURE_MSG(context, (before_padding >= 0 && after_padding >= 0), + "Pad value has to be greater than equal to 0."); + + output_size->data[idx] = + (input_size->data[idx] + before_padding + after_padding); + } + + return context->ResizeTensor(context, op_context->output, output_size); +} + TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { - TF_LITE_ENSURE(context, NumInputs(node) == 1 || NumInputs(node) == 2); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); - // Determines size of output tensor. PadContext op_context(context, node); - int dims = NumDimensions(op_context.input); - TF_LITE_ENSURE_EQ(context, dims, op_context.params->num_dimensions); TF_LITE_ENSURE_EQ(context, op_context.input->type, op_context.output->type); - // TODO(nupurgarg): Our current implementations rely on the inputs being 4D. - TF_LITE_ENSURE_EQ(context, dims, 4); - - const TfLiteIntArray* input_size = op_context.input->dims; - TfLiteIntArray* output_size = TfLiteIntArrayCreate(dims); - for (int idx = 0; idx < dims; ++idx) { - TF_LITE_ENSURE_MSG(context, - (op_context.params->before_padding[idx] >= 0 && - op_context.params->after_padding[idx] >= 0), - "Pad value has to be greater than equal to 0."); - output_size->data[idx] = - (input_size->data[idx] + op_context.params->before_padding[idx] + - op_context.params->after_padding[idx]); + // TODO(nupurgarg): Create wrapper functions for dynamic tensor logic. + // Exit early if paddings is a non-const tensor. Set output tensor to + // dynamic so output size can be determined in Eval. + if (op_context.paddings->allocation_type != kTfLiteMmapRo) { + op_context.output->allocation_type = kTfLiteDynamic; + return kTfLiteOk; } - - return context->ResizeTensor(context, op_context.output, output_size); + return ResizeOutputTensor(context, &op_context); } template TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { PadContext op_context(context, node); - std::vector before_padding( - op_context.params->before_padding, - op_context.params->before_padding + op_context.params->num_dimensions); - std::vector after_padding( - op_context.params->after_padding, - op_context.params->after_padding + op_context.params->num_dimensions); - - // TODO(nupurgarg): Change TOCO's implementation to use padding arrays - // in forward order (depth, width, height, batch). - // Converts from int[] = {depth, width, height, batch} to int[] = {batch, - // height, width, depth} to match TOCO's implementation of pad in - // referenced_ops.h and optimized_ops.h. - std::reverse(before_padding.begin(), before_padding.end()); - std::reverse(after_padding.begin(), after_padding.end()); + // Resize the output tensor if the output tensor is dynamic. + if (op_context.output->allocation_type == kTfLiteDynamic) { + TF_LITE_ENSURE_OK(context, ResizeOutputTensor(context, &op_context)); + TfLiteTensorRealloc(op_context.output->bytes, op_context.output); + } + + // TODO(nupurgarg): Change kernel implementation to take in int* instead of + // vector to remove malloc from Eval(). + // Create before and after padding arrays that are accepted by the kernel. + std::vector before_padding; + std::vector after_padding; + const int32* paddings_data = GetTensorData(op_context.paddings); + + // TODO(nupurgarg): Change kernel implementation to use padding arrays in + // forward order (depth, width, height, batch). + // Build paddings in order of int[] = {batch, height, width, depth} to match + // kernel implementation of Pad in referenced_ops.h and optimized_ops.h. + for (int idx = op_context.dims - 1; idx >= 0; --idx) { + before_padding.push_back(paddings_data[idx * 2]); + after_padding.push_back(paddings_data[idx * 2 + 1]); + } #define TF_LITE_PAD(type, scalar) \ type::Pad(GetTensorData(op_context.input), \ diff --git a/tensorflow/contrib/lite/kernels/pad_test.cc b/tensorflow/contrib/lite/kernels/pad_test.cc index f3ea9417df..28834ad071 100644 --- a/tensorflow/contrib/lite/kernels/pad_test.cc +++ b/tensorflow/contrib/lite/kernels/pad_test.cc @@ -25,52 +25,87 @@ using ::testing::ElementsAreArray; class PadOpModel : public SingleOpModel { public: - PadOpModel(std::initializer_list input_shape, - std::initializer_list before_padding, - std::initializer_list after_padding) { - input_ = AddInput(TensorType_FLOAT32); - output_ = AddOutput(TensorType_FLOAT32); - SetBuiltinOp( - BuiltinOperator_PAD, BuiltinOptions_PadOptions, - CreatePadOptions(builder_, builder_.CreateVector(before_padding), - builder_.CreateVector(after_padding)) - .Union()); - BuildInterpreter({input_shape}); - } - void SetInput(std::initializer_list data) { PopulateTensor(input_, data); } + void SetPaddings(std::initializer_list paddings) { + PopulateTensor(paddings_, paddings); + } + std::vector GetOutput() { return ExtractVector(output_); } std::vector GetOutputShape() { return GetTensorShape(output_); } - private: + protected: int input_; int output_; + int paddings_; +}; + +// Tests case where paddings is a const tensor. +// +// Example usage is as follows: +// PadOpDynamicModel m(input_shape, paddings_shape, paddings_data); +// m.SetInput(input_data); +// m.Invoke(); +class PadOpConstModel : public PadOpModel { + public: + PadOpConstModel(std::initializer_list input_shape, + std::initializer_list paddings_shape, + std::initializer_list paddings) { + input_ = AddInput(TensorType_FLOAT32); + paddings_ = AddConstInput(TensorType_INT32, paddings, paddings_shape); + output_ = AddOutput(TensorType_FLOAT32); + + SetBuiltinOp(BuiltinOperator_PAD, BuiltinOptions_PadOptions, + CreatePadOptions(builder_).Union()); + BuildInterpreter({input_shape}); + } +}; + +// Test case where paddings is a non-const tensor. +// +// Example usage is as follows: +// PadOpDynamicModel m(input_shape, paddings_shape); +// m.SetInput(input_data); +// m.SetPaddings(paddings_data); +// m.Invoke(); +class PadOpDynamicModel : public PadOpModel { + public: + PadOpDynamicModel(std::initializer_list input_shape, + std::initializer_list paddings_shape) { + input_ = AddInput(TensorType_FLOAT32); + paddings_ = AddInput(TensorType_INT32); + output_ = AddOutput(TensorType_FLOAT32); + + SetBuiltinOp(BuiltinOperator_PAD, BuiltinOptions_PadOptions, + CreatePadOptions(builder_).Union()); + BuildInterpreter({input_shape, paddings_shape}); + } }; TEST(PadOpTest, TooManyDimensions) { EXPECT_DEATH( - PadOpModel({1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 2, 3, 4, 5, 6, 7, 8, 9}, - {1, 2, 3, 4, 5, 6, 7, 8, 9}), + PadOpConstModel({1, 2, 3, 4, 5, 6, 7, 8, 9}, {9, 2}, + {1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9}), "dims != 4"); } -// TODO(nupurgarg): Test case where before padding and after padding arrays -// don't contain the same number of dimensions. TEST(PadOpTest, UnequalDimensions) { - EXPECT_DEATH(PadOpModel({1, 1, 2, 1}, {1, 2, 3}, {1, 2, 3}), - "dims != op_context.params->num_dimensions"); + EXPECT_DEATH(PadOpConstModel({1, 1, 2, 1}, {3, 2}, {1, 1, 2, 2, 3, 3}), + "3 != 4"); } TEST(PadOpTest, InvalidPadValue) { - EXPECT_DEATH(PadOpModel({1, 1, 2, 1}, {0, 1, 2, 0}, {0, -1, -1, 0}), - "Pad value has to be greater than equal to 0."); + EXPECT_DEATH( + PadOpConstModel({1, 1, 2, 1}, {4, 2}, {0, 0, 1, -1, 2, -1, 0, 0}), + "Pad value has to be greater than equal to 0."); } -TEST(PadOpTest, SimpleTest) { - PadOpModel m({1, 2, 2, 1}, {0, 1, 1, 0}, {0, 1, 1, 0}); +TEST(PadOpTest, SimpleConstTest) { + // Padding is represented as four 2-D lists representing above padding and + // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). + PadOpConstModel m({1, 2, 2, 1}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}); m.SetInput({1, 2, 3, 4}); m.Invoke(); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4, @@ -78,10 +113,30 @@ TEST(PadOpTest, SimpleTest) { EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } -TEST(PadOpTest, AdvancedTest) { - // The padding is input in the order of batch, height, width, depth. - PadOpModel m({1, 2, 3, 1}, {0, 0, 1, 0}, {0, 2, 3, 0}); +TEST(PadOpTest, SimpleDynamicTest) { + PadOpDynamicModel m({1, 2, 2, 1}, {4, 2}); + m.SetInput({1, 2, 3, 4}); + m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); + m.Invoke(); + EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4, + 0, 0, 0, 0, 0})); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); +} + +TEST(PadOpTest, AdvancedConstTest) { + PadOpConstModel m({1, 2, 3, 1}, {4, 2}, {0, 0, 0, 2, 1, 3, 0, 0}); + m.SetInput({1, 2, 3, 4, 5, 6}); + m.Invoke(); + EXPECT_THAT(m.GetOutput(), + ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); +} + +TEST(PadOpTest, AdvancedDynamicTest) { + PadOpDynamicModel m({1, 2, 3, 1}, {4, 2}); m.SetInput({1, 2, 3, 4, 5, 6}); + m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0}); m.Invoke(); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, diff --git a/tensorflow/contrib/lite/kernels/test_util.cc b/tensorflow/contrib/lite/kernels/test_util.cc index b69f2b3e4b..3a58e7ec32 100644 --- a/tensorflow/contrib/lite/kernels/test_util.cc +++ b/tensorflow/contrib/lite/kernels/test_util.cc @@ -49,7 +49,7 @@ std::vector> ArrayFloatNear(const std::vector& values, return matchers; } -int SingleOpModel::AddTensor(TensorData t) { +int SingleOpModel::AddTensor(TensorData t, std::initializer_list data) { int id = tensors_.size(); // This is slightly different depending on whether we are adding a @@ -78,8 +78,23 @@ int SingleOpModel::AddTensor(TensorData t) { builder_.CreateVector({t.zero_point})); } - tensors_.push_back(CreateTensor(builder_, builder_.CreateVector({}), - t.type, /*buffer=*/0, + int buffer_id = 0; + if (data.size()) { + // Initialize buffers list with empty buffer to allow for non-const tensors. + if (buffers_.empty()) { + buffers_.push_back(CreateBuffer(builder_, builder_.CreateVector({}))); + } + + // Add data as a Buffer to buffers list. + buffer_id = buffers_.size(); + auto data_buffer = + builder_.CreateVector(reinterpret_cast(data.begin()), + sizeof(int) * data.size()); + buffers_.push_back(CreateBuffer(builder_, data_buffer)); + } + + tensors_.push_back(CreateTensor(builder_, builder_.CreateVector(t.shape), + t.type, /*buffer=*/buffer_id, /*name=*/0, q_params)); tensor_data_[id] = t; @@ -88,7 +103,15 @@ int SingleOpModel::AddTensor(TensorData t) { } int SingleOpModel::AddInput(const TensorData& t) { - int id = AddTensor(t); + int id = AddTensor(t, {}); + inputs_.push_back(id); + return id; +} + +int SingleOpModel::AddConstInput(TensorType type, + std::initializer_list data, + std::initializer_list shape) { + int id = AddTensor(TensorData{type, shape}, data); inputs_.push_back(id); return id; } @@ -100,7 +123,7 @@ int SingleOpModel::AddNullInput() { } int SingleOpModel::AddOutput(const TensorData& t) { - int id = AddTensor(t); + int id = AddTensor(t, {}); outputs_.push_back(id); return id; } @@ -142,8 +165,7 @@ void SingleOpModel::BuildInterpreter( subgraphs.push_back(subgraph); auto subgraphs_flatbuffer = builder_.CreateVector(subgraphs); - std::vector> buffers_vec; - auto buffers = builder_.CreateVector(buffers_vec); + auto buffers = builder_.CreateVector(buffers_); auto description = builder_.CreateString("programmatic model"); builder_.Finish(CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes, subgraphs_flatbuffer, description, buffers)); diff --git a/tensorflow/contrib/lite/kernels/test_util.h b/tensorflow/contrib/lite/kernels/test_util.h index 531c1366a8..b9c0ba8f47 100644 --- a/tensorflow/contrib/lite/kernels/test_util.h +++ b/tensorflow/contrib/lite/kernels/test_util.h @@ -98,6 +98,10 @@ class SingleOpModel { int AddInput(TensorType type) { return AddInput(TensorData{type}); } int AddInput(const TensorData& t); + // Add a Tensor containing const data and return the tensor id. + int AddConstInput(TensorType type, std::initializer_list data, + std::initializer_list shape); + // Add a null input tensor (optional input) and return kOptionalTensor. int AddNullInput(); @@ -181,7 +185,7 @@ class SingleOpModel { std::unique_ptr interpreter_; private: - int AddTensor(TensorData t); + int AddTensor(TensorData t, std::initializer_list data); std::map tensor_data_; std::vector inputs_; @@ -189,6 +193,7 @@ class SingleOpModel { std::vector> tensors_; std::vector> opcodes_; std::vector> operators_; + std::vector> buffers_; std::map> custom_registrations_; }; diff --git a/tensorflow/contrib/lite/model.cc b/tensorflow/contrib/lite/model.cc index a01b74f9da..95949be9e6 100644 --- a/tensorflow/contrib/lite/model.cc +++ b/tensorflow/contrib/lite/model.cc @@ -486,25 +486,6 @@ void* ParseOpData(const Operator* op, BuiltinOperator op_type, break; } case BuiltinOperator_PAD: { - auto* params = MallocPOD(); - if (auto* schema_params = op->builtin_options_as_PadOptions()) { - auto* before_padding = schema_params->before_padding(); - FlatBufferIntVectorToArray(sizeof(params->before_padding), - before_padding, params->before_padding, - error_reporter); - - auto* after_padding = schema_params->after_padding(); - FlatBufferIntVectorToArray(sizeof(params->after_padding), after_padding, - params->after_padding, error_reporter); - - if (before_padding->Length() != after_padding->Length()) { - error_reporter->Report( - "Before padding and after padding arrays need to contain the " - "same number of dimensions.\n"); - } - params->num_dimensions = after_padding->Length(); - } - builtin_data = reinterpret_cast(params); break; } case BuiltinOperator_RESHAPE: { diff --git a/tensorflow/contrib/lite/schema/schema.fbs b/tensorflow/contrib/lite/schema/schema.fbs index 2172135f49..ec202cd407 100644 --- a/tensorflow/contrib/lite/schema/schema.fbs +++ b/tensorflow/contrib/lite/schema/schema.fbs @@ -275,8 +275,6 @@ table CallOptions { } table PadOptions { - before_padding:[int]; - after_padding:[int]; } table ReshapeOptions { diff --git a/tensorflow/contrib/lite/schema/schema_generated.h b/tensorflow/contrib/lite/schema/schema_generated.h index b756891f66..c04a73a2bf 100644 --- a/tensorflow/contrib/lite/schema/schema_generated.h +++ b/tensorflow/contrib/lite/schema/schema_generated.h @@ -2657,26 +2657,13 @@ flatbuffers::Offset CreateCallOptions( struct PadOptionsT : public flatbuffers::NativeTable { typedef PadOptions TableType; - std::vector before_padding; - std::vector after_padding; PadOptionsT() {} }; struct PadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef PadOptionsT NativeTableType; - enum { VT_BEFORE_PADDING = 4, VT_AFTER_PADDING = 6 }; - const flatbuffers::Vector *before_padding() const { - return GetPointer *>(VT_BEFORE_PADDING); - } - const flatbuffers::Vector *after_padding() const { - return GetPointer *>(VT_AFTER_PADDING); - } bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_BEFORE_PADDING) && - verifier.Verify(before_padding()) && - VerifyOffset(verifier, VT_AFTER_PADDING) && - verifier.Verify(after_padding()) && verifier.EndTable(); + return VerifyTableStart(verifier) && verifier.EndTable(); } PadOptionsT *UnPack( const flatbuffers::resolver_function_t *_resolver = nullptr) const; @@ -2691,14 +2678,6 @@ struct PadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct PadOptionsBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_before_padding( - flatbuffers::Offset> before_padding) { - fbb_.AddOffset(PadOptions::VT_BEFORE_PADDING, before_padding); - } - void add_after_padding( - flatbuffers::Offset> after_padding) { - fbb_.AddOffset(PadOptions::VT_AFTER_PADDING, after_padding); - } explicit PadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -2712,24 +2691,11 @@ struct PadOptionsBuilder { }; inline flatbuffers::Offset CreatePadOptions( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset> before_padding = 0, - flatbuffers::Offset> after_padding = 0) { + flatbuffers::FlatBufferBuilder &_fbb) { PadOptionsBuilder builder_(_fbb); - builder_.add_after_padding(after_padding); - builder_.add_before_padding(before_padding); return builder_.Finish(); } -inline flatbuffers::Offset CreatePadOptionsDirect( - flatbuffers::FlatBufferBuilder &_fbb, - const std::vector *before_padding = nullptr, - const std::vector *after_padding = nullptr) { - return tflite::CreatePadOptions( - _fbb, before_padding ? _fbb.CreateVector(*before_padding) : 0, - after_padding ? _fbb.CreateVector(*after_padding) : 0); -} - flatbuffers::Offset CreatePadOptions( flatbuffers::FlatBufferBuilder &_fbb, const PadOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); @@ -5572,24 +5538,6 @@ inline void PadOptions::UnPackTo( PadOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { (void)_o; (void)_resolver; - { - auto _e = before_padding(); - if (_e) { - _o->before_padding.resize(_e->size()); - for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { - _o->before_padding[_i] = _e->Get(_i); - } - } - }; - { - auto _e = after_padding(); - if (_e) { - _o->after_padding.resize(_e->size()); - for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { - _o->after_padding[_i] = _e->Get(_i); - } - } - }; } inline flatbuffers::Offset PadOptions::Pack( @@ -5609,11 +5557,7 @@ inline flatbuffers::Offset CreatePadOptions( const flatbuffers::rehasher_function_t *__rehasher; } _va = {&_fbb, _o, _rehasher}; (void)_va; - auto _before_padding = - _o->before_padding.size() ? _fbb.CreateVector(_o->before_padding) : 0; - auto _after_padding = - _o->after_padding.size() ? _fbb.CreateVector(_o->after_padding) : 0; - return tflite::CreatePadOptions(_fbb, _before_padding, _after_padding); + return tflite::CreatePadOptions(_fbb); } inline ReshapeOptionsT *ReshapeOptions::UnPack( diff --git a/tensorflow/contrib/lite/testing/generate_examples.py b/tensorflow/contrib/lite/testing/generate_examples.py index c225cd4f00..a639351657 100644 --- a/tensorflow/contrib/lite/testing/generate_examples.py +++ b/tensorflow/contrib/lite/testing/generate_examples.py @@ -1141,28 +1141,43 @@ def make_pad_tests(zip_path): "input_shape": [[1, 1, 2, 1], [2, 1, 1, 1]], "paddings": [[[0, 0], [0, 1], [2, 3], [0, 0]], [[0, 1], [0, 0], [0, 0], [2, 3]]], + "constant_paddings": [True, False], }, # Non-4D use case. { "dtype": [tf.int32, tf.int64, tf.float32], "input_shape": [[1, 2], [0, 1, 2]], "paddings": [[[0, 1], [2, 3]]], + "constant_paddings": [True, False], }, ] def build_graph(parameters): + """Build a pad graph given `parameters`.""" input_tensor = tf.placeholder( dtype=parameters["dtype"], name="input", shape=parameters["input_shape"]) - out = tf.pad(input_tensor, paddings=parameters["paddings"]) - return [input_tensor], [out] + + # Get paddings as either a placeholder or constants. + if parameters["constant_paddings"]: + paddings = parameters["paddings"] + input_tensors = [input_tensor] + else: + shape = [len(parameters["paddings"]), 2] + paddings = tf.placeholder(dtype=tf.int32, name="padding", shape=shape) + input_tensors = [input_tensor, paddings] + + out = tf.pad(input_tensor, paddings=paddings) + return input_tensors, [out] def build_inputs(parameters, sess, inputs, outputs): - input_values = create_tensor_data(parameters["dtype"], - parameters["input_shape"]) - return [input_values], sess.run( - outputs, feed_dict=dict(zip(inputs, [input_values]))) + values = [ + create_tensor_data(parameters["dtype"], parameters["input_shape"]) + ] + if not parameters["constant_paddings"]: + values.append(np.array(parameters["paddings"])) + return values, sess.run(outputs, feed_dict=dict(zip(inputs, values))) make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) diff --git a/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc b/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc index 36aa09090b..41652a07d2 100644 --- a/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc +++ b/tensorflow/contrib/lite/testing/generated_examples_zip_test.cc @@ -48,50 +48,51 @@ tensorflow::Env* env = tensorflow::Env::Default(); // TODO(ahentz): make sure we clean this list up frequently. std::map kBrokenTests = { // Add doesn't support broadcasting. - {R"(adda.*input_shape_1=\[1,3,4,3\],input_shape_2=\[3\])", "68500195"}, - {R"(mula.*input_shape_1=\[1,3,4,3\],input_shape_2=\[3\])", "68500195"}, - {R"(diva.*input_shape_1=\[1,3,4,3\],input_shape_2=\[3\])", "68500195"}, - {R"(suba.*input_shape_1=\[1,3,4,3\],input_shape_2=\[3\])", "68500195"}, + {R"(^\/adda.*input_shape_1=\[1,3,4,3\],input_shape_2=\[3\])", "68500195"}, + {R"(^\/mula.*input_shape_1=\[1,3,4,3\],input_shape_2=\[3\])", "68500195"}, + {R"(^\/diva.*input_shape_1=\[1,3,4,3\],input_shape_2=\[3\])", "68500195"}, + {R"(^\/suba.*input_shape_1=\[1,3,4,3\],input_shape_2=\[3\])", "68500195"}, // Add only supports float32. (and "constant" tests use Add) - {R"(adda.*int32)", "68808744"}, - {R"(constant.*int32)", "68808744"}, - {R"(mul.*int32)", "68808744"}, - {R"(div.*int32)", "68808744"}, - {R"(sub.*int32)", "68808744"}, + {R"(^\/adda.*int32)", "68808744"}, + {R"(^\/constant.*int32)", "68808744"}, + {R"(^\/mul.*int32)", "68808744"}, + {R"(^\/div.*int32)", "68808744"}, + {R"(^\/sub.*int32)", "68808744"}, // Pad only supports 4D tensors. - {R"(paddtype=.*,input_shape=\[.,.\],paddings=\[\[.,.\],\[.,.\]\])", + {R"(^\/pad.*,input_shape=\[.,.\],paddings=\[\[.,.\],\[.,.\]\])", "70527055"}, // L2Norm only supports tensors with 4D or fewer. - {R"(l2normdim=.*,epsilon=.*,input_shape=\[.,.,.,.,.*\])", "67963684"}, + {R"(^\/l2normdim=.*,epsilon=.*,input_shape=\[.,.,.,.,.*\])", "67963684"}, // SpaceToBatch only supports 4D tensors. - {R"(space_to_batch_nd.*input_shape=\[1,4,4,4,1,1\])", "70848787"}, + {R"(^\/space_to_batch_nd.*input_shape=\[1,4,4,4,1,1\])", "70848787"}, // L2Norm only works for dim=-1. - {R"(l2normdim=-2,epsilon=.*,input_shape=\[.,.\])", "67963812"}, - {R"(l2normdim=0,epsilon=.*,input_shape=\[.,.\])", "67963812"}, - {R"(l2normdim=-2,epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, - {R"(l2normdim=-2,epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, - {R"(l2normdim=2,epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, - {R"(l2normdim=2,epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, - {R"(l2normdim=0,epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, - {R"(l2normdim=0,epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, - {R"(l2normdim=1,epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, - {R"(l2normdim=1,epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, - {R"(l2normdim=\[2,3\],epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, - {R"(l2normdim=\[2,3\],epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, + {R"(^\/l2normdim=-2,epsilon=.*,input_shape=\[.,.\])", "67963812"}, + {R"(^\/l2normdim=0,epsilon=.*,input_shape=\[.,.\])", "67963812"}, + {R"(^\/l2normdim=-2,epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, + {R"(^\/l2normdim=-2,epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, + {R"(^\/l2normdim=2,epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, + {R"(^\/l2normdim=2,epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, + {R"(^\/l2normdim=0,epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, + {R"(^\/l2normdim=0,epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, + {R"(^\/l2normdim=1,epsilon=.*,input_shape=\[3,15,14,3\])", "67963812"}, + {R"(^\/l2normdim=1,epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, + {R"(^\/l2normdim=\[2,3\],epsilon=.*,input_shape=\[3,15,14,3\])", + "67963812"}, + {R"(^\/l2normdim=\[2,3\],epsilon=.*,input_shape=\[1,3,4,3\])", "67963812"}, // ResizeBilinear looks completely incompatible with Tensorflow - {R"(resize_bilinear.*dtype=tf.int32)", "72401107"}, - {R"(resize_bilinearalign_corners=True,.*,size=\[2,2\])", "72401483"}, - {R"(resize_bilinearalign_corners=True,.*,size=\[4,3\])", "72401483"}, - {R"(resize_bilinearalign_corners=True,.*,size=\[5,6\])", "72401483"}, + {R"(^\/resize_bilinear.*dtype=tf.int32)", "72401107"}, + {R"(^\/resize_bilinearalign_corners=True,.*,size=\[2,2\])", "72401483"}, + {R"(^\/resize_bilinearalign_corners=True,.*,size=\[4,3\])", "72401483"}, + {R"(^\/resize_bilinearalign_corners=True,.*,size=\[5,6\])", "72401483"}, // Transpose only supports 1D-4D input tensors. - {R"(transposedtype=.*,input_shape=\[.,.,.,.,.\],perm=.*)", "71545879"}, + {R"(^\/transposedtype=.*,input_shape=\[.,.,.,.,.\],perm=.*)", "71545879"}, }; // Allows test data to be unzipped into a temporary directory and makes diff --git a/tensorflow/contrib/lite/toco/tflite/operator.cc b/tensorflow/contrib/lite/toco/tflite/operator.cc index 0c2b570aad..d75d1fcc5b 100644 --- a/tensorflow/contrib/lite/toco/tflite/operator.cc +++ b/tensorflow/contrib/lite/toco/tflite/operator.cc @@ -474,19 +474,11 @@ class Pad : public BuiltinOperator WriteOptions( const TocoOperator& op, flatbuffers::FlatBufferBuilder* builder) const override { - auto before_padding = builder->CreateVector(op.left_padding); - auto after_padding = builder->CreateVector(op.right_padding); - return ::tflite::CreatePadOptions(*builder, before_padding, after_padding); + return ::tflite::CreatePadOptions(*builder); } void ReadOptions(const TfLiteOptions& options, TocoOperator* op) const override { - op->left_padding.insert(op->left_padding.end(), - options.before_padding()->begin(), - options.before_padding()->end()); - op->right_padding.insert(op->right_padding.end(), - options.after_padding()->begin(), - options.after_padding()->end()); } }; diff --git a/tensorflow/contrib/lite/toco/tflite/operator_test.cc b/tensorflow/contrib/lite/toco/tflite/operator_test.cc index de79c70e1b..9036a16d1c 100644 --- a/tensorflow/contrib/lite/toco/tflite/operator_test.cc +++ b/tensorflow/contrib/lite/toco/tflite/operator_test.cc @@ -258,16 +258,6 @@ TEST_F(OperatorTest, BuiltinMaxPool) { EXPECT_EQ(op.kheight, output_toco_op->kheight); } -TEST_F(OperatorTest, BuiltinPad) { - PadOperator op; - op.left_padding = {1, 2, 3}; - op.right_padding = {1, 2, 3}; - auto output_toco_op = - SerializeAndDeserialize(GetOperator("PAD", OperatorType::kPad), op); - EXPECT_EQ(op.left_padding, output_toco_op->left_padding); - EXPECT_EQ(op.right_padding, output_toco_op->right_padding); -} - TEST_F(OperatorTest, BuiltinReshape) { TensorFlowReshapeOperator op; op.shape = {1, 2, 4, 5, 8}; -- GitLab From 7ed85251e0b17f04a073100717b97a36ebc1b61d Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Wed, 24 Jan 2018 13:31:33 -0800 Subject: [PATCH 203/258] Update docs and test cases for missing types in `tf.zeros_like` (#15934) * Update docs for missing types in `tf.zeros_like` This fix update docs for missing types in `tf.zeros_like` where `half` and `string` are supported but not listed. Signed-off-by: Yong Tang * Also enable test cases for missing types to `tf.zeros_like` Signed-off-by: Yong Tang --- tensorflow/python/kernel_tests/constant_op_test.py | 14 ++++++++------ tensorflow/python/ops/array_ops.py | 6 +++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tensorflow/python/kernel_tests/constant_op_test.py b/tensorflow/python/kernel_tests/constant_op_test.py index 030c690167..576bb68ba4 100644 --- a/tensorflow/python/kernel_tests/constant_op_test.py +++ b/tensorflow/python/kernel_tests/constant_op_test.py @@ -454,18 +454,20 @@ class ZerosLikeTest(test.TestCase): def testZerosLikeCPU(self): for dtype in [ - dtypes_lib.float32, dtypes_lib.float64, dtypes_lib.int8, - dtypes_lib.uint8, dtypes_lib.int16, dtypes_lib.uint16, dtypes_lib.int32, - dtypes_lib.int64, dtypes_lib.bool, dtypes_lib.complex64, - dtypes_lib.complex128, dtypes_lib.string + dtypes_lib.half, dtypes_lib.float32, dtypes_lib.float64, + dtypes_lib.int8, dtypes_lib.uint8, dtypes_lib.int16, dtypes_lib.uint16, + dtypes_lib.int32, dtypes_lib.int64, dtypes_lib.bool, + dtypes_lib.complex64, dtypes_lib.complex128, dtypes_lib.string ]: self._compareZeros(dtype, fully_defined_shape=False, use_gpu=False) self._compareZeros(dtype, fully_defined_shape=True, use_gpu=False) def testZerosLikeGPU(self): for dtype in [ - dtypes_lib.float32, dtypes_lib.float64, dtypes_lib.int32, - dtypes_lib.bool, dtypes_lib.int64, dtypes_lib.string + dtypes_lib.half, dtypes_lib.float32, dtypes_lib.float64, + dtypes_lib.int32, dtypes_lib.int64, + dtypes_lib.complex64, dtypes_lib.complex128, + dtypes_lib.bool ]: self._compareZeros(dtype, fully_defined_shape=False, use_gpu=True) self._compareZeros(dtype, fully_defined_shape=True, use_gpu=True) diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index 6210204d80..24a0c18619 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -1588,9 +1588,9 @@ def zeros_like(tensor, dtype=None, name=None, optimize=True): Args: tensor: A `Tensor`. - dtype: A type for the returned `Tensor`. Must be `float32`, `float64`, - `int8`, `uint8`, `int16`, `uint16`, int32`, `int64`, - `complex64`, `complex128` or `bool`. + dtype: A type for the returned `Tensor`. Must be `float16`, `float32`, + `float64`, `int8`, `uint8`, `int16`, `uint16`, `int32`, `int64`, + `complex64`, `complex128`, `bool` or `string`. name: A name for the operation (optional). optimize: if true, attempt to statically determine the shape of 'tensor' and encode it as a constant. -- GitLab From 64cbff313353c248241b7a447f5ef57838f116fa Mon Sep 17 00:00:00 2001 From: Darjan Salaj Date: Wed, 24 Jan 2018 22:31:51 +0100 Subject: [PATCH 204/258] Documentation fix to contrib.signals (#15877) * Documentation fix to contrib.signals Fixed very confusing little typo * Update contrib.signal.md * Update contrib.signal.md --- tensorflow/docs_src/api_guides/python/contrib.signal.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/docs_src/api_guides/python/contrib.signal.md b/tensorflow/docs_src/api_guides/python/contrib.signal.md index 85ef3ad134..0f7690f80a 100644 --- a/tensorflow/docs_src/api_guides/python/contrib.signal.md +++ b/tensorflow/docs_src/api_guides/python/contrib.signal.md @@ -28,14 +28,14 @@ The `axis` parameter to @{tf.contrib.signal.frame} allows you to frame tensors with inner structure (e.g. a spectrogram): ```python -# `magnitude_spectrograms` is a [batch_size, ?, 127] tensor of spectrograms. We +# `magnitude_spectrograms` is a [batch_size, ?, 129] tensor of spectrograms. We # would like to produce overlapping fixed-size spectrogram patches; for example, # for use in a situation where a fixed size input is needed. magnitude_spectrograms = tf.abs(tf.contrib.signal.stft( signals, frame_length=256, frame_step=64, fft_length=256)) -# `spectrogram_patches` is a [batch_size, ?, 64, 127] tensor containing a -# variable number of [64, 127] spectrogram patches per batch item. +# `spectrogram_patches` is a [batch_size, ?, 64, 129] tensor containing a +# variable number of [64, 129] spectrogram patches per batch item. spectrogram_patches = tf.contrib.signal.frame( magnitude_spectrograms, frame_length=64, frame_step=16, axis=1) ``` -- GitLab From a651cd8a44426d2ce6cf62138ea5f18e922656e9 Mon Sep 17 00:00:00 2001 From: Scott Tseng Date: Thu, 25 Jan 2018 05:41:55 +0800 Subject: [PATCH 205/258] Fix a buildscript error which prevents macro being used by other workspaces (#16241) Converting to label and back to string will prepend current workspace, e.g: "//tensorflow" -> "@org_tensorflow//tensorflow". Projects who integrate TensorFlow from another Bazel workspace, and use macros like tflite_copts() need the prefix. For more info please take a look at: https://github.com/bazelbuild/bazel/issues/1551 --- tensorflow/contrib/lite/build_def.bzl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tensorflow/contrib/lite/build_def.bzl b/tensorflow/contrib/lite/build_def.bzl index 0a097d5a69..19829e4991 100644 --- a/tensorflow/contrib/lite/build_def.bzl +++ b/tensorflow/contrib/lite/build_def.bzl @@ -5,25 +5,25 @@ def tflite_copts(): copts = [ "-DFARMHASH_NO_CXX_STRING", ] + select({ - "//tensorflow:android_arm64": [ + str(Label("//tensorflow:android_arm64")): [ "-std=c++11", "-O3", ], - "//tensorflow:android_arm": [ + str(Label("//tensorflow:android_arm")): [ "-mfpu=neon", "-mfloat-abi=softfp", "-std=c++11", "-O3", ], - "//tensorflow:android_x86": [ + str(Label("//tensorflow:android_x86")): [ "-DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK", ], - "//tensorflow:ios_x86_64": [ + str(Label("//tensorflow:ios_x86_64")): [ "-msse4.1", ], "//conditions:default": [], }) + select({ - "//tensorflow:with_default_optimizations": [], + str(Label("//tensorflow:with_default_optimizations")): [], "//conditions:default": ["-DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK"], }) -- GitLab From aa53e0f5411a844bf4b7e0ea832c18485697d3e0 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 24 Jan 2018 13:39:02 -0800 Subject: [PATCH 206/258] [TF:XLA] Bump open source llvm revision to r323309 PiperOrigin-RevId: 183133556 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 79e14e0e92..9145d9e58a 100644 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -475,11 +475,11 @@ def tf_workspace(path_prefix="", tf_repo_name=""): tf_http_archive( name = "llvm", urls = [ - "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/95461910b8134c70de1d94f6854b64cfff3615d9.tar.gz", - "https://github.com/llvm-mirror/llvm/archive/95461910b8134c70de1d94f6854b64cfff3615d9.tar.gz", + "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/11a2ca6eea8a7fe240a14c0c35fd2017341279be.tar.gz", + "https://github.com/llvm-mirror/llvm/archive/11a2ca6eea8a7fe240a14c0c35fd2017341279be.tar.gz", ], - sha256 = "2e16617820ec59e3b57b6800aab00238c2e5955182b56a0fbc03bde12b5f2d7b", - strip_prefix = "llvm-95461910b8134c70de1d94f6854b64cfff3615d9", + sha256 = "b5429ccf8d57273cb8489714f728c997cd720ec66fc2c0292422ab8f0e729ce0", + strip_prefix = "llvm-11a2ca6eea8a7fe240a14c0c35fd2017341279be", build_file = str(Label("//third_party/llvm:llvm.BUILD")), ) -- GitLab From a8343c49796018234b692831050865509c6e5398 Mon Sep 17 00:00:00 2001 From: Jianwei Xie Date: Wed, 24 Jan 2018 13:50:09 -0800 Subject: [PATCH 207/258] fix lite problem --- tensorflow/contrib/lite/model.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tensorflow/contrib/lite/model.cc b/tensorflow/contrib/lite/model.cc index a01b74f9da..409259b14f 100644 --- a/tensorflow/contrib/lite/model.cc +++ b/tensorflow/contrib/lite/model.cc @@ -476,13 +476,6 @@ void* ParseOpData(const Operator* op, BuiltinOperator op_type, break; } case BuiltinOperator_RESIZE_BILINEAR: { - auto* params = MallocPOD(); - if (auto* schema_params = - op->builtin_options_as_ResizeBilinearOptions()) { - params->new_height = schema_params->new_height(); - params->new_width = schema_params->new_width(); - } - builtin_data = reinterpret_cast(params); break; } case BuiltinOperator_PAD: { -- GitLab From f7b60fd704ced02f250b2dd0da436cf0ad9c9a8c Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Wed, 24 Jan 2018 14:02:14 -0800 Subject: [PATCH 208/258] Silent copies for int32 tensors in TFE. Fixes #16106 PiperOrigin-RevId: 183137298 --- tensorflow/c/eager/c_api.cc | 9 ++++++++- tensorflow/c/eager/c_api.h | 6 ++++-- tensorflow/c/eager/c_api_internal.h | 3 ++- tensorflow/python/eager/context.py | 4 ++++ tensorflow/python/eager/core_test.py | 9 +++++++++ tensorflow/python/eager/function_test.py | 5 +++-- tensorflow/python/eager/ops_test.py | 10 ---------- tensorflow/python/framework/ops.py | 8 +++++--- tensorflow/python/pywrap_tfe.i | 1 + 9 files changed, 36 insertions(+), 19 deletions(-) diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc index ecba8c0109..a76c8f5ec0 100644 --- a/tensorflow/c/eager/c_api.cc +++ b/tensorflow/c/eager/c_api.cc @@ -453,9 +453,16 @@ tensorflow::Status ValidateInputTypeAndPlacement( op->input_devices[i] == nullptr ? host_device : op->input_devices[i]; if (expected_device != actual_device) { switch (TFE_ContextGetDevicePlacementPolicy(ctx)) { - case TFE_DEVICE_PLACEMENT_EXPLICIT: + case TFE_DEVICE_PLACEMENT_SILENT_FOR_INT32: // TODO(xpan): See if we could bubble python related error up // to python level. + if (op->inputs[i].dtype() == tensorflow::DT_INT32) { + // Note: enabling silent copies of int32 tensors to match behavior + // of graph mode. + break; + } + TF_FALLTHROUGH_INTENDED; + case TFE_DEVICE_PLACEMENT_EXPLICIT: return tensorflow::errors::InvalidArgument( "Tensors on conflicting devices:" " cannot compute ", diff --git a/tensorflow/c/eager/c_api.h b/tensorflow/c/eager/c_api.h index 26e6d94753..387de07894 100644 --- a/tensorflow/c/eager/c_api.h +++ b/tensorflow/c/eager/c_api.h @@ -61,14 +61,16 @@ TF_CAPI_EXPORT extern void TFE_ContextOptionsSetConfig( // Controls how to act when we try to run an operation on a given device but // some input tensors are not on that device. typedef enum TFE_ContextDevicePlacementPolicy { - // The default: running operations with input tensors on the wrong device will - // fail. + // Running operations with input tensors on the wrong device will fail. TFE_DEVICE_PLACEMENT_EXPLICIT = 0, // Copy the tensor to the right device but log a warning. TFE_DEVICE_PLACEMENT_WARN = 1, // Silently copy the tensor, which has a performance cost since the // operation will be blocked till the copy completes. TFE_DEVICE_PLACEMENT_SILENT = 2, + // Default placement policy which silently copies int32 tensors but not other + // dtypes. + TFE_DEVICE_PLACEMENT_SILENT_FOR_INT32 = 3, } TFE_ContextDevicePlacementPolicy; TF_CAPI_EXPORT extern void TFE_ContextOptionsSetDevicePlacementPolicy( diff --git a/tensorflow/c/eager/c_api_internal.h b/tensorflow/c/eager/c_api_internal.h index f40c41576c..a6f76c732f 100644 --- a/tensorflow/c/eager/c_api_internal.h +++ b/tensorflow/c/eager/c_api_internal.h @@ -38,7 +38,8 @@ limitations under the License. struct TFE_ContextOptions { TF_SessionOptions session_options; - TFE_ContextDevicePlacementPolicy policy{TFE_DEVICE_PLACEMENT_EXPLICIT}; + TFE_ContextDevicePlacementPolicy policy{ + TFE_DEVICE_PLACEMENT_SILENT_FOR_INT32}; }; struct TFE_Context { diff --git a/tensorflow/python/eager/context.py b/tensorflow/python/eager/context.py index 0569791352..b6c7d82323 100644 --- a/tensorflow/python/eager/context.py +++ b/tensorflow/python/eager/context.py @@ -49,6 +49,8 @@ _MAXINT32 = 2**31 - 1 DEVICE_PLACEMENT_EXPLICIT = pywrap_tensorflow.TFE_DEVICE_PLACEMENT_EXPLICIT DEVICE_PLACEMENT_WARN = pywrap_tensorflow.TFE_DEVICE_PLACEMENT_WARN DEVICE_PLACEMENT_SILENT = pywrap_tensorflow.TFE_DEVICE_PLACEMENT_SILENT +DEVICE_PLACEMENT_SILENT_FOR_INT32 = ( + pywrap_tensorflow.TFE_DEVICE_PLACEMENT_SILENT_FOR_INT32) # TODO(agarwal): better name ? @@ -122,6 +124,8 @@ class Context(object): right device but raises a warning. tfe.DEVICE_PLACEMENT_SILENT: silently copies the tensors. This might hide performance problems. + tfe.DEVICE_PLACEMENT_SILENT_FOR_INT32: silently copies int32 tensors, + raising errors on the other ones. """ self._eager_context = _EagerContext() self._context_handle = None diff --git a/tensorflow/python/eager/core_test.py b/tensorflow/python/eager/core_test.py index 82438ecadb..ee3c10633e 100644 --- a/tensorflow/python/eager/core_test.py +++ b/tensorflow/python/eager/core_test.py @@ -33,6 +33,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import test_util +from tensorflow.python.ops import nn_ops def execute(op_name, num_outputs, inputs, attrs=None): @@ -112,6 +113,14 @@ class TFETest(test_util.TensorFlowTestCase): # is enabled; the stack entry should reflect this fact. self.assertFalse(stack_entry.is_building_function) + def testInt32GPU(self): + if not context.context().num_gpus(): + self.skipTest('No GPUs found') + with ops.device('gpu:0'): + xent = nn_ops.sparse_softmax_cross_entropy_with_logits( + logits=[[0.0, 0.0]], labels=[0]) + self.assertAllClose(xent, [0.69314718]) + def _runInThread(self, target, args): t = threading.Thread(target=target, args=args) try: diff --git a/tensorflow/python/eager/function_test.py b/tensorflow/python/eager/function_test.py index 9b08a35ff1..0babc29f17 100644 --- a/tensorflow/python/eager/function_test.py +++ b/tensorflow/python/eager/function_test.py @@ -400,10 +400,11 @@ class FunctionTest(test.TestCase): # The Reshape op requires the shape tensor to be placed in host memory. reshape = function.defun(array_ops.reshape) - value = constant_op.constant([1., 2.]).gpu() + value = constant_op.constant([1., 2.]) shape = constant_op.constant([2, 1]).gpu() with self.assertRaises(errors.InvalidArgumentError): - reshape(value, shape) + with ops.device('gpu:0'): + reshape(value, shape) def testDifferentiableFunctionNoneOutputs(self): diff --git a/tensorflow/python/eager/ops_test.py b/tensorflow/python/eager/ops_test.py index f8c5037dcf..f2e70341d9 100644 --- a/tensorflow/python/eager/ops_test.py +++ b/tensorflow/python/eager/ops_test.py @@ -24,7 +24,6 @@ from tensorflow.python.eager import execute from tensorflow.python.eager import test from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes -from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import test_util @@ -246,15 +245,6 @@ class OpsTest(test_util.TensorFlowTestCase): reshaped = array_ops.reshape(value, shape) self.assertAllEqual([[1], [2]], reshaped.cpu()) - # And if the shape is in device memory, it should complain - # TODO(ashankar): Revisit this - perhaps instead of complaining, - # it should implicitly copy the tensor to host memory? - with self.assertRaisesRegexp( - errors.InvalidArgumentError, - 'cannot compute Reshape as input #1 was expected to be on.*' - 'using.*DEVICE_PLACEMENT_SILENT'): - reshaped = array_ops.reshape(value, shape.gpu()) - def testInt64(self): # Fill requires the first input to be an int32 tensor. self.assertAllEqual( diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index 6c4563f769..a1c2e07e94 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -5048,6 +5048,8 @@ def enable_eager_execution(config=None, device_policy=None): right device but raises a warning. tfe.DEVICE_PLACEMENT_SILENT: silently copies the tensors. This might hide performance problems. + tfe.DEVICE_PLACEMENT_SILENT_FOR_INT32: silently copies int32 tensors, + raising errors on the other ones. Raises: ValueError: If trying to create a context after using graph operations @@ -5059,10 +5061,10 @@ def enable_eager_execution(config=None, device_policy=None): "config must be a tf.ConfigProto, but got %s" % type(config)) if device_policy not in (None, context.DEVICE_PLACEMENT_EXPLICIT, context.DEVICE_PLACEMENT_WARN, - context.DEVICE_PLACEMENT_SILENT): + context.DEVICE_PLACEMENT_SILENT, + context.DEVICE_PLACEMENT_SILENT_FOR_INT32): raise ValueError( - "device_policy must be one of None, tfe.DEVICE_PLACEMENT_EXPLICIT, " - "tfe.DEVICE_PLACEMENT_WARN, tfe.DEVICE_PLACEMENT_SILENT" + "device_policy must be one of None, tfe.DEVICE_PLACEMENT_*" ) # pylint: disable=protected-access if context._default_mode == context.GRAPH_MODE: diff --git a/tensorflow/python/pywrap_tfe.i b/tensorflow/python/pywrap_tfe.i index ed7e4b17ad..3f25311a83 100644 --- a/tensorflow/python/pywrap_tfe.i +++ b/tensorflow/python/pywrap_tfe.i @@ -121,6 +121,7 @@ limitations under the License. %rename("%s") TFE_DEVICE_PLACEMENT_EXPLICIT; %rename("%s") TFE_DEVICE_PLACEMENT_WARN; %rename("%s") TFE_DEVICE_PLACEMENT_SILENT; +%rename("%s") TFE_DEVICE_PLACEMENT_SILENT_FOR_INT32; %include "tensorflow/c/eager/c_api.h" -- GitLab From 3ec5b5855eb4dc781f471df2f8c981b1f0951ff2 Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Wed, 24 Jan 2018 14:03:09 -0800 Subject: [PATCH 209/258] [Eager mode] Add an Eager-optimized version of the IteratorGetNext op. Since in eager mode the kernel execution happens on the calling thread (which would be blocked anyway), we can invoke the iterator synchronously, and do not need to perform a context switch to and from a background thread. Improves the latency benchmarks in //third_party/tensorflow/contrib/eager/python:datasets_test by approximately 7us to 13us per element. PiperOrigin-RevId: 183137488 --- tensorflow/contrib/eager/python/datasets.py | 7 +- .../api_def_IteratorGetNextSync.pbtxt | 10 +++ tensorflow/core/kernels/data/iterator_ops.cc | 39 ++++++++++- tensorflow/core/ops/dataset_ops.cc | 68 +++++++++---------- 4 files changed, 85 insertions(+), 39 deletions(-) create mode 100644 tensorflow/core/api_def/base_api/api_def_IteratorGetNextSync.pbtxt diff --git a/tensorflow/contrib/eager/python/datasets.py b/tensorflow/contrib/eager/python/datasets.py index a7f50c13bb..544a3eafc0 100644 --- a/tensorflow/contrib/eager/python/datasets.py +++ b/tensorflow/contrib/eager/python/datasets.py @@ -141,7 +141,12 @@ class Iterator(object): # TODO(ashankar): Consider removing this ops.device() contextmanager # and instead mimic ops placement in graphs: Operations on resource # handles execute on the same device as where the resource is placed. - ret = gen_dataset_ops.iterator_get_next( + # NOTE(mrry): Here we use the "_sync" variant of `iterator_get_next` + # because in eager mode this code will run synchronously on the calling + # thread. Therefore we do not need to make a defensive context switch + # to a background thread, and can achieve a small constant performance + # boost by invoking the iterator synchronously. + ret = gen_dataset_ops.iterator_get_next_sync( self._resource, output_types=self._flat_output_types, output_shapes=self._flat_output_shapes) diff --git a/tensorflow/core/api_def/base_api/api_def_IteratorGetNextSync.pbtxt b/tensorflow/core/api_def/base_api/api_def_IteratorGetNextSync.pbtxt new file mode 100644 index 0000000000..641679e8ea --- /dev/null +++ b/tensorflow/core/api_def/base_api/api_def_IteratorGetNextSync.pbtxt @@ -0,0 +1,10 @@ +op { + graph_op_name: "IteratorGetNextSync" + summary: "Gets the next output from the given iterator." + description: <GetNext()` may block and depend on an // inter-op thread pool thread, so we issue the call from the // owned thread pool. @@ -870,6 +870,39 @@ class IteratorGetNextOp : public AsyncOpKernel { std::unique_ptr thread_pool_; }; +class IteratorGetNextSyncOp : public OpKernel { + public: + explicit IteratorGetNextSyncOp(OpKernelConstruction* ctx) : OpKernel(ctx) {} + + void Compute(OpKernelContext* ctx) override { + IteratorResource* iterator; + OP_REQUIRES_OK(ctx, + LookupResource(ctx, HandleFromInput(ctx, 0), &iterator)); + core::ScopedUnref unref_iterator(iterator); + + std::vector components; + bool end_of_sequence = false; + + IteratorContext::Params params; + params.env = ctx->env(); + params.stats_aggregator_getter = [iterator]() { + return iterator->stats_aggregator(); + }; + params.runner = *(ctx->runner()); + params.function_library = iterator->function_library(); + IteratorContext iter_ctx(std::move(params)); + + OP_REQUIRES_OK(ctx, + iterator->GetNext(&iter_ctx, &components, &end_of_sequence)); + OP_REQUIRES(ctx, !end_of_sequence, errors::OutOfRange("End of sequence")); + + for (int i = 0; i < components.size(); ++i) { + // TODO(mrry): Check that the shapes match the shape attrs. + ctx->set_output(i, components[i]); + } + } +}; + class IteratorToStringHandleOp : public OpKernel { public: explicit IteratorToStringHandleOp(OpKernelConstruction* ctx) @@ -1033,6 +1066,8 @@ REGISTER_KERNEL_BUILDER(Name("OneShotIterator").Device(DEVICE_CPU), OneShotIteratorOp); REGISTER_KERNEL_BUILDER(Name("IteratorGetNext").Device(DEVICE_CPU), IteratorGetNextOp); +REGISTER_KERNEL_BUILDER(Name("IteratorGetNextSync").Device(DEVICE_CPU), + IteratorGetNextSyncOp); REGISTER_KERNEL_BUILDER(Name("IteratorToStringHandle").Device(DEVICE_CPU), IteratorToStringHandleOp); REGISTER_KERNEL_BUILDER(Name("IteratorFromStringHandle").Device(DEVICE_CPU), diff --git a/tensorflow/core/ops/dataset_ops.cc b/tensorflow/core/ops/dataset_ops.cc index b86816bb54..2cae814eab 100644 --- a/tensorflow/core/ops/dataset_ops.cc +++ b/tensorflow/core/ops/dataset_ops.cc @@ -409,53 +409,49 @@ REGISTER_OP("OneShotIterator") .SetIsStateful() .SetShapeFn(shape_inference::ScalarShape); +namespace { + +Status IteratorGetNextShapeFn(shape_inference::InferenceContext* c) { + shape_inference::ShapeHandle unused; + TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); + std::vector output_shapes; + TF_RETURN_IF_ERROR(c->GetAttr("output_shapes", &output_shapes)); + if (output_shapes.size() != c->num_outputs()) { + return errors::InvalidArgument( + "`output_shapes` must be the same length as `output_types` (", + output_shapes.size(), " vs. ", c->num_outputs()); + } + for (size_t i = 0; i < output_shapes.size(); ++i) { + shape_inference::ShapeHandle output_shape_handle; + TF_RETURN_IF_ERROR(c->MakeShapeFromPartialTensorShape( + output_shapes[i], &output_shape_handle)); + c->set_output(static_cast(i), output_shape_handle); + } + return Status::OK(); +} + +} // namespace + REGISTER_OP("IteratorGetNext") .Input("iterator: resource") .Output("components: output_types") .Attr("output_types: list(type) >= 1") .Attr("output_shapes: list(shape) >= 1") - .SetShapeFn([](shape_inference::InferenceContext* c) { - shape_inference::ShapeHandle unused; - TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); - std::vector output_shapes; - TF_RETURN_IF_ERROR(c->GetAttr("output_shapes", &output_shapes)); - if (output_shapes.size() != c->num_outputs()) { - return errors::InvalidArgument( - "`output_shapes` must be the same length as `output_types` (", - output_shapes.size(), " vs. ", c->num_outputs()); - } - for (size_t i = 0; i < output_shapes.size(); ++i) { - shape_inference::ShapeHandle output_shape_handle; - TF_RETURN_IF_ERROR(c->MakeShapeFromPartialTensorShape( - output_shapes[i], &output_shape_handle)); - c->set_output(static_cast(i), output_shape_handle); - } - return Status::OK(); - }); + .SetShapeFn(IteratorGetNextShapeFn); + +REGISTER_OP("IteratorGetNextSync") + .Input("iterator: resource") + .Output("components: output_types") + .Attr("output_types: list(type) >= 1") + .Attr("output_shapes: list(shape) >= 1") + .SetShapeFn(IteratorGetNextShapeFn); REGISTER_OP("DatasetToSingleElement") .Input("dataset: variant") .Output("components: output_types") .Attr("output_types: list(type) >= 1") .Attr("output_shapes: list(shape) >= 1") - .SetShapeFn([](shape_inference::InferenceContext* c) { - shape_inference::ShapeHandle unused; - TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); - std::vector output_shapes; - TF_RETURN_IF_ERROR(c->GetAttr("output_shapes", &output_shapes)); - if (output_shapes.size() != c->num_outputs()) { - return errors::InvalidArgument( - "`output_shapes` must be the same length as `output_types` (", - output_shapes.size(), " vs. ", c->num_outputs()); - } - for (size_t i = 0; i < output_shapes.size(); ++i) { - shape_inference::ShapeHandle output_shape_handle; - TF_RETURN_IF_ERROR(c->MakeShapeFromPartialTensorShape( - output_shapes[i], &output_shape_handle)); - c->set_output(static_cast(i), output_shape_handle); - } - return Status::OK(); - }); + .SetShapeFn(IteratorGetNextShapeFn); REGISTER_OP("IteratorToStringHandle") .Input("resource_handle: resource") -- GitLab From 43b4de97147ee7d62f5161ea07c76700f2089e36 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 14:17:05 -0800 Subject: [PATCH 210/258] Adds loss_reduction argument to canned estimators. PiperOrigin-RevId: 183139970 --- tensorflow/python/estimator/BUILD | 3 +++ tensorflow/python/estimator/canned/dnn.py | 16 ++++++++++++--- .../estimator/canned/dnn_linear_combined.py | 20 ++++++++++++++----- tensorflow/python/estimator/canned/linear.py | 20 ++++++++++++++----- ...nsorflow.estimator.-d-n-n-classifier.pbtxt | 2 +- ...or.-d-n-n-linear-combined-classifier.pbtxt | 2 +- ...tor.-d-n-n-linear-combined-regressor.pbtxt | 2 +- ...ensorflow.estimator.-d-n-n-regressor.pbtxt | 2 +- ...sorflow.estimator.-linear-classifier.pbtxt | 2 +- ...nsorflow.estimator.-linear-regressor.pbtxt | 2 +- 10 files changed, 52 insertions(+), 19 deletions(-) diff --git a/tensorflow/python/estimator/BUILD b/tensorflow/python/estimator/BUILD index 58d540b1ec..41f55b12af 100644 --- a/tensorflow/python/estimator/BUILD +++ b/tensorflow/python/estimator/BUILD @@ -267,6 +267,7 @@ py_library( "//tensorflow/python:training", "//tensorflow/python:variable_scope", "//tensorflow/python/feature_column", + "//tensorflow/python/ops/losses", "@six_archive//:six", ], ) @@ -356,6 +357,7 @@ py_library( "//tensorflow/python:training", "//tensorflow/python:variable_scope", "//tensorflow/python/feature_column", + "//tensorflow/python/ops/losses", "@six_archive//:six", ], ) @@ -680,6 +682,7 @@ py_library( "//tensorflow/python:training", "//tensorflow/python:variable_scope", "//tensorflow/python/feature_column", + "//tensorflow/python/ops/losses", "@six_archive//:six", ], ) diff --git a/tensorflow/python/estimator/canned/dnn.py b/tensorflow/python/estimator/canned/dnn.py index 0392ff9a71..ba96d738ae 100644 --- a/tensorflow/python/estimator/canned/dnn.py +++ b/tensorflow/python/estimator/canned/dnn.py @@ -31,6 +31,7 @@ from tensorflow.python.ops import init_ops from tensorflow.python.ops import nn from tensorflow.python.ops import partitioned_variables from tensorflow.python.ops import variable_scope +from tensorflow.python.ops.losses import losses from tensorflow.python.summary import summary from tensorflow.python.training import training_util @@ -280,6 +281,7 @@ class DNNClassifier(estimator.Estimator): input_layer_partitioner=None, config=None, warm_start_from=None, + loss_reduction=losses.Reduction.SUM, ): """Initializes a `DNNClassifier` instance. @@ -323,15 +325,19 @@ class DNNClassifier(estimator.Estimator): string filepath is provided instead of a `WarmStartSettings`, then all weights are warm-started, and it is assumed that vocabularies and Tensor names are unchanged. + loss_reduction: One of `tf.losses.Reduction` except `NONE`. Describes how + to reduce training loss over batch. Defaults to `SUM`. """ if n_classes == 2: head = head_lib._binary_logistic_head_with_sigmoid_cross_entropy_loss( # pylint: disable=protected-access weight_column=weight_column, - label_vocabulary=label_vocabulary) + label_vocabulary=label_vocabulary, + loss_reduction=loss_reduction) else: head = head_lib._multi_class_head_with_softmax_cross_entropy_loss( # pylint: disable=protected-access n_classes, weight_column=weight_column, - label_vocabulary=label_vocabulary) + label_vocabulary=label_vocabulary, + loss_reduction=loss_reduction) def _model_fn(features, labels, mode, config): """Call the defined shared _dnn_model_fn and possibly warm-start.""" @@ -441,6 +447,7 @@ class DNNRegressor(estimator.Estimator): input_layer_partitioner=None, config=None, warm_start_from=None, + loss_reduction=losses.Reduction.SUM, ): """Initializes a `DNNRegressor` instance. @@ -478,6 +485,8 @@ class DNNRegressor(estimator.Estimator): string filepath is provided instead of a `WarmStartSettings`, then all weights are warm-started, and it is assumed that vocabularies and Tensor names are unchanged. + loss_reduction: One of `tf.losses.Reduction` except `NONE`. Describes how + to reduce training loss over batch. Defaults to `SUM`. """ def _model_fn(features, labels, mode, config): @@ -488,7 +497,8 @@ class DNNRegressor(estimator.Estimator): mode=mode, head=head_lib. # pylint: disable=protected-access _regression_head_with_mean_squared_error_loss( - label_dimension=label_dimension, weight_column=weight_column), + label_dimension=label_dimension, weight_column=weight_column, + loss_reduction=loss_reduction), hidden_units=hidden_units, feature_columns=tuple(feature_columns or []), optimizer=optimizer, diff --git a/tensorflow/python/estimator/canned/dnn_linear_combined.py b/tensorflow/python/estimator/canned/dnn_linear_combined.py index 1d06a54a32..d29c892662 100644 --- a/tensorflow/python/estimator/canned/dnn_linear_combined.py +++ b/tensorflow/python/estimator/canned/dnn_linear_combined.py @@ -34,6 +34,7 @@ from tensorflow.python.ops import nn from tensorflow.python.ops import partitioned_variables from tensorflow.python.ops import state_ops from tensorflow.python.ops import variable_scope +from tensorflow.python.ops.losses import losses from tensorflow.python.summary import summary from tensorflow.python.training import sync_replicas_optimizer from tensorflow.python.training import training_util @@ -309,7 +310,8 @@ class DNNLinearCombinedClassifier(estimator.Estimator): label_vocabulary=None, input_layer_partitioner=None, config=None, - warm_start_from=None): + warm_start_from=None, + loss_reduction=losses.Reduction.SUM): """Initializes a DNNLinearCombinedClassifier instance. Args: @@ -356,6 +358,8 @@ class DNNLinearCombinedClassifier(estimator.Estimator): string filepath is provided instead of a `WarmStartSettings`, then all weights are warm-started, and it is assumed that vocabularies and Tensor names are unchanged. + loss_reduction: One of `tf.losses.Reduction` except `NONE`. Describes how + to reduce training loss over batch. Defaults to `SUM`. Raises: ValueError: If both linear_feature_columns and dnn_features_columns are @@ -371,12 +375,14 @@ class DNNLinearCombinedClassifier(estimator.Estimator): if n_classes == 2: head = head_lib._binary_logistic_head_with_sigmoid_cross_entropy_loss( # pylint: disable=protected-access weight_column=weight_column, - label_vocabulary=label_vocabulary) + label_vocabulary=label_vocabulary, + loss_reduction=loss_reduction) else: head = head_lib._multi_class_head_with_softmax_cross_entropy_loss( # pylint: disable=protected-access n_classes, weight_column=weight_column, - label_vocabulary=label_vocabulary) + label_vocabulary=label_vocabulary, + loss_reduction=loss_reduction) def _model_fn(features, labels, mode, config): """Call the _dnn_linear_combined_model_fn and possibly warm-start.""" @@ -490,7 +496,8 @@ class DNNLinearCombinedRegressor(estimator.Estimator): weight_column=None, input_layer_partitioner=None, config=None, - warm_start_from=None): + warm_start_from=None, + loss_reduction=losses.Reduction.SUM): """Initializes a DNNLinearCombinedRegressor instance. Args: @@ -531,6 +538,8 @@ class DNNLinearCombinedRegressor(estimator.Estimator): string filepath is provided instead of a `WarmStartSettings`, then all weights are warm-started, and it is assumed that vocabularies and Tensor names are unchanged. + loss_reduction: One of `tf.losses.Reduction` except `NONE`. Describes how + to reduce training loss over batch. Defaults to `SUM`. Raises: ValueError: If both linear_feature_columns and dnn_features_columns are @@ -552,7 +561,8 @@ class DNNLinearCombinedRegressor(estimator.Estimator): mode=mode, head=head_lib. # pylint: disable=protected-access _regression_head_with_mean_squared_error_loss( - label_dimension=label_dimension, weight_column=weight_column), + label_dimension=label_dimension, weight_column=weight_column, + loss_reduction=loss_reduction), linear_feature_columns=linear_feature_columns, linear_optimizer=linear_optimizer, dnn_feature_columns=dnn_feature_columns, diff --git a/tensorflow/python/estimator/canned/linear.py b/tensorflow/python/estimator/canned/linear.py index 97cfd24a10..7a80dfacc2 100644 --- a/tensorflow/python/estimator/canned/linear.py +++ b/tensorflow/python/estimator/canned/linear.py @@ -31,6 +31,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import nn from tensorflow.python.ops import partitioned_variables from tensorflow.python.ops import variable_scope +from tensorflow.python.ops.losses import losses from tensorflow.python.summary import summary from tensorflow.python.training import ftrl from tensorflow.python.training import training_util @@ -245,7 +246,8 @@ class LinearClassifier(estimator.Estimator): optimizer='Ftrl', config=None, partitioner=None, - warm_start_from=None): + warm_start_from=None, + loss_reduction=losses.Reduction.SUM): """Construct a `LinearClassifier` estimator object. Args: @@ -282,6 +284,8 @@ class LinearClassifier(estimator.Estimator): string filepath is provided instead of a `WarmStartSettings`, then all weights and biases are warm-started, and it is assumed that vocabularies and Tensor names are unchanged. + loss_reduction: One of `tf.losses.Reduction` except `NONE`. Describes how + to reduce training loss over batch. Defaults to `SUM`. Returns: A `LinearClassifier` estimator. @@ -292,11 +296,13 @@ class LinearClassifier(estimator.Estimator): if n_classes == 2: head = head_lib._binary_logistic_head_with_sigmoid_cross_entropy_loss( # pylint: disable=protected-access weight_column=weight_column, - label_vocabulary=label_vocabulary) + label_vocabulary=label_vocabulary, + loss_reduction=loss_reduction) else: head = head_lib._multi_class_head_with_softmax_cross_entropy_loss( # pylint: disable=protected-access n_classes, weight_column=weight_column, - label_vocabulary=label_vocabulary) + label_vocabulary=label_vocabulary, + loss_reduction=loss_reduction) def _model_fn(features, labels, mode, config): """Call the defined shared _linear_model_fn and possibly warm-start.""" @@ -388,7 +394,8 @@ class LinearRegressor(estimator.Estimator): optimizer='Ftrl', config=None, partitioner=None, - warm_start_from=None): + warm_start_from=None, + loss_reduction=losses.Reduction.SUM): """Initializes a `LinearRegressor` instance. Args: @@ -417,9 +424,12 @@ class LinearRegressor(estimator.Estimator): string filepath is provided instead of a `WarmStartSettings`, then all weights and biases are warm-started, and it is assumed that vocabularies and Tensor names are unchanged. + loss_reduction: One of `tf.losses.Reduction` except `NONE`. Describes how + to reduce training loss over batch. Defaults to `SUM`. """ head = head_lib._regression_head_with_mean_squared_error_loss( # pylint: disable=protected-access - label_dimension=label_dimension, weight_column=weight_column) + label_dimension=label_dimension, weight_column=weight_column, + loss_reduction=loss_reduction) def _model_fn(features, labels, mode, config): """Call the defined shared _linear_model_fn and possibly warm-start.""" diff --git a/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-classifier.pbtxt b/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-classifier.pbtxt index 46d5957057..efc441ae2f 100644 --- a/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-classifier.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-classifier.pbtxt @@ -21,7 +21,7 @@ tf_class { } member_method { name: "__init__" - argspec: "args=[\'self\', \'hidden_units\', \'feature_columns\', \'model_dir\', \'n_classes\', \'weight_column\', \'label_vocabulary\', \'optimizer\', \'activation_fn\', \'dropout\', \'input_layer_partitioner\', \'config\', \'warm_start_from\'], varargs=None, keywords=None, defaults=[\'None\', \'2\', \'None\', \'None\', \'Adagrad\', \'\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'self\', \'hidden_units\', \'feature_columns\', \'model_dir\', \'n_classes\', \'weight_column\', \'label_vocabulary\', \'optimizer\', \'activation_fn\', \'dropout\', \'input_layer_partitioner\', \'config\', \'warm_start_from\', \'loss_reduction\'], varargs=None, keywords=None, defaults=[\'None\', \'2\', \'None\', \'None\', \'Adagrad\', \'\', \'None\', \'None\', \'None\', \'None\', \'weighted_sum\'], " } member_method { name: "evaluate" diff --git a/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt b/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt index 439e87375b..20ce879870 100644 --- a/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt @@ -21,7 +21,7 @@ tf_class { } member_method { name: "__init__" - argspec: "args=[\'self\', \'model_dir\', \'linear_feature_columns\', \'linear_optimizer\', \'dnn_feature_columns\', \'dnn_optimizer\', \'dnn_hidden_units\', \'dnn_activation_fn\', \'dnn_dropout\', \'n_classes\', \'weight_column\', \'label_vocabulary\', \'input_layer_partitioner\', \'config\', \'warm_start_from\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'Ftrl\', \'None\', \'Adagrad\', \'None\', \'\', \'None\', \'2\', \'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'self\', \'model_dir\', \'linear_feature_columns\', \'linear_optimizer\', \'dnn_feature_columns\', \'dnn_optimizer\', \'dnn_hidden_units\', \'dnn_activation_fn\', \'dnn_dropout\', \'n_classes\', \'weight_column\', \'label_vocabulary\', \'input_layer_partitioner\', \'config\', \'warm_start_from\', \'loss_reduction\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'Ftrl\', \'None\', \'Adagrad\', \'None\', \'\', \'None\', \'2\', \'None\', \'None\', \'None\', \'None\', \'None\', \'weighted_sum\'], " } member_method { name: "evaluate" diff --git a/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt b/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt index f79a8be3f6..73211aaf8b 100644 --- a/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt @@ -21,7 +21,7 @@ tf_class { } member_method { name: "__init__" - argspec: "args=[\'self\', \'model_dir\', \'linear_feature_columns\', \'linear_optimizer\', \'dnn_feature_columns\', \'dnn_optimizer\', \'dnn_hidden_units\', \'dnn_activation_fn\', \'dnn_dropout\', \'label_dimension\', \'weight_column\', \'input_layer_partitioner\', \'config\', \'warm_start_from\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'Ftrl\', \'None\', \'Adagrad\', \'None\', \'\', \'None\', \'1\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'self\', \'model_dir\', \'linear_feature_columns\', \'linear_optimizer\', \'dnn_feature_columns\', \'dnn_optimizer\', \'dnn_hidden_units\', \'dnn_activation_fn\', \'dnn_dropout\', \'label_dimension\', \'weight_column\', \'input_layer_partitioner\', \'config\', \'warm_start_from\', \'loss_reduction\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'Ftrl\', \'None\', \'Adagrad\', \'None\', \'\', \'None\', \'1\', \'None\', \'None\', \'None\', \'None\', \'weighted_sum\'], " } member_method { name: "evaluate" diff --git a/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-regressor.pbtxt b/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-regressor.pbtxt index c466dcb4c2..27a159639d 100644 --- a/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-regressor.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.estimator.-d-n-n-regressor.pbtxt @@ -21,7 +21,7 @@ tf_class { } member_method { name: "__init__" - argspec: "args=[\'self\', \'hidden_units\', \'feature_columns\', \'model_dir\', \'label_dimension\', \'weight_column\', \'optimizer\', \'activation_fn\', \'dropout\', \'input_layer_partitioner\', \'config\', \'warm_start_from\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'Adagrad\', \'\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'self\', \'hidden_units\', \'feature_columns\', \'model_dir\', \'label_dimension\', \'weight_column\', \'optimizer\', \'activation_fn\', \'dropout\', \'input_layer_partitioner\', \'config\', \'warm_start_from\', \'loss_reduction\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'Adagrad\', \'\', \'None\', \'None\', \'None\', \'None\', \'weighted_sum\'], " } member_method { name: "evaluate" diff --git a/tensorflow/tools/api/golden/tensorflow.estimator.-linear-classifier.pbtxt b/tensorflow/tools/api/golden/tensorflow.estimator.-linear-classifier.pbtxt index cb9e95588d..c45318b98a 100644 --- a/tensorflow/tools/api/golden/tensorflow.estimator.-linear-classifier.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.estimator.-linear-classifier.pbtxt @@ -21,7 +21,7 @@ tf_class { } member_method { name: "__init__" - argspec: "args=[\'self\', \'feature_columns\', \'model_dir\', \'n_classes\', \'weight_column\', \'label_vocabulary\', \'optimizer\', \'config\', \'partitioner\', \'warm_start_from\'], varargs=None, keywords=None, defaults=[\'None\', \'2\', \'None\', \'None\', \'Ftrl\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'self\', \'feature_columns\', \'model_dir\', \'n_classes\', \'weight_column\', \'label_vocabulary\', \'optimizer\', \'config\', \'partitioner\', \'warm_start_from\', \'loss_reduction\'], varargs=None, keywords=None, defaults=[\'None\', \'2\', \'None\', \'None\', \'Ftrl\', \'None\', \'None\', \'None\', \'weighted_sum\'], " } member_method { name: "evaluate" diff --git a/tensorflow/tools/api/golden/tensorflow.estimator.-linear-regressor.pbtxt b/tensorflow/tools/api/golden/tensorflow.estimator.-linear-regressor.pbtxt index 637f19ba26..04a2aa080d 100644 --- a/tensorflow/tools/api/golden/tensorflow.estimator.-linear-regressor.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.estimator.-linear-regressor.pbtxt @@ -21,7 +21,7 @@ tf_class { } member_method { name: "__init__" - argspec: "args=[\'self\', \'feature_columns\', \'model_dir\', \'label_dimension\', \'weight_column\', \'optimizer\', \'config\', \'partitioner\', \'warm_start_from\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'Ftrl\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'self\', \'feature_columns\', \'model_dir\', \'label_dimension\', \'weight_column\', \'optimizer\', \'config\', \'partitioner\', \'warm_start_from\', \'loss_reduction\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'Ftrl\', \'None\', \'None\', \'None\', \'weighted_sum\'], " } member_method { name: "evaluate" -- GitLab From c80dd872bfb722b45eff48f3fdd6fc06c3a5aefb Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 14:17:07 -0800 Subject: [PATCH 211/258] Expose shared_embedding_columns in tf.feature_column. PiperOrigin-RevId: 183139975 --- tensorflow/python/feature_column/BUILD | 3 ++ .../python/feature_column/feature_column.py | 10 +++---- .../feature_column/feature_column_lib.py | 1 + .../feature_column/feature_column_test.py | 29 +++++++++---------- .../golden/tensorflow.feature_column.pbtxt | 4 +++ 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/tensorflow/python/feature_column/BUILD b/tensorflow/python/feature_column/BUILD index 76d44fc474..a758f8a4fc 100644 --- a/tensorflow/python/feature_column/BUILD +++ b/tensorflow/python/feature_column/BUILD @@ -85,6 +85,7 @@ py_test( "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:framework_ops", + "//tensorflow/python:framework_test_lib", "//tensorflow/python:lookup_ops", "//tensorflow/python:parsing_ops", "//tensorflow/python:partitioned_variables", @@ -93,6 +94,8 @@ py_test( "//tensorflow/python:training", "//tensorflow/python:variable_scope", "//tensorflow/python:variables", + "//tensorflow/python/eager:backprop", + "//tensorflow/python/eager:context", "//tensorflow/python/estimator:numpy_io", ], ) diff --git a/tensorflow/python/feature_column/feature_column.py b/tensorflow/python/feature_column/feature_column.py index a7fe528ee1..7feb209cc4 100644 --- a/tensorflow/python/feature_column/feature_column.py +++ b/tensorflow/python/feature_column/feature_column.py @@ -657,11 +657,11 @@ def embedding_column( trainable=trainable) -def _shared_embedding_columns( +def shared_embedding_columns( categorical_columns, dimension, combiner='mean', initializer=None, shared_embedding_collection_name=None, ckpt_to_load_from=None, tensor_name_in_ckpt=None, max_norm=None, trainable=True): - """List of `_DenseColumn`s that convert from sparse, categorical input. + """List of dense columns that convert from sparse, categorical input. This is similar to `embedding_column`, except that that it produces a list of embedding columns that share the same embedding weights. @@ -670,7 +670,7 @@ def _shared_embedding_columns( impression video IDs that share the same vocabulary), and you want to convert them to a dense representation (e.g., to feed to a DNN). - Inputs must be a list of `_CategoricalColumn` created by any of the + Inputs must be a list of categorical columns created by any of the `categorical_column_*` function. They must all be of the same type and have the same arguments except `key`. E.g. they can be categorical_column_with_vocabulary_file with the same vocabulary_file. Some or @@ -714,7 +714,7 @@ def _shared_embedding_columns( ``` Args: - categorical_columns: List of `_CategoricalColumn`s created by a + categorical_columns: List of categorical columns created by a `categorical_column_with_*` function. These columns produce the sparse IDs that are inputs to the embedding lookup. All columns must be of the same type and have the same arguments except `key`. E.g. they can be @@ -744,7 +744,7 @@ def _shared_embedding_columns( trainable: Whether or not the embedding is trainable. Default is True. Returns: - A list of `_DenseColumn`s that converts from sparse input. The order of + A list of dense columns that converts from sparse input. The order of results follows the ordering of `categorical_columns`. Raises: diff --git a/tensorflow/python/feature_column/feature_column_lib.py b/tensorflow/python/feature_column/feature_column_lib.py index 8a57986764..505a1408d2 100644 --- a/tensorflow/python/feature_column/feature_column_lib.py +++ b/tensorflow/python/feature_column/feature_column_lib.py @@ -29,6 +29,7 @@ _allowed_symbols = [ 'linear_model', 'make_parse_example_spec', 'embedding_column', + 'shared_embedding_columns', 'crossed_column', 'numeric_column', 'bucketized_column', diff --git a/tensorflow/python/feature_column/feature_column_test.py b/tensorflow/python/feature_column/feature_column_test.py index d78d74c8ca..6f366e7722 100644 --- a/tensorflow/python/feature_column/feature_column_test.py +++ b/tensorflow/python/feature_column/feature_column_test.py @@ -29,7 +29,6 @@ from tensorflow.python.client import session from tensorflow.python.eager import backprop from tensorflow.python.eager import context from tensorflow.python.estimator.inputs import numpy_io -from tensorflow.python.feature_column import feature_column as fc_lib from tensorflow.python.feature_column import feature_column_lib as fc from tensorflow.python.feature_column.feature_column import _CategoricalColumn from tensorflow.python.feature_column.feature_column import _DenseColumn @@ -4151,7 +4150,7 @@ class SharedEmbeddingColumnTest(test.TestCase): categorical_column_b = fc.categorical_column_with_identity( key='bbb', num_buckets=3) embedding_dimension = 2 - embedding_column_b, embedding_column_a = fc_lib._shared_embedding_columns( + embedding_column_b, embedding_column_a = fc.shared_embedding_columns( [categorical_column_b, categorical_column_a], dimension=embedding_dimension) self.assertIs(categorical_column_a, embedding_column_a.categorical_column) @@ -4197,7 +4196,7 @@ class SharedEmbeddingColumnTest(test.TestCase): categorical_column_b = fc.categorical_column_with_identity( key='bbb', num_buckets=3) embedding_dimension = 2 - embedding_column_a, embedding_column_b = fc_lib._shared_embedding_columns( + embedding_column_a, embedding_column_b = fc.shared_embedding_columns( [categorical_column_a, categorical_column_b], dimension=embedding_dimension, combiner='my_combiner', @@ -4250,7 +4249,7 @@ class SharedEmbeddingColumnTest(test.TestCase): categorical_column_b = fc.categorical_column_with_identity( key='bbb', num_buckets=3) embedding_dimension = 2 - original_a, _ = fc_lib._shared_embedding_columns( + original_a, _ = fc.shared_embedding_columns( [categorical_column_a, categorical_column_b], dimension=embedding_dimension, combiner='my_combiner', @@ -4288,7 +4287,7 @@ class SharedEmbeddingColumnTest(test.TestCase): categorical_column_b = fc.categorical_column_with_identity( key='bbb', num_buckets=3) with self.assertRaisesRegexp(ValueError, 'initializer must be callable'): - fc_lib._shared_embedding_columns( + fc.shared_embedding_columns( [categorical_column_a, categorical_column_b], dimension=2, initializer='not_fn') @@ -4303,7 +4302,7 @@ class SharedEmbeddingColumnTest(test.TestCase): ValueError, 'all categorical_columns must have the same type.*' '_IdentityCategoricalColumn.*_HashedCategoricalColumn'): - fc_lib._shared_embedding_columns( + fc.shared_embedding_columns( [categorical_column_a, categorical_column_b, categorical_column_c], dimension=2) @@ -4316,11 +4315,11 @@ class SharedEmbeddingColumnTest(test.TestCase): key='bbb', num_buckets=3) weighted_categorical_column_b = fc.weighted_categorical_column( categorical_column_b, weight_feature_key='bbb_weights') - fc_lib._shared_embedding_columns( + fc.shared_embedding_columns( [weighted_categorical_column_a, categorical_column_b], dimension=2) - fc_lib._shared_embedding_columns( + fc.shared_embedding_columns( [categorical_column_a, weighted_categorical_column_b], dimension=2) - fc_lib._shared_embedding_columns( + fc.shared_embedding_columns( [weighted_categorical_column_a, weighted_categorical_column_b], dimension=2) @@ -4329,7 +4328,7 @@ class SharedEmbeddingColumnTest(test.TestCase): key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) b = fc.categorical_column_with_vocabulary_list( key='bbb', vocabulary_list=('omar', 'stringer', 'marlo')) - a_embedded, b_embedded = fc_lib._shared_embedding_columns( + a_embedded, b_embedded = fc.shared_embedding_columns( [a, b], dimension=2) data = example_pb2.Example(features=feature_pb2.Features( feature={ @@ -4364,7 +4363,7 @@ class SharedEmbeddingColumnTest(test.TestCase): def test_transform_feature(self): a = fc.categorical_column_with_identity(key='aaa', num_buckets=3) b = fc.categorical_column_with_identity(key='bbb', num_buckets=3) - a_embedded, b_embedded = fc_lib._shared_embedding_columns( + a_embedded, b_embedded = fc.shared_embedding_columns( [a, b], dimension=2) features = { 'aaa': sparse_tensor.SparseTensor( @@ -4434,7 +4433,7 @@ class SharedEmbeddingColumnTest(test.TestCase): key='aaa', num_buckets=vocabulary_size) categorical_column_b = fc.categorical_column_with_identity( key='bbb', num_buckets=vocabulary_size) - embedding_column_a, embedding_column_b = fc_lib._shared_embedding_columns( + embedding_column_a, embedding_column_b = fc.shared_embedding_columns( [categorical_column_a, categorical_column_b], dimension=embedding_dimension, initializer=_initializer) @@ -4496,7 +4495,7 @@ class SharedEmbeddingColumnTest(test.TestCase): key='aaa', num_buckets=vocabulary_size) categorical_column_b = fc.categorical_column_with_identity( key='bbb', num_buckets=vocabulary_size) - embedding_column_a, embedding_column_b = fc_lib._shared_embedding_columns( + embedding_column_a, embedding_column_b = fc.shared_embedding_columns( [categorical_column_a, categorical_column_b], dimension=embedding_dimension, initializer=_initializer) @@ -4536,7 +4535,7 @@ class SharedEmbeddingColumnTest(test.TestCase): key='aaa', num_buckets=vocabulary_size) categorical_column_b = fc.categorical_column_with_identity( key='bbb', num_buckets=vocabulary_size) - embedding_column_a, embedding_column_b = fc_lib._shared_embedding_columns( + embedding_column_a, embedding_column_b = fc.shared_embedding_columns( [categorical_column_a, categorical_column_b], dimension=embedding_dimension, initializer=_initializer) @@ -4642,7 +4641,7 @@ class SharedEmbeddingColumnTest(test.TestCase): key='aaa', num_buckets=vocabulary_size) categorical_column_b = fc.categorical_column_with_identity( key='bbb', num_buckets=vocabulary_size) - embedding_column_a, embedding_column_b = fc_lib._shared_embedding_columns( + embedding_column_a, embedding_column_b = fc.shared_embedding_columns( [categorical_column_a, categorical_column_b], dimension=embedding_dimension, initializer=_initializer, trainable=trainable) diff --git a/tensorflow/tools/api/golden/tensorflow.feature_column.pbtxt b/tensorflow/tools/api/golden/tensorflow.feature_column.pbtxt index 018e8c909a..24a58fb118 100644 --- a/tensorflow/tools/api/golden/tensorflow.feature_column.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.feature_column.pbtxt @@ -48,6 +48,10 @@ tf_module { name: "numeric_column" argspec: "args=[\'key\', \'shape\', \'default_value\', \'dtype\', \'normalizer_fn\'], varargs=None, keywords=None, defaults=[\'(1,)\', \'None\', \"\", \'None\'], " } + member_method { + name: "shared_embedding_columns" + argspec: "args=[\'categorical_columns\', \'dimension\', \'combiner\', \'initializer\', \'shared_embedding_collection_name\', \'ckpt_to_load_from\', \'tensor_name_in_ckpt\', \'max_norm\', \'trainable\'], varargs=None, keywords=None, defaults=[\'mean\', \'None\', \'None\', \'None\', \'None\', \'None\', \'True\'], " + } member_method { name: "weighted_categorical_column" argspec: "args=[\'categorical_column\', \'weight_feature_key\', \'dtype\'], varargs=None, keywords=None, defaults=[\"\"], " -- GitLab From 1b0a771d92227c0d31a24d1dbd37d9fa28637e8e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 14:18:30 -0800 Subject: [PATCH 212/258] Update ops-related pbtxt files. PiperOrigin-RevId: 183140179 --- .../core/ops/compat/ops_history.v1.pbtxt | 24 +++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 24 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index 47de3d398e..65ab81931a 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -22679,6 +22679,30 @@ op { } is_stateful: true } +op { + name: "IteratorGetNextSync" + input_arg { + name: "iterator" + type: DT_RESOURCE + } + output_arg { + name: "components" + type_list_attr: "output_types" + } + attr { + name: "output_types" + type: "list(type)" + has_minimum: true + minimum: 1 + } + attr { + name: "output_shapes" + type: "list(shape)" + has_minimum: true + minimum: 1 + } + is_stateful: true +} op { name: "IteratorSetStatsAggregator" input_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index fe0b362d8f..b57206c9c4 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -10866,6 +10866,30 @@ op { } is_stateful: true } +op { + name: "IteratorGetNextSync" + input_arg { + name: "iterator" + type: DT_RESOURCE + } + output_arg { + name: "components" + type_list_attr: "output_types" + } + attr { + name: "output_types" + type: "list(type)" + has_minimum: true + minimum: 1 + } + attr { + name: "output_shapes" + type: "list(shape)" + has_minimum: true + minimum: 1 + } + is_stateful: true +} op { name: "IteratorSetStatsAggregator" input_arg { -- GitLab From f8347ceebbad0e06552633fcdf8e63f52246ba62 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 24 Jan 2018 14:23:02 -0800 Subject: [PATCH 213/258] Remove THIRD_PARTY_ from #include guards They don't make sense in the open source repository. PiperOrigin-RevId: 183140889 --- tensorflow/c/c_test_util.h | 6 +++--- tensorflow/c/python_api.h | 6 +++--- tensorflow/cc/framework/cc_op_gen.h | 6 +++--- tensorflow/cc/framework/grad_op_registry.h | 6 +++--- tensorflow/cc/framework/gradient_checker.h | 6 +++--- tensorflow/cc/framework/gradients.h | 6 +++--- tensorflow/cc/framework/ops.h | 6 +++--- tensorflow/cc/framework/scope.h | 6 +++--- tensorflow/cc/framework/scope_internal.h | 6 +++--- tensorflow/cc/framework/testutil.h | 6 +++--- tensorflow/cc/framework/while_gradients.h | 6 +++--- tensorflow/cc/gradients/grad_testutil.h | 6 +++--- tensorflow/cc/ops/const_op.h | 6 +++--- tensorflow/cc/ops/standard_ops.h | 6 +++--- tensorflow/cc/ops/while_loop.h | 6 +++--- tensorflow/cc/profiler/profiler.h | 6 +++--- tensorflow/cc/saved_model/constants.h | 6 +++--- tensorflow/cc/saved_model/loader.h | 6 +++--- tensorflow/cc/saved_model/signature_constants.h | 6 +++--- tensorflow/cc/saved_model/tag_constants.h | 6 +++--- tensorflow/cc/tools/freeze_saved_model.h | 6 +++--- tensorflow/cc/training/coordinator.h | 6 +++--- tensorflow/cc/training/queue_runner.h | 6 +++--- tensorflow/compiler/tf2xla/kernels/shape_util.h | 2 +- tensorflow/compiler/xla/execution_options_util.h | 6 +++--- tensorflow/compiler/xla/iterator_util.h | 6 +++--- .../compiler/xla/legacy_flags/debug_options_flags.h | 6 +++--- .../compiler/xla/legacy_flags/debug_options_parsers.h | 6 +++--- .../compiler/xla/service/cpu/cpu_hlo_support_checker.h | 6 +++--- .../xla/service/cpu/custom_call_target_registry.h | 6 +++--- .../compiler/xla/service/cpu/external_constant_pool.h | 6 +++--- tensorflow/compiler/xla/service/cpu/ir_function.h | 6 +++--- .../compiler/xla/service/cpu/orc_jit_memory_mapper.h | 6 +++--- .../compiler/xla/service/cpu/parallel_loop_emitter.h | 6 +++--- .../compiler/xla/service/cpu/parallel_task_assignment.h | 6 +++--- tensorflow/compiler/xla/service/cpu/runtime_fork_join.h | 6 +++--- tensorflow/compiler/xla/service/cpu/runtime_matvec.h | 6 +++--- tensorflow/compiler/xla/service/cpu/shape_partition.h | 6 +++--- tensorflow/compiler/xla/service/dot_decomposer.h | 6 +++--- tensorflow/compiler/xla/service/gpu/for_thunk.h | 6 +++--- tensorflow/compiler/xla/service/gpu/fusion_merger.h | 6 +++--- tensorflow/compiler/xla/service/gpu/gpu_constants.h | 6 +++--- .../compiler/xla/service/gpu/gpu_hlo_support_checker.h | 6 +++--- tensorflow/compiler/xla/service/gpu/while_transformer.h | 6 +++--- tensorflow/compiler/xla/service/hlo_evaluator.h | 6 +++--- tensorflow/compiler/xla/service/hlo_profile_printer.h | 6 +++--- tensorflow/compiler/xla/service/hlo_tfgraph_builder.h | 6 +++--- tensorflow/compiler/xla/service/hlo_verifier.h | 6 +++--- .../compiler/xla/service/llvm_ir/kernel_support_library.h | 6 +++--- tensorflow/compiler/xla/service/llvm_ir/ops.h | 6 +++--- tensorflow/compiler/xla/service/logical_buffer_analysis.h | 6 +++--- tensorflow/compiler/xla/service/while_loop_simplifier.h | 6 +++--- .../compiler/xla/service/zero_sized_hlo_elimination.h | 6 +++--- tensorflow/compiler/xla/sparse_index_array.h | 6 +++--- tensorflow/compiler/xla/statusor_internals.h | 6 +++--- tensorflow/compiler/xla/tests/filecheck.h | 6 +++--- tensorflow/contrib/android/asset_manager_filesystem.h | 6 +++--- .../contrib/batching/adaptive_shared_batch_scheduler.h | 6 +++--- tensorflow/contrib/batching/basic_batch_scheduler.h | 6 +++--- tensorflow/contrib/batching/batch_scheduler.h | 6 +++--- tensorflow/contrib/batching/shared_batch_scheduler.h | 6 +++--- tensorflow/contrib/batching/test_util/fake_clock_env.h | 6 +++--- tensorflow/contrib/batching/util/periodic_function.h | 6 +++--- .../lib/learner/common/accumulators/class-partition-key.h | 6 +++--- .../common/accumulators/feature-stats-accumulator.h | 6 +++--- .../lib/learner/common/partitioners/example_partitioner.h | 6 +++--- .../lib/learner/common/stats/feature-split-candidate.h | 6 +++--- .../lib/learner/common/stats/gradient-stats.h | 6 +++--- .../boosted_trees/lib/learner/common/stats/node-stats.h | 6 +++--- .../boosted_trees/lib/learner/common/stats/split-stats.h | 6 +++--- .../boosted_trees/lib/models/multiple_additive_trees.h | 6 +++--- .../lib/quantiles/weighted_quantiles_buffer.h | 6 +++--- .../lib/quantiles/weighted_quantiles_stream.h | 6 +++--- .../lib/quantiles/weighted_quantiles_summary.h | 6 +++--- .../boosted_trees/lib/testutil/batch_features_testutil.h | 6 +++--- .../contrib/boosted_trees/lib/testutil/random_tree_gen.h | 6 +++--- .../contrib/boosted_trees/lib/trees/decision_tree.h | 6 +++--- .../contrib/boosted_trees/lib/utils/batch_features.h | 6 +++--- .../contrib/boosted_trees/lib/utils/dropout_utils.h | 6 +++--- tensorflow/contrib/boosted_trees/lib/utils/example.h | 6 +++--- .../contrib/boosted_trees/lib/utils/examples_iterable.h | 6 +++--- tensorflow/contrib/boosted_trees/lib/utils/macros.h | 6 +++--- .../contrib/boosted_trees/lib/utils/optional_value.h | 6 +++--- tensorflow/contrib/boosted_trees/lib/utils/parallel_for.h | 6 +++--- tensorflow/contrib/boosted_trees/lib/utils/random.h | 6 +++--- .../boosted_trees/lib/utils/sparse_column_iterable.h | 6 +++--- tensorflow/contrib/boosted_trees/lib/utils/tensor_utils.h | 6 +++--- .../resources/decision_tree_ensemble_resource.h | 6 +++--- .../boosted_trees/resources/quantile_stream_resource.h | 6 +++--- .../contrib/boosted_trees/resources/stamped_resource.h | 6 +++--- .../contrib/cloud/kernels/bigquery_table_accessor.h | 6 +++--- .../cloud/kernels/bigquery_table_accessor_test_data.h | 6 +++--- tensorflow/contrib/coder/kernels/range_coder.h | 6 +++--- tensorflow/contrib/coder/kernels/range_coder_ops_util.h | 6 +++--- tensorflow/contrib/ffmpeg/ffmpeg_lib.h | 6 +++--- .../contrib/fused_conv/kernels/fused_conv_ops_gpu.h | 6 +++--- tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.h | 6 +++--- tensorflow/contrib/lite/allocation.h | 6 +++--- tensorflow/contrib/lite/arena_planner.h | 6 +++--- tensorflow/contrib/lite/builtin_op_data.h | 6 +++--- tensorflow/contrib/lite/context.h | 6 +++--- tensorflow/contrib/lite/error_reporter.h | 6 +++--- tensorflow/contrib/lite/graph_info.h | 6 +++--- tensorflow/contrib/lite/interpreter.h | 6 +++--- tensorflow/contrib/lite/kernels/activation_functor.h | 6 +++--- tensorflow/contrib/lite/kernels/gemm_support.h | 6 +++--- tensorflow/contrib/lite/kernels/internal/common.h | 6 +++--- tensorflow/contrib/lite/kernels/internal/compatibility.h | 6 +++--- .../lite/kernels/internal/optimized/depthwiseconv_float.h | 6 +++--- .../lite/kernels/internal/optimized/depthwiseconv_uint8.h | 6 +++--- .../internal/optimized/eigen_spatial_convolutions.h | 6 +++--- .../eigen_tensor_reduced_instantiations_google.h | 6 +++--- .../optimized/eigen_tensor_reduced_instantiations_oss.h | 6 +++--- .../lite/kernels/internal/optimized/multithreaded_conv.h | 6 +++--- .../lite/kernels/internal/optimized/neon_tensor_utils.h | 6 +++--- .../lite/kernels/internal/optimized/optimized_ops.h | 6 +++--- .../lite/kernels/internal/reference/depthwiseconv_float.h | 6 +++--- .../lite/kernels/internal/reference/depthwiseconv_uint8.h | 6 +++--- .../kernels/internal/reference/portable_tensor_utils.h | 6 +++--- .../lite/kernels/internal/reference/reference_ops.h | 6 +++--- tensorflow/contrib/lite/kernels/internal/round.h | 6 +++--- tensorflow/contrib/lite/kernels/internal/tensor.h | 6 +++--- tensorflow/contrib/lite/kernels/internal/tensor_utils.h | 6 +++--- tensorflow/contrib/lite/kernels/internal/types.h | 6 +++--- tensorflow/contrib/lite/kernels/kernel_util.h | 6 +++--- tensorflow/contrib/lite/kernels/op_macros.h | 6 +++--- tensorflow/contrib/lite/kernels/padding.h | 6 +++--- tensorflow/contrib/lite/kernels/register.h | 6 +++--- tensorflow/contrib/lite/kernels/test_util.h | 6 +++--- tensorflow/contrib/lite/memory_planner.h | 6 +++--- tensorflow/contrib/lite/model.h | 6 +++--- tensorflow/contrib/lite/models/smartreply/predictor.h | 6 +++--- tensorflow/contrib/lite/nnapi_delegate.h | 6 +++--- tensorflow/contrib/lite/optional_debug_tools.h | 6 +++--- tensorflow/contrib/lite/simple_memory_arena.h | 6 +++--- tensorflow/contrib/lite/string_util.h | 6 +++--- tensorflow/contrib/lite/testing/message.h | 6 +++--- tensorflow/contrib/lite/testing/parse_testdata.h | 6 +++--- tensorflow/contrib/lite/testing/split.h | 6 +++--- tensorflow/contrib/lite/testing/test_runner.h | 6 +++--- tensorflow/contrib/lite/testing/tflite_driver.h | 6 +++--- tensorflow/contrib/lite/testing/tokenize.h | 6 +++--- tensorflow/contrib/lite/testing/util.h | 6 +++--- tensorflow/contrib/lite/toco/allocate_transient_arrays.h | 6 +++--- tensorflow/contrib/lite/toco/args.h | 6 +++--- tensorflow/contrib/lite/toco/dump_graphviz.h | 6 +++--- tensorflow/contrib/lite/toco/export_tensorflow.h | 6 +++--- tensorflow/contrib/lite/toco/format_port.h | 6 +++--- .../toco/graph_transformations/graph_transformations.h | 6 +++--- .../graph_transformations/remove_trivial_passthrough.h | 6 +++--- tensorflow/contrib/lite/toco/import_tensorflow.h | 6 +++--- tensorflow/contrib/lite/toco/model.h | 6 +++--- tensorflow/contrib/lite/toco/model_cmdline_flags.h | 7 +++---- tensorflow/contrib/lite/toco/runtime/common.h | 6 +++--- tensorflow/contrib/lite/toco/runtime/types.h | 6 +++--- tensorflow/contrib/lite/toco/tensorflow_util.h | 6 +++--- tensorflow/contrib/lite/toco/tflite/builtin_operator.h | 6 +++--- tensorflow/contrib/lite/toco/tflite/custom_operator.h | 6 +++--- tensorflow/contrib/lite/toco/tflite/export.h | 6 +++--- tensorflow/contrib/lite/toco/tflite/import.h | 6 +++--- tensorflow/contrib/lite/toco/tflite/operator.h | 6 +++--- tensorflow/contrib/lite/toco/tflite/simple_operator.h | 6 +++--- tensorflow/contrib/lite/toco/tflite/types.h | 6 +++--- tensorflow/contrib/lite/toco/toco_cmdline_flags.h | 6 +++--- tensorflow/contrib/lite/toco/toco_graphviz_dump_options.h | 6 +++--- tensorflow/contrib/lite/toco/toco_port.h | 6 +++--- tensorflow/contrib/lite/toco/toco_tooling.h | 6 +++--- tensorflow/contrib/lite/toco/toco_types.h | 6 +++--- tensorflow/contrib/lite/toco/tooling_util.h | 6 +++--- tensorflow/contrib/lite/tools/gen_op_registration.h | 6 +++--- tensorflow/contrib/lite/tools/mutable_op_resolver.h | 6 +++--- tensorflow/contrib/lite/version.h | 6 +++--- tensorflow/contrib/nccl/kernels/nccl_manager.h | 6 +++--- tensorflow/contrib/nearest_neighbor/kernels/heap.h | 6 +++--- .../nearest_neighbor/kernels/hyperplane_lsh_probes.h | 6 +++--- .../contrib/reduce_slice_ops/kernels/reduce_slice_ops.h | 6 +++--- tensorflow/contrib/resampler/kernels/resampler_ops.h | 7 +++---- tensorflow/contrib/rnn/kernels/blas_gemm.h | 6 +++--- tensorflow/contrib/rnn/kernels/gru_ops.h | 6 +++--- tensorflow/contrib/rnn/kernels/lstm_ops.h | 6 +++--- .../saved_model/cc/saved_model/signature_def_utils.h | 6 +++--- tensorflow/contrib/seq2seq/kernels/beam_search_ops.h | 6 +++--- tensorflow/contrib/session_bundle/bundle_shim.h | 6 +++--- tensorflow/contrib/session_bundle/session_bundle.h | 6 +++--- tensorflow/contrib/session_bundle/signature.h | 6 +++--- tensorflow/contrib/session_bundle/test_util.h | 6 +++--- tensorflow/contrib/tensor_forest/kernels/data_spec.h | 6 +++--- tensorflow/contrib/tensor_forest/kernels/tree_utils.h | 6 +++--- .../tensor_forest/kernels/v4/candidate_graph_runner.h | 6 +++--- .../tensor_forest/kernels/v4/decision-tree-resource.h | 6 +++--- .../tensor_forest/kernels/v4/decision_node_evaluator.h | 6 +++--- .../tensor_forest/kernels/v4/fertile-stats-resource.h | 6 +++--- .../tensor_forest/kernels/v4/graph_collection_operator.h | 6 +++--- tensorflow/contrib/tensor_forest/kernels/v4/grow_stats.h | 6 +++--- tensorflow/contrib/tensor_forest/kernels/v4/input_data.h | 6 +++--- .../contrib/tensor_forest/kernels/v4/input_target.h | 6 +++--- .../tensor_forest/kernels/v4/leaf_model_operators.h | 6 +++--- tensorflow/contrib/tensor_forest/kernels/v4/params.h | 7 +++---- .../tensor_forest/kernels/v4/split_collection_operators.h | 8 +++----- tensorflow/contrib/tensor_forest/kernels/v4/stat_utils.h | 6 +++--- tensorflow/contrib/tensor_forest/kernels/v4/test_utils.h | 6 +++--- tensorflow/contrib/tpu/profiler/dump_tpu_profile.h | 6 +++--- tensorflow/contrib/tpu/profiler/trace_events_to_json.h | 6 +++--- tensorflow/contrib/tpu/profiler/version.h | 6 +++--- .../contrib/util/convert_graphdef_memmapped_format_lib.h | 6 +++--- tensorflow/contrib/verbs/grpc_verbs_client.h | 6 +++--- tensorflow/contrib/verbs/grpc_verbs_service.h | 6 +++--- tensorflow/contrib/verbs/grpc_verbs_service_impl.h | 6 +++--- tensorflow/contrib/verbs/rdma.h | 6 +++--- tensorflow/contrib/verbs/rdma_mgr.h | 6 +++--- tensorflow/contrib/verbs/rdma_rendezvous_mgr.h | 6 +++--- tensorflow/contrib/verbs/verbs_server_lib.h | 6 +++--- tensorflow/core/api_def/update_api_def.h | 6 +++--- tensorflow/core/common_runtime/function_testlib.h | 6 +++--- tensorflow/core/common_runtime/gpu/gpu_id.h | 6 +++--- tensorflow/core/common_runtime/gpu/gpu_id_utils.h | 6 +++--- .../core/common_runtime/gpu/gpu_managed_allocator.h | 6 +++--- tensorflow/core/common_runtime/graph_optimizer.h | 6 +++--- tensorflow/core/common_runtime/memory_types.h | 6 +++--- tensorflow/core/common_runtime/pending_counts.h | 6 +++--- .../common_runtime/process_function_library_runtime.h | 6 +++--- tensorflow/core/common_runtime/profile_handler.h | 6 +++--- tensorflow/core/common_runtime/renamed_device.h | 6 +++--- tensorflow/core/common_runtime/rendezvous_util.h | 6 +++--- tensorflow/core/common_runtime/shape_refiner.h | 6 +++--- .../core/common_runtime/stats_publisher_interface.h | 6 +++--- .../cluster_function_library_runtime.h | 6 +++--- tensorflow/core/distributed_runtime/local_master.h | 6 +++--- tensorflow/core/distributed_runtime/message_wrappers.h | 6 +++--- tensorflow/core/distributed_runtime/partial_run_mgr.h | 6 +++--- tensorflow/core/distributed_runtime/recent_request_ids.h | 6 +++--- tensorflow/core/distributed_runtime/request_id.h | 6 +++--- .../distributed_runtime/rpc/async_service_interface.h | 6 +++--- tensorflow/core/distributed_runtime/rpc/grpc_call.h | 6 +++--- tensorflow/core/distributed_runtime/rpc/grpc_channel.h | 6 +++--- .../core/distributed_runtime/rpc/grpc_client_cq_tag.h | 6 +++--- .../core/distributed_runtime/rpc/grpc_master_service.h | 6 +++--- .../distributed_runtime/rpc/grpc_master_service_impl.h | 6 +++--- .../core/distributed_runtime/rpc/grpc_remote_master.h | 6 +++--- .../core/distributed_runtime/rpc/grpc_remote_worker.h | 6 +++--- .../distributed_runtime/rpc/grpc_serialization_traits.h | 6 +++--- tensorflow/core/distributed_runtime/rpc/grpc_server_lib.h | 6 +++--- tensorflow/core/distributed_runtime/rpc/grpc_session.h | 6 +++--- tensorflow/core/distributed_runtime/rpc/grpc_state.h | 6 +++--- tensorflow/core/distributed_runtime/rpc/grpc_testlib.h | 6 +++--- tensorflow/core/distributed_runtime/rpc/grpc_util.h | 6 +++--- .../core/distributed_runtime/rpc/grpc_worker_cache.h | 6 +++--- .../core/distributed_runtime/rpc/grpc_worker_service.h | 6 +++--- .../distributed_runtime/rpc/grpc_worker_service_impl.h | 6 +++--- tensorflow/core/distributed_runtime/server_lib.h | 6 +++--- tensorflow/core/distributed_runtime/session_mgr.h | 6 +++--- tensorflow/core/distributed_runtime/worker.h | 6 +++--- tensorflow/core/distributed_runtime/worker_session.h | 6 +++--- tensorflow/core/example/example_parser_configuration.h | 6 +++--- tensorflow/core/framework/common_shape_fns.h | 6 +++--- tensorflow/core/framework/shape_inference.h | 6 +++--- tensorflow/core/framework/shape_inference_testutil.h | 6 +++--- tensorflow/core/graph/gradients.h | 6 +++--- tensorflow/core/grappler/costs/op_context.h | 6 +++--- tensorflow/core/grappler/costs/virtual_scheduler.h | 6 +++--- .../core/grappler/optimizers/dependency_optimizer.h | 6 +++--- tensorflow/core/grappler/optimizers/static_schedule.h | 6 +++--- tensorflow/core/grappler/utils/frame.h | 6 +++--- tensorflow/core/grappler/utils/scc.h | 6 +++--- tensorflow/core/grappler/utils/topological_sort.h | 6 +++--- tensorflow/core/kernels/adjust_hsv_gpu.cu.h | 6 +++--- tensorflow/core/kernels/batch_util.h | 6 +++--- .../batching_util/adaptive_shared_batch_scheduler.h | 7 +++---- .../core/kernels/batching_util/basic_batch_scheduler.h | 6 +++--- tensorflow/core/kernels/batching_util/batch_scheduler.h | 6 +++--- tensorflow/core/kernels/batching_util/fake_clock_env.h | 6 +++--- tensorflow/core/kernels/batching_util/periodic_function.h | 7 +++---- .../core/kernels/batching_util/shared_batch_scheduler.h | 6 +++--- tensorflow/core/kernels/bitcast_op.h | 6 +++--- tensorflow/core/kernels/captured_function.h | 6 +++--- tensorflow/core/kernels/cast_op_impl.h | 6 +++--- tensorflow/core/kernels/compare_and_bitpack_op.h | 6 +++--- tensorflow/core/kernels/cuda_device_array.h | 6 +++--- tensorflow/core/kernels/cuda_device_array_gpu.h | 6 +++--- tensorflow/core/kernels/data/captured_function.h | 6 +++--- tensorflow/core/kernels/data/dataset.h | 6 +++--- tensorflow/core/kernels/data/dataset_utils.h | 6 +++--- tensorflow/core/kernels/data/sql/driver_manager.h | 6 +++--- tensorflow/core/kernels/data/sql/query_connection.h | 6 +++--- .../core/kernels/data/sql/sqlite_query_connection.h | 6 +++--- tensorflow/core/kernels/data/stats_aggregator.h | 6 +++--- tensorflow/core/kernels/data/window_dataset.h | 6 +++--- tensorflow/core/kernels/dataset.h | 6 +++--- tensorflow/core/kernels/deep_conv2d.h | 6 +++--- tensorflow/core/kernels/depthwise_conv_op.h | 6 +++--- tensorflow/core/kernels/determinant_op.h | 6 +++--- tensorflow/core/kernels/eigen_activations.h | 6 +++--- tensorflow/core/kernels/eigen_attention.h | 6 +++--- .../core/kernels/eigen_backward_cuboid_convolutions.h | 6 +++--- .../core/kernels/eigen_backward_spatial_convolutions.h | 4 ++-- tensorflow/core/kernels/eigen_cuboid_convolution.h | 6 +++--- tensorflow/core/kernels/eigen_pooling.h | 6 +++--- tensorflow/core/kernels/eigen_softmax.h | 6 +++--- tensorflow/core/kernels/eigen_spatial_convolutions.h | 6 +++--- tensorflow/core/kernels/eigen_volume_patch.h | 6 +++--- tensorflow/core/kernels/eye_functor.h | 6 +++--- tensorflow/core/kernels/fake_quant_ops_functor.h | 6 +++--- tensorflow/core/kernels/gather_functor_gpu.cu.h | 6 +++--- tensorflow/core/kernels/gpu_utils.h | 6 +++--- tensorflow/core/kernels/hexagon/graph_transferer.h | 6 +++--- tensorflow/core/kernels/hexagon/hexagon_control_wrapper.h | 6 +++--- tensorflow/core/kernels/hexagon/hexagon_ops_definitions.h | 6 +++--- tensorflow/core/kernels/i_remote_fused_graph_executor.h | 6 +++--- .../core/kernels/i_remote_fused_graph_ops_definitions.h | 6 +++--- tensorflow/core/kernels/list_kernels.h | 6 +++--- tensorflow/core/kernels/meta_support.h | 6 +++--- tensorflow/core/kernels/mfcc.h | 6 +++--- tensorflow/core/kernels/mfcc_dct.h | 6 +++--- tensorflow/core/kernels/mfcc_mel_filterbank.h | 6 +++--- tensorflow/core/kernels/mirror_pad_op_cpu_impl.h | 6 +++--- tensorflow/core/kernels/neon/depthwiseconv_float.h | 6 +++--- tensorflow/core/kernels/neon/types.h | 6 +++--- tensorflow/core/kernels/population_count_op.h | 6 +++--- tensorflow/core/kernels/quantization_utils.h | 6 +++--- tensorflow/core/kernels/reference_gemm.h | 6 +++--- .../kernels/remote_fused_graph_execute_op_test_utils.h | 6 +++--- .../core/kernels/remote_fused_graph_execute_utils.h | 6 +++--- tensorflow/core/kernels/reshape_util.h | 6 +++--- tensorflow/core/kernels/scatter_nd_op_cpu_impl.h | 6 +++--- tensorflow/core/kernels/segment_reduction_ops.h | 6 +++--- tensorflow/core/kernels/slice_op_cpu_impl.h | 6 +++--- tensorflow/core/kernels/spectrogram.h | 6 +++--- tensorflow/core/kernels/spectrogram_test_utils.h | 6 +++--- tensorflow/core/kernels/tile_ops_cpu_impl.h | 6 +++--- tensorflow/core/kernels/tile_ops_gpu_impl.h | 6 +++--- tensorflow/core/kernels/winograd_transform.h | 6 +++--- tensorflow/core/kernels/xsmm_conv2d.h | 6 +++--- tensorflow/core/lib/core/bitmap.h | 6 +++--- tensorflow/core/lib/gtl/compactptrset.h | 6 +++--- tensorflow/core/lib/gtl/flatmap.h | 6 +++--- tensorflow/core/lib/gtl/flatrep.h | 6 +++--- tensorflow/core/lib/gtl/flatset.h | 6 +++--- tensorflow/core/lib/io/buffered_inputstream.h | 2 +- tensorflow/core/lib/io/compression.h | 6 +++--- tensorflow/core/lib/io/inputstream_interface.h | 2 +- tensorflow/core/lib/io/snappy/snappy_outputbuffer.h | 6 +++--- tensorflow/core/lib/io/zlib_outputbuffer.h | 6 +++--- tensorflow/core/lib/monitoring/collected_metrics.h | 6 +++--- tensorflow/core/lib/monitoring/collection_registry.h | 6 +++--- tensorflow/core/lib/monitoring/counter.h | 6 +++--- tensorflow/core/lib/monitoring/gauge.h | 6 +++--- tensorflow/core/lib/monitoring/metric_def.h | 6 +++--- tensorflow/core/lib/monitoring/mobile_counter.h | 6 +++--- tensorflow/core/lib/monitoring/mobile_gauge.h | 6 +++--- tensorflow/core/lib/monitoring/mobile_sampler.h | 6 +++--- tensorflow/core/lib/monitoring/sampler.h | 6 +++--- tensorflow/core/lib/strings/proto_text_util.h | 6 +++--- tensorflow/core/platform/cloud/gcs_dns_cache.h | 6 +++--- tensorflow/core/platform/cloud/oauth_client.h | 6 +++--- tensorflow/core/platform/cloud/retrying_utils.h | 6 +++--- tensorflow/core/platform/cloud/time_util.h | 6 +++--- tensorflow/core/platform/cuda_libdevice_path.h | 6 +++--- tensorflow/core/platform/cupti_wrapper.h | 6 +++--- tensorflow/core/platform/default/gpu/cupti_wrapper.h | 6 +++--- tensorflow/core/platform/demangle.h | 6 +++--- tensorflow/core/platform/file_statistics.h | 6 +++--- tensorflow/core/platform/hadoop/hadoop_file_system.h | 6 +++--- tensorflow/core/platform/stacktrace_handler.h | 6 +++--- .../internal/advisor/accelerator_utilization_checker.h | 6 +++--- tensorflow/core/profiler/internal/advisor/checker.h | 6 +++--- .../internal/advisor/expensive_operation_checker.h | 6 +++--- .../profiler/internal/advisor/internal_checker_runner.h | 6 +++--- .../core/profiler/internal/advisor/operation_checker.h | 6 +++--- .../core/profiler/internal/advisor/tfprof_advisor.h | 6 +++--- tensorflow/core/profiler/internal/print_model_analysis.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_code.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_constants.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_graph.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_node.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_node_show.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_op.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_scope.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_show.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_show_multi.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_stats.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_tensor.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_timeline.h | 6 +++--- tensorflow/core/profiler/internal/tfprof_utils.h | 6 +++--- tensorflow/core/profiler/tfprof_options.h | 6 +++--- tensorflow/core/util/command_line_flags.h | 6 +++--- tensorflow/core/util/example_proto_fast_parsing.h | 6 +++--- tensorflow/core/util/example_proto_helper.h | 6 +++--- tensorflow/core/util/matmul_autotune.h | 6 +++--- tensorflow/core/util/strided_slice_op.h | 6 +++--- tensorflow/examples/android/jni/object_tracking/config.h | 6 +++--- .../examples/android/jni/object_tracking/flow_cache.h | 6 +++--- .../examples/android/jni/object_tracking/frame_pair.h | 6 +++--- tensorflow/examples/android/jni/object_tracking/geom.h | 6 +++--- .../examples/android/jni/object_tracking/gl_utils.h | 6 +++--- .../examples/android/jni/object_tracking/image-inl.h | 6 +++--- tensorflow/examples/android/jni/object_tracking/image.h | 6 +++--- .../examples/android/jni/object_tracking/image_data.h | 6 +++--- .../examples/android/jni/object_tracking/image_utils.h | 6 +++--- .../examples/android/jni/object_tracking/integral_image.h | 6 +++--- .../examples/android/jni/object_tracking/jni_utils.h | 4 ++-- .../examples/android/jni/object_tracking/keypoint.h | 6 +++--- .../android/jni/object_tracking/keypoint_detector.h | 6 +++--- tensorflow/examples/android/jni/object_tracking/logging.h | 6 +++--- .../android/jni/object_tracking/object_detector.h | 6 +++--- .../examples/android/jni/object_tracking/object_model.h | 6 +++--- .../examples/android/jni/object_tracking/object_tracker.h | 6 +++--- .../examples/android/jni/object_tracking/optical_flow.h | 6 +++--- tensorflow/examples/android/jni/object_tracking/sprite.h | 6 +++--- .../examples/android/jni/object_tracking/time_log.h | 6 +++--- .../examples/android/jni/object_tracking/tracked_object.h | 6 +++--- tensorflow/examples/android/jni/object_tracking/utils.h | 6 +++--- tensorflow/examples/speech_commands/accuracy_utils.h | 6 +++--- tensorflow/examples/speech_commands/recognize_commands.h | 6 +++--- .../examples/wav_to_spectrogram/wav_to_spectrogram.h | 6 +++--- tensorflow/python/eager/python_eager_op_gen.h | 6 +++--- tensorflow/python/framework/cpp_shape_inference.h | 6 +++--- tensorflow/python/framework/python_op_gen_internal.h | 6 +++--- tensorflow/python/lib/core/ndarray_tensor.h | 6 +++--- tensorflow/python/lib/core/py_seq_tensor.h | 6 +++--- tensorflow/python/lib/core/safe_ptr.h | 6 +++--- tensorflow/python/util/kernel_registry.h | 6 +++--- tensorflow/python/util/util.h | 6 +++--- tensorflow/tools/graph_transforms/file_utils.h | 6 +++--- .../tools/proto_text/gen_proto_text_functions_lib.h | 6 +++--- .../Eigen/CXX11/src/FixedPoint/PacketMathAVX2.h | 6 +++--- .../Eigen/CXX11/src/FixedPoint/PacketMathAVX512.h | 6 +++--- .../Eigen/CXX11/src/FixedPoint/TypeCastingAVX2.h | 6 +++--- .../Eigen/CXX11/src/FixedPoint/TypeCastingAVX512.h | 6 +++--- third_party/fft2d/fft.h | 6 +++--- 429 files changed, 1279 insertions(+), 1286 deletions(-) diff --git a/tensorflow/c/c_test_util.h b/tensorflow/c/c_test_util.h index 3429009a71..6acc2fec00 100644 --- a/tensorflow/c/c_test_util.h +++ b/tensorflow/c/c_test_util.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_C_C_TEST_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_C_C_TEST_UTIL_H_ +#ifndef TENSORFLOW_C_C_TEST_UTIL_H_ +#define TENSORFLOW_C_C_TEST_UTIL_H_ #include "tensorflow/c/c_api.h" @@ -136,4 +136,4 @@ class CSession { std::vector targets_; }; -#endif // THIRD_PARTY_TENSORFLOW_C_C_TEST_UTIL_H_ +#endif // TENSORFLOW_C_C_TEST_UTIL_H_ diff --git a/tensorflow/c/python_api.h b/tensorflow/c/python_api.h index b51ef2b531..aa9d9e06b2 100644 --- a/tensorflow/c/python_api.h +++ b/tensorflow/c/python_api.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_C_PYTHON_API_H_ -#define THIRD_PARTY_TENSORFLOW_C_PYTHON_API_H_ +#ifndef TENSORFLOW_C_PYTHON_API_H_ +#define TENSORFLOW_C_PYTHON_API_H_ #include "tensorflow/c/c_api.h" @@ -39,4 +39,4 @@ void RemoveAllControlInputs(TF_Graph* graph, TF_Operation* op); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_C_PYTHON_API_H_ +#endif // TENSORFLOW_C_PYTHON_API_H_ diff --git a/tensorflow/cc/framework/cc_op_gen.h b/tensorflow/cc/framework/cc_op_gen.h index 1b5f7dd923..c7256a7dc3 100644 --- a/tensorflow/cc/framework/cc_op_gen.h +++ b/tensorflow/cc/framework/cc_op_gen.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_CC_OP_GEN_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_CC_OP_GEN_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_CC_OP_GEN_H_ +#define TENSORFLOW_CC_FRAMEWORK_CC_OP_GEN_H_ #include "tensorflow/core/framework/op_def.pb.h" #include "tensorflow/core/framework/op_gen_lib.h" @@ -28,4 +28,4 @@ void WriteCCOps(const OpList& ops, const ApiDefMap& api_def_map, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_CC_OP_GEN_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_CC_OP_GEN_H_ diff --git a/tensorflow/cc/framework/grad_op_registry.h b/tensorflow/cc/framework/grad_op_registry.h index 190b96f685..0fc5abb20c 100644 --- a/tensorflow/cc/framework/grad_op_registry.h +++ b/tensorflow/cc/framework/grad_op_registry.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRAD_OP_REGISTRY_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRAD_OP_REGISTRY_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_GRAD_OP_REGISTRY_H_ +#define TENSORFLOW_CC_FRAMEWORK_GRAD_OP_REGISTRY_H_ #include @@ -72,4 +72,4 @@ class GradOpRegistry { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRAD_OP_REGISTRY_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_GRAD_OP_REGISTRY_H_ diff --git a/tensorflow/cc/framework/gradient_checker.h b/tensorflow/cc/framework/gradient_checker.h index d055c60d09..1aa215a908 100644 --- a/tensorflow/cc/framework/gradient_checker.h +++ b/tensorflow/cc/framework/gradient_checker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRADIENT_CHECKER_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRADIENT_CHECKER_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_GRADIENT_CHECKER_H_ +#define TENSORFLOW_CC_FRAMEWORK_GRADIENT_CHECKER_H_ #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -60,4 +60,4 @@ Status ComputeGradientError(const Scope& scope, const Output& x, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRADIENT_CHECKER_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_GRADIENT_CHECKER_H_ diff --git a/tensorflow/cc/framework/gradients.h b/tensorflow/cc/framework/gradients.h index 717f6f0636..0a377ad56d 100644 --- a/tensorflow/cc/framework/gradients.h +++ b/tensorflow/cc/framework/gradients.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRADIENTS_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRADIENTS_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_GRADIENTS_H_ +#define TENSORFLOW_CC_FRAMEWORK_GRADIENTS_H_ #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -49,4 +49,4 @@ Output NoGradient(); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_GRADIENTS_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_GRADIENTS_H_ diff --git a/tensorflow/cc/framework/ops.h b/tensorflow/cc/framework/ops.h index 8d4154220c..a085e1d6e2 100644 --- a/tensorflow/cc/framework/ops.h +++ b/tensorflow/cc/framework/ops.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_OPS_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_OPS_H_ +#define TENSORFLOW_CC_FRAMEWORK_OPS_H_ #include @@ -296,4 +296,4 @@ class InputList { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_OPS_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_OPS_H_ diff --git a/tensorflow/cc/framework/scope.h b/tensorflow/cc/framework/scope.h index 0225ac0472..30c32bd44b 100644 --- a/tensorflow/cc/framework/scope.h +++ b/tensorflow/cc/framework/scope.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_SCOPE_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_SCOPE_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_SCOPE_H_ +#define TENSORFLOW_CC_FRAMEWORK_SCOPE_H_ #include #include @@ -242,4 +242,4 @@ struct CompositeOpScopes { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_SCOPE_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_SCOPE_H_ diff --git a/tensorflow/cc/framework/scope_internal.h b/tensorflow/cc/framework/scope_internal.h index 968c366550..8efcfed20d 100644 --- a/tensorflow/cc/framework/scope_internal.h +++ b/tensorflow/cc/framework/scope_internal.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_SCOPE_INTERNAL_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_SCOPE_INTERNAL_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_SCOPE_INTERNAL_H_ +#define TENSORFLOW_CC_FRAMEWORK_SCOPE_INTERNAL_H_ #include "tensorflow/cc/framework/scope.h" @@ -117,4 +117,4 @@ class Scope::Impl { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_SCOPE_INTERNAL_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_SCOPE_INTERNAL_H_ diff --git a/tensorflow/cc/framework/testutil.h b/tensorflow/cc/framework/testutil.h index a3e19870ec..7ad6fb4a67 100644 --- a/tensorflow/cc/framework/testutil.h +++ b/tensorflow/cc/framework/testutil.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_TESTUTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_TESTUTIL_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_TESTUTIL_H_ +#define TENSORFLOW_CC_FRAMEWORK_TESTUTIL_H_ #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -44,4 +44,4 @@ void GetTensor(const Scope& scope, const std::vector& assign_vars, } // namespace test } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_TESTUTIL_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_TESTUTIL_H_ diff --git a/tensorflow/cc/framework/while_gradients.h b/tensorflow/cc/framework/while_gradients.h index 8f592accc9..cb4e579c85 100644 --- a/tensorflow/cc/framework/while_gradients.h +++ b/tensorflow/cc/framework/while_gradients.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_WHILE_GRADIENTS_H_ -#define THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_WHILE_GRADIENTS_H_ +#ifndef TENSORFLOW_CC_FRAMEWORK_WHILE_GRADIENTS_H_ +#define TENSORFLOW_CC_FRAMEWORK_WHILE_GRADIENTS_H_ #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -37,4 +37,4 @@ Status AddWhileLoopGradient(WhileContext* while_ctx, const Scope& scope, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_FRAMEWORK_WHILE_GRADIENTS_H_ +#endif // TENSORFLOW_CC_FRAMEWORK_WHILE_GRADIENTS_H_ diff --git a/tensorflow/cc/gradients/grad_testutil.h b/tensorflow/cc/gradients/grad_testutil.h index d31f412754..70c81f1a73 100644 --- a/tensorflow/cc/gradients/grad_testutil.h +++ b/tensorflow/cc/gradients/grad_testutil.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_GRADIENTS_GRAD_TESTUTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CC_GRADIENTS_GRAD_TESTUTIL_H_ +#ifndef TENSORFLOW_CC_GRADIENTS_GRAD_TESTUTIL_H_ +#define TENSORFLOW_CC_GRADIENTS_GRAD_TESTUTIL_H_ #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -32,4 +32,4 @@ Status CallGradFunction(const Scope& scope, const Operation& op, } // namespace test } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_GRADIENTS_GRAD_TESTUTIL_H_ +#endif // TENSORFLOW_CC_GRADIENTS_GRAD_TESTUTIL_H_ diff --git a/tensorflow/cc/ops/const_op.h b/tensorflow/cc/ops/const_op.h index d11fda475b..424a683665 100644 --- a/tensorflow/cc/ops/const_op.h +++ b/tensorflow/cc/ops/const_op.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_OPS_CONST_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CC_OPS_CONST_OP_H_ +#ifndef TENSORFLOW_CC_OPS_CONST_OP_H_ +#define TENSORFLOW_CC_OPS_CONST_OP_H_ #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -82,4 +82,4 @@ std::vector AsNodeOutList(const Scope& scope, } // namespace ops } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_OPS_CONST_OP_H_ +#endif // TENSORFLOW_CC_OPS_CONST_OP_H_ diff --git a/tensorflow/cc/ops/standard_ops.h b/tensorflow/cc/ops/standard_ops.h index 0c021f0b3a..98f53010ec 100644 --- a/tensorflow/cc/ops/standard_ops.h +++ b/tensorflow/cc/ops/standard_ops.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_OPS_STANDARD_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CC_OPS_STANDARD_OPS_H_ +#ifndef TENSORFLOW_CC_OPS_STANDARD_OPS_H_ +#define TENSORFLOW_CC_OPS_STANDARD_OPS_H_ #include "tensorflow/cc/ops/array_ops.h" #include "tensorflow/cc/ops/candidate_sampling_ops.h" @@ -37,4 +37,4 @@ limitations under the License. #include "tensorflow/cc/ops/training_ops.h" #include "tensorflow/cc/ops/user_ops.h" -#endif // THIRD_PARTY_TENSORFLOW_CC_OPS_STANDARD_OPS_H_ +#endif // TENSORFLOW_CC_OPS_STANDARD_OPS_H_ diff --git a/tensorflow/cc/ops/while_loop.h b/tensorflow/cc/ops/while_loop.h index a04476056a..727237b5c7 100644 --- a/tensorflow/cc/ops/while_loop.h +++ b/tensorflow/cc/ops/while_loop.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_OPS_WHILE_LOOP_H_ -#define THIRD_PARTY_TENSORFLOW_CC_OPS_WHILE_LOOP_H_ +#ifndef TENSORFLOW_CC_OPS_WHILE_LOOP_H_ +#define TENSORFLOW_CC_OPS_WHILE_LOOP_H_ #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -71,4 +71,4 @@ Status BuildWhileLoop(const Scope& scope, const std::vector& inputs, } // namespace ops } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_OPS_WHILE_LOOP_H_ +#endif // TENSORFLOW_CC_OPS_WHILE_LOOP_H_ diff --git a/tensorflow/cc/profiler/profiler.h b/tensorflow/cc/profiler/profiler.h index e1ce315d3c..6077c45c58 100644 --- a/tensorflow/cc/profiler/profiler.h +++ b/tensorflow/cc/profiler/profiler.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_PROFILER_PROFILER_H_ -#define THIRD_PARTY_TENSORFLOW_CC_PROFILER_PROFILER_H_ +#ifndef TENSORFLOW_CC_PROFILER_PROFILER_H_ +#define TENSORFLOW_CC_PROFILER_PROFILER_H_ #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/lib/core/status.h" @@ -94,4 +94,4 @@ class Profiler { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_PROFILER_PROFILER_H_ +#endif // TENSORFLOW_CC_PROFILER_PROFILER_H_ diff --git a/tensorflow/cc/saved_model/constants.h b/tensorflow/cc/saved_model/constants.h index c940df8a87..645a3f101d 100644 --- a/tensorflow/cc/saved_model/constants.h +++ b/tensorflow/cc/saved_model/constants.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_CONSTANTS_H_ -#define THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_CONSTANTS_H_ +#ifndef TENSORFLOW_CC_SAVED_MODEL_CONSTANTS_H_ +#define TENSORFLOW_CC_SAVED_MODEL_CONSTANTS_H_ namespace tensorflow { @@ -47,4 +47,4 @@ constexpr char kSavedModelVariablesFilename[] = "variables"; } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_CONSTANTS_H_ +#endif // TENSORFLOW_CC_SAVED_MODEL_CONSTANTS_H_ diff --git a/tensorflow/cc/saved_model/loader.h b/tensorflow/cc/saved_model/loader.h index 3d634dd515..a8e098fa54 100644 --- a/tensorflow/cc/saved_model/loader.h +++ b/tensorflow/cc/saved_model/loader.h @@ -15,8 +15,8 @@ limitations under the License. /// SavedModel loading functions and SavedModelBundle struct. -#ifndef THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_LOADER_H_ -#define THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_LOADER_H_ +#ifndef TENSORFLOW_CC_SAVED_MODEL_LOADER_H_ +#define TENSORFLOW_CC_SAVED_MODEL_LOADER_H_ #include #include @@ -61,4 +61,4 @@ bool MaybeSavedModelDirectory(const string& export_dir); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_LOADER_H_ +#endif // TENSORFLOW_CC_SAVED_MODEL_LOADER_H_ diff --git a/tensorflow/cc/saved_model/signature_constants.h b/tensorflow/cc/saved_model/signature_constants.h index b2d39bd55b..7d8c07f5cf 100644 --- a/tensorflow/cc/saved_model/signature_constants.h +++ b/tensorflow/cc/saved_model/signature_constants.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_SIGNATURE_CONSTANTS_H_ -#define THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_SIGNATURE_CONSTANTS_H_ +#ifndef TENSORFLOW_CC_SAVED_MODEL_SIGNATURE_CONSTANTS_H_ +#define TENSORFLOW_CC_SAVED_MODEL_SIGNATURE_CONSTANTS_H_ namespace tensorflow { @@ -66,4 +66,4 @@ static constexpr char kRegressOutputs[] = "outputs"; } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_SIGNATURE_CONSTANTS_H_ +#endif // TENSORFLOW_CC_SAVED_MODEL_SIGNATURE_CONSTANTS_H_ diff --git a/tensorflow/cc/saved_model/tag_constants.h b/tensorflow/cc/saved_model/tag_constants.h index b71cb263ca..68a090e0c4 100644 --- a/tensorflow/cc/saved_model/tag_constants.h +++ b/tensorflow/cc/saved_model/tag_constants.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_TAG_CONSTANTS_H_ -#define THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_TAG_CONSTANTS_H_ +#ifndef TENSORFLOW_CC_SAVED_MODEL_TAG_CONSTANTS_H_ +#define TENSORFLOW_CC_SAVED_MODEL_TAG_CONSTANTS_H_ namespace tensorflow { @@ -32,4 +32,4 @@ constexpr char kSavedModelTagTrain[] = "train"; } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_SAVED_MODEL_TAG_CONSTANTS_H_ +#endif // TENSORFLOW_CC_SAVED_MODEL_TAG_CONSTANTS_H_ diff --git a/tensorflow/cc/tools/freeze_saved_model.h b/tensorflow/cc/tools/freeze_saved_model.h index bd5e0516c8..b10f29805a 100644 --- a/tensorflow/cc/tools/freeze_saved_model.h +++ b/tensorflow/cc/tools/freeze_saved_model.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CC_TOOLS_FREEZE_SAVED_MODEL_H_ -#define THIRD_PARTY_TENSORFLOW_CC_TOOLS_FREEZE_SAVED_MODEL_H_ +#ifndef TENSORFLOW_CC_TOOLS_FREEZE_SAVED_MODEL_H_ +#define TENSORFLOW_CC_TOOLS_FREEZE_SAVED_MODEL_H_ #include @@ -40,4 +40,4 @@ Status FreezeSavedModel(const SavedModelBundle& saved_model_bundle, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_TOOLS_FREEZE_SAVED_MODEL_H_ +#endif // TENSORFLOW_CC_TOOLS_FREEZE_SAVED_MODEL_H_ diff --git a/tensorflow/cc/training/coordinator.h b/tensorflow/cc/training/coordinator.h index 0e01b19cd9..7168b77525 100644 --- a/tensorflow/cc/training/coordinator.h +++ b/tensorflow/cc/training/coordinator.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_TRAINING_COORDINATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CC_TRAINING_COORDINATOR_H_ +#ifndef TENSORFLOW_CC_TRAINING_COORDINATOR_H_ +#define TENSORFLOW_CC_TRAINING_COORDINATOR_H_ #include #include @@ -128,4 +128,4 @@ class Coordinator { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_TRAINING_COORDINATOR_H_ +#endif // TENSORFLOW_CC_TRAINING_COORDINATOR_H_ diff --git a/tensorflow/cc/training/queue_runner.h b/tensorflow/cc/training/queue_runner.h index 2d34500323..21189b4b04 100644 --- a/tensorflow/cc/training/queue_runner.h +++ b/tensorflow/cc/training/queue_runner.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CC_TRAINING_QUEUE_RUNNER_H_ -#define THIRD_PARTY_TENSORFLOW_CC_TRAINING_QUEUE_RUNNER_H_ +#ifndef TENSORFLOW_CC_TRAINING_QUEUE_RUNNER_H_ +#define TENSORFLOW_CC_TRAINING_QUEUE_RUNNER_H_ #include #include @@ -137,4 +137,4 @@ class QueueRunner : public RunnerInterface { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CC_TRAINING_QUEUE_RUNNER_H_ +#endif // TENSORFLOW_CC_TRAINING_QUEUE_RUNNER_H_ diff --git a/tensorflow/compiler/tf2xla/kernels/shape_util.h b/tensorflow/compiler/tf2xla/kernels/shape_util.h index 575086e118..ca57be3d47 100644 --- a/tensorflow/compiler/tf2xla/kernels/shape_util.h +++ b/tensorflow/compiler/tf2xla/kernels/shape_util.h @@ -31,4 +31,4 @@ Status TensorShapeToConstant(const TensorShape& input_shape, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_TF2XLA_KERNELS_SHAPE_UTIL_H_ +#endif // TENSORFLOW_COMPILER_TF2XLA_KERNELS_SHAPE_UTIL_H_ diff --git a/tensorflow/compiler/xla/execution_options_util.h b/tensorflow/compiler/xla/execution_options_util.h index 562da78e83..a8ca27ec8d 100644 --- a/tensorflow/compiler/xla/execution_options_util.h +++ b/tensorflow/compiler/xla/execution_options_util.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_EXECUTION_OPTIONS_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_EXECUTION_OPTIONS_UTIL_H_ +#ifndef TENSORFLOW_COMPILER_XLA_EXECUTION_OPTIONS_UTIL_H_ +#define TENSORFLOW_COMPILER_XLA_EXECUTION_OPTIONS_UTIL_H_ #include "tensorflow/compiler/xla/xla.pb.h" @@ -26,4 +26,4 @@ ExecutionOptions CreateDefaultExecutionOptions(); } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_EXECUTION_OPTIONS_UTIL_H_ +#endif // TENSORFLOW_COMPILER_XLA_EXECUTION_OPTIONS_UTIL_H_ diff --git a/tensorflow/compiler/xla/iterator_util.h b/tensorflow/compiler/xla/iterator_util.h index a39999705e..a8bb8c7a7e 100644 --- a/tensorflow/compiler/xla/iterator_util.h +++ b/tensorflow/compiler/xla/iterator_util.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_ITERATOR_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_ITERATOR_UTIL_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_ITERATOR_UTIL_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_ITERATOR_UTIL_H_ #include #include @@ -95,4 +95,4 @@ UnwrappingIterator MakeUnwrappingIterator(NestedIter iter) { } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_ITERATOR_UTIL_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_ITERATOR_UTIL_H_ diff --git a/tensorflow/compiler/xla/legacy_flags/debug_options_flags.h b/tensorflow/compiler/xla/legacy_flags/debug_options_flags.h index d0ef8e66ab..b53157f59c 100644 --- a/tensorflow/compiler/xla/legacy_flags/debug_options_flags.h +++ b/tensorflow/compiler/xla/legacy_flags/debug_options_flags.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_FLAGS_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_FLAGS_H_ +#ifndef TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_FLAGS_H_ +#define TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_FLAGS_H_ #include @@ -35,4 +35,4 @@ xla::DebugOptions GetDebugOptionsFromFlags(); } // namespace legacy_flags } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_FLAGS_H_ +#endif // TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_FLAGS_H_ diff --git a/tensorflow/compiler/xla/legacy_flags/debug_options_parsers.h b/tensorflow/compiler/xla/legacy_flags/debug_options_parsers.h index 0c238e6a5d..e9cf435d83 100644 --- a/tensorflow/compiler/xla/legacy_flags/debug_options_parsers.h +++ b/tensorflow/compiler/xla/legacy_flags/debug_options_parsers.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_PARSERS_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_PARSERS_H_ +#ifndef TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_PARSERS_H_ +#define TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_PARSERS_H_ #include #include "tensorflow/compiler/xla/service/hlo_opcode.h" @@ -148,4 +148,4 @@ inline bool parse_xla_reduce_precision_option( } // namespace legacy_flags } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_PARSERS_H_ +#endif // TENSORFLOW_COMPILER_XLA_LEGACY_FLAGS_DEBUG_OPTIONS_PARSERS_H_ diff --git a/tensorflow/compiler/xla/service/cpu/cpu_hlo_support_checker.h b/tensorflow/compiler/xla/service/cpu/cpu_hlo_support_checker.h index 2271af7b24..2924b63659 100644 --- a/tensorflow/compiler/xla/service/cpu/cpu_hlo_support_checker.h +++ b/tensorflow/compiler/xla/service/cpu/cpu_hlo_support_checker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CPU_HLO_SUPPORT_CHECKER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CPU_HLO_SUPPORT_CHECKER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CPU_HLO_SUPPORT_CHECKER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CPU_HLO_SUPPORT_CHECKER_H_ #include "tensorflow/compiler/xla/service/hlo_pass_interface.h" @@ -39,4 +39,4 @@ class CpuHloSupportChecker : public HloPassInterface { } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CPU_HLO_SUPPORT_CHECKER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CPU_HLO_SUPPORT_CHECKER_H_ diff --git a/tensorflow/compiler/xla/service/cpu/custom_call_target_registry.h b/tensorflow/compiler/xla/service/cpu/custom_call_target_registry.h index 2994642356..664125ecc9 100644 --- a/tensorflow/compiler/xla/service/cpu/custom_call_target_registry.h +++ b/tensorflow/compiler/xla/service/cpu/custom_call_target_registry.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CUSTOM_CALL_TARGET_REGISTRY_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CUSTOM_CALL_TARGET_REGISTRY_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CUSTOM_CALL_TARGET_REGISTRY_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CUSTOM_CALL_TARGET_REGISTRY_H_ // This file is depended on by kernels that have to build for mobile devices. // For this reason, we avoid relying on TensorFlow and instead only use the @@ -71,4 +71,4 @@ class RegisterCustomCallTarget { } // namespace cpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CUSTOM_CALL_TARGET_REGISTRY_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_CUSTOM_CALL_TARGET_REGISTRY_H_ diff --git a/tensorflow/compiler/xla/service/cpu/external_constant_pool.h b/tensorflow/compiler/xla/service/cpu/external_constant_pool.h index 9c00d476b1..8008a56df4 100644 --- a/tensorflow/compiler/xla/service/cpu/external_constant_pool.h +++ b/tensorflow/compiler/xla/service/cpu/external_constant_pool.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_EXTERNAL_CONSTANT_POOL_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_EXTERNAL_CONSTANT_POOL_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_EXTERNAL_CONSTANT_POOL_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_EXTERNAL_CONSTANT_POOL_H_ #include @@ -62,4 +62,4 @@ class ExternalConstantPool { } // namespace cpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_EXTERNAL_CONSTANT_POOL_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_EXTERNAL_CONSTANT_POOL_H_ diff --git a/tensorflow/compiler/xla/service/cpu/ir_function.h b/tensorflow/compiler/xla/service/cpu/ir_function.h index 1fd2da4dce..557aa4a6bf 100644 --- a/tensorflow/compiler/xla/service/cpu/ir_function.h +++ b/tensorflow/compiler/xla/service/cpu/ir_function.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_IR_FUNCTION_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_IR_FUNCTION_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_IR_FUNCTION_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_IR_FUNCTION_H_ #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -131,4 +131,4 @@ Status EmitCallToParallelForkJoin( } // namespace cpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_IR_FUNCTION_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_IR_FUNCTION_H_ diff --git a/tensorflow/compiler/xla/service/cpu/orc_jit_memory_mapper.h b/tensorflow/compiler/xla/service/cpu/orc_jit_memory_mapper.h index 2d29550fd5..f896384115 100644 --- a/tensorflow/compiler/xla/service/cpu/orc_jit_memory_mapper.h +++ b/tensorflow/compiler/xla/service/cpu/orc_jit_memory_mapper.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_ORC_JIT_MEMORY_MAPPER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_ORC_JIT_MEMORY_MAPPER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_ORC_JIT_MEMORY_MAPPER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_ORC_JIT_MEMORY_MAPPER_H_ #include @@ -53,4 +53,4 @@ class Registrar { } // namespace cpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_ORC_JIT_MEMORY_MAPPER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_ORC_JIT_MEMORY_MAPPER_H_ diff --git a/tensorflow/compiler/xla/service/cpu/parallel_loop_emitter.h b/tensorflow/compiler/xla/service/cpu/parallel_loop_emitter.h index 9335d2818e..ce92e36a94 100644 --- a/tensorflow/compiler/xla/service/cpu/parallel_loop_emitter.h +++ b/tensorflow/compiler/xla/service/cpu/parallel_loop_emitter.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_LOOP_EMITTER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_LOOP_EMITTER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_LOOP_EMITTER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_LOOP_EMITTER_H_ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Value.h" @@ -70,4 +70,4 @@ class ParallelLoopEmitter : public llvm_ir::LoopEmitter { } // namespace cpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_LOOP_EMITTER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_LOOP_EMITTER_H_ diff --git a/tensorflow/compiler/xla/service/cpu/parallel_task_assignment.h b/tensorflow/compiler/xla/service/cpu/parallel_task_assignment.h index 5801ec8d27..7140dabe51 100644 --- a/tensorflow/compiler/xla/service/cpu/parallel_task_assignment.h +++ b/tensorflow/compiler/xla/service/cpu/parallel_task_assignment.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_TASK_ASSIGNMENT_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_TASK_ASSIGNMENT_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_TASK_ASSIGNMENT_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_TASK_ASSIGNMENT_H_ #include "tensorflow/compiler/xla/service/hlo_cost_analysis.h" #include "tensorflow/compiler/xla/service/hlo_module.h" @@ -99,4 +99,4 @@ class ParallelTaskAssigner : public HloPassInterface { } // namespace cpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_TASK_ASSIGNMENT_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_PARALLEL_TASK_ASSIGNMENT_H_ diff --git a/tensorflow/compiler/xla/service/cpu/runtime_fork_join.h b/tensorflow/compiler/xla/service/cpu/runtime_fork_join.h index fcf1cc6207..1cf0ec6e3d 100644 --- a/tensorflow/compiler/xla/service/cpu/runtime_fork_join.h +++ b/tensorflow/compiler/xla/service/cpu/runtime_fork_join.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_FORK_JOIN_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_FORK_JOIN_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_FORK_JOIN_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_FORK_JOIN_H_ #include "tensorflow/core/platform/types.h" @@ -30,4 +30,4 @@ extern void __xla_cpu_runtime_ParallelForkJoin( } // extern "C" -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_FORK_JOIN_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_FORK_JOIN_H_ diff --git a/tensorflow/compiler/xla/service/cpu/runtime_matvec.h b/tensorflow/compiler/xla/service/cpu/runtime_matvec.h index cb7e0a81f0..1bd8dfb377 100644 --- a/tensorflow/compiler/xla/service/cpu/runtime_matvec.h +++ b/tensorflow/compiler/xla/service/cpu/runtime_matvec.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_MATVEC_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_MATVEC_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_MATVEC_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_MATVEC_H_ #include "tensorflow/core/platform/types.h" @@ -42,4 +42,4 @@ void EigenMatVecF64(double* out, double* lhs, double* rhs, tensorflow::int64 m, } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_MATVEC_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_RUNTIME_MATVEC_H_ diff --git a/tensorflow/compiler/xla/service/cpu/shape_partition.h b/tensorflow/compiler/xla/service/cpu/shape_partition.h index 7a2d00421c..33d02b70e6 100644 --- a/tensorflow/compiler/xla/service/cpu/shape_partition.h +++ b/tensorflow/compiler/xla/service/cpu/shape_partition.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_SHAPE_PARTITION_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_SHAPE_PARTITION_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_SHAPE_PARTITION_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_SHAPE_PARTITION_H_ #include @@ -102,4 +102,4 @@ class ShapePartitionIterator { } // namespace cpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_SHAPE_PARTITION_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_SHAPE_PARTITION_H_ diff --git a/tensorflow/compiler/xla/service/dot_decomposer.h b/tensorflow/compiler/xla/service/dot_decomposer.h index 5ff0ab34ea..1959b687f1 100644 --- a/tensorflow/compiler/xla/service/dot_decomposer.h +++ b/tensorflow/compiler/xla/service/dot_decomposer.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_DOT_DECOMPOSER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_DOT_DECOMPOSER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_DOT_DECOMPOSER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_DOT_DECOMPOSER_H_ #include "tensorflow/compiler/xla/service/hlo_module.h" #include "tensorflow/compiler/xla/service/hlo_pass_interface.h" @@ -41,4 +41,4 @@ class DotDecomposer : public HloPassInterface { } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_DOT_DECOMPOSER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_DOT_DECOMPOSER_H_ diff --git a/tensorflow/compiler/xla/service/gpu/for_thunk.h b/tensorflow/compiler/xla/service/gpu/for_thunk.h index 525a2af941..832494d17e 100644 --- a/tensorflow/compiler/xla/service/gpu/for_thunk.h +++ b/tensorflow/compiler/xla/service/gpu/for_thunk.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FOR_THUNK_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FOR_THUNK_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FOR_THUNK_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FOR_THUNK_H_ #include @@ -49,4 +49,4 @@ class ForThunk : public Thunk { } // namespace gpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FOR_THUNK_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FOR_THUNK_H_ diff --git a/tensorflow/compiler/xla/service/gpu/fusion_merger.h b/tensorflow/compiler/xla/service/gpu/fusion_merger.h index bd720f8584..4c523a66de 100644 --- a/tensorflow/compiler/xla/service/gpu/fusion_merger.h +++ b/tensorflow/compiler/xla/service/gpu/fusion_merger.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FUSION_MERGER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FUSION_MERGER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FUSION_MERGER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FUSION_MERGER_H_ #include "tensorflow/compiler/xla/service/hlo_module.h" #include "tensorflow/compiler/xla/service/hlo_pass_interface.h" @@ -44,4 +44,4 @@ class FusionMerger : public HloPassInterface { } // namespace gpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FUSION_MERGER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_GPU_FUSION_MERGER_H_ diff --git a/tensorflow/compiler/xla/service/gpu/gpu_constants.h b/tensorflow/compiler/xla/service/gpu/gpu_constants.h index 572c856282..eb1ca4c6c9 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_constants.h +++ b/tensorflow/compiler/xla/service/gpu/gpu_constants.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_CONSTANTS_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_CONSTANTS_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_CONSTANTS_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_CONSTANTS_H_ #include "tensorflow/compiler/xla/types.h" @@ -28,4 +28,4 @@ extern const int64 kCudaMallocAlignBytes; } // namespace gpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_CONSTANTS_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_CONSTANTS_H_ diff --git a/tensorflow/compiler/xla/service/gpu/gpu_hlo_support_checker.h b/tensorflow/compiler/xla/service/gpu/gpu_hlo_support_checker.h index d9550f81b5..d63e213d2b 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_hlo_support_checker.h +++ b/tensorflow/compiler/xla/service/gpu/gpu_hlo_support_checker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_HLO_SUPPORT_CHECKER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_HLO_SUPPORT_CHECKER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_HLO_SUPPORT_CHECKER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_HLO_SUPPORT_CHECKER_H_ #include "tensorflow/compiler/xla/service/hlo_pass_interface.h" @@ -39,4 +39,4 @@ class GpuHloSupportChecker : public HloPassInterface { } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_HLO_SUPPORT_CHECKER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_GPU_GPU_HLO_SUPPORT_CHECKER_H_ diff --git a/tensorflow/compiler/xla/service/gpu/while_transformer.h b/tensorflow/compiler/xla/service/gpu/while_transformer.h index a4f527fce0..fe3a954e18 100644 --- a/tensorflow/compiler/xla/service/gpu/while_transformer.h +++ b/tensorflow/compiler/xla/service/gpu/while_transformer.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_WHILE_TRANSFORMER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_WHILE_TRANSFORMER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_GPU_WHILE_TRANSFORMER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_GPU_WHILE_TRANSFORMER_H_ #include "tensorflow/compiler/xla/service/hlo_instruction.h" #include "tensorflow/compiler/xla/statusor.h" @@ -40,4 +40,4 @@ StatusOr> CanTransformWhileToFor( } // namespace gpu } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_GPU_WHILE_TRANSFORMER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_GPU_WHILE_TRANSFORMER_H_ diff --git a/tensorflow/compiler/xla/service/hlo_evaluator.h b/tensorflow/compiler/xla/service/hlo_evaluator.h index 02bb8b0a47..3b2b697e49 100644 --- a/tensorflow/compiler/xla/service/hlo_evaluator.h +++ b/tensorflow/compiler/xla/service/hlo_evaluator.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_EVALUATOR_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_EVALUATOR_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_HLO_EVALUATOR_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_HLO_EVALUATOR_H_ #include @@ -195,4 +195,4 @@ class HloEvaluator : public DfsHloVisitorWithDefault { } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_EVALUATOR_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_HLO_EVALUATOR_H_ diff --git a/tensorflow/compiler/xla/service/hlo_profile_printer.h b/tensorflow/compiler/xla/service/hlo_profile_printer.h index 2f056490ae..35152e744d 100644 --- a/tensorflow/compiler/xla/service/hlo_profile_printer.h +++ b/tensorflow/compiler/xla/service/hlo_profile_printer.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_PROFILE_PRINTER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_PROFILE_PRINTER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_HLO_PROFILE_PRINTER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_HLO_PROFILE_PRINTER_H_ #include #include @@ -100,4 +100,4 @@ class HloProfilePrinter { }; } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_PROFILE_PRINTER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_HLO_PROFILE_PRINTER_H_ diff --git a/tensorflow/compiler/xla/service/hlo_tfgraph_builder.h b/tensorflow/compiler/xla/service/hlo_tfgraph_builder.h index 9aa3e501d5..c4876b852e 100644 --- a/tensorflow/compiler/xla/service/hlo_tfgraph_builder.h +++ b/tensorflow/compiler/xla/service/hlo_tfgraph_builder.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_TFGRAPH_BUILDER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_TFGRAPH_BUILDER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_HLO_TFGRAPH_BUILDER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_HLO_TFGRAPH_BUILDER_H_ #include "tensorflow/compiler/xla/service/hlo_computation.h" #include "tensorflow/compiler/xla/xla.pb.h" @@ -56,4 +56,4 @@ class HloTfGraphBuilder { } // namespace hlo_graph_dumper } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_TFGRAPH_BUILDER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_HLO_TFGRAPH_BUILDER_H_ diff --git a/tensorflow/compiler/xla/service/hlo_verifier.h b/tensorflow/compiler/xla/service/hlo_verifier.h index 6368611f32..5a1d864e03 100644 --- a/tensorflow/compiler/xla/service/hlo_verifier.h +++ b/tensorflow/compiler/xla/service/hlo_verifier.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_VERIFIER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_VERIFIER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_HLO_VERIFIER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_HLO_VERIFIER_H_ #include "tensorflow/compiler/xla/service/hlo_pass_interface.h" @@ -127,4 +127,4 @@ class HloVerifier : public HloPassInterface { } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_HLO_VERIFIER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_HLO_VERIFIER_H_ diff --git a/tensorflow/compiler/xla/service/llvm_ir/kernel_support_library.h b/tensorflow/compiler/xla/service/llvm_ir/kernel_support_library.h index 827e092a3f..1c00b2aabd 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/kernel_support_library.h +++ b/tensorflow/compiler/xla/service/llvm_ir/kernel_support_library.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_KERNEL_SUPPORT_LIBRARY_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_KERNEL_SUPPORT_LIBRARY_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_CPU_KERNEL_SUPPORT_LIBRARY_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_CPU_KERNEL_SUPPORT_LIBRARY_H_ #include @@ -179,4 +179,4 @@ class KernelSupportLibrary { }; } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_CPU_KERNEL_SUPPORT_LIBRARY_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_CPU_KERNEL_SUPPORT_LIBRARY_H_ diff --git a/tensorflow/compiler/xla/service/llvm_ir/ops.h b/tensorflow/compiler/xla/service/llvm_ir/ops.h index f72f482e31..175b081e84 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/ops.h +++ b/tensorflow/compiler/xla/service/llvm_ir/ops.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_OPS_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_OPS_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_OPS_H_ #include "tensorflow/compiler/xla/service/buffer_assignment.h" #include "tensorflow/compiler/xla/service/elemental_ir_emitter.h" @@ -90,4 +90,4 @@ Status EmitParallelFusedDynamicUpdateSliceInPlace( } // namespace llvm_ir } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_OPS_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_OPS_H_ diff --git a/tensorflow/compiler/xla/service/logical_buffer_analysis.h b/tensorflow/compiler/xla/service/logical_buffer_analysis.h index 598d08b720..f4c63dd86b 100644 --- a/tensorflow/compiler/xla/service/logical_buffer_analysis.h +++ b/tensorflow/compiler/xla/service/logical_buffer_analysis.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_LOGICAL_BUFFER_ANALYSIS_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_LOGICAL_BUFFER_ANALYSIS_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_LOGICAL_BUFFER_ANALYSIS_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_LOGICAL_BUFFER_ANALYSIS_H_ #include "tensorflow/compiler/xla/service/hlo_instruction.h" #include "tensorflow/compiler/xla/service/hlo_module.h" @@ -90,4 +90,4 @@ class LogicalBufferAnalysis : public DfsHloVisitorWithDefault { } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_LOGICAL_BUFFER_ANALYSIS_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_LOGICAL_BUFFER_ANALYSIS_H_ diff --git a/tensorflow/compiler/xla/service/while_loop_simplifier.h b/tensorflow/compiler/xla/service/while_loop_simplifier.h index 50dac32a4a..d3d55634c9 100644 --- a/tensorflow/compiler/xla/service/while_loop_simplifier.h +++ b/tensorflow/compiler/xla/service/while_loop_simplifier.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_WHILE_LOOP_SIMPLIFIER_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_WHILE_LOOP_SIMPLIFIER_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_WHILE_LOOP_SIMPLIFIER_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_WHILE_LOOP_SIMPLIFIER_H_ #include "tensorflow/compiler/xla/service/hlo_module.h" #include "tensorflow/compiler/xla/service/hlo_pass_interface.h" @@ -41,4 +41,4 @@ class WhileLoopSimplifier : public HloPassInterface { } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_WHILE_LOOP_SIMPLIFIER_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_WHILE_LOOP_SIMPLIFIER_H_ diff --git a/tensorflow/compiler/xla/service/zero_sized_hlo_elimination.h b/tensorflow/compiler/xla/service/zero_sized_hlo_elimination.h index 63afab4206..063e312df6 100644 --- a/tensorflow/compiler/xla/service/zero_sized_hlo_elimination.h +++ b/tensorflow/compiler/xla/service/zero_sized_hlo_elimination.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_ZERO_SIZED_HLO_ELIMINATION_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_ZERO_SIZED_HLO_ELIMINATION_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_ZERO_SIZED_HLO_ELIMINATION_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_ZERO_SIZED_HLO_ELIMINATION_H_ #include "tensorflow/compiler/xla/service/hlo_module.h" #include "tensorflow/compiler/xla/service/hlo_pass_interface.h" @@ -29,4 +29,4 @@ class ZeroSizedHloElimination : public HloPassInterface { } }; } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SERVICE_ZERO_SIZED_HLO_ELIMINATION_H_ +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_ZERO_SIZED_HLO_ELIMINATION_H_ diff --git a/tensorflow/compiler/xla/sparse_index_array.h b/tensorflow/compiler/xla/sparse_index_array.h index 903fee5255..f2ce22d672 100644 --- a/tensorflow/compiler/xla/sparse_index_array.h +++ b/tensorflow/compiler/xla/sparse_index_array.h @@ -15,8 +15,8 @@ limitations under the License. // Utility class for managing sparse array indices. -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SPARSE_INDEX_ARRAY_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SPARSE_INDEX_ARRAY_H_ +#ifndef TENSORFLOW_COMPILER_XLA_SPARSE_INDEX_ARRAY_H_ +#define TENSORFLOW_COMPILER_XLA_SPARSE_INDEX_ARRAY_H_ #include @@ -173,4 +173,4 @@ void SparseIndexArray::SortWithValues( } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_SPARSE_INDEX_ARRAY_H_ +#endif // TENSORFLOW_COMPILER_XLA_SPARSE_INDEX_ARRAY_H_ diff --git a/tensorflow/compiler/xla/statusor_internals.h b/tensorflow/compiler/xla/statusor_internals.h index a2fda5bb3c..14636bd144 100644 --- a/tensorflow/compiler/xla/statusor_internals.h +++ b/tensorflow/compiler/xla/statusor_internals.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_ +#ifndef TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_ +#define TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_ #include "tensorflow/compiler/xla/status.h" #include "tensorflow/core/platform/macros.h" @@ -242,4 +242,4 @@ struct TraitsBase { } // namespace internal_statusor } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_ +#endif // TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_ diff --git a/tensorflow/compiler/xla/tests/filecheck.h b/tensorflow/compiler/xla/tests/filecheck.h index 493ff7414b..3830d5a44d 100644 --- a/tensorflow/compiler/xla/tests/filecheck.h +++ b/tensorflow/compiler/xla/tests/filecheck.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_COMPILER_XLA_TESTS_FILECHECK_H_ -#define THIRD_PARTY_TENSORFLOW_COMPILER_XLA_TESTS_FILECHECK_H_ +#ifndef TENSORFLOW_COMPILER_XLA_TESTS_FILECHECK_H_ +#define TENSORFLOW_COMPILER_XLA_TESTS_FILECHECK_H_ #include @@ -30,4 +30,4 @@ StatusOr RunFileCheck(const string& input, const string& pattern); } // namespace xla -#endif // THIRD_PARTY_TENSORFLOW_COMPILER_XLA_TESTS_FILECHECK_H_ +#endif // TENSORFLOW_COMPILER_XLA_TESTS_FILECHECK_H_ diff --git a/tensorflow/contrib/android/asset_manager_filesystem.h b/tensorflow/contrib/android/asset_manager_filesystem.h index 2b43939f14..665304b5ee 100644 --- a/tensorflow/contrib/android/asset_manager_filesystem.h +++ b/tensorflow/contrib/android/asset_manager_filesystem.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_ANDROID_ASSET_MANAGER_FILESYSTEM_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_ANDROID_ASSET_MANAGER_FILESYSTEM_H_ +#ifndef TENSORFLOW_CONTRIB_ANDROID_ASSET_MANAGER_FILESYSTEM_H_ +#define TENSORFLOW_CONTRIB_ANDROID_ASSET_MANAGER_FILESYSTEM_H_ #include #include @@ -79,4 +79,4 @@ class AssetManagerFileSystem : public FileSystem { }; } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_ANDROID_ASSET_MANAGER_FILESYSTEM_H_ +#endif // TENSORFLOW_CONTRIB_ANDROID_ASSET_MANAGER_FILESYSTEM_H_ diff --git a/tensorflow/contrib/batching/adaptive_shared_batch_scheduler.h b/tensorflow/contrib/batching/adaptive_shared_batch_scheduler.h index 60861f83f4..86250e6692 100644 --- a/tensorflow/contrib/batching/adaptive_shared_batch_scheduler.h +++ b/tensorflow/contrib/batching/adaptive_shared_batch_scheduler.h @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ +#ifndef TENSORFLOW_CONTRIB_BATCHING_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ +#define TENSORFLOW_CONTRIB_BATCHING_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ #include "tensorflow/core/kernels/batching_util/adaptive_shared_batch_scheduler.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ +#endif // TENSORFLOW_CONTRIB_BATCHING_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ diff --git a/tensorflow/contrib/batching/basic_batch_scheduler.h b/tensorflow/contrib/batching/basic_batch_scheduler.h index 63ba8fcf45..d9b37da693 100644 --- a/tensorflow/contrib/batching/basic_batch_scheduler.h +++ b/tensorflow/contrib/batching/basic_batch_scheduler.h @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_BASIC_BATCH_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_BASIC_BATCH_SCHEDULER_H_ +#ifndef TENSORFLOW_CONTRIB_BATCHING_BASIC_BATCH_SCHEDULER_H_ +#define TENSORFLOW_CONTRIB_BATCHING_BASIC_BATCH_SCHEDULER_H_ #include "tensorflow/core/kernels/batching_util/basic_batch_scheduler.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_BASIC_BATCH_SCHEDULER_H_ +#endif // TENSORFLOW_CONTRIB_BATCHING_BASIC_BATCH_SCHEDULER_H_ diff --git a/tensorflow/contrib/batching/batch_scheduler.h b/tensorflow/contrib/batching/batch_scheduler.h index 3afce2761f..8e94e1fd8b 100644 --- a/tensorflow/contrib/batching/batch_scheduler.h +++ b/tensorflow/contrib/batching/batch_scheduler.h @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_BATCH_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_BATCH_SCHEDULER_H_ +#ifndef TENSORFLOW_CONTRIB_BATCHING_BATCH_SCHEDULER_H_ +#define TENSORFLOW_CONTRIB_BATCHING_BATCH_SCHEDULER_H_ #include "tensorflow/core/kernels/batching_util/batch_scheduler.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_BATCH_SCHEDULER_H_ +#endif // TENSORFLOW_CONTRIB_BATCHING_BATCH_SCHEDULER_H_ diff --git a/tensorflow/contrib/batching/shared_batch_scheduler.h b/tensorflow/contrib/batching/shared_batch_scheduler.h index 7eb1e20c42..83a59695d7 100644 --- a/tensorflow/contrib/batching/shared_batch_scheduler.h +++ b/tensorflow/contrib/batching/shared_batch_scheduler.h @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_SHARED_BATCH_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_SHARED_BATCH_SCHEDULER_H_ +#ifndef TENSORFLOW_CONTRIB_BATCHING_SHARED_BATCH_SCHEDULER_H_ +#define TENSORFLOW_CONTRIB_BATCHING_SHARED_BATCH_SCHEDULER_H_ #include "tensorflow/core/kernels/batching_util/shared_batch_scheduler.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_SHARED_BATCH_SCHEDULER_H_ +#endif // TENSORFLOW_CONTRIB_BATCHING_SHARED_BATCH_SCHEDULER_H_ diff --git a/tensorflow/contrib/batching/test_util/fake_clock_env.h b/tensorflow/contrib/batching/test_util/fake_clock_env.h index ced27a8833..40a39a5569 100644 --- a/tensorflow/contrib/batching/test_util/fake_clock_env.h +++ b/tensorflow/contrib/batching/test_util/fake_clock_env.h @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_TEST_UTIL_FAKE_CLOCK_ENV_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_TEST_UTIL_FAKE_CLOCK_ENV_H_ +#ifndef TENSORFLOW_CONTRIB_BATCHING_TEST_UTIL_FAKE_CLOCK_ENV_H_ +#define TENSORFLOW_CONTRIB_BATCHING_TEST_UTIL_FAKE_CLOCK_ENV_H_ #include "tensorflow/core/kernels/batching_util/fake_clock_env.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_TEST_UTIL_FAKE_CLOCK_ENV_H_ +#endif // TENSORFLOW_CONTRIB_BATCHING_TEST_UTIL_FAKE_CLOCK_ENV_H_ diff --git a/tensorflow/contrib/batching/util/periodic_function.h b/tensorflow/contrib/batching/util/periodic_function.h index fb61bc2eea..aa2ed0a385 100644 --- a/tensorflow/contrib/batching/util/periodic_function.h +++ b/tensorflow/contrib/batching/util/periodic_function.h @@ -12,9 +12,9 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_UTIL_PERIODIC_FUNCTION_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_UTIL_PERIODIC_FUNCTION_H_ +#ifndef TENSORFLOW_CONTRIB_BATCHING_UTIL_PERIODIC_FUNCTION_H_ +#define TENSORFLOW_CONTRIB_BATCHING_UTIL_PERIODIC_FUNCTION_H_ #include "tensorflow/core/kernels/batching_util/periodic_function.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BATCHING_UTIL_PERIODIC_FUNCTION_H_ +#endif // TENSORFLOW_CONTRIB_BATCHING_UTIL_PERIODIC_FUNCTION_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/learner/common/accumulators/class-partition-key.h b/tensorflow/contrib/boosted_trees/lib/learner/common/accumulators/class-partition-key.h index e1bef02788..3c54868951 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/common/accumulators/class-partition-key.h +++ b/tensorflow/contrib/boosted_trees/lib/learner/common/accumulators/class-partition-key.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_CLASS_PARTITION_KEY_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_CLASS_PARTITION_KEY_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_CLASS_PARTITION_KEY_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_CLASS_PARTITION_KEY_H_ #include "tensorflow/core/lib/hash/hash.h" @@ -58,4 +58,4 @@ struct ClassPartitionKey { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_CLASS_PARTITION_KEY_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_CLASS_PARTITION_KEY_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/learner/common/accumulators/feature-stats-accumulator.h b/tensorflow/contrib/boosted_trees/lib/learner/common/accumulators/feature-stats-accumulator.h index 3814edb567..ec4e7c52bb 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/common/accumulators/feature-stats-accumulator.h +++ b/tensorflow/contrib/boosted_trees/lib/learner/common/accumulators/feature-stats-accumulator.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_FEATURE_STATS_ACCUMULATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_FEATURE_STATS_ACCUMULATOR_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_FEATURE_STATS_ACCUMULATOR_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_FEATURE_STATS_ACCUMULATOR_H_ #include #include @@ -79,4 +79,4 @@ class FeatureStatsAccumulator { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_FEATURE_STATS_ACCUMULATOR_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_ACCUMULATORS_FEATURE_STATS_ACCUMULATOR_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/learner/common/partitioners/example_partitioner.h b/tensorflow/contrib/boosted_trees/lib/learner/common/partitioners/example_partitioner.h index aed0d9fdac..37a7103704 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/common/partitioners/example_partitioner.h +++ b/tensorflow/contrib/boosted_trees/lib/learner/common/partitioners/example_partitioner.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_PARTITIONERS_EXAMPLE_PARTITIONER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_PARTITIONERS_EXAMPLE_PARTITIONER_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_PARTITIONERS_EXAMPLE_PARTITIONER_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_PARTITIONERS_EXAMPLE_PARTITIONER_H_ #include #include "tensorflow/contrib/boosted_trees/lib/trees/decision_tree.h" @@ -50,4 +50,4 @@ class ExamplePartitioner { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_PARTITIONERS_EXAMPLE_PARTITIONER_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_PARTITIONERS_EXAMPLE_PARTITIONER_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/learner/common/stats/feature-split-candidate.h b/tensorflow/contrib/boosted_trees/lib/learner/common/stats/feature-split-candidate.h index 339c2e0fde..382b85cf0b 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/common/stats/feature-split-candidate.h +++ b/tensorflow/contrib/boosted_trees/lib/learner/common/stats/feature-split-candidate.h @@ -13,8 +13,8 @@ // limitations under the License. // // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_FEATURE_SPLIT_CANDIDATE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_FEATURE_SPLIT_CANDIDATE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_FEATURE_SPLIT_CANDIDATE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_FEATURE_SPLIT_CANDIDATE_H_ #include "tensorflow/contrib/boosted_trees/lib/learner/common/stats/split-stats.h" #include "tensorflow/contrib/boosted_trees/proto/tree_config.pb.h" @@ -58,4 +58,4 @@ struct FeatureSplitCandidate { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_FEATURE_SPLIT_CANDIDATE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_FEATURE_SPLIT_CANDIDATE_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/learner/common/stats/gradient-stats.h b/tensorflow/contrib/boosted_trees/lib/learner/common/stats/gradient-stats.h index 34e3ddb777..3dd03215d8 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/common/stats/gradient-stats.h +++ b/tensorflow/contrib/boosted_trees/lib/learner/common/stats/gradient-stats.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_GRADIENT_STATS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_GRADIENT_STATS_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_GRADIENT_STATS_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_GRADIENT_STATS_H_ #include @@ -190,4 +190,4 @@ inline GradientStats operator-(const GradientStats& a, const GradientStats& b) { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_GRADIENT_STATS_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_GRADIENT_STATS_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/learner/common/stats/node-stats.h b/tensorflow/contrib/boosted_trees/lib/learner/common/stats/node-stats.h index 642a183aec..cd925f6b65 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/common/stats/node-stats.h +++ b/tensorflow/contrib/boosted_trees/lib/learner/common/stats/node-stats.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_NODE_STATS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_NODE_STATS_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_NODE_STATS_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_NODE_STATS_H_ #include "third_party/eigen3/Eigen/Core" #include "third_party/eigen3/Eigen/Eigenvalues" @@ -298,4 +298,4 @@ struct NodeStats { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_NODE_STATS_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_NODE_STATS_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/learner/common/stats/split-stats.h b/tensorflow/contrib/boosted_trees/lib/learner/common/stats/split-stats.h index 054ccd9a8c..81ee2774bd 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/common/stats/split-stats.h +++ b/tensorflow/contrib/boosted_trees/lib/learner/common/stats/split-stats.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_SPLIT_STATS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_SPLIT_STATS_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_SPLIT_STATS_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_SPLIT_STATS_H_ #include @@ -81,4 +81,4 @@ struct SplitStats { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_SPLIT_STATS_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_LEARNER_COMMON_STATS_SPLIT_STATS_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/models/multiple_additive_trees.h b/tensorflow/contrib/boosted_trees/lib/models/multiple_additive_trees.h index ee29a8aa79..cc3dc226cd 100644 --- a/tensorflow/contrib/boosted_trees/lib/models/multiple_additive_trees.h +++ b/tensorflow/contrib/boosted_trees/lib/models/multiple_additive_trees.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_MODELS_MULTIPLE_ADDITIVE_TREES_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_MODELS_MULTIPLE_ADDITIVE_TREES_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_MODELS_MULTIPLE_ADDITIVE_TREES_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_MODELS_MULTIPLE_ADDITIVE_TREES_H_ #include @@ -45,4 +45,4 @@ class MultipleAdditiveTrees { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_MODELS_MULTIPLE_ADDITIVE_TREES_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_MODELS_MULTIPLE_ADDITIVE_TREES_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_buffer.h b/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_buffer.h index 70037d5bd8..804b218f1c 100644 --- a/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_buffer.h +++ b/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_buffer.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_BUFFER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_BUFFER_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_BUFFER_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_BUFFER_H_ #include #include @@ -129,4 +129,4 @@ constexpr decltype(CompareFn()) } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_BUFFER_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_BUFFER_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_stream.h b/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_stream.h index fd577ad712..1c4181f1b1 100644 --- a/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_stream.h +++ b/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_stream.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_STREAM_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_STREAM_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_STREAM_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_STREAM_H_ #include #include @@ -322,4 +322,4 @@ WeightedQuantilesStream::GetQuantileSpecs( } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_STREAM_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_STREAM_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_summary.h b/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_summary.h index c329c6d4f7..aec232f3cb 100644 --- a/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_summary.h +++ b/tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_summary.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_SUMMARY_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_SUMMARY_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_SUMMARY_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_SUMMARY_H_ #include #include @@ -334,4 +334,4 @@ constexpr decltype(CompareFn()) } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_SUMMARY_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_QUANTILES_WEIGHTED_QUANTILES_SUMMARY_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/testutil/batch_features_testutil.h b/tensorflow/contrib/boosted_trees/lib/testutil/batch_features_testutil.h index d95878ec87..b98190b10d 100644 --- a/tensorflow/contrib/boosted_trees/lib/testutil/batch_features_testutil.h +++ b/tensorflow/contrib/boosted_trees/lib/testutil/batch_features_testutil.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_BATCH_FEATURES_TESTUTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_BATCH_FEATURES_TESTUTIL_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_BATCH_FEATURES_TESTUTIL_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_BATCH_FEATURES_TESTUTIL_H_ #include "tensorflow/contrib/boosted_trees/lib/utils/batch_features.h" #include "tensorflow/core/framework/tensor.h" @@ -42,4 +42,4 @@ void RandomlyInitializeBatchFeatures( } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_BATCH_FEATURES_TESTUTIL_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_BATCH_FEATURES_TESTUTIL_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/testutil/random_tree_gen.h b/tensorflow/contrib/boosted_trees/lib/testutil/random_tree_gen.h index 5e12429ba7..1838b4cee2 100644 --- a/tensorflow/contrib/boosted_trees/lib/testutil/random_tree_gen.h +++ b/tensorflow/contrib/boosted_trees/lib/testutil/random_tree_gen.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_RANDOM_TREE_GEN_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_RANDOM_TREE_GEN_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_RANDOM_TREE_GEN_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_RANDOM_TREE_GEN_H_ #include @@ -72,4 +72,4 @@ class RandomTreeGen { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_RANDOM_TREE_GEN_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TESTUTIL_RANDOM_TREE_GEN_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/trees/decision_tree.h b/tensorflow/contrib/boosted_trees/lib/trees/decision_tree.h index 604ff02744..43526c229a 100644 --- a/tensorflow/contrib/boosted_trees/lib/trees/decision_tree.h +++ b/tensorflow/contrib/boosted_trees/lib/trees/decision_tree.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TREES_DECISION_TREE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TREES_DECISION_TREE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TREES_DECISION_TREE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TREES_DECISION_TREE_H_ #include "tensorflow/contrib/boosted_trees/lib/utils/example.h" #include "tensorflow/contrib/boosted_trees/proto/tree_config.pb.h" // NOLINT @@ -46,4 +46,4 @@ class DecisionTree { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TREES_DECISION_TREE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_TREES_DECISION_TREE_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/batch_features.h b/tensorflow/contrib/boosted_trees/lib/utils/batch_features.h index badc629a11..da5e744851 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/batch_features.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/batch_features.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_BATCH_FEATURES_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_BATCH_FEATURES_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_BATCH_FEATURES_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_BATCH_FEATURES_H_ #include #include "tensorflow/contrib/boosted_trees/lib/utils/examples_iterable.h" @@ -92,4 +92,4 @@ class BatchFeatures { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_BATCH_FEATURES_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_BATCH_FEATURES_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/dropout_utils.h b/tensorflow/contrib/boosted_trees/lib/utils/dropout_utils.h index c3f1c918ca..928bfbfe5c 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/dropout_utils.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/dropout_utils.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_DROPOUT_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_DROPOUT_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_DROPOUT_UTILS_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_DROPOUT_UTILS_H_ #include #include @@ -74,4 +74,4 @@ class DropoutUtils { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_DROPOUT_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_DROPOUT_UTILS_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/example.h b/tensorflow/contrib/boosted_trees/lib/utils/example.h index 54f60e1dee..1371ff337f 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/example.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/example.h @@ -13,8 +13,8 @@ // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLE_H_ #include #include @@ -131,4 +131,4 @@ struct Example { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLE_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/examples_iterable.h b/tensorflow/contrib/boosted_trees/lib/utils/examples_iterable.h index 5b33c81588..1b654e1c44 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/examples_iterable.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/examples_iterable.h @@ -13,8 +13,8 @@ // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLES_ITERABLE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLES_ITERABLE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLES_ITERABLE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLES_ITERABLE_H_ #include @@ -205,4 +205,4 @@ class ExamplesIterable { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLES_ITERABLE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_EXAMPLES_ITERABLE_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/macros.h b/tensorflow/contrib/boosted_trees/lib/utils/macros.h index 28ea0a4dc1..9a53fb2ef7 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/macros.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/macros.h @@ -13,8 +13,8 @@ // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_MACROS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_MACROS_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_MACROS_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_MACROS_H_ #include "tensorflow/core/platform/macros.h" @@ -23,4 +23,4 @@ return (STATUS); \ } -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_MACROS_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_MACROS_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/optional_value.h b/tensorflow/contrib/boosted_trees/lib/utils/optional_value.h index c141fe059d..b2166f53d7 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/optional_value.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/optional_value.h @@ -13,8 +13,8 @@ // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_OPTIONAL_VALUE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_OPTIONAL_VALUE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_OPTIONAL_VALUE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_OPTIONAL_VALUE_H_ #include "tensorflow/core/platform/logging.h" @@ -44,4 +44,4 @@ class OptionalValue { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_OPTIONAL_VALUE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_OPTIONAL_VALUE_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/parallel_for.h b/tensorflow/contrib/boosted_trees/lib/utils/parallel_for.h index c80431b558..ec06787e1d 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/parallel_for.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/parallel_for.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LIB_UTILS_PARALLEL_FOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LIB_UTILS_PARALLEL_FOR_H_ +#ifndef TENSORFLOW_CONTRIB_LIB_UTILS_PARALLEL_FOR_H_ +#define TENSORFLOW_CONTRIB_LIB_UTILS_PARALLEL_FOR_H_ #include "tensorflow/core/lib/core/threadpool.h" @@ -30,4 +30,4 @@ void ParallelFor(int64 batch_size, int64 desired_parallelism, } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LIB_UTILS_PARALLEL_FOR_H_ +#endif // TENSORFLOW_CONTRIB_LIB_UTILS_PARALLEL_FOR_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/random.h b/tensorflow/contrib/boosted_trees/lib/utils/random.h index 6dd55fcacc..546d344f55 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/random.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/random.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LIB_UTILS_RANDOM_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LIB_UTILS_RANDOM_H_ +#ifndef TENSORFLOW_CONTRIB_LIB_UTILS_RANDOM_H_ +#define TENSORFLOW_CONTRIB_LIB_UTILS_RANDOM_H_ #include "tensorflow/core/lib/random/simple_philox.h" @@ -36,4 +36,4 @@ inline int32 PoissonBootstrap(random::SimplePhilox* rng) { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LIB_UTILS_RANDOM_H_ +#endif // TENSORFLOW_CONTRIB_LIB_UTILS_RANDOM_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/sparse_column_iterable.h b/tensorflow/contrib/boosted_trees/lib/utils/sparse_column_iterable.h index 9664c9d1c6..87fb1fbf5a 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/sparse_column_iterable.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/sparse_column_iterable.h @@ -13,8 +13,8 @@ // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_SPARSE_COLUMN_ITERABLE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_SPARSE_COLUMN_ITERABLE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_SPARSE_COLUMN_ITERABLE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_SPARSE_COLUMN_ITERABLE_H_ #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/framework/tensor_types.h" @@ -127,4 +127,4 @@ class SparseColumnIterable { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_SPARSE_COLUMN_ITERABLE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_SPARSE_COLUMN_ITERABLE_H_ diff --git a/tensorflow/contrib/boosted_trees/lib/utils/tensor_utils.h b/tensorflow/contrib/boosted_trees/lib/utils/tensor_utils.h index 58f5e5a0d1..475d3718ec 100644 --- a/tensorflow/contrib/boosted_trees/lib/utils/tensor_utils.h +++ b/tensorflow/contrib/boosted_trees/lib/utils/tensor_utils.h @@ -13,8 +13,8 @@ // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_TENSOR_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_TENSOR_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_TENSOR_UTILS_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_TENSOR_UTILS_H_ #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/tensor.h" @@ -57,4 +57,4 @@ class TensorUtils { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_TENSOR_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_LIB_UTILS_TENSOR_UTILS_H_ diff --git a/tensorflow/contrib/boosted_trees/resources/decision_tree_ensemble_resource.h b/tensorflow/contrib/boosted_trees/resources/decision_tree_ensemble_resource.h index ad9c8961aa..3ebf28ea44 100644 --- a/tensorflow/contrib/boosted_trees/resources/decision_tree_ensemble_resource.h +++ b/tensorflow/contrib/boosted_trees/resources/decision_tree_ensemble_resource.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_DECISION_TREE_ENSEMBLE_RESOURCE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_DECISION_TREE_ENSEMBLE_RESOURCE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_DECISION_TREE_ENSEMBLE_RESOURCE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_DECISION_TREE_ENSEMBLE_RESOURCE_H_ #include "tensorflow/contrib/boosted_trees/lib/trees/decision_tree.h" #include "tensorflow/contrib/boosted_trees/resources/stamped_resource.h" @@ -179,4 +179,4 @@ class DecisionTreeEnsembleResource : public StampedResource { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_DECISION_TREE_ENSEMBLE_RESOURCE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_DECISION_TREE_ENSEMBLE_RESOURCE_H_ diff --git a/tensorflow/contrib/boosted_trees/resources/quantile_stream_resource.h b/tensorflow/contrib/boosted_trees/resources/quantile_stream_resource.h index c1fa35eaf1..fdaaae7f47 100644 --- a/tensorflow/contrib/boosted_trees/resources/quantile_stream_resource.h +++ b/tensorflow/contrib/boosted_trees/resources/quantile_stream_resource.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_QUANTILE_STREAM_RESOURCE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_QUANTILE_STREAM_RESOURCE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_QUANTILE_STREAM_RESOURCE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_QUANTILE_STREAM_RESOURCE_H_ #include "tensorflow/contrib/boosted_trees/lib/quantiles/weighted_quantiles_stream.h" #include "tensorflow/contrib/boosted_trees/proto/quantiles.pb.h" // NOLINT @@ -113,4 +113,4 @@ class QuantileStreamResource : public StampedResource { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_QUANTILE_STREAM_RESOURCE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_QUANTILE_STREAM_RESOURCE_H_ diff --git a/tensorflow/contrib/boosted_trees/resources/stamped_resource.h b/tensorflow/contrib/boosted_trees/resources/stamped_resource.h index aabeeb9851..957bbe8d61 100644 --- a/tensorflow/contrib/boosted_trees/resources/stamped_resource.h +++ b/tensorflow/contrib/boosted_trees/resources/stamped_resource.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_STAMPED_RESOURCE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_STAMPED_RESOURCE_H_ +#ifndef TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_STAMPED_RESOURCE_H_ +#define TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_STAMPED_RESOURCE_H_ #include "tensorflow/core/framework/resource_mgr.h" #include "tensorflow/core/platform/mutex.h" @@ -39,4 +39,4 @@ class StampedResource : public ResourceBase { } // namespace boosted_trees } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_STAMPED_RESOURCE_H_ +#endif // TENSORFLOW_CONTRIB_BOOSTED_TREES_RESOURCES_STAMPED_RESOURCE_H_ diff --git a/tensorflow/contrib/cloud/kernels/bigquery_table_accessor.h b/tensorflow/contrib/cloud/kernels/bigquery_table_accessor.h index 7d0eee59ae..b349063715 100644 --- a/tensorflow/contrib/cloud/kernels/bigquery_table_accessor.h +++ b/tensorflow/contrib/cloud/kernels/bigquery_table_accessor.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_PARTITION_ACCESSOR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_PARTITION_ACCESSOR_H_ +#ifndef TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_PARTITION_ACCESSOR_H_ +#define TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_PARTITION_ACCESSOR_H_ #include #include @@ -205,4 +205,4 @@ class BigQueryTableAccessor { }; } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_PARTITION_ACCESSOR_H_ +#endif // TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_PARTITION_ACCESSOR_H_ diff --git a/tensorflow/contrib/cloud/kernels/bigquery_table_accessor_test_data.h b/tensorflow/contrib/cloud/kernels/bigquery_table_accessor_test_data.h index b2b11f4f57..59f2333298 100644 --- a/tensorflow/contrib/cloud/kernels/bigquery_table_accessor_test_data.h +++ b/tensorflow/contrib/cloud/kernels/bigquery_table_accessor_test_data.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_TABLE_ACCESSOR_TEST_DATA_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_TABLE_ACCESSOR_TEST_DATA_H_ +#ifndef TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_TABLE_ACCESSOR_TEST_DATA_H_ +#define TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_TABLE_ACCESSOR_TEST_DATA_H_ #include @@ -401,4 +401,4 @@ const string kTestEmptyRow = R"({ } // namespace } // namepsace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_TABLE_ACCESSOR_TEST_DATA_H_ +#endif // TENSORFLOW_CORE_KERNELS_CLOUD_BIGQUERY_TABLE_ACCESSOR_TEST_DATA_H_ diff --git a/tensorflow/contrib/coder/kernels/range_coder.h b/tensorflow/contrib/coder/kernels/range_coder.h index c24fb707fc..f46413072e 100644 --- a/tensorflow/contrib/coder/kernels/range_coder.h +++ b/tensorflow/contrib/coder/kernels/range_coder.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_H_ +#ifndef TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_H_ +#define TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_H_ #include #include @@ -106,4 +106,4 @@ class RangeDecoder { }; } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_H_ +#endif // TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_H_ diff --git a/tensorflow/contrib/coder/kernels/range_coder_ops_util.h b/tensorflow/contrib/coder/kernels/range_coder_ops_util.h index 95241a8682..b8aabcef62 100644 --- a/tensorflow/contrib/coder/kernels/range_coder_ops_util.h +++ b/tensorflow/contrib/coder/kernels/range_coder_ops_util.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_OPS_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_OPS_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_OPS_UTIL_H_ +#define TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_OPS_UTIL_H_ #include @@ -30,4 +30,4 @@ Status MergeAxes(const TensorShape& broadcast_shape, std::vector* merged_storage_shape_pointer); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_OPS_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_CODER_KERNELS_RANGE_CODER_OPS_UTIL_H_ diff --git a/tensorflow/contrib/ffmpeg/ffmpeg_lib.h b/tensorflow/contrib/ffmpeg/ffmpeg_lib.h index bc1733ead8..a8d5a0dd83 100644 --- a/tensorflow/contrib/ffmpeg/ffmpeg_lib.h +++ b/tensorflow/contrib/ffmpeg/ffmpeg_lib.h @@ -13,8 +13,8 @@ // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_FFMPEG_LIB_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_FFMPEG_LIB_H_ +#ifndef TENSORFLOW_CONTRIB_FFMPEG_FFMPEG_LIB_H_ +#define TENSORFLOW_CONTRIB_FFMPEG_FFMPEG_LIB_H_ #include #include @@ -61,4 +61,4 @@ Status ReadVideoFile(const string& filename, std::vector* output_data, } // namespace ffmpeg } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_DEFAULT_FFMPEG_LIB_H_ +#endif // TENSORFLOW_CONTRIB_FFMPEG_DEFAULT_FFMPEG_LIB_H_ diff --git a/tensorflow/contrib/fused_conv/kernels/fused_conv_ops_gpu.h b/tensorflow/contrib/fused_conv/kernels/fused_conv_ops_gpu.h index fa7a3c03aa..ba52697679 100644 --- a/tensorflow/contrib/fused_conv/kernels/fused_conv_ops_gpu.h +++ b/tensorflow/contrib/fused_conv/kernels/fused_conv_ops_gpu.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_FUSED_CONV_KERNELS_FUSED_CONV_OPS_GPU_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_FUSED_CONV_KERNELS_FUSED_CONV_OPS_GPU_H_ +#ifndef TENSORFLOW_CONTRIB_FUSED_CONV_KERNELS_FUSED_CONV_OPS_GPU_H_ +#define TENSORFLOW_CONTRIB_FUSED_CONV_KERNELS_FUSED_CONV_OPS_GPU_H_ #if GOOGLE_CUDA @@ -72,4 +72,4 @@ class FusedConvParameters : public ConvParameters { #endif // GOOGLE_CUDA -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_FUSED_CONV_KERNELS_FUSED_CONV_OPS_GPU_H_ +#endif // TENSORFLOW_CONTRIB_FUSED_CONV_KERNELS_FUSED_CONV_OPS_GPU_H_ diff --git a/tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.h b/tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.h index 194ae2ba47..8968da6d82 100644 --- a/tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.h +++ b/tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.h @@ -11,8 +11,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_IMAGE_KERNELS_ADJUST_HSV_IN_YIQ_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_IMAGE_KERNELS_ADJUST_HSV_IN_YIQ_OP_H_ +#ifndef TENSORFLOW_CONTRIB_IMAGE_KERNELS_ADJUST_HSV_IN_YIQ_OP_H_ +#define TENSORFLOW_CONTRIB_IMAGE_KERNELS_ADJUST_HSV_IN_YIQ_OP_H_ #if GOOGLE_CUDA #define EIGEN_USE_GPU @@ -84,4 +84,4 @@ struct AdjustHsvInYiqGPU { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_IMAGE_KERNELS_ADJUST_HSV_IN_YIQ_OP_H_ +#endif // TENSORFLOW_CONTRIB_IMAGE_KERNELS_ADJUST_HSV_IN_YIQ_OP_H_ diff --git a/tensorflow/contrib/lite/allocation.h b/tensorflow/contrib/lite/allocation.h index ee8a7ccd0b..68aee2e644 100644 --- a/tensorflow/contrib/lite/allocation.h +++ b/tensorflow/contrib/lite/allocation.h @@ -14,8 +14,8 @@ limitations under the License. ==============================================================================*/ // Main abstraction controlling the tflite interpreter. // See context.h for the API for defining operations (TfLiteRegistration). -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ALLOCATION_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ALLOCATION_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_ALLOCATION_H_ +#define TENSORFLOW_CONTRIB_LITE_ALLOCATION_H_ #include #include @@ -91,4 +91,4 @@ class MemoryAllocation : public Allocation { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ALLOCATION_H_ +#endif // TENSORFLOW_CONTRIB_LITE_ALLOCATION_H_ diff --git a/tensorflow/contrib/lite/arena_planner.h b/tensorflow/contrib/lite/arena_planner.h index bd87414ec3..58bc164619 100644 --- a/tensorflow/contrib/lite/arena_planner.h +++ b/tensorflow/contrib/lite/arena_planner.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ARENA_PLANNER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ARENA_PLANNER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_ARENA_PLANNER_H_ +#define TENSORFLOW_CONTRIB_LITE_ARENA_PLANNER_H_ #include #include @@ -104,4 +104,4 @@ class ArenaPlanner : public MemoryPlanner { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ARENA_PLANNER_H_ +#endif // TENSORFLOW_CONTRIB_LITE_ARENA_PLANNER_H_ diff --git a/tensorflow/contrib/lite/builtin_op_data.h b/tensorflow/contrib/lite/builtin_op_data.h index 8269de8e3f..0b48ef4741 100644 --- a/tensorflow/contrib/lite/builtin_op_data.h +++ b/tensorflow/contrib/lite/builtin_op_data.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_BUILTIN_OP_DATA_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_BUILTIN_OP_DATA_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_BUILTIN_OP_DATA_H_ +#define TENSORFLOW_CONTRIB_LITE_BUILTIN_OP_DATA_H_ #include @@ -239,4 +239,4 @@ typedef struct { } // extern "C" #endif // __cplusplus -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_BUILTIN_OP_DATA_H_ +#endif // TENSORFLOW_CONTRIB_LITE_BUILTIN_OP_DATA_H_ diff --git a/tensorflow/contrib/lite/context.h b/tensorflow/contrib/lite/context.h index fca7116503..d6dfc20ae8 100644 --- a/tensorflow/contrib/lite/context.h +++ b/tensorflow/contrib/lite/context.h @@ -26,8 +26,8 @@ limitations under the License. // TfLiteRegistration - the implementation of a conceptual operation. // // Some abstractions in this file are created and managed by Interpreter. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_CONTEXT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_CONTEXT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_CONTEXT_H_ +#define TENSORFLOW_CONTRIB_LITE_CONTEXT_H_ #include #include @@ -296,4 +296,4 @@ typedef struct { #ifdef __cplusplus } // extern "C" #endif // __cplusplus -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_CONTEXT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_CONTEXT_H_ diff --git a/tensorflow/contrib/lite/error_reporter.h b/tensorflow/contrib/lite/error_reporter.h index d5715e4f90..da193d2586 100644 --- a/tensorflow/contrib/lite/error_reporter.h +++ b/tensorflow/contrib/lite/error_reporter.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ERROR_REPORTER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ERROR_REPORTER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_ERROR_REPORTER_H_ +#define TENSORFLOW_CONTRIB_LITE_ERROR_REPORTER_H_ #include #include "tensorflow/contrib/lite/context.h" @@ -51,4 +51,4 @@ ErrorReporter* DefaultErrorReporter(); } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_ERROR_REPORTER_H_ +#endif // TENSORFLOW_CONTRIB_LITE_ERROR_REPORTER_H_ diff --git a/tensorflow/contrib/lite/graph_info.h b/tensorflow/contrib/lite/graph_info.h index 5481aede60..57690058c4 100644 --- a/tensorflow/contrib/lite/graph_info.h +++ b/tensorflow/contrib/lite/graph_info.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_GRAPH_INFO_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_GRAPH_INFO_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_GRAPH_INFO_H_ +#define TENSORFLOW_CONTRIB_LITE_GRAPH_INFO_H_ #include @@ -50,4 +50,4 @@ class GraphInfo { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_GRAPH_INFO_H_ +#endif // TENSORFLOW_CONTRIB_LITE_GRAPH_INFO_H_ diff --git a/tensorflow/contrib/lite/interpreter.h b/tensorflow/contrib/lite/interpreter.h index 38dd402e8a..4f732769f9 100644 --- a/tensorflow/contrib/lite/interpreter.h +++ b/tensorflow/contrib/lite/interpreter.h @@ -14,8 +14,8 @@ limitations under the License. ==============================================================================*/ // Main abstraction controlling the tflite interpreter. // See context.h for the API for defining operations (TfLiteRegistration). -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_INTERPRETER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_INTERPRETER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_INTERPRETER_H_ +#define TENSORFLOW_CONTRIB_LITE_INTERPRETER_H_ #include #include @@ -363,4 +363,4 @@ class Interpreter { }; } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_INTERPRETER_H_ +#endif // TENSORFLOW_CONTRIB_LITE_INTERPRETER_H_ diff --git a/tensorflow/contrib/lite/kernels/activation_functor.h b/tensorflow/contrib/lite/kernels/activation_functor.h index cfb3369e99..41ec3cca33 100644 --- a/tensorflow/contrib/lite/kernels/activation_functor.h +++ b/tensorflow/contrib/lite/kernels/activation_functor.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_ACTIVATION_FUNCTOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_ACTIVATION_FUNCTOR_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_ACTIVATION_FUNCTOR_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_ACTIVATION_FUNCTOR_H_ #include #include @@ -55,4 +55,4 @@ class ActivationFunctor { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_ACTIVATION_FUNCTOR_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_ACTIVATION_FUNCTOR_H_ diff --git a/tensorflow/contrib/lite/kernels/gemm_support.h b/tensorflow/contrib/lite/kernels/gemm_support.h index b531959ffb..466781cbce 100644 --- a/tensorflow/contrib/lite/kernels/gemm_support.h +++ b/tensorflow/contrib/lite/kernels/gemm_support.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_GEMM_SUPPORT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_GEMM_SUPPORT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_GEMM_SUPPORT_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_GEMM_SUPPORT_H_ #include "public/gemmlowp.h" #include "tensorflow/contrib/lite/context.h" @@ -51,4 +51,4 @@ void SetMaxNumThreads(TfLiteContext* context, int num_threads); } // namespace gemm_support } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_GEMM_SUPPORT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_GEMM_SUPPORT_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/common.h b/tensorflow/contrib/lite/kernels/internal/common.h index 28f19a2506..fdeacedace 100644 --- a/tensorflow/contrib/lite/kernels/internal/common.h +++ b/tensorflow/contrib/lite/kernels/internal/common.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMMON_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMMON_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMMON_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMMON_H_ #ifndef ALLOW_SLOW_GENERIC_DEPTHWISECONV_FALLBACK #ifdef GEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK @@ -104,4 +104,4 @@ inline int32 MultiplyByQuantizedMultiplierGreaterThanOne( } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMMON_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMMON_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/compatibility.h b/tensorflow/contrib/lite/kernels/internal/compatibility.h index 796a03566a..1d963afb7e 100644 --- a/tensorflow/contrib/lite/kernels/internal/compatibility.h +++ b/tensorflow/contrib/lite/kernels/internal/compatibility.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ #include #include @@ -75,4 +75,4 @@ using uint16 = std::uint16_t; using int32 = std::int32_t; using uint32 = std::uint32_t; -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/depthwiseconv_float.h b/tensorflow/contrib/lite/kernels/internal/optimized/depthwiseconv_float.h index da34c8aef9..81796e295d 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/depthwiseconv_float.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/depthwiseconv_float.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_FLOAT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_FLOAT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_FLOAT_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_FLOAT_H_ #include "public/gemmlowp.h" #include "tensorflow/contrib/lite/kernels/internal/common.h" @@ -1057,4 +1057,4 @@ void DepthwiseConv(const float* input_data, const Dims<4>& input_dims, } // namespace optimized_ops } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_FLOAT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_FLOAT_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/depthwiseconv_uint8.h b/tensorflow/contrib/lite/kernels/internal/optimized/depthwiseconv_uint8.h index 051ed2a2c4..f993fd6a00 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/depthwiseconv_uint8.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/depthwiseconv_uint8.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_UINT8_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_UINT8_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_UINT8_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_UINT8_H_ #include "fixedpoint/fixedpoint.h" #include "public/gemmlowp.h" @@ -1913,4 +1913,4 @@ void DepthwiseConv(const uint8* input_data, const Dims<4>& input_dims, } // namespace optimized_ops } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_UINT8_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_DEPTHWISECONV_UINT8_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/eigen_spatial_convolutions.h b/tensorflow/contrib/lite/kernels/internal/optimized/eigen_spatial_convolutions.h index 8004c24a99..f21fbf532a 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/eigen_spatial_convolutions.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/eigen_spatial_convolutions.h @@ -16,8 +16,8 @@ limitations under the License. // Copied from tensorflow/core/kernels/eigen_spatial_convolutions.h. // TODO(petewarden) - move this to a common location in Eigen itself. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_SPATIAL_CONVOLUTIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_SPATIAL_CONVOLUTIONS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_SPATIAL_CONVOLUTIONS_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_SPATIAL_CONVOLUTIONS_H_ #define EIGEN_USE_CUSTOM_THREAD_POOL #define EIGEN_USE_THREADS @@ -228,4 +228,4 @@ EIGEN_DEVICE_FUNC // clang-format on -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_SPATIAL_CONVOLUTIONS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_SPATIAL_CONVOLUTIONS_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/eigen_tensor_reduced_instantiations_google.h b/tensorflow/contrib/lite/kernels/internal/optimized/eigen_tensor_reduced_instantiations_google.h index 7f78f69360..d85e06a5d5 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/eigen_tensor_reduced_instantiations_google.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/eigen_tensor_reduced_instantiations_google.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_GOOGLE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_GOOGLE_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_GOOGLE_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_GOOGLE_H_ #define EIGEN_USE_CUSTOM_THREAD_POOL #define EIGEN_USE_THREADS @@ -140,4 +140,4 @@ limitations under the License. #include "third_party/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorIO.h" #include "Eigen/src/Core/util/ReenableStupidWarnings.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_H +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_H diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/eigen_tensor_reduced_instantiations_oss.h b/tensorflow/contrib/lite/kernels/internal/optimized/eigen_tensor_reduced_instantiations_oss.h index 1d5c316194..d34708b8fd 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/eigen_tensor_reduced_instantiations_oss.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/eigen_tensor_reduced_instantiations_oss.h @@ -19,8 +19,8 @@ limitations under the License. // clang-format off -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_OSS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_OSS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_OSS_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_OSS_H_ #include "Eigen/Core" @@ -164,4 +164,4 @@ typedef unsigned __int64 uint64_t; #include "Eigen/src/Core/util/ReenableStupidWarnings.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_OSS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_EIGEN_TENSOR_REDUCED_INSTANTIATIONS_OSS_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/multithreaded_conv.h b/tensorflow/contrib/lite/kernels/internal/optimized/multithreaded_conv.h index b3615f4658..0bfb4e9b1f 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/multithreaded_conv.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/multithreaded_conv.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_MULTITHREAD_CONV -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_MULTITHREAD_CONV +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_MULTITHREAD_CONV +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_MULTITHREAD_CONV #include #include @@ -192,4 +192,4 @@ inline void Conv(const float* input_data, const Dims<4>& input_dims, } // namespace multithreaded_ops } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_MULTITHREAD_CONV +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_MULTITHREAD_CONV diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/neon_tensor_utils.h b/tensorflow/contrib/lite/kernels/internal/optimized/neon_tensor_utils.h index 3a4af87304..b7e317dc60 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/neon_tensor_utils.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/neon_tensor_utils.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_TENSOR_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_TENSOR_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_TENSOR_UTILS_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_TENSOR_UTILS_H_ // TODO(ghodrat): Remove this header file and the dependency to internal data // structure. @@ -110,4 +110,4 @@ void ReductionSumVector(const float* input_vector, float* output_vector, } // namespace tensor_utils } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_TENSOR_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_TENSOR_UTILS_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h b/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h index 1b1f455855..c35b9da938 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_OPS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_OPS_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_OPS_H_ #include #include @@ -3805,4 +3805,4 @@ void ArgMax(const T3* axis, const T1* input_data, const Dims<4>& input_dims, #pragma GCC diagnostic pop #endif -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_OPS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_OPTIMIZED_OPS_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/reference/depthwiseconv_float.h b/tensorflow/contrib/lite/kernels/internal/reference/depthwiseconv_float.h index 8e0f234545..9aabee5000 100644 --- a/tensorflow/contrib/lite/kernels/internal/reference/depthwiseconv_float.h +++ b/tensorflow/contrib/lite/kernels/internal/reference/depthwiseconv_float.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ #include "tensorflow/contrib/lite/kernels/internal/common.h" #include "tensorflow/contrib/lite/kernels/internal/compatibility.h" @@ -112,4 +112,4 @@ void DepthwiseConv(const float* input_data, const Dims<4>& input_dims, } // end namespace reference_ops } // end namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/reference/depthwiseconv_uint8.h b/tensorflow/contrib/lite/kernels/internal/reference/depthwiseconv_uint8.h index 8a80558b32..e9b6baeaee 100644 --- a/tensorflow/contrib/lite/kernels/internal/reference/depthwiseconv_uint8.h +++ b/tensorflow/contrib/lite/kernels/internal/reference/depthwiseconv_uint8.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ #include @@ -135,4 +135,4 @@ void DepthwiseConv(const uint8* input_data, const Dims<4>& input_dims, } // end namespace reference_ops } // end namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/reference/portable_tensor_utils.h b/tensorflow/contrib/lite/kernels/internal/reference/portable_tensor_utils.h index 7f90d731b8..afc3e26e79 100644 --- a/tensorflow/contrib/lite/kernels/internal/reference/portable_tensor_utils.h +++ b/tensorflow/contrib/lite/kernels/internal/reference/portable_tensor_utils.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ // TDOD(ghodrat): Remove this header file and the dependency to internal data // structure. @@ -186,4 +186,4 @@ void ReductionSumVector(const float* input_vector, float* output_vector, } // namespace tensor_utils } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h b/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h index 03708eb32b..64651d8348 100644 --- a/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_REFERENCE_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_REFERENCE_OPS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_REFERENCE_OPS_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_REFERENCE_OPS_H_ #include #include @@ -2655,4 +2655,4 @@ void Transpose(const T* input, const Dims<4>& input_dims, T* output, } // namespace reference_ops } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_REFERENCE_OPS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_REFERENCE_REFERENCE_OPS_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/round.h b/tensorflow/contrib/lite/kernels/internal/round.h index 38525b0e20..f299d0bd87 100644 --- a/tensorflow/contrib/lite/kernels/internal/round.h +++ b/tensorflow/contrib/lite/kernels/internal/round.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_ROUND_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_ROUND_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_ROUND_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_ROUND_H_ #include @@ -36,4 +36,4 @@ inline T TfLiteRound(const T x) { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_ROUND_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_ROUND_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/tensor.h b/tensorflow/contrib/lite/kernels/internal/tensor.h index 1961e1a2d5..dfe76c2afd 100644 --- a/tensorflow/contrib/lite/kernels/internal/tensor.h +++ b/tensorflow/contrib/lite/kernels/internal/tensor.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_H_ #include #include "tensorflow/contrib/lite/context.h" @@ -83,4 +83,4 @@ inline Dims<4> GetTensorDims(const TfLiteTensor* tensor) { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/tensor_utils.h b/tensorflow/contrib/lite/kernels/internal/tensor_utils.h index e7e2994397..40d144979b 100644 --- a/tensorflow/contrib/lite/kernels/internal/tensor_utils.h +++ b/tensorflow/contrib/lite/kernels/internal/tensor_utils.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ #include "tensorflow/contrib/lite/builtin_op_data.h" @@ -113,4 +113,4 @@ void ReductionSumVector(const float* input_vector, float* output_vector, } // namespace tensor_utils } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ diff --git a/tensorflow/contrib/lite/kernels/internal/types.h b/tensorflow/contrib/lite/kernels/internal/types.h index 5989ac8fcd..afe131b06e 100644 --- a/tensorflow/contrib/lite/kernels/internal/types.h +++ b/tensorflow/contrib/lite/kernels/internal/types.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TYPES_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TYPES_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TYPES_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TYPES_H_ #include "tensorflow/contrib/lite/kernels/internal/compatibility.h" @@ -134,4 +134,4 @@ bool IsPackedWithoutStrides(const Dims& dims) { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TYPES_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_INTERNAL_TYPES_H_ diff --git a/tensorflow/contrib/lite/kernels/kernel_util.h b/tensorflow/contrib/lite/kernels/kernel_util.h index 25556ae456..1cf30ecff9 100644 --- a/tensorflow/contrib/lite/kernels/kernel_util.h +++ b/tensorflow/contrib/lite/kernels/kernel_util.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_KERNEL_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_KERNEL_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_KERNEL_UTIL_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_KERNEL_UTIL_H_ #include "tensorflow/contrib/lite/builtin_op_data.h" #include "tensorflow/contrib/lite/context.h" @@ -62,4 +62,4 @@ void CalculateActivationRangeFloat(TfLiteFusedActivation activation, } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_KERNEL_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_KERNEL_UTIL_H_ diff --git a/tensorflow/contrib/lite/kernels/op_macros.h b/tensorflow/contrib/lite/kernels/op_macros.h index 63670efcb1..7568eaa88e 100644 --- a/tensorflow/contrib/lite/kernels/op_macros.h +++ b/tensorflow/contrib/lite/kernels/op_macros.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_OP_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_OP_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_OP_UTIL_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_OP_UTIL_H_ #include @@ -31,4 +31,4 @@ limitations under the License. if ((x) != (y)) TF_LITE_FATAL(#x " didn't equal " #y); \ } while (0) -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_OP_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_OP_UTIL_H_ diff --git a/tensorflow/contrib/lite/kernels/padding.h b/tensorflow/contrib/lite/kernels/padding.h index 3a60274524..40b8476b37 100644 --- a/tensorflow/contrib/lite/kernels/padding.h +++ b/tensorflow/contrib/lite/kernels/padding.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_PADDING_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_PADDING_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_PADDING_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_PADDING_H_ namespace tflite { @@ -25,4 +25,4 @@ inline int ComputePadding(int stride, int in_size, int filter_size, } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_PADDING_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_PADDING_H_ diff --git a/tensorflow/contrib/lite/kernels/register.h b/tensorflow/contrib/lite/kernels/register.h index 28f5e0fcc8..b9cff0ae21 100644 --- a/tensorflow/contrib/lite/kernels/register.h +++ b/tensorflow/contrib/lite/kernels/register.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_REGISTER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_REGISTER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_REGISTER_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_REGISTER_H_ #include #include "tensorflow/contrib/lite/context.h" @@ -47,4 +47,4 @@ class BuiltinOpResolver : public OpResolver { } // namespace ops } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_BUILTIN_KERNELS_H +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_BUILTIN_KERNELS_H diff --git a/tensorflow/contrib/lite/kernels/test_util.h b/tensorflow/contrib/lite/kernels/test_util.h index b9c0ba8f47..cc445299ff 100644 --- a/tensorflow/contrib/lite/kernels/test_util.h +++ b/tensorflow/contrib/lite/kernels/test_util.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_TEST_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_TEST_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_KERNELS_TEST_UTIL_H_ +#define TENSORFLOW_CONTRIB_LITE_KERNELS_TEST_UTIL_H_ #include @@ -202,4 +202,4 @@ template <> std::vector SingleOpModel::ExtractVector(int index); } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_KERNELS_TEST_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_KERNELS_TEST_UTIL_H_ diff --git a/tensorflow/contrib/lite/memory_planner.h b/tensorflow/contrib/lite/memory_planner.h index b11d86c375..5cd6c20850 100644 --- a/tensorflow/contrib/lite/memory_planner.h +++ b/tensorflow/contrib/lite/memory_planner.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MEMORY_PLANNER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MEMORY_PLANNER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_MEMORY_PLANNER_H_ +#define TENSORFLOW_CONTRIB_LITE_MEMORY_PLANNER_H_ #include "tensorflow/contrib/lite/context.h" @@ -42,4 +42,4 @@ class MemoryPlanner { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MEMORY_PLANNER_H_ +#endif // TENSORFLOW_CONTRIB_LITE_MEMORY_PLANNER_H_ diff --git a/tensorflow/contrib/lite/model.h b/tensorflow/contrib/lite/model.h index e0c96f7f04..a467df5bb4 100644 --- a/tensorflow/contrib/lite/model.h +++ b/tensorflow/contrib/lite/model.h @@ -31,8 +31,8 @@ limitations under the License. // OpResolver must be defined to provide your kernel implementations to the // interpreter. This is environment specific and may consist of just the builtin // ops, or some custom operators you defined to extend tflite. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODEL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODEL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_MODEL_H_ +#define TENSORFLOW_CONTRIB_LITE_MODEL_H_ #include #include "tensorflow/contrib/lite/error_reporter.h" @@ -173,4 +173,4 @@ class InterpreterBuilder { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODEL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_MODEL_H_ diff --git a/tensorflow/contrib/lite/models/smartreply/predictor.h b/tensorflow/contrib/lite/models/smartreply/predictor.h index d17323a3f9..90260c8d62 100644 --- a/tensorflow/contrib/lite/models/smartreply/predictor.h +++ b/tensorflow/contrib/lite/models/smartreply/predictor.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODELS_SMARTREPLY_PREDICTOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODELS_SMARTREPLY_PREDICTOR_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_MODELS_SMARTREPLY_PREDICTOR_H_ +#define TENSORFLOW_CONTRIB_LITE_MODELS_SMARTREPLY_PREDICTOR_H_ #include #include @@ -77,4 +77,4 @@ struct SmartReplyConfig { } // namespace custom } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_MODELS_SMARTREPLY_PREDICTOR_H_ +#endif // TENSORFLOW_CONTRIB_LITE_MODELS_SMARTREPLY_PREDICTOR_H_ diff --git a/tensorflow/contrib/lite/nnapi_delegate.h b/tensorflow/contrib/lite/nnapi_delegate.h index f29aa9e18e..e98000929a 100644 --- a/tensorflow/contrib/lite/nnapi_delegate.h +++ b/tensorflow/contrib/lite/nnapi_delegate.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_NNAPI_DELEGATE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_NNAPI_DELEGATE_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_NNAPI_DELEGATE_H_ +#define TENSORFLOW_CONTRIB_LITE_NNAPI_DELEGATE_H_ #include "tensorflow/contrib/lite/allocation.h" #include "tensorflow/contrib/lite/context.h" @@ -63,4 +63,4 @@ class NNAPIDelegate { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_NNAPI_DELEGATE_H_ +#endif // TENSORFLOW_CONTRIB_LITE_NNAPI_DELEGATE_H_ diff --git a/tensorflow/contrib/lite/optional_debug_tools.h b/tensorflow/contrib/lite/optional_debug_tools.h index 54d4876095..1b6998cda3 100644 --- a/tensorflow/contrib/lite/optional_debug_tools.h +++ b/tensorflow/contrib/lite/optional_debug_tools.h @@ -14,8 +14,8 @@ limitations under the License. ==============================================================================*/ // Optional debugging functionality. For small sized binaries, these are not // needed. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_DEBUG_TOOLS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_DEBUG_TOOLS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_DEBUG_TOOLS_H_ +#define TENSORFLOW_CONTRIB_LITE_DEBUG_TOOLS_H_ #include "tensorflow/contrib/lite/interpreter.h" @@ -29,4 +29,4 @@ TfLiteStatus ValidateInterpreterState(const Interpreter* interpreter); } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_DEBUG_TOOLS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_DEBUG_TOOLS_H_ diff --git a/tensorflow/contrib/lite/simple_memory_arena.h b/tensorflow/contrib/lite/simple_memory_arena.h index 07a38c4243..0c5e00a1f2 100644 --- a/tensorflow/contrib/lite/simple_memory_arena.h +++ b/tensorflow/contrib/lite/simple_memory_arena.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_SIMPLE_MEMORY_ARENA_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_SIMPLE_MEMORY_ARENA_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_SIMPLE_MEMORY_ARENA_H_ +#define TENSORFLOW_CONTRIB_LITE_SIMPLE_MEMORY_ARENA_H_ #include #include @@ -85,4 +85,4 @@ class SimpleMemoryArena { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_SIMPLE_MEMORY_ARENA_H_ +#endif // TENSORFLOW_CONTRIB_LITE_SIMPLE_MEMORY_ARENA_H_ diff --git a/tensorflow/contrib/lite/string_util.h b/tensorflow/contrib/lite/string_util.h index 12872d1123..c35a2fff3c 100644 --- a/tensorflow/contrib/lite/string_util.h +++ b/tensorflow/contrib/lite/string_util.h @@ -37,8 +37,8 @@ limitations under the License. // # described above. // buf.WriteToTensor(tensor) -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_STRING_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_STRING_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_STRING_UTIL_H_ +#define TENSORFLOW_CONTRIB_LITE_STRING_UTIL_H_ #include @@ -88,4 +88,4 @@ int GetStringCount(const TfLiteTensor* tensor); StringRef GetString(const TfLiteTensor* tensor, int string_index); } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_STRING_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_STRING_UTIL_H_ diff --git a/tensorflow/contrib/lite/testing/message.h b/tensorflow/contrib/lite/testing/message.h index 78ef7e2cbe..e2bc408214 100644 --- a/tensorflow/contrib/lite/testing/message.h +++ b/tensorflow/contrib/lite/testing/message.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_MESSAGE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_MESSAGE_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TESTING_MESSAGE_H_ +#define TENSORFLOW_CONTRIB_LITE_TESTING_MESSAGE_H_ #include #include @@ -79,4 +79,4 @@ class Message { } // namespace testing } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_MESSAGE_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TESTING_MESSAGE_H_ diff --git a/tensorflow/contrib/lite/testing/parse_testdata.h b/tensorflow/contrib/lite/testing/parse_testdata.h index 90839fe245..7ebf362eb9 100644 --- a/tensorflow/contrib/lite/testing/parse_testdata.h +++ b/tensorflow/contrib/lite/testing/parse_testdata.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_NNAPI_PARSE_TESTDATA_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_NNAPI_PARSE_TESTDATA_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_NNAPI_PARSE_TESTDATA_H_ +#define TENSORFLOW_CONTRIB_LITE_NNAPI_PARSE_TESTDATA_H_ #include #include "tensorflow/contrib/lite/interpreter.h" @@ -71,4 +71,4 @@ bool ParseAndRunTests(std::istream* input, TestRunner* test_runner); } // namespace testing } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_NNAPI_PARSE_TESTDATA_H_ +#endif // TENSORFLOW_CONTRIB_LITE_NNAPI_PARSE_TESTDATA_H_ diff --git a/tensorflow/contrib/lite/testing/split.h b/tensorflow/contrib/lite/testing/split.h index cfc1e929e9..428cfda4f2 100644 --- a/tensorflow/contrib/lite/testing/split.h +++ b/tensorflow/contrib/lite/testing/split.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_SPLIT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_SPLIT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TESTING_SPLIT_H_ +#define TENSORFLOW_CONTRIB_LITE_TESTING_SPLIT_H_ #include #include @@ -83,4 +83,4 @@ inline std::vector Split(const string& s, const string& delimiter) { } // namespace testing } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_SPLIT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TESTING_SPLIT_H_ diff --git a/tensorflow/contrib/lite/testing/test_runner.h b/tensorflow/contrib/lite/testing/test_runner.h index f4b26949b5..60eaafa474 100644 --- a/tensorflow/contrib/lite/testing/test_runner.h +++ b/tensorflow/contrib/lite/testing/test_runner.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TEST_RUNNER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TEST_RUNNER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TESTING_TEST_RUNNER_H_ +#define TENSORFLOW_CONTRIB_LITE_TESTING_TEST_RUNNER_H_ #include #include @@ -121,4 +121,4 @@ class TestRunner { } // namespace testing } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TEST_RUNNER_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TESTING_TEST_RUNNER_H_ diff --git a/tensorflow/contrib/lite/testing/tflite_driver.h b/tensorflow/contrib/lite/testing/tflite_driver.h index 4440d4285e..25689a9fb4 100644 --- a/tensorflow/contrib/lite/testing/tflite_driver.h +++ b/tensorflow/contrib/lite/testing/tflite_driver.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TFLITE_DRIVER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TFLITE_DRIVER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TESTING_TFLITE_DRIVER_H_ +#define TENSORFLOW_CONTRIB_LITE_TESTING_TFLITE_DRIVER_H_ #include @@ -59,4 +59,4 @@ class TfLiteDriver : public TestRunner { } // namespace testing } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TFLITE_DRIVER_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TESTING_TFLITE_DRIVER_H_ diff --git a/tensorflow/contrib/lite/testing/tokenize.h b/tensorflow/contrib/lite/testing/tokenize.h index daccf0e84a..7ed8eb96b7 100644 --- a/tensorflow/contrib/lite/testing/tokenize.h +++ b/tensorflow/contrib/lite/testing/tokenize.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TOKENIZER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TOKENIZER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TESTING_TOKENIZER_H_ +#define TENSORFLOW_CONTRIB_LITE_TESTING_TOKENIZER_H_ #include #include @@ -39,4 +39,4 @@ void Tokenize(std::istream* input, TokenProcessor* processor); } // namespace testing } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_TOKENIZER_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TESTING_TOKENIZER_H_ diff --git a/tensorflow/contrib/lite/testing/util.h b/tensorflow/contrib/lite/testing/util.h index 4d4304f022..6d20aec141 100644 --- a/tensorflow/contrib/lite/testing/util.h +++ b/tensorflow/contrib/lite/testing/util.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TESTING_UTIL_H_ +#define TENSORFLOW_CONTRIB_LITE_TESTING_UTIL_H_ namespace tflite { @@ -25,4 +25,4 @@ inline void LogToStderr() { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TESTING_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TESTING_UTIL_H_ diff --git a/tensorflow/contrib/lite/toco/allocate_transient_arrays.h b/tensorflow/contrib/lite/toco/allocate_transient_arrays.h index 12d0d0498f..59d8ada1e9 100644 --- a/tensorflow/contrib/lite/toco/allocate_transient_arrays.h +++ b/tensorflow/contrib/lite/toco/allocate_transient_arrays.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_ALLOCATE_TRANSIENT_ARRAYS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_ALLOCATE_TRANSIENT_ARRAYS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_ALLOCATE_TRANSIENT_ARRAYS_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_ALLOCATE_TRANSIENT_ARRAYS_H_ #include "tensorflow/contrib/lite/toco/model.h" @@ -41,4 +41,4 @@ void AllocateTransientArrays(Model* model, } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_ALLOCATE_TRANSIENT_ARRAYS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_ALLOCATE_TRANSIENT_ARRAYS_H_ diff --git a/tensorflow/contrib/lite/toco/args.h b/tensorflow/contrib/lite/toco/args.h index e988cbda33..8004a1a37a 100644 --- a/tensorflow/contrib/lite/toco/args.h +++ b/tensorflow/contrib/lite/toco/args.h @@ -15,8 +15,8 @@ limitations under the License. // This abstracts command line arguments in toco. // Arg is a parseable type that can register a default value, be able to // parse itself, and keep track of whether it was specified. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_ARGS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_ARGS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_ARGS_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_ARGS_H_ #include #include @@ -232,4 +232,4 @@ struct ParsedTocoFlags { }; } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_ARGS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_ARGS_H_ diff --git a/tensorflow/contrib/lite/toco/dump_graphviz.h b/tensorflow/contrib/lite/toco/dump_graphviz.h index 0fb28e3de8..ea5a4031c3 100644 --- a/tensorflow/contrib/lite/toco/dump_graphviz.h +++ b/tensorflow/contrib/lite/toco/dump_graphviz.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_DUMP_GRAPHVIZ_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_DUMP_GRAPHVIZ_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_DUMP_GRAPHVIZ_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_DUMP_GRAPHVIZ_H_ #include @@ -25,4 +25,4 @@ void DumpGraphviz(const Model& model, string* output_file_contents); } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_DUMP_GRAPHVIZ_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_DUMP_GRAPHVIZ_H_ diff --git a/tensorflow/contrib/lite/toco/export_tensorflow.h b/tensorflow/contrib/lite/toco/export_tensorflow.h index eca9774576..79682153a8 100644 --- a/tensorflow/contrib/lite/toco/export_tensorflow.h +++ b/tensorflow/contrib/lite/toco/export_tensorflow.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_EXPORT_TENSORFLOW_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_EXPORT_TENSORFLOW_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_EXPORT_TENSORFLOW_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_EXPORT_TENSORFLOW_H_ #include #include "tensorflow/contrib/lite/toco/model.h" @@ -24,4 +24,4 @@ void ExportTensorFlowGraphDef(const Model& model, string* output_file_contents); } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_EXPORT_TENSORFLOW_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_EXPORT_TENSORFLOW_H_ diff --git a/tensorflow/contrib/lite/toco/format_port.h b/tensorflow/contrib/lite/toco/format_port.h index 0e999001e0..eb81e90faf 100644 --- a/tensorflow/contrib/lite/toco/format_port.h +++ b/tensorflow/contrib/lite/toco/format_port.h @@ -16,8 +16,8 @@ limitations under the License. // and util::format::AppendF. Unfortunately, type safety is not as good as a // a full C++ example. // TODO(aselle): When absl adds support for StrFormat, use that instead. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_FORMAT_PORT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_FORMAT_PORT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_FORMAT_PORT_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_FORMAT_PORT_H_ #include "tensorflow/contrib/lite/toco/toco_types.h" #include "tensorflow/core/lib/strings/stringprintf.h" @@ -74,4 +74,4 @@ inline string StringF(const char* fmt, Args&&... args) { } // namespace port } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_FORMAT_PORT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_FORMAT_PORT_H_ diff --git a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h index d6950cf987..4ac2265be9 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h +++ b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_GRAPH_TRANSFORMATIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_GRAPH_TRANSFORMATIONS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_GRAPH_TRANSFORMATIONS_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_GRAPH_TRANSFORMATIONS_H_ #include #include @@ -193,4 +193,4 @@ class RemoveTrivialReshape : public GraphTransformation { } // end namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_GRAPH_TRANSFORMATIONS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_GRAPH_TRANSFORMATIONS_H_ diff --git a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_passthrough.h b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_passthrough.h index a06181ca0b..9d448c3ee9 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_passthrough.h +++ b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_passthrough.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_REMOVE_TRIVIAL_PASSTHROUGH_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_REMOVE_TRIVIAL_PASSTHROUGH_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_REMOVE_TRIVIAL_PASSTHROUGH_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_REMOVE_TRIVIAL_PASSTHROUGH_H_ #include "tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h" #include "tensorflow/contrib/lite/toco/model.h" @@ -54,4 +54,4 @@ bool RemoveTrivialPassthroughOp(GraphTransformation* transformation, } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_REMOVE_TRIVIAL_PASSTHROUGH_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_GRAPH_TRANSFORMATIONS_REMOVE_TRIVIAL_PASSTHROUGH_H_ diff --git a/tensorflow/contrib/lite/toco/import_tensorflow.h b/tensorflow/contrib/lite/toco/import_tensorflow.h index 312e3b8f17..2177872334 100644 --- a/tensorflow/contrib/lite/toco/import_tensorflow.h +++ b/tensorflow/contrib/lite/toco/import_tensorflow.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_IMPORT_TENSORFLOW_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_IMPORT_TENSORFLOW_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_IMPORT_TENSORFLOW_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_IMPORT_TENSORFLOW_H_ #include #include @@ -39,4 +39,4 @@ std::unique_ptr ImportTensorFlowGraphDef( } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_IMPORT_TENSORFLOW_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_IMPORT_TENSORFLOW_H_ diff --git a/tensorflow/contrib/lite/toco/model.h b/tensorflow/contrib/lite/toco/model.h index 3cda63a8ce..b1b9b718bb 100644 --- a/tensorflow/contrib/lite/toco/model.h +++ b/tensorflow/contrib/lite/toco/model.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_H_ #include #include @@ -1591,4 +1591,4 @@ class Model { }; } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_H_ diff --git a/tensorflow/contrib/lite/toco/model_cmdline_flags.h b/tensorflow/contrib/lite/toco/model_cmdline_flags.h index 027d7ae1aa..c868d5c7d0 100644 --- a/tensorflow/contrib/lite/toco/model_cmdline_flags.h +++ b/tensorflow/contrib/lite/toco/model_cmdline_flags.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_CMDLINE_FLAGS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_CMDLINE_FLAGS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_CMDLINE_FLAGS_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_CMDLINE_FLAGS_H_ #include #include @@ -40,5 +40,4 @@ ParsedModelFlags* GlobalParsedModelFlags(); } // namespace toco - -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_CMDLINE_FLAGS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_MODEL_CMDLINE_FLAGS_H_ diff --git a/tensorflow/contrib/lite/toco/runtime/common.h b/tensorflow/contrib/lite/toco/runtime/common.h index bd55544f57..3c6828840c 100644 --- a/tensorflow/contrib/lite/toco/runtime/common.h +++ b/tensorflow/contrib/lite/toco/runtime/common.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_COMMON_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_COMMON_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_COMMON_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_COMMON_H_ #ifndef ALLOW_SLOW_GENERIC_DEPTHWISECONV_FALLBACK #ifdef GEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK @@ -23,4 +23,4 @@ limitations under the License. #include "tensorflow/contrib/lite/kernels/internal/common.h" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_COMMON_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_COMMON_H_ diff --git a/tensorflow/contrib/lite/toco/runtime/types.h b/tensorflow/contrib/lite/toco/runtime/types.h index df63b2d59e..f5de5a5781 100644 --- a/tensorflow/contrib/lite/toco/runtime/types.h +++ b/tensorflow/contrib/lite/toco/runtime/types.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_TYPES_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_TYPES_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_TYPES_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_TYPES_H_ #include "tensorflow/contrib/lite/kernels/internal/common.h" #include "tensorflow/contrib/lite/kernels/internal/compatibility.h" @@ -29,4 +29,4 @@ using tflite::RequiredBufferSizeForDims; } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_TYPES_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_RUNTIME_TYPES_H_ diff --git a/tensorflow/contrib/lite/toco/tensorflow_util.h b/tensorflow/contrib/lite/toco/tensorflow_util.h index 152b4f7a72..61f9104268 100644 --- a/tensorflow/contrib/lite/toco/tensorflow_util.h +++ b/tensorflow/contrib/lite/toco/tensorflow_util.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TENSORFLOW_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TENSORFLOW_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TENSORFLOW_UTIL_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TENSORFLOW_UTIL_H_ #include #include @@ -29,4 +29,4 @@ void LogDumpGraphDef(int log_level, const string& message, } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TENSORFLOW_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TENSORFLOW_UTIL_H_ diff --git a/tensorflow/contrib/lite/toco/tflite/builtin_operator.h b/tensorflow/contrib/lite/toco/tflite/builtin_operator.h index 93cc79ddb6..cfe7ecd9f9 100644 --- a/tensorflow/contrib/lite/toco/tflite/builtin_operator.h +++ b/tensorflow/contrib/lite/toco/tflite/builtin_operator.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_BUILTIN_OPERATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_BUILTIN_OPERATOR_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_BUILTIN_OPERATOR_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_BUILTIN_OPERATOR_H_ #include "absl/memory/memory.h" #include "tensorflow/contrib/lite/toco/tflite/operator.h" @@ -71,4 +71,4 @@ class BuiltinOperator : public BaseOperator { } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_BUILTIN_OPERATOR_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_BUILTIN_OPERATOR_H_ diff --git a/tensorflow/contrib/lite/toco/tflite/custom_operator.h b/tensorflow/contrib/lite/toco/tflite/custom_operator.h index 1a4bfac7d4..bd5713618f 100644 --- a/tensorflow/contrib/lite/toco/tflite/custom_operator.h +++ b/tensorflow/contrib/lite/toco/tflite/custom_operator.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_CUSTOM_OPERATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_CUSTOM_OPERATOR_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_CUSTOM_OPERATOR_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_CUSTOM_OPERATOR_H_ #include "flatbuffers/flexbuffers.h" #include "absl/memory/memory.h" @@ -71,4 +71,4 @@ class CustomOperator : public BaseOperator { } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_CUSTOM_OPERATOR_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_CUSTOM_OPERATOR_H_ diff --git a/tensorflow/contrib/lite/toco/tflite/export.h b/tensorflow/contrib/lite/toco/tflite/export.h index 44012b7126..8c79cb8200 100644 --- a/tensorflow/contrib/lite/toco/tflite/export.h +++ b/tensorflow/contrib/lite/toco/tflite/export.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_EXPORT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_EXPORT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_EXPORT_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_EXPORT_H_ #include "tensorflow/contrib/lite/toco/model.h" @@ -73,4 +73,4 @@ void LoadOperatorsMap(const Model& model, OperatorsMap* operators_map); } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_EXPORT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_EXPORT_H_ diff --git a/tensorflow/contrib/lite/toco/tflite/import.h b/tensorflow/contrib/lite/toco/tflite/import.h index 3c27a2843c..280677bae1 100644 --- a/tensorflow/contrib/lite/toco/tflite/import.h +++ b/tensorflow/contrib/lite/toco/tflite/import.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_IMPORT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_IMPORT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_IMPORT_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_IMPORT_H_ #include "tensorflow/contrib/lite/schema/schema_generated.h" #include "tensorflow/contrib/lite/toco/model.h" @@ -46,4 +46,4 @@ void LoadOperatorsTable(const ::tflite::Model &input_model, } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_IMPORT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_IMPORT_H_ diff --git a/tensorflow/contrib/lite/toco/tflite/operator.h b/tensorflow/contrib/lite/toco/tflite/operator.h index 37df302d46..88af3d6ab6 100644 --- a/tensorflow/contrib/lite/toco/tflite/operator.h +++ b/tensorflow/contrib/lite/toco/tflite/operator.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_OPERATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_OPERATOR_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_OPERATOR_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_OPERATOR_H_ #include "flatbuffers/flatbuffers.h" #include "tensorflow/contrib/lite/schema/schema_generated.h" @@ -86,4 +86,4 @@ class BaseOperator { } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_OPERATOR_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_OPERATOR_H_ diff --git a/tensorflow/contrib/lite/toco/tflite/simple_operator.h b/tensorflow/contrib/lite/toco/tflite/simple_operator.h index 992b98baca..72678c82a2 100644 --- a/tensorflow/contrib/lite/toco/tflite/simple_operator.h +++ b/tensorflow/contrib/lite/toco/tflite/simple_operator.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_SIMPLE_OPERATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_SIMPLE_OPERATOR_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_SIMPLE_OPERATOR_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_SIMPLE_OPERATOR_H_ #include "tensorflow/contrib/lite/toco/tflite/operator.h" @@ -47,4 +47,4 @@ class SimpleOperator : public BaseOperator { } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_SIMPLE_OPERATOR_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_SIMPLE_OPERATOR_H_ diff --git a/tensorflow/contrib/lite/toco/tflite/types.h b/tensorflow/contrib/lite/toco/tflite/types.h index f7c5140510..3923756fc9 100644 --- a/tensorflow/contrib/lite/toco/tflite/types.h +++ b/tensorflow/contrib/lite/toco/tflite/types.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_TYPES_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_TYPES_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_TYPES_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_TYPES_H_ #include "tensorflow/contrib/lite/schema/schema_generated.h" #include "tensorflow/contrib/lite/toco/model.h" @@ -55,4 +55,4 @@ struct ActivationFunction { } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_TYPES_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TFLITE_TYPES_H_ diff --git a/tensorflow/contrib/lite/toco/toco_cmdline_flags.h b/tensorflow/contrib/lite/toco/toco_cmdline_flags.h index ba35ca8d5d..46eb3f5728 100644 --- a/tensorflow/contrib/lite/toco/toco_cmdline_flags.h +++ b/tensorflow/contrib/lite/toco/toco_cmdline_flags.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_CMDLINE_FLAGS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_CMDLINE_FLAGS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_CMDLINE_FLAGS_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_CMDLINE_FLAGS_H_ #include #include @@ -33,4 +33,4 @@ void ReadTocoFlagsFromCommandLineFlags(const ParsedTocoFlags& parsed_toco_flags, } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_CMDLINE_FLAGS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_CMDLINE_FLAGS_H_ diff --git a/tensorflow/contrib/lite/toco/toco_graphviz_dump_options.h b/tensorflow/contrib/lite/toco/toco_graphviz_dump_options.h index ae0541f62b..d6c3ba6543 100644 --- a/tensorflow/contrib/lite/toco/toco_graphviz_dump_options.h +++ b/tensorflow/contrib/lite/toco/toco_graphviz_dump_options.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_GRAPHVIZ_DUMP_OPTIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_GRAPHVIZ_DUMP_OPTIONS_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_GRAPHVIZ_DUMP_OPTIONS_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_GRAPHVIZ_DUMP_OPTIONS_H_ #include @@ -31,4 +31,4 @@ struct GraphVizDumpOptions { } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_GRAPHVIZ_DUMP_OPTIONS_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_GRAPHVIZ_DUMP_OPTIONS_H_ diff --git a/tensorflow/contrib/lite/toco/toco_port.h b/tensorflow/contrib/lite/toco/toco_port.h index b5cb7a11e7..0572848cb5 100644 --- a/tensorflow/contrib/lite/toco/toco_port.h +++ b/tensorflow/contrib/lite/toco/toco_port.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_PORT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_PORT_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_PORT_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_PORT_H_ // Portability layer for toco tool. Mainly, abstract filesystem access so we // can build and use on google internal environments and on OSX. @@ -77,4 +77,4 @@ void CopyToBuffer(const string& src, char* dest); } // namespace port } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_PORT_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_PORT_H_ diff --git a/tensorflow/contrib/lite/toco/toco_tooling.h b/tensorflow/contrib/lite/toco/toco_tooling.h index 9c5a93a211..e731c149ee 100644 --- a/tensorflow/contrib/lite/toco/toco_tooling.h +++ b/tensorflow/contrib/lite/toco/toco_tooling.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_TOOLING_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_TOOLING_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_TOOLING_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_TOOLING_H_ #include #include @@ -47,4 +47,4 @@ inline void Export(const TocoFlags& toco_flags, const Model& model, } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_TOOLING_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TOCO_TOOLING_H_ diff --git a/tensorflow/contrib/lite/toco/toco_types.h b/tensorflow/contrib/lite/toco/toco_types.h index ad42497ada..d72a3bd1f3 100644 --- a/tensorflow/contrib/lite/toco/toco_types.h +++ b/tensorflow/contrib/lite/toco/toco_types.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TYPES_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TYPES_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TYPES_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TYPES_H_ #include #include "tensorflow/core/platform/platform.h" @@ -42,4 +42,4 @@ using tensorflow::uint8; } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TYPES_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TYPES_H_ diff --git a/tensorflow/contrib/lite/toco/tooling_util.h b/tensorflow/contrib/lite/toco/tooling_util.h index 72fb0fd1a7..5986d63649 100644 --- a/tensorflow/contrib/lite/toco/tooling_util.h +++ b/tensorflow/contrib/lite/toco/tooling_util.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOOLING_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOOLING_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOCO_TOOLING_UTIL_H_ +#define TENSORFLOW_CONTRIB_LITE_TOCO_TOOLING_UTIL_H_ #include #include @@ -300,4 +300,4 @@ ArrayDataType ConvertIODataTypeToArrayDataType(IODataType type); } // namespace toco -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOCO_TOOLING_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOCO_TOOLING_UTIL_H_ diff --git a/tensorflow/contrib/lite/tools/gen_op_registration.h b/tensorflow/contrib/lite/tools/gen_op_registration.h index 318859e23d..5f2ac6ca97 100644 --- a/tensorflow/contrib/lite/tools/gen_op_registration.h +++ b/tensorflow/contrib/lite/tools/gen_op_registration.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOOLS_GEN_OP_REGISTRATION_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOOLS_GEN_OP_REGISTRATION_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOOLS_GEN_OP_REGISTRATION_H_ +#define TENSORFLOW_CONTRIB_LITE_TOOLS_GEN_OP_REGISTRATION_H_ #include "tensorflow/contrib/lite/model.h" #include "tensorflow/contrib/lite/string.h" @@ -36,4 +36,4 @@ void ReadOpsFromModel(const ::tflite::Model* model, } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOOLS_GEN_OP_REGISTRATION_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOOLS_GEN_OP_REGISTRATION_H_ diff --git a/tensorflow/contrib/lite/tools/mutable_op_resolver.h b/tensorflow/contrib/lite/tools/mutable_op_resolver.h index 906553da57..573a359c45 100644 --- a/tensorflow/contrib/lite/tools/mutable_op_resolver.h +++ b/tensorflow/contrib/lite/tools/mutable_op_resolver.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOOLS_MUTABLE_OP_RESOLVER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOOLS_MUTABLE_OP_RESOLVER_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_TOOLS_MUTABLE_OP_RESOLVER_H_ +#define TENSORFLOW_CONTRIB_LITE_TOOLS_MUTABLE_OP_RESOLVER_H_ #include #include "tensorflow/contrib/lite/context.h" @@ -52,4 +52,4 @@ class MutableOpResolver : public OpResolver { } // namespace tflite -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_TOOLS_MUTABLE_OP_RESOLVER_H_ +#endif // TENSORFLOW_CONTRIB_LITE_TOOLS_MUTABLE_OP_RESOLVER_H_ diff --git a/tensorflow/contrib/lite/version.h b/tensorflow/contrib/lite/version.h index a751afabe7..efd63f4006 100644 --- a/tensorflow/contrib/lite/version.h +++ b/tensorflow/contrib/lite/version.h @@ -12,12 +12,12 @@ 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 THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_VERSION_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_VERSION_H_ +#ifndef TENSORFLOW_CONTRIB_LITE_VERSION_H_ +#define TENSORFLOW_CONTRIB_LITE_VERSION_H_ // The version number of the Schema. Ideally all changes will be backward // compatible. If that ever changes, we must ensure that version is the first // entry in the new tflite root so that we can see that version is not 1. #define TFLITE_SCHEMA_VERSION (3) -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_LITE_VERSION_H_ +#endif // TENSORFLOW_CONTRIB_LITE_VERSION_H_ diff --git a/tensorflow/contrib/nccl/kernels/nccl_manager.h b/tensorflow/contrib/nccl/kernels/nccl_manager.h index cb1719c3be..bb219e0edc 100644 --- a/tensorflow/contrib/nccl/kernels/nccl_manager.h +++ b/tensorflow/contrib/nccl/kernels/nccl_manager.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NCCL_COMMUNICATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NCCL_COMMUNICATOR_H_ +#ifndef TENSORFLOW_CORE_KERNELS_NCCL_COMMUNICATOR_H_ +#define TENSORFLOW_CORE_KERNELS_NCCL_COMMUNICATOR_H_ #ifdef GOOGLE_CUDA @@ -136,4 +136,4 @@ class NcclManager { #endif // GOOGLE_CUDA -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NCCL_COMMUNICATOR_H_ +#endif // TENSORFLOW_CORE_KERNELS_NCCL_COMMUNICATOR_H_ diff --git a/tensorflow/contrib/nearest_neighbor/kernels/heap.h b/tensorflow/contrib/nearest_neighbor/kernels/heap.h index 6e33a574e2..32925569a8 100644 --- a/tensorflow/contrib/nearest_neighbor/kernels/heap.h +++ b/tensorflow/contrib/nearest_neighbor/kernels/heap.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HEAP_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HEAP_H_ +#ifndef TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HEAP_H_ +#define TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HEAP_H_ #include #include @@ -205,4 +205,4 @@ class AugmentedHeap : public HeapBase { } // namespace nearest_neighbor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HEAP_H_ +#endif // TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HEAP_H_ diff --git a/tensorflow/contrib/nearest_neighbor/kernels/hyperplane_lsh_probes.h b/tensorflow/contrib/nearest_neighbor/kernels/hyperplane_lsh_probes.h index 1670e2f83b..c53205e1a4 100644 --- a/tensorflow/contrib/nearest_neighbor/kernels/hyperplane_lsh_probes.h +++ b/tensorflow/contrib/nearest_neighbor/kernels/hyperplane_lsh_probes.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HYPERPLANE_LSH_PROBES_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HYPERPLANE_LSH_PROBES_H_ +#ifndef TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HYPERPLANE_LSH_PROBES_H_ +#define TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HYPERPLANE_LSH_PROBES_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" @@ -232,4 +232,4 @@ class HyperplaneMultiprobe { } // namespace nearest_neighbor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HYPERPLANE_LSH_PROBES_H_ +#endif // TENSORFLOW_CONTRIB_NEAREST_NEIGHBOR_KERNELS_HYPERPLANE_LSH_PROBES_H_ diff --git a/tensorflow/contrib/reduce_slice_ops/kernels/reduce_slice_ops.h b/tensorflow/contrib/reduce_slice_ops/kernels/reduce_slice_ops.h index fc3a2da9b3..9bb1724a2c 100644 --- a/tensorflow/contrib/reduce_slice_ops/kernels/reduce_slice_ops.h +++ b/tensorflow/contrib/reduce_slice_ops/kernels/reduce_slice_ops.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_PARTIAL_REDUCTION_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_PARTIAL_REDUCTION_OPS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_PARTIAL_REDUCTION_OPS_H_ +#define TENSORFLOW_CORE_KERNELS_PARTIAL_REDUCTION_OPS_H_ #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/framework/tensor_shape.h" @@ -81,4 +81,4 @@ CALL_ALL_REDUCEOPS(ReduceSliceFunctorReduceop) } // namespace functor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_PARTIAL_REDUCTION_OPS_H_ +#endif // TENSORFLOW_CORE_KERNELS_PARTIAL_REDUCTION_OPS_H_ diff --git a/tensorflow/contrib/resampler/kernels/resampler_ops.h b/tensorflow/contrib/resampler/kernels/resampler_ops.h index 8258ecaf5d..85d3676efa 100644 --- a/tensorflow/contrib/resampler/kernels/resampler_ops.h +++ b/tensorflow/contrib/resampler/kernels/resampler_ops.h @@ -13,8 +13,8 @@ // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_RESAMPLER_KERNELS_RESAMPLER_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_RESAMPLER_KERNELS_RESAMPLER_OPS_H_ +#ifndef TENSORFLOW_CONTRIB_RESAMPLER_KERNELS_RESAMPLER_OPS_H_ +#define TENSORFLOW_CONTRIB_RESAMPLER_KERNELS_RESAMPLER_OPS_H_ #if PLATFORM_WINDOWS #define __restrict__ __restrict @@ -64,5 +64,4 @@ struct ResamplerGrad2DFunctor{ } // namespace functor } // namespace tensorflow - -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_RESAMPLER_KERNELS_RESAMPLER_OPS_H_ +#endif // TENSORFLOW_CONTRIB_RESAMPLER_KERNELS_RESAMPLER_OPS_H_ diff --git a/tensorflow/contrib/rnn/kernels/blas_gemm.h b/tensorflow/contrib/rnn/kernels/blas_gemm.h index e33eceadff..a52c934233 100644 --- a/tensorflow/contrib/rnn/kernels/blas_gemm.h +++ b/tensorflow/contrib/rnn/kernels/blas_gemm.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_BLAS_GEMM_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_BLAS_GEMM_H_ +#ifndef TENSORFLOW_CONTRIB_RNN_KERNELS_BLAS_GEMM_H_ +#define TENSORFLOW_CONTRIB_RNN_KERNELS_BLAS_GEMM_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/framework/tensor_types.h" @@ -74,4 +74,4 @@ struct TensorBlasGemm { } // namespace functor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_BLAS_GEMM_H_ +#endif // TENSORFLOW_CONTRIB_RNN_KERNELS_BLAS_GEMM_H_ diff --git a/tensorflow/contrib/rnn/kernels/gru_ops.h b/tensorflow/contrib/rnn/kernels/gru_ops.h index 06a5665062..3e2cb39e64 100644 --- a/tensorflow/contrib/rnn/kernels/gru_ops.h +++ b/tensorflow/contrib/rnn/kernels/gru_ops.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ +#ifndef TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ +#define TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/contrib/rnn/kernels/blas_gemm.h" @@ -181,4 +181,4 @@ struct GRUBlockCellBprop : public GRUCell { } // namespace functor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ +#endif // TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ diff --git a/tensorflow/contrib/rnn/kernels/lstm_ops.h b/tensorflow/contrib/rnn/kernels/lstm_ops.h index 1906581b16..bc6b85f3f1 100644 --- a/tensorflow/contrib/rnn/kernels/lstm_ops.h +++ b/tensorflow/contrib/rnn/kernels/lstm_ops.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_LSTM_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_LSTM_OPS_H_ +#ifndef TENSORFLOW_CONTRIB_RNN_KERNELS_LSTM_OPS_H_ +#define TENSORFLOW_CONTRIB_RNN_KERNELS_LSTM_OPS_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/contrib/rnn/kernels/blas_gemm.h" @@ -291,4 +291,4 @@ struct BlockLSTMBprop : public LSTMBlockCell { } // namespace functor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_LSTM_OPS_H_ +#endif // TENSORFLOW_CONTRIB_RNN_KERNELS_LSTM_OPS_H_ diff --git a/tensorflow/contrib/saved_model/cc/saved_model/signature_def_utils.h b/tensorflow/contrib/saved_model/cc/saved_model/signature_def_utils.h index c0df224bc8..b732cdd41e 100644 --- a/tensorflow/contrib/saved_model/cc/saved_model/signature_def_utils.h +++ b/tensorflow/contrib/saved_model/cc/saved_model/signature_def_utils.h @@ -15,8 +15,8 @@ limitations under the License. // Helpers for working with the SignatureDefs of TensorFlow SavedModels. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_SAVED_MODEL_CC_SAVED_MODEL_SIGNATURE_DEF_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_SAVED_MODEL_CC_SAVED_MODEL_SIGNATURE_DEF_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_SAVED_MODEL_CC_SAVED_MODEL_SIGNATURE_DEF_UTILS_H_ +#define TENSORFLOW_CONTRIB_SAVED_MODEL_CC_SAVED_MODEL_SIGNATURE_DEF_UTILS_H_ #include #include @@ -66,4 +66,4 @@ Status FindOutputTensorNameByKey(const SignatureDef& signature_def, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_SAVED_MODEL_CC_SAVED_MODEL_SIGNATURE_DEF_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_SAVED_MODEL_CC_SAVED_MODEL_SIGNATURE_DEF_UTILS_H_ diff --git a/tensorflow/contrib/seq2seq/kernels/beam_search_ops.h b/tensorflow/contrib/seq2seq/kernels/beam_search_ops.h index 693b02dc43..34da8c82cd 100644 --- a/tensorflow/contrib/seq2seq/kernels/beam_search_ops.h +++ b/tensorflow/contrib/seq2seq/kernels/beam_search_ops.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_SEQ2SEQ_KERNELS_BEAM_SEARCH_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_SEQ2SEQ_KERNELS_BEAM_SEARCH_OPS_H_ +#ifndef TENSORFLOW_CONTRIB_SEQ2SEQ_KERNELS_BEAM_SEARCH_OPS_H_ +#define TENSORFLOW_CONTRIB_SEQ2SEQ_KERNELS_BEAM_SEARCH_OPS_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/framework/tensor_types.h" @@ -38,4 +38,4 @@ struct GatherTree { } // namespace functor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_SEQ2SEQ_KERNELS_BEAM_SEARCH_OPS_H_ +#endif // TENSORFLOW_CONTRIB_SEQ2SEQ_KERNELS_BEAM_SEARCH_OPS_H_ diff --git a/tensorflow/contrib/session_bundle/bundle_shim.h b/tensorflow/contrib/session_bundle/bundle_shim.h index e24efa0de1..4628b6ab1b 100644 --- a/tensorflow/contrib/session_bundle/bundle_shim.h +++ b/tensorflow/contrib/session_bundle/bundle_shim.h @@ -15,8 +15,8 @@ limitations under the License. // Shim for systems that need to load both SessionBundle and // SavedModelBundle interchangeably during migration to SavedModel. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_BUNDLE_SHIM_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_BUNDLE_SHIM_H_ +#ifndef TENSORFLOW_CONTRIB_SESSION_BUNDLE_BUNDLE_SHIM_H_ +#define TENSORFLOW_CONTRIB_SESSION_BUNDLE_BUNDLE_SHIM_H_ #include @@ -67,4 +67,4 @@ Status LoadSessionBundleOrSavedModelBundle( } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_BUNDLE_SHIM_H_ +#endif // TENSORFLOW_CONTRIB_SESSION_BUNDLE_BUNDLE_SHIM_H_ diff --git a/tensorflow/contrib/session_bundle/session_bundle.h b/tensorflow/contrib/session_bundle/session_bundle.h index 2ff258411d..b2be46efa6 100644 --- a/tensorflow/contrib/session_bundle/session_bundle.h +++ b/tensorflow/contrib/session_bundle/session_bundle.h @@ -15,8 +15,8 @@ limitations under the License. // Low-level functionality for setting up a inference Session. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_SESSION_BUNDLE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_SESSION_BUNDLE_H_ +#ifndef TENSORFLOW_CONTRIB_SESSION_BUNDLE_SESSION_BUNDLE_H_ +#define TENSORFLOW_CONTRIB_SESSION_BUNDLE_SESSION_BUNDLE_H_ #include @@ -82,4 +82,4 @@ bool IsPossibleExportDirectory(const StringPiece export_dir); } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_SESSION_BUNDLE_H_ +#endif // TENSORFLOW_CONTRIB_SESSION_BUNDLE_SESSION_BUNDLE_H_ diff --git a/tensorflow/contrib/session_bundle/signature.h b/tensorflow/contrib/session_bundle/signature.h index 0049bea008..4ef1277cec 100644 --- a/tensorflow/contrib/session_bundle/signature.h +++ b/tensorflow/contrib/session_bundle/signature.h @@ -15,8 +15,8 @@ limitations under the License. // Helpers for working with TensorFlow exports and their signatures. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_SIGNATURE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_SIGNATURE_H_ +#ifndef TENSORFLOW_CONTRIB_SESSION_BUNDLE_SIGNATURE_H_ +#define TENSORFLOW_CONTRIB_SESSION_BUNDLE_SIGNATURE_H_ #include #include @@ -121,4 +121,4 @@ Status BindGenericNames(const GenericSignature& signature, } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_SIGNATURE_H_ +#endif // TENSORFLOW_CONTRIB_SESSION_BUNDLE_SIGNATURE_H_ diff --git a/tensorflow/contrib/session_bundle/test_util.h b/tensorflow/contrib/session_bundle/test_util.h index dd0fc8d1c0..f0d41ce5a4 100644 --- a/tensorflow/contrib/session_bundle/test_util.h +++ b/tensorflow/contrib/session_bundle/test_util.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_TEST_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_TEST_UTIL_H_ +#ifndef TENSORFLOW_CONTRIB_SESSION_BUNDLE_TEST_UTIL_H_ +#define TENSORFLOW_CONTRIB_SESSION_BUNDLE_TEST_UTIL_H_ #include @@ -35,4 +35,4 @@ string TestSrcDirPath(const string& relative_path); } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_SESSION_BUNDLE_TEST_UTIL_H_ +#endif // TENSORFLOW_CONTRIB_SESSION_BUNDLE_TEST_UTIL_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/data_spec.h b/tensorflow/contrib/tensor_forest/kernels/data_spec.h index 05590d6992..0a3abe56df 100644 --- a/tensorflow/contrib/tensor_forest/kernels/data_spec.h +++ b/tensorflow/contrib/tensor_forest/kernels/data_spec.h @@ -15,8 +15,8 @@ // This is a surrogate for using a proto, since it doesn't seem to be possible // to use protos in a dynamically-loaded/shared-linkage library, which is // what is used for custom ops in tensorflow/contrib. -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_DATA_SPEC_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_DATA_SPEC_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_DATA_SPEC_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_DATA_SPEC_H_ #include #include "tensorflow/core/lib/strings/numbers.h" @@ -138,4 +138,4 @@ class TensorForestDataSpec { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_DATA_SPEC_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_DATA_SPEC_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/tree_utils.h b/tensorflow/contrib/tensor_forest/kernels/tree_utils.h index 35f9fb7eaf..dad9df4898 100644 --- a/tensorflow/contrib/tensor_forest/kernels/tree_utils.h +++ b/tensorflow/contrib/tensor_forest/kernels/tree_utils.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_TREE_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_TREE_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_TREE_UTILS_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_TREE_UTILS_H_ #include @@ -307,4 +307,4 @@ void GetParentWeightedMean(float leaf_sum, const float* leaf_data, } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_TREE_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_CORE_OPS_TREE_UTILS_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/candidate_graph_runner.h b/tensorflow/contrib/tensor_forest/kernels/v4/candidate_graph_runner.h index 4bd1f06c72..2e7368dc12 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/candidate_graph_runner.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/candidate_graph_runner.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_CANDIDATE_GRAPH_RUNNER_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_CANDIDATE_GRAPH_RUNNER_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_CANDIDATE_GRAPH_RUNNER_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_CANDIDATE_GRAPH_RUNNER_H_ #include #include @@ -70,4 +70,4 @@ class CandidateGraphRunner { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_CANDIDATE_GRAPH_RUNNER_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_CANDIDATE_GRAPH_RUNNER_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/decision-tree-resource.h b/tensorflow/contrib/tensor_forest/kernels/v4/decision-tree-resource.h index bf88216d66..cced26b903 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/decision-tree-resource.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/decision-tree-resource.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_TREE_RESOURCE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_TREE_RESOURCE_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_TREE_RESOURCE_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_TREE_RESOURCE_H_ #include "tensorflow/contrib/decision_trees/proto/generic_tree_model.pb.h" #include "tensorflow/contrib/tensor_forest/kernels/v4/decision_node_evaluator.h" @@ -88,4 +88,4 @@ class DecisionTreeResource : public ResourceBase { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_TREE_RESOURCE_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_TREE_RESOURCE_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/decision_node_evaluator.h b/tensorflow/contrib/tensor_forest/kernels/v4/decision_node_evaluator.h index 3f03c2d05b..85ce7b825b 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/decision_node_evaluator.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/decision_node_evaluator.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_NODE_EVALUATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_NODE_EVALUATOR_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_NODE_EVALUATOR_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_NODE_EVALUATOR_H_ #include "tensorflow/contrib/decision_trees/proto/generic_tree_model.pb.h" #include "tensorflow/contrib/decision_trees/proto/generic_tree_model_extensions.pb.h" @@ -104,4 +104,4 @@ struct CandidateEvalatorCollection { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_NODE_EVALUATOR_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_DECISION_NODE_EVALUATOR_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/fertile-stats-resource.h b/tensorflow/contrib/tensor_forest/kernels/v4/fertile-stats-resource.h index dacf033d99..0d6712e9e5 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/fertile-stats-resource.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/fertile-stats-resource.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_FERTILE_STATS_RESOURCE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_FERTILE_STATS_RESOURCE_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_FERTILE_STATS_RESOURCE_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_FERTILE_STATS_RESOURCE_H_ #include @@ -98,4 +98,4 @@ class FertileStatsResource : public ResourceBase { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_FERTILE_STATS_RESOURCE_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_FERTILE_STATS_RESOURCE_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/graph_collection_operator.h b/tensorflow/contrib/tensor_forest/kernels/v4/graph_collection_operator.h index 2ae3a79b3d..4ae48179af 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/graph_collection_operator.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/graph_collection_operator.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GRAPH_COLLECTION_OPERATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GRAPH_COLLECTION_OPERATOR_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GRAPH_COLLECTION_OPERATOR_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GRAPH_COLLECTION_OPERATOR_H_ #include #include "tensorflow/contrib/decision_trees/proto/generic_tree_model.pb.h" @@ -78,4 +78,4 @@ class GraphRunnerSplitCollectionOperator : public SplitCollectionOperator { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GRAPH_COLLECTION_OPERATOR_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GRAPH_COLLECTION_OPERATOR_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/grow_stats.h b/tensorflow/contrib/tensor_forest/kernels/v4/grow_stats.h index 3e41ab50b9..f938d08c84 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/grow_stats.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/grow_stats.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GROW_STATS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GROW_STATS_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GROW_STATS_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GROW_STATS_H_ #include #include @@ -609,4 +609,4 @@ class LeastSquaresRegressionGrowStats : public GrowStats { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GROW_STATS_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_GROW_STATS_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/input_data.h b/tensorflow/contrib/tensor_forest/kernels/v4/input_data.h index e3d4edbf8a..eafad6b591 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/input_data.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/input_data.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_DATA_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_DATA_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_DATA_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_DATA_H_ #include #include #include "google/protobuf/any.pb.h" @@ -123,4 +123,4 @@ class TensorDataSet { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_DATA_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_DATA_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/input_target.h b/tensorflow/contrib/tensor_forest/kernels/v4/input_target.h index 0309ec1de9..44ec09c50e 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/input_target.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/input_target.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_TARGET_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_TARGET_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_TARGET_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_TARGET_H_ #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/framework/tensor_types.h" @@ -89,4 +89,4 @@ class TensorInputTarget : public StoredInputTarget { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_TARGET_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_INPUT_TARGET_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/leaf_model_operators.h b/tensorflow/contrib/tensor_forest/kernels/v4/leaf_model_operators.h index 946a648f22..cc4ec8dc9e 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/leaf_model_operators.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/leaf_model_operators.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_LEAF_MODEL_OPERATORS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_LEAF_MODEL_OPERATORS_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_LEAF_MODEL_OPERATORS_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_LEAF_MODEL_OPERATORS_H_ #include "tensorflow/contrib/decision_trees/proto/generic_tree_model.pb.h" #include "tensorflow/contrib/tensor_forest/kernels/v4/input_target.h" @@ -146,4 +146,4 @@ class LeafModelOperatorFactory { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_LEAF_MODEL_OPERATORS_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_LEAF_MODEL_OPERATORS_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/params.h b/tensorflow/contrib/tensor_forest/kernels/v4/params.h index 97a9d8d096..b0ed949424 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/params.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/params.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_PARAMS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_PARAMS_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_PARAMS_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_PARAMS_H_ #include "tensorflow/contrib/tensor_forest/proto/tensor_forest_params.pb.h" #include "tensorflow/core/platform/types.h" @@ -28,5 +28,4 @@ float ResolveParam(const DepthDependentParam& param, int32 depth); } // namespace tensorforest } // namespace tensorflow - -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_PARAMS_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_PARAMS_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/split_collection_operators.h b/tensorflow/contrib/tensor_forest/kernels/v4/split_collection_operators.h index 6c21c0bd34..ad52f89fad 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/split_collection_operators.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/split_collection_operators.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_SPLIT_COLLECTION_OPERATORS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_SPLIT_COLLECTION_OPERATORS_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_SPLIT_COLLECTION_OPERATORS_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_SPLIT_COLLECTION_OPERATORS_H_ #include #include "tensorflow/contrib/decision_trees/proto/generic_tree_model.pb.h" @@ -128,6 +128,4 @@ class AnyCollectionCreator : public CollectionCreator { } // namespace tensorforest } // namespace tensorflow - - -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_SPLIT_COLLECTION_OPERATORS_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_SPLIT_COLLECTION_OPERATORS_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/stat_utils.h b/tensorflow/contrib/tensor_forest/kernels/v4/stat_utils.h index 8e002d0414..e6140065bb 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/stat_utils.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/stat_utils.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_STAT_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_STAT_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_STAT_UTILS_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_STAT_UTILS_H_ #include "tensorflow/contrib/tensor_forest/proto/fertile_stats.pb.h" #include "tensorflow/core/platform/types.h" @@ -47,4 +47,4 @@ float WeightedSmoothedGini(float sum, float square, int num_classes); } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_STAT_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_STAT_UTILS_H_ diff --git a/tensorflow/contrib/tensor_forest/kernels/v4/test_utils.h b/tensorflow/contrib/tensor_forest/kernels/v4/test_utils.h index b6e543b96f..289c81e9d5 100644 --- a/tensorflow/contrib/tensor_forest/kernels/v4/test_utils.h +++ b/tensorflow/contrib/tensor_forest/kernels/v4/test_utils.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================= -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_TEST_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_TEST_UTILS_H_ +#ifndef TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_TEST_UTILS_H_ +#define TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_TEST_UTILS_H_ #include "tensorflow/contrib/tensor_forest/kernels/v4/input_data.h" #include "tensorflow/contrib/tensor_forest/kernels/v4/input_target.h" @@ -71,4 +71,4 @@ class TestableDataSet : public TensorDataSet { } // namespace tensorforest } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_TEST_UTILS_H_ +#endif // TENSORFLOW_CONTRIB_TENSOR_FOREST_KERNELS_V4_TEST_UTILS_H_ diff --git a/tensorflow/contrib/tpu/profiler/dump_tpu_profile.h b/tensorflow/contrib/tpu/profiler/dump_tpu_profile.h index 65b92aa418..25b958bcfe 100644 --- a/tensorflow/contrib/tpu/profiler/dump_tpu_profile.h +++ b/tensorflow/contrib/tpu/profiler/dump_tpu_profile.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_DUMP_TPU_PROFILE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_DUMP_TPU_PROFILE_H_ +#ifndef TENSORFLOW_CONTRIB_TPU_PROFILER_DUMP_TPU_PROFILE_H_ +#define TENSORFLOW_CONTRIB_TPU_PROFILER_DUMP_TPU_PROFILE_H_ #include "tensorflow/contrib/tpu/profiler/tpu_profiler.grpc.pb.h" #include "tensorflow/core/lib/core/status.h" @@ -35,4 +35,4 @@ Status WriteTensorboardTPUProfile(const string& logdir, const string& run, } // namespace tpu } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_DUMP_TPU_PROFILE_H_ +#endif // TENSORFLOW_CONTRIB_TPU_PROFILER_DUMP_TPU_PROFILE_H_ diff --git a/tensorflow/contrib/tpu/profiler/trace_events_to_json.h b/tensorflow/contrib/tpu/profiler/trace_events_to_json.h index 992eae43d9..3bd76dd01c 100644 --- a/tensorflow/contrib/tpu/profiler/trace_events_to_json.h +++ b/tensorflow/contrib/tpu/profiler/trace_events_to_json.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_TRACE_EVENTS_TO_JSON_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_TRACE_EVENTS_TO_JSON_H_ +#ifndef TENSORFLOW_CONTRIB_TPU_PROFILER_TRACE_EVENTS_TO_JSON_H_ +#define TENSORFLOW_CONTRIB_TPU_PROFILER_TRACE_EVENTS_TO_JSON_H_ #include "tensorflow/contrib/tpu/profiler/trace_events.pb.h" #include "tensorflow/core/platform/types.h" @@ -29,4 +29,4 @@ string TraceEventsToJson(const Trace &trace); } // namespace tpu } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_TRACE_EVENTS_TO_JSON_H_ +#endif // TENSORFLOW_CONTRIB_TPU_PROFILER_TRACE_EVENTS_TO_JSON_H_ diff --git a/tensorflow/contrib/tpu/profiler/version.h b/tensorflow/contrib/tpu/profiler/version.h index a6c9a9503d..0f645a5492 100644 --- a/tensorflow/contrib/tpu/profiler/version.h +++ b/tensorflow/contrib/tpu/profiler/version.h @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ +#ifndef TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ +#define TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ #define TPU_PROFILER_VERSION "1.4.3" -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ +#endif // TENSORFLOW_CONTRIB_TPU_PROFILER_VERSION_H_ diff --git a/tensorflow/contrib/util/convert_graphdef_memmapped_format_lib.h b/tensorflow/contrib/util/convert_graphdef_memmapped_format_lib.h index 6518e7a10f..61fc6f36f7 100644 --- a/tensorflow/contrib/util/convert_graphdef_memmapped_format_lib.h +++ b/tensorflow/contrib/util/convert_graphdef_memmapped_format_lib.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_UTIL_CONVERT_GRAPHDEF_MEMMAPPED_FORMAT_LIB_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_UTIL_CONVERT_GRAPHDEF_MEMMAPPED_FORMAT_LIB_H_ +#ifndef TENSORFLOW_CONTRIB_UTIL_CONVERT_GRAPHDEF_MEMMAPPED_FORMAT_LIB_H_ +#define TENSORFLOW_CONTRIB_UTIL_CONVERT_GRAPHDEF_MEMMAPPED_FORMAT_LIB_H_ #include @@ -31,4 +31,4 @@ Status ConvertConstantsToImmutable(const string& in_graph_filename, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_UTIL_CONVERT_GRAPHDEF_MEMMAPPED_FORMAT_LIB_H_ +#endif // TENSORFLOW_CONTRIB_UTIL_CONVERT_GRAPHDEF_MEMMAPPED_FORMAT_LIB_H_ diff --git a/tensorflow/contrib/verbs/grpc_verbs_client.h b/tensorflow/contrib/verbs/grpc_verbs_client.h index 358977f925..2cfaa4986c 100644 --- a/tensorflow/contrib/verbs/grpc_verbs_client.h +++ b/tensorflow/contrib/verbs/grpc_verbs_client.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_GRPC_VERBS_CLIENT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_GRPC_VERBS_CLIENT_H_ +#ifndef TENSORFLOW_CONTRIB_GRPC_VERBS_CLIENT_H_ +#define TENSORFLOW_CONTRIB_GRPC_VERBS_CLIENT_H_ #include "tensorflow/contrib/verbs/grpc_verbs_service_impl.h" #include "tensorflow/contrib/verbs/verbs_service.pb.h" @@ -47,4 +47,4 @@ class GrpcVerbsClient { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_GRPC_VERBS_CLIENT_H_ +#endif // TENSORFLOW_CONTRIB_GRPC_VERBS_CLIENT_H_ diff --git a/tensorflow/contrib/verbs/grpc_verbs_service.h b/tensorflow/contrib/verbs/grpc_verbs_service.h index aa509602b5..444c863b94 100644 --- a/tensorflow/contrib/verbs/grpc_verbs_service.h +++ b/tensorflow/contrib/verbs/grpc_verbs_service.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_GRPC_VERBS_SERVICE_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_GRPC_VERBS_SERVICE_H_ +#ifndef TENSORFLOW_CONTRIB_VERBS_GRPC_VERBS_SERVICE_H_ +#define TENSORFLOW_CONTRIB_VERBS_GRPC_VERBS_SERVICE_H_ #ifdef TENSORFLOW_USE_VERBS @@ -69,4 +69,4 @@ void SetNewVerbsService(GrpcVerbsService** handle, const WorkerEnv* worker_env, } // namespace tensorflow #endif // TENSORFLOW_USE_VERBS -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_GRPC_VERBS_SERVICE_H_ +#endif // TENSORFLOW_CONTRIB_VERBS_GRPC_VERBS_SERVICE_H_ diff --git a/tensorflow/contrib/verbs/grpc_verbs_service_impl.h b/tensorflow/contrib/verbs/grpc_verbs_service_impl.h index 86431ca030..1f0f10517e 100644 --- a/tensorflow/contrib/verbs/grpc_verbs_service_impl.h +++ b/tensorflow/contrib/verbs/grpc_verbs_service_impl.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_GRPC_VERBS_SERVICE_IMPL_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_GRPC_VERBS_SERVICE_IMPL_H_ +#ifndef TENSORFLOW_CONTRIB_GRPC_VERBS_SERVICE_IMPL_H_ +#define TENSORFLOW_CONTRIB_GRPC_VERBS_SERVICE_IMPL_H_ #include "grpc++/impl/codegen/async_stream.h" #include "grpc++/impl/codegen/async_unary_call.h" @@ -86,4 +86,4 @@ class VerbsService GRPC_FINAL { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_GRPC_VERBS_SERVICE_IMPL_H_ +#endif // TENSORFLOW_CONTRIB_GRPC_VERBS_SERVICE_IMPL_H_ diff --git a/tensorflow/contrib/verbs/rdma.h b/tensorflow/contrib/verbs/rdma.h index b6c41de6ee..94203ee2b3 100644 --- a/tensorflow/contrib/verbs/rdma.h +++ b/tensorflow/contrib/verbs/rdma.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_H_ +#ifndef TENSORFLOW_CONTRIB_VERBS_RDMA_H_ +#define TENSORFLOW_CONTRIB_VERBS_RDMA_H_ #ifdef TENSORFLOW_USE_VERBS @@ -524,4 +524,4 @@ class RdmaMessageBuffer { } // namespace tensorflow #endif // TENSORFLOW_USE_VERBS -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_H_ +#endif // TENSORFLOW_CONTRIB_VERBS_RDMA_H_ diff --git a/tensorflow/contrib/verbs/rdma_mgr.h b/tensorflow/contrib/verbs/rdma_mgr.h index 29227a9544..9fffc335bb 100644 --- a/tensorflow/contrib/verbs/rdma_mgr.h +++ b/tensorflow/contrib/verbs/rdma_mgr.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_MGR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_MGR_H_ +#ifndef TENSORFLOW_CONTRIB_VERBS_RDMA_MGR_H_ +#define TENSORFLOW_CONTRIB_VERBS_RDMA_MGR_H_ #ifdef TENSORFLOW_USE_VERBS @@ -55,4 +55,4 @@ class RdmaMgr { } // namespace tensorflow #endif // TENSORFLOW_USE_VERBS -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_MGR_H_ +#endif // TENSORFLOW_CONTRIB_VERBS_RDMA_MGR_H_ diff --git a/tensorflow/contrib/verbs/rdma_rendezvous_mgr.h b/tensorflow/contrib/verbs/rdma_rendezvous_mgr.h index 2dedd6c48f..c0d6f59c48 100644 --- a/tensorflow/contrib/verbs/rdma_rendezvous_mgr.h +++ b/tensorflow/contrib/verbs/rdma_rendezvous_mgr.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_RENDEZVOUS_MGR_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_RENDEZVOUS_MGR_H_ +#ifndef TENSORFLOW_CONTRIB_VERBS_RDMA_RENDEZVOUS_MGR_H_ +#define TENSORFLOW_CONTRIB_VERBS_RDMA_RENDEZVOUS_MGR_H_ #ifdef TENSORFLOW_USE_VERBS @@ -60,4 +60,4 @@ class RdmaRendezvousMgr : public BaseRendezvousMgr { } // end namespace tensorflow #endif // TENSORFLOW_USE_VERBS -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_RDMA_RENDEZVOUS_MGR_H_ +#endif // TENSORFLOW_CONTRIB_VERBS_RDMA_RENDEZVOUS_MGR_H_ diff --git a/tensorflow/contrib/verbs/verbs_server_lib.h b/tensorflow/contrib/verbs/verbs_server_lib.h index 855380129f..54ce8c1d47 100644 --- a/tensorflow/contrib/verbs/verbs_server_lib.h +++ b/tensorflow/contrib/verbs/verbs_server_lib.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_VERBS_SERVER_LIB_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_VERBS_SERVER_LIB_H_ +#ifndef TENSORFLOW_CONTRIB_VERBS_VERBS_SERVER_LIB_H_ +#define TENSORFLOW_CONTRIB_VERBS_VERBS_SERVER_LIB_H_ #ifdef TENSORFLOW_USE_VERBS @@ -63,4 +63,4 @@ class VerbsServer : public GrpcServer { } // namespace tensorflow #endif // TENSORFLOW_USE_VERBS -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_VERBS_VERBS_SERVER_LIB_H_ +#endif // TENSORFLOW_CONTRIB_VERBS_VERBS_SERVER_LIB_H_ diff --git a/tensorflow/core/api_def/update_api_def.h b/tensorflow/core/api_def/update_api_def.h index 5d6c15010d..1e285c0688 100644 --- a/tensorflow/core/api_def/update_api_def.h +++ b/tensorflow/core/api_def/update_api_def.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_API_DEF_UPDATE_API_DEF_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_API_DEF_UPDATE_API_DEF_H_ +#ifndef TENSORFLOW_CORE_API_DEF_UPDATE_API_DEF_H_ +#define TENSORFLOW_CORE_API_DEF_UPDATE_API_DEF_H_ // Functions for updating ApiDef when new ops are added. #include "tensorflow/core/framework/op_def.pb.h" @@ -42,4 +42,4 @@ void CreateApiDefs(const OpList& ops, const string& api_def_dir, const string& op_file_pattern); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_API_DEF_UPDATE_API_DEF_H_ +#endif // TENSORFLOW_CORE_API_DEF_UPDATE_API_DEF_H_ diff --git a/tensorflow/core/common_runtime/function_testlib.h b/tensorflow/core/common_runtime/function_testlib.h index 0bf6699f5a..3ddb26de92 100644 --- a/tensorflow/core/common_runtime/function_testlib.h +++ b/tensorflow/core/common_runtime/function_testlib.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_FUNCTION_TESTLIB_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_FUNCTION_TESTLIB_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_FUNCTION_TESTLIB_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_FUNCTION_TESTLIB_H_ #include "tensorflow/cc/framework/scope.h" #include "tensorflow/core/framework/function.h" @@ -34,4 +34,4 @@ Output Call(Scope* scope, const string& op_name, const string& fn_name, } // namespace test } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_FUNCTION_TESTLIB_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_FUNCTION_TESTLIB_H_ diff --git a/tensorflow/core/common_runtime/gpu/gpu_id.h b/tensorflow/core/common_runtime/gpu/gpu_id.h index ff81ccd432..4e9c4abce1 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_id.h +++ b/tensorflow/core/common_runtime/gpu/gpu_id.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_H_ #include "tensorflow/core/lib/gtl/int_type.h" @@ -85,4 +85,4 @@ TF_LIB_GTL_DEFINE_INT_TYPE(CudaGpuId, int32); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_H_ diff --git a/tensorflow/core/common_runtime/gpu/gpu_id_utils.h b/tensorflow/core/common_runtime/gpu/gpu_id_utils.h index 78e51c84c1..6d196b16ed 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_id_utils.h +++ b/tensorflow/core/common_runtime/gpu/gpu_id_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_UTILS_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_UTILS_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_UTILS_H_ #include "tensorflow/core/common_runtime/gpu/gpu_id.h" #include "tensorflow/core/common_runtime/gpu/gpu_init.h" @@ -58,4 +58,4 @@ class GpuIdUtil { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_UTILS_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_ID_UTILS_H_ diff --git a/tensorflow/core/common_runtime/gpu/gpu_managed_allocator.h b/tensorflow/core/common_runtime/gpu/gpu_managed_allocator.h index 006b2ca448..2d49a64c0f 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_managed_allocator.h +++ b/tensorflow/core/common_runtime/gpu/gpu_managed_allocator.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_MANAGED_ALLOCATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_MANAGED_ALLOCATOR_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_MANAGED_ALLOCATOR_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_MANAGED_ALLOCATOR_H_ #include "tensorflow/core/framework/allocator.h" @@ -33,4 +33,4 @@ class GpuManagedAllocator : public Allocator { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_MANAGED_ALLOCATOR_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_GPU_GPU_MANAGED_ALLOCATOR_H_ diff --git a/tensorflow/core/common_runtime/graph_optimizer.h b/tensorflow/core/common_runtime/graph_optimizer.h index 8f3a082134..8477cea126 100644 --- a/tensorflow/core/common_runtime/graph_optimizer.h +++ b/tensorflow/core/common_runtime/graph_optimizer.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GRAPH_OPTIMIZER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GRAPH_OPTIMIZER_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_GRAPH_OPTIMIZER_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_GRAPH_OPTIMIZER_H_ #include "tensorflow/core/framework/function.h" #include "tensorflow/core/graph/graph.h" @@ -60,4 +60,4 @@ class GraphOptimizer { } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_GRAPH_OPTIMIZER_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_GRAPH_OPTIMIZER_H_ diff --git a/tensorflow/core/common_runtime/memory_types.h b/tensorflow/core/common_runtime/memory_types.h index fa0a7595f3..f854acfdc5 100644 --- a/tensorflow/core/common_runtime/memory_types.h +++ b/tensorflow/core/common_runtime/memory_types.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_MEMORY_TYPES_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_MEMORY_TYPES_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_MEMORY_TYPES_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_MEMORY_TYPES_H_ #include "tensorflow/core/framework/memory_types.h" #include "tensorflow/core/graph/graph.h" @@ -45,4 +45,4 @@ Status MemoryTypeForOutput(const DeviceType& device_type, const Graph* g, } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_MEMORY_TYPES_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_MEMORY_TYPES_H_ diff --git a/tensorflow/core/common_runtime/pending_counts.h b/tensorflow/core/common_runtime/pending_counts.h index 5707f52592..5e1925c401 100644 --- a/tensorflow/core/common_runtime/pending_counts.h +++ b/tensorflow/core/common_runtime/pending_counts.h @@ -1,5 +1,5 @@ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PENDING_COUNTS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PENDING_COUNTS_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_PENDING_COUNTS_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_PENDING_COUNTS_H_ /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. @@ -328,4 +328,4 @@ inline PendingCounts::Handle PendingCounts::Layout::CreateHandle( } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PENDING_COUNTS_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_PENDING_COUNTS_H_ diff --git a/tensorflow/core/common_runtime/process_function_library_runtime.h b/tensorflow/core/common_runtime/process_function_library_runtime.h index 38003b7726..a1adc4b6b3 100644 --- a/tensorflow/core/common_runtime/process_function_library_runtime.h +++ b/tensorflow/core/common_runtime/process_function_library_runtime.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PROCESS_FUNCTION_LIBRARY_RUNTIME_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PROCESS_FUNCTION_LIBRARY_RUNTIME_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_PROCESS_FUNCTION_LIBRARY_RUNTIME_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_PROCESS_FUNCTION_LIBRARY_RUNTIME_H_ #include @@ -173,4 +173,4 @@ class ProcessFunctionLibraryRuntime { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PROCESS_FUNCTION_LIBRARY_RUNTIME_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_PROCESS_FUNCTION_LIBRARY_RUNTIME_H_ diff --git a/tensorflow/core/common_runtime/profile_handler.h b/tensorflow/core/common_runtime/profile_handler.h index 57c83c2e6f..9d31b1aecb 100644 --- a/tensorflow/core/common_runtime/profile_handler.h +++ b/tensorflow/core/common_runtime/profile_handler.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PROFILE_HANDLER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PROFILE_HANDLER_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_PROFILE_HANDLER_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_PROFILE_HANDLER_H_ #include "tensorflow/core/framework/step_stats.pb.h" #include "tensorflow/core/graph/types.h" @@ -80,4 +80,4 @@ class ProfileHandler { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_PROFILE_HANDLER_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_PROFILE_HANDLER_H_ diff --git a/tensorflow/core/common_runtime/renamed_device.h b/tensorflow/core/common_runtime/renamed_device.h index c5c204d4fa..fe4df1c106 100644 --- a/tensorflow/core/common_runtime/renamed_device.h +++ b/tensorflow/core/common_runtime/renamed_device.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_RENAMED_DEVICE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_RENAMED_DEVICE_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_RENAMED_DEVICE_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_RENAMED_DEVICE_H_ #include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/util/device_name_utils.h" @@ -134,4 +134,4 @@ class RenamedDevice : public Device { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_RENAMED_DEVICE_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_RENAMED_DEVICE_H_ diff --git a/tensorflow/core/common_runtime/rendezvous_util.h b/tensorflow/core/common_runtime/rendezvous_util.h index 3b6354603b..aad910f6d8 100644 --- a/tensorflow/core/common_runtime/rendezvous_util.h +++ b/tensorflow/core/common_runtime/rendezvous_util.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_RENDEZVOUS_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_RENDEZVOUS_UTIL_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_RENDEZVOUS_UTIL_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_RENDEZVOUS_UTIL_H_ #include @@ -49,4 +49,4 @@ Status RecvOutputsFromRendezvous(Rendezvous* rendezvous, NamedTensors* out, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_RENDEZVOUS_UTIL_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_RENDEZVOUS_UTIL_H_ diff --git a/tensorflow/core/common_runtime/shape_refiner.h b/tensorflow/core/common_runtime/shape_refiner.h index da42c30ce9..75eb5bf0d2 100644 --- a/tensorflow/core/common_runtime/shape_refiner.h +++ b/tensorflow/core/common_runtime/shape_refiner.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_SHAPE_REFINER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_SHAPE_REFINER_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_SHAPE_REFINER_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_SHAPE_REFINER_H_ #include @@ -303,4 +303,4 @@ class ShapeRefiner { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_SHAPE_REFINER_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_SHAPE_REFINER_H_ diff --git a/tensorflow/core/common_runtime/stats_publisher_interface.h b/tensorflow/core/common_runtime/stats_publisher_interface.h index b285420798..f063ee5297 100644 --- a/tensorflow/core/common_runtime/stats_publisher_interface.h +++ b/tensorflow/core/common_runtime/stats_publisher_interface.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_STATS_PUBLISHER_INTERFACE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_STATS_PUBLISHER_INTERFACE_H_ +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_STATS_PUBLISHER_INTERFACE_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_STATS_PUBLISHER_INTERFACE_H_ #include "tensorflow/core/common_runtime/build_graph_options.h" #include "tensorflow/core/common_runtime/profile_handler.h" @@ -61,4 +61,4 @@ std::unique_ptr CreateNoOpStatsPublisher( } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_COMMON_RUNTIME_STATS_PUBLISHER_INTERFACE_H_ +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_STATS_PUBLISHER_INTERFACE_H_ diff --git a/tensorflow/core/distributed_runtime/cluster_function_library_runtime.h b/tensorflow/core/distributed_runtime/cluster_function_library_runtime.h index 3deb80dff7..d3ca350e36 100644 --- a/tensorflow/core/distributed_runtime/cluster_function_library_runtime.h +++ b/tensorflow/core/distributed_runtime/cluster_function_library_runtime.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_CLUSTER_FUNCTION_LIBRARY_RUNTIME_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_CLUSTER_FUNCTION_LIBRARY_RUNTIME_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_CLUSTER_FUNCTION_LIBRARY_RUNTIME_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_CLUSTER_FUNCTION_LIBRARY_RUNTIME_H_ #include "tensorflow/core/distributed_runtime/worker_interface.h" #include "tensorflow/core/distributed_runtime/worker_session.h" @@ -74,4 +74,4 @@ class ClusterFunctionLibraryRuntime : public DistributedFunctionLibraryRuntime { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_CLUSTER_FUNCTION_LIBRARY_RUNTIME_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_CLUSTER_FUNCTION_LIBRARY_RUNTIME_H_ diff --git a/tensorflow/core/distributed_runtime/local_master.h b/tensorflow/core/distributed_runtime/local_master.h index 5fc21d3a1e..c20b40329a 100644 --- a/tensorflow/core/distributed_runtime/local_master.h +++ b/tensorflow/core/distributed_runtime/local_master.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_LOCAL_MASTER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_LOCAL_MASTER_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_LOCAL_MASTER_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_LOCAL_MASTER_H_ #include @@ -98,4 +98,4 @@ class LocalMaster : public MasterInterface { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_LOCAL_MASTER_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_LOCAL_MASTER_H_ diff --git a/tensorflow/core/distributed_runtime/message_wrappers.h b/tensorflow/core/distributed_runtime/message_wrappers.h index 7113d73dd7..79fa6f926e 100644 --- a/tensorflow/core/distributed_runtime/message_wrappers.h +++ b/tensorflow/core/distributed_runtime/message_wrappers.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_MESSAGE_WRAPPERS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_MESSAGE_WRAPPERS_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_MESSAGE_WRAPPERS_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_MESSAGE_WRAPPERS_H_ #include "tensorflow/core/framework/allocator.h" #include "tensorflow/core/framework/cost_graph.pb.h" @@ -702,4 +702,4 @@ class NonOwnedProtoRunStepResponse : public MutableRunStepResponseWrapper { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW +#endif // TENSORFLOW diff --git a/tensorflow/core/distributed_runtime/partial_run_mgr.h b/tensorflow/core/distributed_runtime/partial_run_mgr.h index af56e723a9..e95f4da6c3 100644 --- a/tensorflow/core/distributed_runtime/partial_run_mgr.h +++ b/tensorflow/core/distributed_runtime/partial_run_mgr.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_PARTIAL_RUN_MGR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_PARTIAL_RUN_MGR_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_PARTIAL_RUN_MGR_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_PARTIAL_RUN_MGR_H_ #include @@ -84,4 +84,4 @@ class PartialRunMgr { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_PARTIAL_RUN_MGR_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_PARTIAL_RUN_MGR_H_ diff --git a/tensorflow/core/distributed_runtime/recent_request_ids.h b/tensorflow/core/distributed_runtime/recent_request_ids.h index 396235dcc6..e8e45331dd 100644 --- a/tensorflow/core/distributed_runtime/recent_request_ids.h +++ b/tensorflow/core/distributed_runtime/recent_request_ids.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ #include @@ -69,4 +69,4 @@ class RecentRequestIds { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RECENT_REQUEST_IDS_H_ diff --git a/tensorflow/core/distributed_runtime/request_id.h b/tensorflow/core/distributed_runtime/request_id.h index 288c49153d..a882b69ab1 100644 --- a/tensorflow/core/distributed_runtime/request_id.h +++ b/tensorflow/core/distributed_runtime/request_id.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ #include "tensorflow/core/lib/random/random.h" #include "tensorflow/core/platform/types.h" @@ -28,4 +28,4 @@ int64 GetUniqueRequestId(); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_REQUEST_ID_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/async_service_interface.h b/tensorflow/core/distributed_runtime/rpc/async_service_interface.h index 63b0f2272d..b2730a583b 100644 --- a/tensorflow/core/distributed_runtime/rpc/async_service_interface.h +++ b/tensorflow/core/distributed_runtime/rpc/async_service_interface.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_ASYNC_SERVICE_INTERFACE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_ASYNC_SERVICE_INTERFACE_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_ASYNC_SERVICE_INTERFACE_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_ASYNC_SERVICE_INTERFACE_H_ namespace tensorflow { @@ -38,4 +38,4 @@ class AsyncServiceInterface { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_ASYNC_SERVICE_INTERFACE_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_ASYNC_SERVICE_INTERFACE_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_call.h b/tensorflow/core/distributed_runtime/rpc/grpc_call.h index 2ab0a40f33..ecad1274cc 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_call.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_call.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CALL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CALL_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CALL_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CALL_H_ #include "tensorflow/core/lib/core/refcount.h" #include "tensorflow/core/platform/macros.h" @@ -265,4 +265,4 @@ class Call : public UntypedCall { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CALL_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CALL_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_channel.h b/tensorflow/core/distributed_runtime/rpc/grpc_channel.h index c662cde9be..de9840fca8 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_channel.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_channel.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CHANNEL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CHANNEL_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CHANNEL_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CHANNEL_H_ #include #include @@ -93,4 +93,4 @@ Status NewHostPortGrpcChannel(const string& target, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CHANNEL_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CHANNEL_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_client_cq_tag.h b/tensorflow/core/distributed_runtime/rpc/grpc_client_cq_tag.h index 95c2c935f0..d367b83ee7 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_client_cq_tag.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_client_cq_tag.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CLIENT_CQ_TAG_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CLIENT_CQ_TAG_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CLIENT_CQ_TAG_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CLIENT_CQ_TAG_H_ #include "grpc++/grpc++.h" @@ -41,4 +41,4 @@ class GrpcClientCQTag { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CLIENT_CQ_TAG_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_CLIENT_CQ_TAG_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_master_service.h b/tensorflow/core/distributed_runtime/rpc/grpc_master_service.h index 8770dcc3ac..473604f257 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_master_service.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_master_service.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_H_ #include #include "tensorflow/core/platform/types.h" @@ -34,4 +34,4 @@ AsyncServiceInterface* NewGrpcMasterService(Master* master, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_master_service_impl.h b/tensorflow/core/distributed_runtime/rpc/grpc_master_service_impl.h index 412395c526..4e203e260a 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_master_service_impl.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_master_service_impl.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_IMPL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_IMPL_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_IMPL_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_IMPL_H_ #include "grpc++/impl/codegen/async_stream.h" #include "grpc++/impl/codegen/async_unary_call.h" @@ -186,4 +186,4 @@ class MasterService final { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_IMPL_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_MASTER_SERVICE_IMPL_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_remote_master.h b/tensorflow/core/distributed_runtime/rpc/grpc_remote_master.h index d661caaa60..c80668e899 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_remote_master.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_remote_master.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_MASTER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_MASTER_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_MASTER_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_MASTER_H_ #include "tensorflow/core/distributed_runtime/master_interface.h" #include "tensorflow/core/distributed_runtime/rpc/grpc_util.h" @@ -24,4 +24,4 @@ namespace tensorflow { MasterInterface* NewGrpcMaster(const SharedGrpcChannelPtr& channel); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_MASTER_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_MASTER_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_remote_worker.h b/tensorflow/core/distributed_runtime/rpc/grpc_remote_worker.h index 8ad4133540..709c3833e7 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_remote_worker.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_remote_worker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_WORKER_H_ -#define THIRD_PARTY_TENSORFLOW_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_WORKER_H_ +#ifndef TENSORFLOW_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_WORKER_H_ +#define TENSORFLOW_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_WORKER_H_ #include @@ -35,4 +35,4 @@ WorkerInterface* NewGrpcRemoteWorker(SharedGrpcChannelPtr channel, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_WORKER_H_ +#endif // TENSORFLOW_DISTRIBUTED_RUNTIME_RPC_GRPC_REMOTE_WORKER_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_serialization_traits.h b/tensorflow/core/distributed_runtime/rpc/grpc_serialization_traits.h index b35d4843e8..dd114d39c6 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_serialization_traits.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_serialization_traits.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERIALIZATION_TRAITS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERIALIZATION_TRAITS_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERIALIZATION_TRAITS_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERIALIZATION_TRAITS_H_ #include "grpc++/impl/codegen/proto_utils.h" #include "grpc++/support/slice.h" @@ -231,4 +231,4 @@ class UnlimitedSizeProtoSerializationTraits { : public UnlimitedSizeProtoSerializationTraits {}; \ } // namespace grpc -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERIALIZATION_TRAITS_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERIALIZATION_TRAITS_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.h b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.h index c3f513d492..8b12ac1461 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERVER_LIB_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERVER_LIB_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERVER_LIB_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERVER_LIB_H_ #include @@ -141,4 +141,4 @@ class GrpcServer : public ServerInterface { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERVER_LIB_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SERVER_LIB_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_session.h b/tensorflow/core/distributed_runtime/rpc/grpc_session.h index 300f727124..d87956a135 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_session.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_session.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SESSION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SESSION_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SESSION_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SESSION_H_ #include #include @@ -130,4 +130,4 @@ class GrpcSession : public Session { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SESSION_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_SESSION_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_state.h b/tensorflow/core/distributed_runtime/rpc/grpc_state.h index 3f80bdfb70..0b6f9474dd 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_state.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_state.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_STATE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_STATE_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_STATE_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_STATE_H_ #include @@ -96,4 +96,4 @@ class RPCState : public GrpcClientCQTag { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_STATE_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_STATE_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_testlib.h b/tensorflow/core/distributed_runtime/rpc/grpc_testlib.h index 5e81b90189..4b3a03b1d7 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_testlib.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_testlib.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_TESTLIB_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_TESTLIB_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_TESTLIB_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_TESTLIB_H_ #include #include @@ -70,4 +70,4 @@ class TestCluster { } // end namespace test } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_TESTLIB_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_TESTLIB_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_util.h b/tensorflow/core/distributed_runtime/rpc/grpc_util.h index bb85478347..d5e7e9f5b3 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_util.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_util.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_UTIL_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_UTIL_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_UTIL_H_ #include @@ -114,4 +114,4 @@ class GrpcByteBufferSource : public ::grpc::protobuf::io::ZeroCopyInputStream { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_UTIL_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_UTIL_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.h b/tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.h index 17a307a6d9..7a35fdbca0 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_CACHE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_CACHE_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_CACHE_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_CACHE_H_ #include "tensorflow/core/distributed_runtime/rpc/grpc_channel.h" #include "tensorflow/core/distributed_runtime/worker_cache.h" @@ -29,4 +29,4 @@ WorkerCacheInterface* NewGrpcWorkerCacheWithLocalWorker( const string& local_target); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_CACHE_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_CACHE_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h index 28b389b25f..78a21fd9f6 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_H_ #include "tensorflow/core/distributed_runtime/recent_request_ids.h" #include "tensorflow/core/distributed_runtime/worker.h" @@ -54,4 +54,4 @@ std::unique_ptr NewGrpcWorkerService( } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_H_ diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.h b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.h index fb23f8631f..1a5e2edfb2 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_IMPL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_IMPL_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_IMPL_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_IMPL_H_ #include "grpc++/impl/codegen/async_stream.h" #include "grpc++/impl/codegen/async_unary_call.h" @@ -147,4 +147,4 @@ class WorkerService final { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_IMPL_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_RPC_GRPC_WORKER_SERVICE_IMPL_H_ diff --git a/tensorflow/core/distributed_runtime/server_lib.h b/tensorflow/core/distributed_runtime/server_lib.h index a064d20cdb..275f526d31 100644 --- a/tensorflow/core/distributed_runtime/server_lib.h +++ b/tensorflow/core/distributed_runtime/server_lib.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SERVER_LIB_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SERVER_LIB_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SERVER_LIB_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SERVER_LIB_H_ #include @@ -95,4 +95,4 @@ Status NewServer(const ServerDef& server_def, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SERVER_LIB_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SERVER_LIB_H_ diff --git a/tensorflow/core/distributed_runtime/session_mgr.h b/tensorflow/core/distributed_runtime/session_mgr.h index ba077c3acc..3ce260d12e 100644 --- a/tensorflow/core/distributed_runtime/session_mgr.h +++ b/tensorflow/core/distributed_runtime/session_mgr.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SESSION_MGR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SESSION_MGR_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SESSION_MGR_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SESSION_MGR_H_ #include @@ -87,4 +87,4 @@ class SessionMgr { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SESSION_MGR_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_SESSION_MGR_H_ diff --git a/tensorflow/core/distributed_runtime/worker.h b/tensorflow/core/distributed_runtime/worker.h index c62347926f..62fa5f3cf5 100644 --- a/tensorflow/core/distributed_runtime/worker.h +++ b/tensorflow/core/distributed_runtime/worker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_H_ #include @@ -120,4 +120,4 @@ class Worker : public WorkerInterface { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_H_ diff --git a/tensorflow/core/distributed_runtime/worker_session.h b/tensorflow/core/distributed_runtime/worker_session.h index 9da3bb253f..0fd19ac27f 100644 --- a/tensorflow/core/distributed_runtime/worker_session.h +++ b/tensorflow/core/distributed_runtime/worker_session.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_SESSION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_SESSION_H_ +#ifndef TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_SESSION_H_ +#define TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_SESSION_H_ #include @@ -61,4 +61,4 @@ struct WorkerSession { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_SESSION_H_ +#endif // TENSORFLOW_CORE_DISTRIBUTED_RUNTIME_WORKER_SESSION_H_ diff --git a/tensorflow/core/example/example_parser_configuration.h b/tensorflow/core/example/example_parser_configuration.h index 69955ec4cb..3d06bd55e2 100644 --- a/tensorflow/core/example/example_parser_configuration.h +++ b/tensorflow/core/example/example_parser_configuration.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_EXAMPLE_EXAMPLE_PARSER_CONFIGURATION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_EXAMPLE_EXAMPLE_PARSER_CONFIGURATION_H_ +#ifndef TENSORFLOW_CORE_EXAMPLE_EXAMPLE_PARSER_CONFIGURATION_H_ +#define TENSORFLOW_CORE_EXAMPLE_EXAMPLE_PARSER_CONFIGURATION_H_ #include #include @@ -53,4 +53,4 @@ Status ExampleParserConfigurationProtoToFeatureVectors( } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_EXAMPLE_EXAMPLE_PARSE_CONFIGURATION_H_ +#endif // TENSORFLOW_CORE_EXAMPLE_EXAMPLE_PARSE_CONFIGURATION_H_ diff --git a/tensorflow/core/framework/common_shape_fns.h b/tensorflow/core/framework/common_shape_fns.h index c0deb473a2..293c40e04d 100644 --- a/tensorflow/core/framework/common_shape_fns.h +++ b/tensorflow/core/framework/common_shape_fns.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_OPS_COMMON_SHAPE_FNS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_OPS_COMMON_SHAPE_FNS_H_ +#ifndef TENSORFLOW_CORE_OPS_COMMON_SHAPE_FNS_H_ +#define TENSORFLOW_CORE_OPS_COMMON_SHAPE_FNS_H_ #include @@ -287,4 +287,4 @@ Status ExplicitShape(InferenceContext* c); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_OPS_COMMON_SHAPE_FNS_H_ +#endif // TENSORFLOW_CORE_OPS_COMMON_SHAPE_FNS_H_ diff --git a/tensorflow/core/framework/shape_inference.h b/tensorflow/core/framework/shape_inference.h index 4a4ef12635..d552ec1693 100644 --- a/tensorflow/core/framework/shape_inference.h +++ b/tensorflow/core/framework/shape_inference.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_H_ +#ifndef TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_H_ +#define TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_H_ #include @@ -787,4 +787,4 @@ Status InferenceContext::GetAttr(StringPiece attr_name, T* value) const { } // namespace shape_inference } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_H_ +#endif // TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_H_ diff --git a/tensorflow/core/framework/shape_inference_testutil.h b/tensorflow/core/framework/shape_inference_testutil.h index fbfd24538b..7977841482 100644 --- a/tensorflow/core/framework/shape_inference_testutil.h +++ b/tensorflow/core/framework/shape_inference_testutil.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_TESTUTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_TESTUTIL_H_ +#ifndef TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_TESTUTIL_H_ +#define TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_TESTUTIL_H_ #include #include "tensorflow/core/framework/node_def.pb.h" @@ -98,4 +98,4 @@ class ShapeInferenceTestutil { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_TESTUTIL_H_ +#endif // TENSORFLOW_CORE_FRAMEWORK_SHAPE_INFERENCE_TESTUTIL_H_ diff --git a/tensorflow/core/graph/gradients.h b/tensorflow/core/graph/gradients.h index 75906e6ce9..ddfed084b0 100644 --- a/tensorflow/core/graph/gradients.h +++ b/tensorflow/core/graph/gradients.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPH_GRADIENTS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_GRAPH_GRADIENTS_H_ +#ifndef TENSORFLOW_CORE_GRAPH_GRADIENTS_H_ +#define TENSORFLOW_CORE_GRAPH_GRADIENTS_H_ #include "tensorflow/core/graph/graph.h" #include "tensorflow/core/lib/core/status.h" @@ -55,4 +55,4 @@ Status AddSymbolicGradients(gtl::ArraySlice y_node_outputs, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPH_GRADIENTS_H_ +#endif // TENSORFLOW_CORE_GRAPH_GRADIENTS_H_ diff --git a/tensorflow/core/grappler/costs/op_context.h b/tensorflow/core/grappler/costs/op_context.h index 735a1e68ea..6391de4a91 100644 --- a/tensorflow/core/grappler/costs/op_context.h +++ b/tensorflow/core/grappler/costs/op_context.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_COSTS_OP_CONTEXT_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_COSTS_OP_CONTEXT_H_ +#ifndef TENSORFLOW_CORE_GRAPPLER_COSTS_OP_CONTEXT_H_ +#define TENSORFLOW_CORE_GRAPPLER_COSTS_OP_CONTEXT_H_ #include "tensorflow/core/framework/function.pb.h" #include "tensorflow/core/grappler/costs/op_performance_data.pb.h" @@ -36,4 +36,4 @@ struct OpContext { } // end namespace grappler } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_COSTS_OP_CONTEXT_H_ +#endif // TENSORFLOW_CORE_GRAPPLER_COSTS_OP_CONTEXT_H_ diff --git a/tensorflow/core/grappler/costs/virtual_scheduler.h b/tensorflow/core/grappler/costs/virtual_scheduler.h index c180250908..8ccc51f545 100644 --- a/tensorflow/core/grappler/costs/virtual_scheduler.h +++ b/tensorflow/core/grappler/costs/virtual_scheduler.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_COSTS_VIRTUAL_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_COSTS_VIRTUAL_SCHEDULER_H_ +#ifndef TENSORFLOW_CORE_GRAPPLER_COSTS_VIRTUAL_SCHEDULER_H_ +#define TENSORFLOW_CORE_GRAPPLER_COSTS_VIRTUAL_SCHEDULER_H_ #include #include @@ -342,4 +342,4 @@ class VirtualScheduler { } // namespace grappler } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_COSTS_VIRTUAL_SCHEDULER_H_ +#endif // TENSORFLOW_CORE_GRAPPLER_COSTS_VIRTUAL_SCHEDULER_H_ diff --git a/tensorflow/core/grappler/optimizers/dependency_optimizer.h b/tensorflow/core/grappler/optimizers/dependency_optimizer.h index 3f6f418bee..02d8a0f32a 100644 --- a/tensorflow/core/grappler/optimizers/dependency_optimizer.h +++ b/tensorflow/core/grappler/optimizers/dependency_optimizer.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_DEPENDENCY_OPTIMIZER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_DEPENDENCY_OPTIMIZER_H_ +#ifndef TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_DEPENDENCY_OPTIMIZER_H_ +#define TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_DEPENDENCY_OPTIMIZER_H_ #include #include "tensorflow/core/grappler/optimizers/graph_optimizer.h" @@ -73,4 +73,4 @@ class DependencyOptimizer : public GraphOptimizer { } // end namespace grappler } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_DEPENDENCY_OPTIMIZER_H_ +#endif // TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_DEPENDENCY_OPTIMIZER_H_ diff --git a/tensorflow/core/grappler/optimizers/static_schedule.h b/tensorflow/core/grappler/optimizers/static_schedule.h index aa2726a2bd..678b4d193f 100644 --- a/tensorflow/core/grappler/optimizers/static_schedule.h +++ b/tensorflow/core/grappler/optimizers/static_schedule.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_STATIC_SCHEDULE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_STATIC_SCHEDULE_H_ +#ifndef TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_STATIC_SCHEDULE_H_ +#define TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_STATIC_SCHEDULE_H_ #include @@ -47,4 +47,4 @@ Status EstimateRequiredTimes( } // namespace grappler } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_STATIC_SCHEDULE_H_ +#endif // TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_STATIC_SCHEDULE_H_ diff --git a/tensorflow/core/grappler/utils/frame.h b/tensorflow/core/grappler/utils/frame.h index be726ae795..95b72748f4 100644 --- a/tensorflow/core/grappler/utils/frame.h +++ b/tensorflow/core/grappler/utils/frame.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_FRAME_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_FRAME_H_ +#ifndef TENSORFLOW_CORE_GRAPPLER_UTILS_FRAME_H_ +#define TENSORFLOW_CORE_GRAPPLER_UTILS_FRAME_H_ #include #include "tensorflow/core/framework/graph.pb.h" @@ -40,4 +40,4 @@ Status IdentifyFramesWithNodeMap(const GraphDef& graph, const NodeMap& node_map, } // namespace grappler } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_FRAME_H_ +#endif // TENSORFLOW_CORE_GRAPPLER_UTILS_FRAME_H_ diff --git a/tensorflow/core/grappler/utils/scc.h b/tensorflow/core/grappler/utils/scc.h index 4e46169971..4fb7aab647 100644 --- a/tensorflow/core/grappler/utils/scc.h +++ b/tensorflow/core/grappler/utils/scc.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_SCC_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_SCC_H_ +#ifndef TENSORFLOW_CORE_GRAPPLER_UTILS_SCC_H_ +#define TENSORFLOW_CORE_GRAPPLER_UTILS_SCC_H_ #include #include "tensorflow/core/framework/graph.pb.h" @@ -43,4 +43,4 @@ int IdentifyLoops(const GraphDef& graph, } // namespace grappler } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_SCC_H_ +#endif // TENSORFLOW_CORE_GRAPPLER_UTILS_SCC_H_ diff --git a/tensorflow/core/grappler/utils/topological_sort.h b/tensorflow/core/grappler/utils/topological_sort.h index f2c9bbfa4e..7700fe41e4 100644 --- a/tensorflow/core/grappler/utils/topological_sort.h +++ b/tensorflow/core/grappler/utils/topological_sort.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_TOPOLOGICAL_SORT_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_TOPOLOGICAL_SORT_H_ +#ifndef TENSORFLOW_CORE_GRAPPLER_UTILS_TOPOLOGICAL_SORT_H_ +#define TENSORFLOW_CORE_GRAPPLER_UTILS_TOPOLOGICAL_SORT_H_ #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/lib/core/status.h" @@ -28,4 +28,4 @@ Status TopologicalSort(GraphDef* graph); } // namespace grappler } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPPLER_UTILS_TOPOLOGICAL_SORT_H_ +#endif // TENSORFLOW_CORE_GRAPPLER_UTILS_TOPOLOGICAL_SORT_H_ diff --git a/tensorflow/core/kernels/adjust_hsv_gpu.cu.h b/tensorflow/core/kernels/adjust_hsv_gpu.cu.h index c160ce2c33..49df5ae296 100644 --- a/tensorflow/core/kernels/adjust_hsv_gpu.cu.h +++ b/tensorflow/core/kernels/adjust_hsv_gpu.cu.h @@ -11,8 +11,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_ADJUST_HSV_GPU_CU_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_ADJUST_HSV_GPU_CU_H_ +#ifndef TENSORFLOW_CORE_KERNELS_ADJUST_HSV_GPU_CU_H_ +#define TENSORFLOW_CORE_KERNELS_ADJUST_HSV_GPU_CU_H_ #if GOOGLE_CUDA @@ -143,4 +143,4 @@ __global__ void adjust_hsv_nhwc(const int64 number_elements, } // namespace tensorflow #endif // GOOGLE_CUDA -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_ADJUST_HSV_GPU_CU_H_ +#endif // TENSORFLOW_CORE_KERNELS_ADJUST_HSV_GPU_CU_H_ diff --git a/tensorflow/core/kernels/batch_util.h b/tensorflow/core/kernels/batch_util.h index b066e2a574..0d634ae7b0 100644 --- a/tensorflow/core/kernels/batch_util.h +++ b/tensorflow/core/kernels/batch_util.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCH_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCH_UTIL_H_ +#ifndef TENSORFLOW_CORE_KERNELS_BATCH_UTIL_H_ +#define TENSORFLOW_CORE_KERNELS_BATCH_UTIL_H_ #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/lib/core/status.h" @@ -35,4 +35,4 @@ Status CopySliceToElement(const Tensor& parent, Tensor* element, int64 index); } // namespace batch_util } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCH_UTIL_H_ +#endif // TENSORFLOW_CORE_KERNELS_BATCH_UTIL_H_ diff --git a/tensorflow/core/kernels/batching_util/adaptive_shared_batch_scheduler.h b/tensorflow/core/kernels/batching_util/adaptive_shared_batch_scheduler.h index ff8ebb349f..25c5f9cf42 100644 --- a/tensorflow/core/kernels/batching_util/adaptive_shared_batch_scheduler.h +++ b/tensorflow/core/kernels/batching_util/adaptive_shared_batch_scheduler.h @@ -13,9 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ - +#ifndef TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ +#define TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ #include #include @@ -657,4 +656,4 @@ size_t ASBSQueue::SchedulingCapacity() const { } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ +#endif // TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_ADAPTIVE_SHARED_BATCH_SCHEDULER_H_ diff --git a/tensorflow/core/kernels/batching_util/basic_batch_scheduler.h b/tensorflow/core/kernels/batching_util/basic_batch_scheduler.h index 9207972100..2b5a991caf 100644 --- a/tensorflow/core/kernels/batching_util/basic_batch_scheduler.h +++ b/tensorflow/core/kernels/batching_util/basic_batch_scheduler.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BASIC_BATCH_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BASIC_BATCH_SCHEDULER_H_ +#ifndef TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BASIC_BATCH_SCHEDULER_H_ +#define TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BASIC_BATCH_SCHEDULER_H_ #include #include @@ -265,4 +265,4 @@ BasicBatchScheduler::BasicBatchScheduler( } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BASIC_BATCH_SCHEDULER_H_ +#endif // TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BASIC_BATCH_SCHEDULER_H_ diff --git a/tensorflow/core/kernels/batching_util/batch_scheduler.h b/tensorflow/core/kernels/batching_util/batch_scheduler.h index a5316f152b..f6d9a8f0c8 100644 --- a/tensorflow/core/kernels/batching_util/batch_scheduler.h +++ b/tensorflow/core/kernels/batching_util/batch_scheduler.h @@ -23,8 +23,8 @@ limitations under the License. // // This file defines an abstract BatchScheduler class. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BATCH_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BATCH_SCHEDULER_H_ +#ifndef TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BATCH_SCHEDULER_H_ +#define TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BATCH_SCHEDULER_H_ #include #include @@ -278,4 +278,4 @@ void Batch::Close() { } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BATCH_SCHEDULER_H_ +#endif // TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_BATCH_SCHEDULER_H_ diff --git a/tensorflow/core/kernels/batching_util/fake_clock_env.h b/tensorflow/core/kernels/batching_util/fake_clock_env.h index b2848afe07..60f1cbe7bd 100644 --- a/tensorflow/core/kernels/batching_util/fake_clock_env.h +++ b/tensorflow/core/kernels/batching_util/fake_clock_env.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_FAKE_CLOCK_ENV_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_FAKE_CLOCK_ENV_H_ +#ifndef TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_FAKE_CLOCK_ENV_H_ +#define TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_FAKE_CLOCK_ENV_H_ #include #include @@ -73,4 +73,4 @@ class FakeClockEnv : public EnvWrapper { } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_FAKE_CLOCK_ENV_H_ +#endif // TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_FAKE_CLOCK_ENV_H_ diff --git a/tensorflow/core/kernels/batching_util/periodic_function.h b/tensorflow/core/kernels/batching_util/periodic_function.h index 6811cd015e..dbf1733dcc 100644 --- a/tensorflow/core/kernels/batching_util/periodic_function.h +++ b/tensorflow/core/kernels/batching_util/periodic_function.h @@ -49,9 +49,8 @@ limitations under the License. // PeriodicFunction periodic_function_; // }; -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_PERIODIC_FUNCTION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_PERIODIC_FUNCTION_H_ - +#ifndef TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_PERIODIC_FUNCTION_H_ +#define TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_PERIODIC_FUNCTION_H_ #include "tensorflow/core/kernels/batching_util/periodic_function.h" @@ -132,4 +131,4 @@ class PeriodicFunction { } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_PERIODIC_FUNCTION_H_ +#endif // TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_PERIODIC_FUNCTION_H_ diff --git a/tensorflow/core/kernels/batching_util/shared_batch_scheduler.h b/tensorflow/core/kernels/batching_util/shared_batch_scheduler.h index 3736d8ef64..b77289aded 100644 --- a/tensorflow/core/kernels/batching_util/shared_batch_scheduler.h +++ b/tensorflow/core/kernels/batching_util/shared_batch_scheduler.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_SHARED_BATCH_SCHEDULER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_SHARED_BATCH_SCHEDULER_H_ +#ifndef TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_SHARED_BATCH_SCHEDULER_H_ +#define TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_SHARED_BATCH_SCHEDULER_H_ #include #include @@ -702,4 +702,4 @@ size_t QueueHandle::SchedulingCapacity() const { } // namespace serving } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_SHARED_BATCH_SCHEDULER_H_ +#endif // TENSORFLOW_CORE_KERNELS_BATCHING_UTIL_SHARED_BATCH_SCHEDULER_H_ diff --git a/tensorflow/core/kernels/bitcast_op.h b/tensorflow/core/kernels/bitcast_op.h index 0413569e79..900ab6f35c 100644 --- a/tensorflow/core/kernels/bitcast_op.h +++ b/tensorflow/core/kernels/bitcast_op.h @@ -15,8 +15,8 @@ limitations under the License. // See docs in ../ops/array_ops.cc. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BITCAST_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BITCAST_OP_H_ +#ifndef TENSORFLOW_CORE_KERNELS_BITCAST_OP_H_ +#define TENSORFLOW_CORE_KERNELS_BITCAST_OP_H_ #include // for memcpy @@ -27,4 +27,4 @@ limitations under the License. #include "tensorflow/core/framework/types.h" #include "tensorflow/core/lib/core/casts.h" -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_BITCAST_OP_H_ +#endif // TENSORFLOW_CORE_KERNELS_BITCAST_OP_H_ diff --git a/tensorflow/core/kernels/captured_function.h b/tensorflow/core/kernels/captured_function.h index cdf191f4c7..2d2d87134e 100644 --- a/tensorflow/core/kernels/captured_function.h +++ b/tensorflow/core/kernels/captured_function.h @@ -12,9 +12,9 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CAPTURED_FUNCTION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CAPTURED_FUNCTION_H_ +#ifndef TENSORFLOW_CORE_KERNELS_CAPTURED_FUNCTION_H_ +#define TENSORFLOW_CORE_KERNELS_CAPTURED_FUNCTION_H_ #include "tensorflow/core/kernels/data/captured_function.h" -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CAPTURED_FUNCTION_H_ +#endif // TENSORFLOW_CORE_KERNELS_CAPTURED_FUNCTION_H_ diff --git a/tensorflow/core/kernels/cast_op_impl.h b/tensorflow/core/kernels/cast_op_impl.h index 6309e4a4dc..470e9e0804 100644 --- a/tensorflow/core/kernels/cast_op_impl.h +++ b/tensorflow/core/kernels/cast_op_impl.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CAST_OP_IMPL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CAST_OP_IMPL_H_ +#ifndef TENSORFLOW_CORE_KERNELS_CAST_OP_IMPL_H_ +#define TENSORFLOW_CORE_KERNELS_CAST_OP_IMPL_H_ #define EIGEN_USE_THREADS @@ -181,4 +181,4 @@ GetSyclCastFromDouble(DataType dst_dtype); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CAST_OP_IMPL_H_ +#endif // TENSORFLOW_CORE_KERNELS_CAST_OP_IMPL_H_ diff --git a/tensorflow/core/kernels/compare_and_bitpack_op.h b/tensorflow/core/kernels/compare_and_bitpack_op.h index 8e020249c1..af8566c7ce 100644 --- a/tensorflow/core/kernels/compare_and_bitpack_op.h +++ b/tensorflow/core/kernels/compare_and_bitpack_op.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_COMPARE_AND_BITPACK_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_COMPARE_AND_BITPACK_OP_H_ +#ifndef TENSORFLOW_CORE_KERNELS_COMPARE_AND_BITPACK_OP_H_ +#define TENSORFLOW_CORE_KERNELS_COMPARE_AND_BITPACK_OP_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/framework/op_kernel.h" @@ -39,4 +39,4 @@ struct CompareAndBitpack { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_COMPARE_AND_BITPACK_OP_H_ +#endif // TENSORFLOW_CORE_KERNELS_COMPARE_AND_BITPACK_OP_H_ diff --git a/tensorflow/core/kernels/cuda_device_array.h b/tensorflow/core/kernels/cuda_device_array.h index a570993cf8..e7a5db0683 100644 --- a/tensorflow/core/kernels/cuda_device_array.h +++ b/tensorflow/core/kernels/cuda_device_array.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_H_ +#ifndef TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_H_ +#define TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_H_ #if GOOGLE_CUDA @@ -117,4 +117,4 @@ class CudaDeviceArrayOnHost { #endif // GOOGLE_CUDA -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_H_ +#endif // TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_H_ diff --git a/tensorflow/core/kernels/cuda_device_array_gpu.h b/tensorflow/core/kernels/cuda_device_array_gpu.h index 220f762636..64fa3cb806 100644 --- a/tensorflow/core/kernels/cuda_device_array_gpu.h +++ b/tensorflow/core/kernels/cuda_device_array_gpu.h @@ -15,8 +15,8 @@ limitations under the License. // Contains structs and functions to be included in device code. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_GPU_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_GPU_H_ +#ifndef TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_GPU_H_ +#define TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_GPU_H_ #if GOOGLE_CUDA @@ -47,4 +47,4 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ValueType* GetCudaDeviceArrayOnDevice( #endif // GOOGLE_CUDA -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_GPU_H_ +#endif // TENSORFLOW_CORE_KERNELS_CUDA_DEVICE_ARRAY_GPU_H_ diff --git a/tensorflow/core/kernels/data/captured_function.h b/tensorflow/core/kernels/data/captured_function.h index 99e0ef426e..32d2bc3aae 100644 --- a/tensorflow/core/kernels/data/captured_function.h +++ b/tensorflow/core/kernels/data/captured_function.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_ +#define TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_ #include #include @@ -105,4 +105,4 @@ class CapturedFunction { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATA_CAPTURED_FUNCTION_H_ diff --git a/tensorflow/core/kernels/data/dataset.h b/tensorflow/core/kernels/data/dataset.h index fbaaf22527..2ef31ddfaa 100644 --- a/tensorflow/core/kernels/data/dataset.h +++ b/tensorflow/core/kernels/data/dataset.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_DATASET_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_DATASET_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATA_DATASET_H_ +#define TENSORFLOW_CORE_KERNELS_DATA_DATASET_H_ #include @@ -606,4 +606,4 @@ Status StoreDatasetInVariantTensor(DatasetBase* dataset, Tensor* tensor); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_DATASET_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATA_DATASET_H_ diff --git a/tensorflow/core/kernels/data/dataset_utils.h b/tensorflow/core/kernels/data/dataset_utils.h index 40bc873584..6c4191c2be 100644 --- a/tensorflow/core/kernels/data/dataset_utils.h +++ b/tensorflow/core/kernels/data/dataset_utils.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_DATASET_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_DATASET_UTILS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATA_DATASET_UTILS_H_ +#define TENSORFLOW_CORE_KERNELS_DATA_DATASET_UTILS_H_ #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/kernels/data/captured_function.h" @@ -32,4 +32,4 @@ Status MakeIteratorFromInputElement( } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_DATASET_UTILS_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATA_DATASET_UTILS_H_ diff --git a/tensorflow/core/kernels/data/sql/driver_manager.h b/tensorflow/core/kernels/data/sql/driver_manager.h index 0d0c38eb58..a34691b5a2 100644 --- a/tensorflow/core/kernels/data/sql/driver_manager.h +++ b/tensorflow/core/kernels/data/sql/driver_manager.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_DRIVER_MANAGER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_DRIVER_MANAGER_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATA_SQL_DRIVER_MANAGER_H_ +#define TENSORFLOW_CORE_KERNELS_DATA_SQL_DRIVER_MANAGER_H_ #include "tensorflow/core/kernels/data/sql/query_connection.h" @@ -38,4 +38,4 @@ class DriverManager { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_DRIVER_MANAGER_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATA_SQL_DRIVER_MANAGER_H_ diff --git a/tensorflow/core/kernels/data/sql/query_connection.h b/tensorflow/core/kernels/data/sql/query_connection.h index 1947148972..f31017bd19 100644 --- a/tensorflow/core/kernels/data/sql/query_connection.h +++ b/tensorflow/core/kernels/data/sql/query_connection.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_QUERY_CONNECTION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_QUERY_CONNECTION_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATA_SQL_QUERY_CONNECTION_H_ +#define TENSORFLOW_CORE_KERNELS_DATA_SQL_QUERY_CONNECTION_H_ #include "tensorflow/core/framework/tensor.h" @@ -64,4 +64,4 @@ class QueryConnection { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_QUERY_CONNECTION_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATA_SQL_QUERY_CONNECTION_H_ diff --git a/tensorflow/core/kernels/data/sql/sqlite_query_connection.h b/tensorflow/core/kernels/data/sql/sqlite_query_connection.h index b36b69eae4..787c17d6c0 100644 --- a/tensorflow/core/kernels/data/sql/sqlite_query_connection.h +++ b/tensorflow/core/kernels/data/sql/sqlite_query_connection.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_SQLITE_QUERY_CONNECTION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_SQLITE_QUERY_CONNECTION_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATA_SQL_SQLITE_QUERY_CONNECTION_H_ +#define TENSORFLOW_CORE_KERNELS_DATA_SQL_SQLITE_QUERY_CONNECTION_H_ #include @@ -53,4 +53,4 @@ class SqliteQueryConnection : public QueryConnection { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_SQL_SQLITE_QUERY_CONNECTION_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATA_SQL_SQLITE_QUERY_CONNECTION_H_ diff --git a/tensorflow/core/kernels/data/stats_aggregator.h b/tensorflow/core/kernels/data/stats_aggregator.h index 4cb8dba5cb..076a56b0bf 100644 --- a/tensorflow/core/kernels/data/stats_aggregator.h +++ b/tensorflow/core/kernels/data/stats_aggregator.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_STATS_AGGREGATOR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_STATS_AGGREGATOR_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATA_STATS_AGGREGATOR_H_ +#define TENSORFLOW_CORE_KERNELS_DATA_STATS_AGGREGATOR_H_ #include #include @@ -81,4 +81,4 @@ class StatsAggregatorResource : public ResourceBase { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_STATS_AGGREGATOR_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATA_STATS_AGGREGATOR_H_ diff --git a/tensorflow/core/kernels/data/window_dataset.h b/tensorflow/core/kernels/data/window_dataset.h index 25396bd3e7..97c31668ac 100644 --- a/tensorflow/core/kernels/data/window_dataset.h +++ b/tensorflow/core/kernels/data/window_dataset.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_WINDOW_DATASET_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_WINDOW_DATASET_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATA_WINDOW_DATASET_H_ +#define TENSORFLOW_CORE_KERNELS_DATA_WINDOW_DATASET_H_ #include @@ -45,4 +45,4 @@ Status NewWindowDataset(std::vector> elements, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATA_WINDOW_DATASET_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATA_WINDOW_DATASET_H_ diff --git a/tensorflow/core/kernels/dataset.h b/tensorflow/core/kernels/dataset.h index 2aa6dbe6f3..69ab78d635 100644 --- a/tensorflow/core/kernels/dataset.h +++ b/tensorflow/core/kernels/dataset.h @@ -12,9 +12,9 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATASET_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATASET_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DATASET_H_ +#define TENSORFLOW_CORE_KERNELS_DATASET_H_ #include "tensorflow/core/kernels/data/dataset.h" -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DATASET_H_ +#endif // TENSORFLOW_CORE_KERNELS_DATASET_H_ diff --git a/tensorflow/core/kernels/deep_conv2d.h b/tensorflow/core/kernels/deep_conv2d.h index c3f6f66dc9..17a0230516 100644 --- a/tensorflow/core/kernels/deep_conv2d.h +++ b/tensorflow/core/kernels/deep_conv2d.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DEEP_CONV2D_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DEEP_CONV2D_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DEEP_CONV2D_H_ +#define TENSORFLOW_CORE_KERNELS_DEEP_CONV2D_H_ #include "tensorflow/core/framework/types.h" @@ -114,4 +114,4 @@ struct DeepConv2D { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DEEP_CONV2D_H_ +#endif // TENSORFLOW_CORE_KERNELS_DEEP_CONV2D_H_ diff --git a/tensorflow/core/kernels/depthwise_conv_op.h b/tensorflow/core/kernels/depthwise_conv_op.h index 097a9f5bfa..ba262d56ee 100644 --- a/tensorflow/core/kernels/depthwise_conv_op.h +++ b/tensorflow/core/kernels/depthwise_conv_op.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DEPTHWISE_CONV_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DEPTHWISE_CONV_OP_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DEPTHWISE_CONV_OP_H_ +#define TENSORFLOW_CORE_KERNELS_DEPTHWISE_CONV_OP_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/framework/types.h" @@ -284,4 +284,4 @@ struct DepthwiseInputCopyOp { } // namespace functor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DEPTHWISE_CONV_OP_H_ +#endif // TENSORFLOW_CORE_KERNELS_DEPTHWISE_CONV_OP_H_ diff --git a/tensorflow/core/kernels/determinant_op.h b/tensorflow/core/kernels/determinant_op.h index e931e328e4..eefdfe0ae4 100644 --- a/tensorflow/core/kernels/determinant_op.h +++ b/tensorflow/core/kernels/determinant_op.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DETERMINANT_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DETERMINANT_OP_H_ +#ifndef TENSORFLOW_CORE_KERNELS_DETERMINANT_OP_H_ +#define TENSORFLOW_CORE_KERNELS_DETERMINANT_OP_H_ #include "tensorflow/core/framework/tensor_types.h" @@ -44,4 +44,4 @@ struct LogDeterminantFromPivotedLUFunctor { } // namespace functor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_DETERMINANT_OP_H_ +#endif // TENSORFLOW_CORE_KERNELS_DETERMINANT_OP_H_ diff --git a/tensorflow/core/kernels/eigen_activations.h b/tensorflow/core/kernels/eigen_activations.h index 57c8157b87..99b4b2abe6 100644 --- a/tensorflow/core/kernels/eigen_activations.h +++ b/tensorflow/core/kernels/eigen_activations.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_ACTIVATIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_ACTIVATIONS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_ACTIVATIONS_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_ACTIVATIONS_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" @@ -122,4 +122,4 @@ struct functor_traits > { } // end namespace Eigen -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_ACTIVATIONS_H_ +#endif // TENSORFLOW_CORE_KERNELS_EIGEN_ACTIVATIONS_H_ diff --git a/tensorflow/core/kernels/eigen_attention.h b/tensorflow/core/kernels/eigen_attention.h index f4c42372b1..3a94b8c993 100644 --- a/tensorflow/core/kernels/eigen_attention.h +++ b/tensorflow/core/kernels/eigen_attention.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_ATTENTION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_ATTENTION_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_ATTENTION_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_ATTENTION_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" @@ -239,4 +239,4 @@ ExtractGlimpses(const Input& input, } // end namespace Eigen -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_ATTENTION_H_ +#endif // TENSORFLOW_CORE_KERNELS_EIGEN_ATTENTION_H_ diff --git a/tensorflow/core/kernels/eigen_backward_cuboid_convolutions.h b/tensorflow/core/kernels/eigen_backward_cuboid_convolutions.h index a44e7197a9..e13e548f86 100644 --- a/tensorflow/core/kernels/eigen_backward_cuboid_convolutions.h +++ b/tensorflow/core/kernels/eigen_backward_cuboid_convolutions.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_CUBOID_CONVOLUTIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_CUBOID_CONVOLUTIONS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_CUBOID_CONVOLUTIONS_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_CUBOID_CONVOLUTIONS_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/kernels/eigen_volume_patch.h" @@ -617,4 +617,4 @@ CuboidConvolutionBackwardKernel( } // end namespace Eigen -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_CUBOID_CONVOLUTIONS_H_ +#endif // TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_CUBOID_CONVOLUTIONS_H_ diff --git a/tensorflow/core/kernels/eigen_backward_spatial_convolutions.h b/tensorflow/core/kernels/eigen_backward_spatial_convolutions.h index d172de8e18..aec7697810 100644 --- a/tensorflow/core/kernels/eigen_backward_spatial_convolutions.h +++ b/tensorflow/core/kernels/eigen_backward_spatial_convolutions.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_SPATIAL_CONVOLUTIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_SPATIAL_CONVOLUTIONS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_SPATIAL_CONVOLUTIONS_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_BACKWARD_SPATIAL_CONVOLUTIONS_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" diff --git a/tensorflow/core/kernels/eigen_cuboid_convolution.h b/tensorflow/core/kernels/eigen_cuboid_convolution.h index 2dca664a86..62e9f9123d 100644 --- a/tensorflow/core/kernels/eigen_cuboid_convolution.h +++ b/tensorflow/core/kernels/eigen_cuboid_convolution.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_CUBOID_CONVOLUTION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_CUBOID_CONVOLUTION_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_CUBOID_CONVOLUTION_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_CUBOID_CONVOLUTION_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/kernels/eigen_volume_patch.h" @@ -224,4 +224,4 @@ CuboidConvolution(const Input& input, const Kernel& kernel, } // end namespace Eigen -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_CUBOID_CONVOLUTION_H_ +#endif // TENSORFLOW_CORE_KERNELS_EIGEN_CUBOID_CONVOLUTION_H_ diff --git a/tensorflow/core/kernels/eigen_pooling.h b/tensorflow/core/kernels/eigen_pooling.h index 94100d71ec..972036833f 100644 --- a/tensorflow/core/kernels/eigen_pooling.h +++ b/tensorflow/core/kernels/eigen_pooling.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_POOLING_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_POOLING_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_POOLING_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_POOLING_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/kernels/eigen_volume_patch.h" @@ -610,4 +610,4 @@ CuboidAvgPooling(const Input& input, DenseIndex patchPlanes, } // end namespace Eigen -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_POOLING_H_ +#endif // TENSORFLOW_CORE_KERNELS_EIGEN_POOLING_H_ diff --git a/tensorflow/core/kernels/eigen_softmax.h b/tensorflow/core/kernels/eigen_softmax.h index 20bb8a44dd..a2930a726f 100644 --- a/tensorflow/core/kernels/eigen_softmax.h +++ b/tensorflow/core/kernels/eigen_softmax.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_SOFTMAX_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_SOFTMAX_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_SOFTMAX_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_SOFTMAX_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" @@ -87,4 +87,4 @@ SoftMax(const Input& input, const float beta) } // end namespace Eigen -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_SOFTMAX_H_ +#endif // TENSORFLOW_CORE_KERNELS_EIGEN_SOFTMAX_H_ diff --git a/tensorflow/core/kernels/eigen_spatial_convolutions.h b/tensorflow/core/kernels/eigen_spatial_convolutions.h index 7702f3e70a..2fe64cd72a 100644 --- a/tensorflow/core/kernels/eigen_spatial_convolutions.h +++ b/tensorflow/core/kernels/eigen_spatial_convolutions.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_SPATIAL_CONVOLUTIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_SPATIAL_CONVOLUTIONS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_SPATIAL_CONVOLUTIONS_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_SPATIAL_CONVOLUTIONS_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" @@ -1069,4 +1069,4 @@ EIGEN_DEVICE_FUNC } // end namespace Eigen -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_SPATIAL_CONVOLUTIONS_H_ +#endif // TENSORFLOW_CORE_KERNELS_EIGEN_SPATIAL_CONVOLUTIONS_H_ diff --git a/tensorflow/core/kernels/eigen_volume_patch.h b/tensorflow/core/kernels/eigen_volume_patch.h index afd5f37e35..a3d795813d 100644 --- a/tensorflow/core/kernels/eigen_volume_patch.h +++ b/tensorflow/core/kernels/eigen_volume_patch.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_VOLUME_PATCH_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_VOLUME_PATCH_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EIGEN_VOLUME_PATCH_H_ +#define TENSORFLOW_CORE_KERNELS_EIGEN_VOLUME_PATCH_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" @@ -653,4 +653,4 @@ OVERRIDE_EVALUATOR(Eigen::DefaultDevice); }; // namespace Eigen -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EIGEN_VOLUME_PATCH_H_ +#endif // TENSORFLOW_CORE_KERNELS_EIGEN_VOLUME_PATCH_H_ diff --git a/tensorflow/core/kernels/eye_functor.h b/tensorflow/core/kernels/eye_functor.h index 70f093f813..3799cfba9a 100644 --- a/tensorflow/core/kernels/eye_functor.h +++ b/tensorflow/core/kernels/eye_functor.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EYE_FUNCTOR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EYE_FUNCTOR_H_ +#ifndef TENSORFLOW_CORE_KERNELS_EYE_FUNCTOR_H_ +#define TENSORFLOW_CORE_KERNELS_EYE_FUNCTOR_H_ #include "tensorflow/core/framework/tensor_types.h" @@ -29,4 +29,4 @@ struct EyeFunctor { } // namespace functor } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_EYE_FUNCTOR_H_ +#endif // TENSORFLOW_CORE_KERNELS_EYE_FUNCTOR_H_ diff --git a/tensorflow/core/kernels/fake_quant_ops_functor.h b/tensorflow/core/kernels/fake_quant_ops_functor.h index 7aaad6e6c7..81189866c3 100644 --- a/tensorflow/core/kernels/fake_quant_ops_functor.h +++ b/tensorflow/core/kernels/fake_quant_ops_functor.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_FAKE_QUANT_FUNCTOR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_FAKE_QUANT_FUNCTOR_H_ +#ifndef TENSORFLOW_CORE_KERNELS_FAKE_QUANT_FUNCTOR_H_ +#define TENSORFLOW_CORE_KERNELS_FAKE_QUANT_FUNCTOR_H_ #include @@ -277,4 +277,4 @@ struct FakeQuantWithMinMaxVarsPerChannelGradientFunctor { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_FAKE_QUANT_FUNCTOR_H_ +#endif // TENSORFLOW_CORE_KERNELS_FAKE_QUANT_FUNCTOR_H_ diff --git a/tensorflow/core/kernels/gather_functor_gpu.cu.h b/tensorflow/core/kernels/gather_functor_gpu.cu.h index a50b51b54b..11ea63d730 100644 --- a/tensorflow/core/kernels/gather_functor_gpu.cu.h +++ b/tensorflow/core/kernels/gather_functor_gpu.cu.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_GATHER_FUNCTOR_GPU_CU_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_GATHER_FUNCTOR_GPU_CU_H_ +#ifndef TENSORFLOW_CORE_KERNELS_GATHER_FUNCTOR_GPU_CU_H_ +#define TENSORFLOW_CORE_KERNELS_GATHER_FUNCTOR_GPU_CU_H_ #if GOOGLE_CUDA @@ -118,4 +118,4 @@ struct GatherFunctor { #endif // GOOGLE_CUDA -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_GATHER_FUNCTOR_GPU_CU_H_ +#endif // TENSORFLOW_CORE_KERNELS_GATHER_FUNCTOR_GPU_CU_H_ diff --git a/tensorflow/core/kernels/gpu_utils.h b/tensorflow/core/kernels/gpu_utils.h index 366877bcf5..ffc733e6bb 100644 --- a/tensorflow/core/kernels/gpu_utils.h +++ b/tensorflow/core/kernels/gpu_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_GPU_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_GPU_UTILS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_GPU_UTILS_H_ +#define TENSORFLOW_CORE_KERNELS_GPU_UTILS_H_ #if GOOGLE_CUDA @@ -162,4 +162,4 @@ class AutoTuneSingleton { #endif // GOOGLE_CUDA -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_GPU_UTILS_H_ +#endif // TENSORFLOW_CORE_KERNELS_GPU_UTILS_H_ diff --git a/tensorflow/core/kernels/hexagon/graph_transferer.h b/tensorflow/core/kernels/hexagon/graph_transferer.h index 125d1fd200..a360d188cc 100644 --- a/tensorflow/core/kernels/hexagon/graph_transferer.h +++ b/tensorflow/core/kernels/hexagon/graph_transferer.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_GRAPH_TRANSFERER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_GRAPH_TRANSFERER_H_ +#ifndef TENSORFLOW_CORE_KERNELS_HEXAGON_GRAPH_TRANSFERER_H_ +#define TENSORFLOW_CORE_KERNELS_HEXAGON_GRAPH_TRANSFERER_H_ #include #include @@ -225,4 +225,4 @@ class GraphTransferer { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_GRAPH_TRANSFERER_H +#endif // TENSORFLOW_CORE_KERNELS_HEXAGON_GRAPH_TRANSFERER_H diff --git a/tensorflow/core/kernels/hexagon/hexagon_control_wrapper.h b/tensorflow/core/kernels/hexagon/hexagon_control_wrapper.h index 8eb3995fc4..dca1f94a9b 100644 --- a/tensorflow/core/kernels/hexagon/hexagon_control_wrapper.h +++ b/tensorflow/core/kernels/hexagon/hexagon_control_wrapper.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_CONTROL_WRAPPER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_CONTROL_WRAPPER_H_ +#ifndef TENSORFLOW_CORE_KERNELS_HEXAGON_CONTROL_WRAPPER_H_ +#define TENSORFLOW_CORE_KERNELS_HEXAGON_CONTROL_WRAPPER_H_ #include #include @@ -88,4 +88,4 @@ class HexagonControlWrapper final : public IRemoteFusedGraphExecutor { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_CONTROL_WRAPPER_H_ +#endif // TENSORFLOW_CORE_KERNELS_HEXAGON_CONTROL_WRAPPER_H_ diff --git a/tensorflow/core/kernels/hexagon/hexagon_ops_definitions.h b/tensorflow/core/kernels/hexagon/hexagon_ops_definitions.h index 993a5f9a3a..b9328c8e0e 100644 --- a/tensorflow/core/kernels/hexagon/hexagon_ops_definitions.h +++ b/tensorflow/core/kernels/hexagon/hexagon_ops_definitions.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_HEXAGON_OPS_DEFINITIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_HEXAGON_OPS_DEFINITIONS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_HEXAGON_HEXAGON_OPS_DEFINITIONS_H_ +#define TENSORFLOW_CORE_KERNELS_HEXAGON_HEXAGON_OPS_DEFINITIONS_H_ #include @@ -55,4 +55,4 @@ class HexagonOpsDefinitions final : public IRemoteFusedGraphOpsDefinitions { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_HEXAGON_HEXAGON_OPS_DEFINITIONS_H +#endif // TENSORFLOW_CORE_KERNELS_HEXAGON_HEXAGON_OPS_DEFINITIONS_H diff --git a/tensorflow/core/kernels/i_remote_fused_graph_executor.h b/tensorflow/core/kernels/i_remote_fused_graph_executor.h index 05b76172b2..eb6b64da58 100644 --- a/tensorflow/core/kernels/i_remote_fused_graph_executor.h +++ b/tensorflow/core/kernels/i_remote_fused_graph_executor.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_I_REMOTE_GRAPH_EXECUTOR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_I_REMOTE_GRAPH_EXECUTOR_H_ +#ifndef TENSORFLOW_CORE_KERNELS_I_REMOTE_GRAPH_EXECUTOR_H_ +#define TENSORFLOW_CORE_KERNELS_I_REMOTE_GRAPH_EXECUTOR_H_ #include "tensorflow/core/framework/remote_fused_graph_execute_info.pb.h" #include "tensorflow/core/framework/tensor.h" @@ -72,4 +72,4 @@ class IRemoteFusedGraphExecutor { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_I_REMOTE_GRAPH_EXECUTOR_H_ +#endif // TENSORFLOW_CORE_KERNELS_I_REMOTE_GRAPH_EXECUTOR_H_ diff --git a/tensorflow/core/kernels/i_remote_fused_graph_ops_definitions.h b/tensorflow/core/kernels/i_remote_fused_graph_ops_definitions.h index 7d3329f490..9e51c9f51f 100644 --- a/tensorflow/core/kernels/i_remote_fused_graph_ops_definitions.h +++ b/tensorflow/core/kernels/i_remote_fused_graph_ops_definitions.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_I_REMOTE_FUSED_GRAPH_OPS_DEFINITIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_I_REMOTE_FUSED_GRAPH_OPS_DEFINITIONS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_I_REMOTE_FUSED_GRAPH_OPS_DEFINITIONS_H_ +#define TENSORFLOW_CORE_KERNELS_I_REMOTE_FUSED_GRAPH_OPS_DEFINITIONS_H_ #include "tensorflow/core/framework/types.h" #include "tensorflow/core/platform/macros.h" @@ -43,4 +43,4 @@ class IRemoteFusedGraphOpsDefinitions { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_I_REMOTE_FUSED_GRAPH_OPS_DEFINITIONS_H_ +#endif // TENSORFLOW_CORE_KERNELS_I_REMOTE_FUSED_GRAPH_OPS_DEFINITIONS_H_ diff --git a/tensorflow/core/kernels/list_kernels.h b/tensorflow/core/kernels/list_kernels.h index 1e6cbfebbe..9733883001 100644 --- a/tensorflow/core/kernels/list_kernels.h +++ b/tensorflow/core/kernels/list_kernels.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_ +#define TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_ #define EIGEN_USE_THREADS #if GOOGLE_CUDA @@ -270,4 +270,4 @@ Status TensorListZerosLike(OpKernelContext* c, const TensorList& x, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_ +#endif // TENSORFLOW_CORE_KERNELS_LIST_KERNELS_H_ diff --git a/tensorflow/core/kernels/meta_support.h b/tensorflow/core/kernels/meta_support.h index 53aece78e8..97f39eb598 100644 --- a/tensorflow/core/kernels/meta_support.h +++ b/tensorflow/core/kernels/meta_support.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_QUANTIZATION_KERNELS_META_SUPPORT_H_ -#define THIRD_PARTY_TENSORFLOW_CONTRIB_QUANTIZATION_KERNELS_META_SUPPORT_H_ +#ifndef TENSORFLOW_CONTRIB_QUANTIZATION_KERNELS_META_SUPPORT_H_ +#define TENSORFLOW_CONTRIB_QUANTIZATION_KERNELS_META_SUPPORT_H_ #include "meta/multi_thread_gemm.h" #include "meta/multi_thread_transform.h" @@ -109,4 +109,4 @@ void Clamp(OpKernelContext* context, const quint8* input, int input_count, } // namespace meta } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_QUANTIZATION_KERNELS_META_SUPPORT_H_ +#endif // TENSORFLOW_CONTRIB_QUANTIZATION_KERNELS_META_SUPPORT_H_ diff --git a/tensorflow/core/kernels/mfcc.h b/tensorflow/core/kernels/mfcc.h index 0d5d9fb90f..8268f47203 100644 --- a/tensorflow/core/kernels/mfcc.h +++ b/tensorflow/core/kernels/mfcc.h @@ -15,8 +15,8 @@ limitations under the License. // Basic class for computing MFCCs from spectrogram slices. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_H_ +#ifndef TENSORFLOW_CORE_KERNELS_MFCC_H_ +#define TENSORFLOW_CORE_KERNELS_MFCC_H_ #include @@ -74,4 +74,4 @@ class Mfcc { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_H_ +#endif // TENSORFLOW_CORE_KERNELS_MFCC_H_ diff --git a/tensorflow/core/kernels/mfcc_dct.h b/tensorflow/core/kernels/mfcc_dct.h index 4fa3c01628..888b8e8df8 100644 --- a/tensorflow/core/kernels/mfcc_dct.h +++ b/tensorflow/core/kernels/mfcc_dct.h @@ -15,8 +15,8 @@ limitations under the License. // Basic minimal DCT class for MFCC speech processing. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_DCT_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_DCT_H_ +#ifndef TENSORFLOW_CORE_KERNELS_MFCC_DCT_H_ +#define TENSORFLOW_CORE_KERNELS_MFCC_DCT_H_ #include @@ -41,4 +41,4 @@ class MfccDct { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_DCT_H_ +#endif // TENSORFLOW_CORE_KERNELS_MFCC_DCT_H_ diff --git a/tensorflow/core/kernels/mfcc_mel_filterbank.h b/tensorflow/core/kernels/mfcc_mel_filterbank.h index a766a20cbc..1bdc2dc93b 100644 --- a/tensorflow/core/kernels/mfcc_mel_filterbank.h +++ b/tensorflow/core/kernels/mfcc_mel_filterbank.h @@ -15,8 +15,8 @@ limitations under the License. // Basic class for applying a mel-scale mapping to a power spectrum. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_MEL_FILTERBANK_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_MEL_FILTERBANK_H_ +#ifndef TENSORFLOW_CORE_KERNELS_MFCC_MEL_FILTERBANK_H_ +#define TENSORFLOW_CORE_KERNELS_MFCC_MEL_FILTERBANK_H_ #include #include "tensorflow/core/framework/op_kernel.h" @@ -63,4 +63,4 @@ class MfccMelFilterbank { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_MFCC_MEL_FILTERBANK_H_ +#endif // TENSORFLOW_CORE_KERNELS_MFCC_MEL_FILTERBANK_H_ diff --git a/tensorflow/core/kernels/mirror_pad_op_cpu_impl.h b/tensorflow/core/kernels/mirror_pad_op_cpu_impl.h index bb22b2aa91..6716a26fac 100644 --- a/tensorflow/core/kernels/mirror_pad_op_cpu_impl.h +++ b/tensorflow/core/kernels/mirror_pad_op_cpu_impl.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_MIRROR_PAD_OP_CPU_IMPL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_MIRROR_PAD_OP_CPU_IMPL_H_ +#ifndef TENSORFLOW_CORE_MIRROR_PAD_OP_CPU_IMPL_H_ +#define TENSORFLOW_CORE_MIRROR_PAD_OP_CPU_IMPL_H_ #define EIGEN_USE_THREADS @@ -41,4 +41,4 @@ TF_CALL_NUMBER_TYPES(DEFINE_CPU_SPECS); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_MIRROR_PAD_OP_CPU_IMPL_H_ +#endif // TENSORFLOW_CORE_MIRROR_PAD_OP_CPU_IMPL_H_ diff --git a/tensorflow/core/kernels/neon/depthwiseconv_float.h b/tensorflow/core/kernels/neon/depthwiseconv_float.h index acd58a644f..11f5be7c03 100644 --- a/tensorflow/core/kernels/neon/depthwiseconv_float.h +++ b/tensorflow/core/kernels/neon/depthwiseconv_float.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NEON_DEPTHWISECONV_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NEON_DEPTHWISECONV_H_ +#ifndef TENSORFLOW_CORE_KERNELS_NEON_DEPTHWISECONV_H_ +#define TENSORFLOW_CORE_KERNELS_NEON_DEPTHWISECONV_H_ #include "public/gemmlowp.h" #include "tensorflow/core/kernels/neon/types.h" @@ -722,4 +722,4 @@ void DepthwiseConv(const float* input_data, const Dims<4>& input_dims, } // end namespace neon } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NEON_DEPTHWISECONV_H_ +#endif // TENSORFLOW_CORE_KERNELS_NEON_DEPTHWISECONV_H_ diff --git a/tensorflow/core/kernels/neon/types.h b/tensorflow/core/kernels/neon/types.h index 4ece22f015..05ff1bcc6c 100644 --- a/tensorflow/core/kernels/neon/types.h +++ b/tensorflow/core/kernels/neon/types.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NEON_TYPES_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NEON_TYPES_H_ +#ifndef TENSORFLOW_CORE_KERNELS_NEON_TYPES_H_ +#define TENSORFLOW_CORE_KERNELS_NEON_TYPES_H_ #include "tensorflow/core/platform/logging.h" @@ -70,4 +70,4 @@ inline int RequiredBufferSizeForDims(const Dims<4>& dims) { } // end namespace neon } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_NEON_TYPES_H_ +#endif // TENSORFLOW_CORE_KERNELS_NEON_TYPES_H_ diff --git a/tensorflow/core/kernels/population_count_op.h b/tensorflow/core/kernels/population_count_op.h index de89582e13..2c98129673 100644 --- a/tensorflow/core/kernels/population_count_op.h +++ b/tensorflow/core/kernels/population_count_op.h @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_POPULATION_COUNT_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_POPULATION_COUNT_OP_H_ +#ifndef TENSORFLOW_CORE_KERNELS_POPULATION_COUNT_OP_H_ +#define TENSORFLOW_CORE_KERNELS_POPULATION_COUNT_OP_H_ #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/tensor_types.h" @@ -35,4 +35,4 @@ struct PopulationCount { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_POPULATION_COUNT_OP_H_ +#endif // TENSORFLOW_CORE_KERNELS_POPULATION_COUNT_OP_H_ diff --git a/tensorflow/core/kernels/quantization_utils.h b/tensorflow/core/kernels/quantization_utils.h index 7c18496357..9fafe6bb65 100644 --- a/tensorflow/core/kernels/quantization_utils.h +++ b/tensorflow/core/kernels/quantization_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_QUANTIZATION_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_QUANTIZATION_UTILS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_QUANTIZATION_UTILS_H_ +#define TENSORFLOW_CORE_KERNELS_QUANTIZATION_UTILS_H_ #define EIGEN_USE_THREADS @@ -956,4 +956,4 @@ class TensorflowGemmContext : public gemmlowp::MultiThreadGemmContextBase { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_QUANTIZATION_UTILS_H_ +#endif // TENSORFLOW_CORE_KERNELS_QUANTIZATION_UTILS_H_ diff --git a/tensorflow/core/kernels/reference_gemm.h b/tensorflow/core/kernels/reference_gemm.h index bb2a21720f..c9cc04ed1b 100644 --- a/tensorflow/core/kernels/reference_gemm.h +++ b/tensorflow/core/kernels/reference_gemm.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REFERENCE_GEMM_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REFERENCE_GEMM_H_ +#ifndef TENSORFLOW_CORE_KERNELS_REFERENCE_GEMM_H_ +#define TENSORFLOW_CORE_KERNELS_REFERENCE_GEMM_H_ #include @@ -92,4 +92,4 @@ void ReferenceGemm(bool transpose_a, bool transpose_b, bool transpose_c, } } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REFERENCE_GEMM_H_ +#endif // TENSORFLOW_CORE_KERNELS_REFERENCE_GEMM_H_ diff --git a/tensorflow/core/kernels/remote_fused_graph_execute_op_test_utils.h b/tensorflow/core/kernels/remote_fused_graph_execute_op_test_utils.h index 3fa052108e..7de45eaaa1 100644 --- a/tensorflow/core/kernels/remote_fused_graph_execute_op_test_utils.h +++ b/tensorflow/core/kernels/remote_fused_graph_execute_op_test_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_OP_TEST_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_OP_TEST_UTILS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_OP_TEST_UTILS_H_ +#define TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_OP_TEST_UTILS_H_ #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -86,4 +86,4 @@ class TestRemoteFusedGraphExecutor final : public IRemoteFusedGraphExecutor { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_OP_TEST_UTILS_H_ +#endif // TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_OP_TEST_UTILS_H_ diff --git a/tensorflow/core/kernels/remote_fused_graph_execute_utils.h b/tensorflow/core/kernels/remote_fused_graph_execute_utils.h index 541c26baaf..f047144278 100644 --- a/tensorflow/core/kernels/remote_fused_graph_execute_utils.h +++ b/tensorflow/core/kernels/remote_fused_graph_execute_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_UTILS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_UTILS_H_ +#define TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_UTILS_H_ #include #include @@ -312,4 +312,4 @@ class RemoteFusedGraphExecuteUtils { }; } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_UTILS_H_ +#endif // TENSORFLOW_CORE_KERNELS_REMOTE_FUSED_GRAPH_EXECUTE_UTILS_H_ diff --git a/tensorflow/core/kernels/reshape_util.h b/tensorflow/core/kernels/reshape_util.h index ed583afd13..6777748b63 100644 --- a/tensorflow/core/kernels/reshape_util.h +++ b/tensorflow/core/kernels/reshape_util.h @@ -13,8 +13,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_RESHAPE_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_RESHAPE_UTIL_H_ +#ifndef TENSORFLOW_CORE_KERNELS_RESHAPE_UTIL_H_ +#define TENSORFLOW_CORE_KERNELS_RESHAPE_UTIL_H_ #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/lib/core/status.h" @@ -28,4 +28,4 @@ void Reshape(OpKernelContext *context, const Tensor &input_indices_in, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_RESHAPE_UTIL_H_ +#endif // TENSORFLOW_CORE_KERNELS_RESHAPE_UTIL_H_ diff --git a/tensorflow/core/kernels/scatter_nd_op_cpu_impl.h b/tensorflow/core/kernels/scatter_nd_op_cpu_impl.h index cffc326174..c6c9d4e658 100644 --- a/tensorflow/core/kernels/scatter_nd_op_cpu_impl.h +++ b/tensorflow/core/kernels/scatter_nd_op_cpu_impl.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SCATTER_ND_OP_CPU_IMPL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SCATTER_ND_OP_CPU_IMPL_H_ +#ifndef TENSORFLOW_CORE_KERNELS_SCATTER_ND_OP_CPU_IMPL_H_ +#define TENSORFLOW_CORE_KERNELS_SCATTER_ND_OP_CPU_IMPL_H_ // Functor definitions for ScatterND ops, must be compilable by nvcc. @@ -257,4 +257,4 @@ REGISTER_SCATTER_ND_MATH_SYCL(int32); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SCATTER_ND_OP_CPU_IMPL_H_ +#endif // TENSORFLOW_CORE_KERNELS_SCATTER_ND_OP_CPU_IMPL_H_ diff --git a/tensorflow/core/kernels/segment_reduction_ops.h b/tensorflow/core/kernels/segment_reduction_ops.h index b10bea72ba..bcdd42c80c 100644 --- a/tensorflow/core/kernels/segment_reduction_ops.h +++ b/tensorflow/core/kernels/segment_reduction_ops.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SEGMENT_REDUCTION_OPS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SEGMENT_REDUCTION_OPS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_SEGMENT_REDUCTION_OPS_H_ +#define TENSORFLOW_CORE_KERNELS_SEGMENT_REDUCTION_OPS_H_ #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/framework/tensor.h" @@ -98,4 +98,4 @@ struct UnsortedSegmentMaxFunctor: public UnsortedSegmentBaseFunctor #include @@ -109,4 +109,4 @@ class Spectrogram { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SPECTROGRAM_H_ +#endif // TENSORFLOW_CORE_KERNELS_SPECTROGRAM_H_ diff --git a/tensorflow/core/kernels/spectrogram_test_utils.h b/tensorflow/core/kernels/spectrogram_test_utils.h index 59a903549e..d4187076e7 100644 --- a/tensorflow/core/kernels/spectrogram_test_utils.h +++ b/tensorflow/core/kernels/spectrogram_test_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SPECTROGRAM_TEST_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SPECTROGRAM_TEST_UTILS_H_ +#ifndef TENSORFLOW_CORE_KERNELS_SPECTROGRAM_TEST_UTILS_H_ +#define TENSORFLOW_CORE_KERNELS_SPECTROGRAM_TEST_UTILS_H_ #include #include @@ -78,4 +78,4 @@ void SineWave(int sample_rate, float frequency, float duration_seconds, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_SPECTROGRAM_TEST_UTILS_H_ +#endif // TENSORFLOW_CORE_KERNELS_SPECTROGRAM_TEST_UTILS_H_ diff --git a/tensorflow/core/kernels/tile_ops_cpu_impl.h b/tensorflow/core/kernels/tile_ops_cpu_impl.h index a6eed4935d..054b31ef9e 100644 --- a/tensorflow/core/kernels/tile_ops_cpu_impl.h +++ b/tensorflow/core/kernels/tile_ops_cpu_impl.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_KERNELS_TILE_OPS_CPU_IMPL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_TILE_OPS_CPU_IMPL_H_ +#ifndef TENSORFLOW_CORE_KERNELS_TILE_OPS_CPU_IMPL_H_ +#define TENSORFLOW_CORE_KERNELS_TILE_OPS_CPU_IMPL_H_ #define EIGEN_USE_THREADS @@ -68,4 +68,4 @@ TF_CALL_int64(DEFINE_TYPE); } // end namespace functor } // end namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_TILE_OPS_CPU_IMPL_H_ +#endif // TENSORFLOW_CORE_KERNELS_TILE_OPS_CPU_IMPL_H_ diff --git a/tensorflow/core/kernels/tile_ops_gpu_impl.h b/tensorflow/core/kernels/tile_ops_gpu_impl.h index 592f99e9b7..8da337dabd 100644 --- a/tensorflow/core/kernels/tile_ops_gpu_impl.h +++ b/tensorflow/core/kernels/tile_ops_gpu_impl.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_TILE_OPS_GPU_IMPL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_TILE_OPS_GPU_IMPL_H_ +#ifndef TENSORFLOW_CORE_KERNELS_TILE_OPS_GPU_IMPL_H_ +#define TENSORFLOW_CORE_KERNELS_TILE_OPS_GPU_IMPL_H_ // Header used to split up compilation of GPU tile ops. For each type you want // to have tile ops, create a .cu.cc file containing @@ -56,4 +56,4 @@ limitations under the License. } \ } -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_TILE_OPS_GPU_IMPL_H_ +#endif // TENSORFLOW_CORE_KERNELS_TILE_OPS_GPU_IMPL_H_ diff --git a/tensorflow/core/kernels/winograd_transform.h b/tensorflow/core/kernels/winograd_transform.h index 5caee9fdc1..d22710e503 100644 --- a/tensorflow/core/kernels/winograd_transform.h +++ b/tensorflow/core/kernels/winograd_transform.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_WINOGRAD_TRANSFORM_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_WINOGRAD_TRANSFORM_H_ +#ifndef TENSORFLOW_CORE_KERNELS_WINOGRAD_TRANSFORM_H_ +#define TENSORFLOW_CORE_KERNELS_WINOGRAD_TRANSFORM_H_ #include "tensorflow/core/kernels/deep_conv2d.h" @@ -374,4 +374,4 @@ void WinogradTransform::GetOutputTransformMatrix(const int64 rows, } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_WINOGRAD_TRANSFORM_H_ +#endif // TENSORFLOW_CORE_KERNELS_WINOGRAD_TRANSFORM_H_ diff --git a/tensorflow/core/kernels/xsmm_conv2d.h b/tensorflow/core/kernels/xsmm_conv2d.h index b439511dc7..003291329a 100644 --- a/tensorflow/core/kernels/xsmm_conv2d.h +++ b/tensorflow/core/kernels/xsmm_conv2d.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_KERNELS_XSMM_CONV2D_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_KERNELS_XSMM_CONV2D_H_ +#ifndef TENSORFLOW_CORE_KERNELS_XSMM_CONV2D_H_ +#define TENSORFLOW_CORE_KERNELS_XSMM_CONV2D_H_ #include "tensorflow/core/framework/types.h" #include "tensorflow/core/util/tensor_format.h" @@ -57,4 +57,4 @@ struct XsmmBkwFilterConv2D { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_KERNELS_XSMM_CONV2D_H_ +#endif // TENSORFLOW_CORE_KERNELS_XSMM_CONV2D_H_ diff --git a/tensorflow/core/lib/core/bitmap.h b/tensorflow/core/lib/core/bitmap.h index b30479fa1b..8ff1e666b4 100644 --- a/tensorflow/core/lib/core/bitmap.h +++ b/tensorflow/core/lib/core/bitmap.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_CORE_BITMAP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_CORE_BITMAP_H_ +#ifndef TENSORFLOW_CORE_LIB_CORE_BITMAP_H_ +#define TENSORFLOW_CORE_LIB_CORE_BITMAP_H_ #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/types.h" @@ -103,4 +103,4 @@ inline void Bitmap::clear(size_t i) { } // namespace core } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_CORE_BITMAP_H_ +#endif // TENSORFLOW_CORE_LIB_CORE_BITMAP_H_ diff --git a/tensorflow/core/lib/gtl/compactptrset.h b/tensorflow/core/lib/gtl/compactptrset.h index 1d4d6cc8d2..d3d23b94aa 100644 --- a/tensorflow/core/lib/gtl/compactptrset.h +++ b/tensorflow/core/lib/gtl/compactptrset.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_COMPACTPTRSET_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_COMPACTPTRSET_H_ +#ifndef TENSORFLOW_CORE_LIB_GTL_COMPACTPTRSET_H_ +#define TENSORFLOW_CORE_LIB_GTL_COMPACTPTRSET_H_ #include #include "tensorflow/core/lib/gtl/flatset.h" @@ -205,4 +205,4 @@ class CompactPointerSet { } // namespace gtl } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_COMPACTPTRSET_H_ +#endif // TENSORFLOW_CORE_LIB_GTL_COMPACTPTRSET_H_ diff --git a/tensorflow/core/lib/gtl/flatmap.h b/tensorflow/core/lib/gtl/flatmap.h index 6dd67ad2ea..889d2ddaa6 100644 --- a/tensorflow/core/lib/gtl/flatmap.h +++ b/tensorflow/core/lib/gtl/flatmap.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATMAP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATMAP_H_ +#ifndef TENSORFLOW_CORE_LIB_GTL_FLATMAP_H_ +#define TENSORFLOW_CORE_LIB_GTL_FLATMAP_H_ #include #include @@ -379,4 +379,4 @@ class FlatMap { } // namespace gtl } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATMAP_H_ +#endif // TENSORFLOW_CORE_LIB_GTL_FLATMAP_H_ diff --git a/tensorflow/core/lib/gtl/flatrep.h b/tensorflow/core/lib/gtl/flatrep.h index bb405b327a..0d7e7487fc 100644 --- a/tensorflow/core/lib/gtl/flatrep.h +++ b/tensorflow/core/lib/gtl/flatrep.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATREP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATREP_H_ +#ifndef TENSORFLOW_CORE_LIB_GTL_FLATREP_H_ +#define TENSORFLOW_CORE_LIB_GTL_FLATREP_H_ #include #include @@ -328,4 +328,4 @@ class FlatRep { } // namespace gtl } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATREP_H_ +#endif // TENSORFLOW_CORE_LIB_GTL_FLATREP_H_ diff --git a/tensorflow/core/lib/gtl/flatset.h b/tensorflow/core/lib/gtl/flatset.h index 2b7f31ab22..f31e3abe41 100644 --- a/tensorflow/core/lib/gtl/flatset.h +++ b/tensorflow/core/lib/gtl/flatset.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATSET_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATSET_H_ +#ifndef TENSORFLOW_CORE_LIB_GTL_FLATSET_H_ +#define TENSORFLOW_CORE_LIB_GTL_FLATSET_H_ #include #include @@ -278,4 +278,4 @@ class FlatSet { } // namespace gtl } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_GTL_FLATSET_H_ +#endif // TENSORFLOW_CORE_LIB_GTL_FLATSET_H_ diff --git a/tensorflow/core/lib/io/buffered_inputstream.h b/tensorflow/core/lib/io/buffered_inputstream.h index 2b824f35f8..924619f40f 100644 --- a/tensorflow/core/lib/io/buffered_inputstream.h +++ b/tensorflow/core/lib/io/buffered_inputstream.h @@ -104,4 +104,4 @@ class BufferedInputStream : public InputStreamInterface { } // namespace io } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_LIB_IO_BUFFERED_INPUTSTREAM_H_ +#endif // TENSORFLOW_LIB_IO_BUFFERED_INPUTSTREAM_H_ diff --git a/tensorflow/core/lib/io/compression.h b/tensorflow/core/lib/io/compression.h index 7a0c5c12a7..ef90c60a3a 100644 --- a/tensorflow/core/lib/io/compression.h +++ b/tensorflow/core/lib/io/compression.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_COMPRESSION_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_COMPRESSION_H_ +#ifndef TENSORFLOW_CORE_LIB_IO_COMPRESSION_H_ +#define TENSORFLOW_CORE_LIB_IO_COMPRESSION_H_ namespace tensorflow { namespace io { @@ -27,4 +27,4 @@ extern const char kGzip[]; } } -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_COMPRESSION_H_ +#endif // TENSORFLOW_CORE_LIB_IO_COMPRESSION_H_ diff --git a/tensorflow/core/lib/io/inputstream_interface.h b/tensorflow/core/lib/io/inputstream_interface.h index 096248693b..3083d20776 100644 --- a/tensorflow/core/lib/io/inputstream_interface.h +++ b/tensorflow/core/lib/io/inputstream_interface.h @@ -54,4 +54,4 @@ class InputStreamInterface { } // namespace io } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_INPUTSTREAM_INTERFACE_H_ +#endif // TENSORFLOW_CORE_LIB_IO_INPUTSTREAM_INTERFACE_H_ diff --git a/tensorflow/core/lib/io/snappy/snappy_outputbuffer.h b/tensorflow/core/lib/io/snappy/snappy_outputbuffer.h index 5d330a2c5a..5aea503846 100644 --- a/tensorflow/core/lib/io/snappy/snappy_outputbuffer.h +++ b/tensorflow/core/lib/io/snappy/snappy_outputbuffer.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ +#ifndef TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ +#define TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ #include #include "tensorflow/core/lib/core/status.h" @@ -117,4 +117,4 @@ class SnappyOutputBuffer { } // namespace io } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ +#endif // TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ diff --git a/tensorflow/core/lib/io/zlib_outputbuffer.h b/tensorflow/core/lib/io/zlib_outputbuffer.h index 5cad2e9457..3d86d89a99 100644 --- a/tensorflow/core/lib/io/zlib_outputbuffer.h +++ b/tensorflow/core/lib/io/zlib_outputbuffer.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_COMPRESSED_OUTPUTBUFFER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_COMPRESSED_OUTPUTBUFFER_H_ +#ifndef TENSORFLOW_CORE_LIB_IO_COMPRESSED_OUTPUTBUFFER_H_ +#define TENSORFLOW_CORE_LIB_IO_COMPRESSED_OUTPUTBUFFER_H_ #include @@ -143,4 +143,4 @@ class ZlibOutputBuffer : public WritableFile { } // namespace io } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_COMPRESSED_OUTPUTBUFFER_H_ +#endif // TENSORFLOW_CORE_LIB_IO_COMPRESSED_OUTPUTBUFFER_H_ diff --git a/tensorflow/core/lib/monitoring/collected_metrics.h b/tensorflow/core/lib/monitoring/collected_metrics.h index acdb0d86ed..e200981609 100644 --- a/tensorflow/core/lib/monitoring/collected_metrics.h +++ b/tensorflow/core/lib/monitoring/collected_metrics.h @@ -17,8 +17,8 @@ limitations under the License. // These are to be used only by the CollectionRegistry and exporters which // collect metrics using the CollectionRegistry. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COLLECTED_METRICS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COLLECTED_METRICS_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_COLLECTED_METRICS_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_COLLECTED_METRICS_H_ #include #include @@ -151,4 +151,4 @@ struct CollectedMetrics { } // namespace monitoring } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COLLECTED_METRICS_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_COLLECTED_METRICS_H_ diff --git a/tensorflow/core/lib/monitoring/collection_registry.h b/tensorflow/core/lib/monitoring/collection_registry.h index 2c8e250c56..63cc0f550d 100644 --- a/tensorflow/core/lib/monitoring/collection_registry.h +++ b/tensorflow/core/lib/monitoring/collection_registry.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COLLECTION_REGISTRY_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COLLECTION_REGISTRY_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_COLLECTION_REGISTRY_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_COLLECTION_REGISTRY_H_ #include #include @@ -356,4 +356,4 @@ MetricCollector MetricCollectorGetter::Get( } // namespace monitoring } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COLLECTION_REGISTRY_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_COLLECTION_REGISTRY_H_ diff --git a/tensorflow/core/lib/monitoring/counter.h b/tensorflow/core/lib/monitoring/counter.h index 7240348a9b..8ff810db41 100644 --- a/tensorflow/core/lib/monitoring/counter.h +++ b/tensorflow/core/lib/monitoring/counter.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COUNTER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COUNTER_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_COUNTER_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_COUNTER_H_ // We replace this implementation with a null implementation for mobile // platforms. @@ -172,4 +172,4 @@ CounterCell* Counter::GetCell(const Labels&... labels) } // namespace tensorflow #endif // IS_MOBILE_PLATFORM -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_COUNTER_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_COUNTER_H_ diff --git a/tensorflow/core/lib/monitoring/gauge.h b/tensorflow/core/lib/monitoring/gauge.h index ec978a9193..ee9a862f40 100644 --- a/tensorflow/core/lib/monitoring/gauge.h +++ b/tensorflow/core/lib/monitoring/gauge.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_ // We replace this implementation with a null implementation for mobile // platforms. @@ -241,4 +241,4 @@ GaugeCell* Gauge::GetCell( } // namespace tensorflow #endif // IS_MOBILE_PLATFORM -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_GAUGE_H_ diff --git a/tensorflow/core/lib/monitoring/metric_def.h b/tensorflow/core/lib/monitoring/metric_def.h index f046842618..5ecadcc427 100644 --- a/tensorflow/core/lib/monitoring/metric_def.h +++ b/tensorflow/core/lib/monitoring/metric_def.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_METRIC_DEF_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_METRIC_DEF_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_METRIC_DEF_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_METRIC_DEF_H_ #include #include @@ -139,4 +139,4 @@ class MetricDef : public AbstractMetricDef { } // namespace monitoring } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_METRIC_DEF_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_METRIC_DEF_H_ diff --git a/tensorflow/core/lib/monitoring/mobile_counter.h b/tensorflow/core/lib/monitoring/mobile_counter.h index c30bfe026f..c297d843d2 100644 --- a/tensorflow/core/lib/monitoring/mobile_counter.h +++ b/tensorflow/core/lib/monitoring/mobile_counter.h @@ -15,8 +15,8 @@ limitations under the License. // Null implementation of the Counter metric for mobile platforms. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_COUNTER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_COUNTER_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_MOBILE_COUNTER_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_MOBILE_COUNTER_H_ #include "tensorflow/core/platform/macros.h" #include "tensorflow/core/platform/types.h" @@ -64,4 +64,4 @@ class Counter { } // namespace monitoring } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_COUNTER_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_MOBILE_COUNTER_H_ diff --git a/tensorflow/core/lib/monitoring/mobile_gauge.h b/tensorflow/core/lib/monitoring/mobile_gauge.h index ac13ad35c0..a03b41aef3 100644 --- a/tensorflow/core/lib/monitoring/mobile_gauge.h +++ b/tensorflow/core/lib/monitoring/mobile_gauge.h @@ -15,8 +15,8 @@ limitations under the License. // Null implementation of the Gauge metric for mobile platforms. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_ #include "tensorflow/core/platform/macros.h" #include "tensorflow/core/platform/types.h" @@ -69,4 +69,4 @@ class Gauge { } // namespace monitoring } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_MOBILE_GAUGE_H_ diff --git a/tensorflow/core/lib/monitoring/mobile_sampler.h b/tensorflow/core/lib/monitoring/mobile_sampler.h index cf390e5c7f..77310dd619 100644 --- a/tensorflow/core/lib/monitoring/mobile_sampler.h +++ b/tensorflow/core/lib/monitoring/mobile_sampler.h @@ -15,8 +15,8 @@ limitations under the License. // Null implementation of the Sampler metric for mobile platforms. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_SAMPLER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_SAMPLER_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_MOBILE_SAMPLER_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_MOBILE_SAMPLER_H_ #include @@ -98,4 +98,4 @@ class Sampler { } // namespace monitoring } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_MOBILE_SAMPLER_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_MOBILE_SAMPLER_H_ diff --git a/tensorflow/core/lib/monitoring/sampler.h b/tensorflow/core/lib/monitoring/sampler.h index c7a05428e2..a4f397f556 100644 --- a/tensorflow/core/lib/monitoring/sampler.h +++ b/tensorflow/core/lib/monitoring/sampler.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_SAMPLER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_SAMPLER_H_ +#ifndef TENSORFLOW_CORE_LIB_MONITORING_SAMPLER_H_ +#define TENSORFLOW_CORE_LIB_MONITORING_SAMPLER_H_ // We replace this implementation with a null implementation for mobile // platforms. @@ -215,4 +215,4 @@ SamplerCell* Sampler::GetCell(const Labels&... labels) } // namespace tensorflow #endif // IS_MOBILE_PLATFORM -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_MONITORING_SAMPLER_H_ +#endif // TENSORFLOW_CORE_LIB_MONITORING_SAMPLER_H_ diff --git a/tensorflow/core/lib/strings/proto_text_util.h b/tensorflow/core/lib/strings/proto_text_util.h index ed6d0af010..05dbda6e15 100644 --- a/tensorflow/core/lib/strings/proto_text_util.h +++ b/tensorflow/core/lib/strings/proto_text_util.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ +#ifndef TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ +#define TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ #include "tensorflow/core/lib/strings/numbers.h" #include "tensorflow/core/lib/strings/scanner.h" @@ -164,4 +164,4 @@ bool ProtoParseStringLiteralFromScanner(Scanner* scanner, string* value); } // namespace strings } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ +#endif // TENSORFLOW_CORE_LIB_STRINGS_PROTO_TEXT_UTIL_H_ diff --git a/tensorflow/core/platform/cloud/gcs_dns_cache.h b/tensorflow/core/platform/cloud/gcs_dns_cache.h index dd95c18f35..40f16f1044 100644 --- a/tensorflow/core/platform/cloud/gcs_dns_cache.h +++ b/tensorflow/core/platform/cloud/gcs_dns_cache.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_PLATNFORM_CLOUD_DNS_CACHE_H_ -#define THIRD_PARTY_TENSORFLOW_PLATNFORM_CLOUD_DNS_CACHE_H_ +#ifndef TENSORFLOW_PLATNFORM_CLOUD_DNS_CACHE_H_ +#define TENSORFLOW_PLATNFORM_CLOUD_DNS_CACHE_H_ #include @@ -74,4 +74,4 @@ class GcsDnsCache { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PLATNFORM_CLOUD_DNS_CACHE_H_ +#endif // TENSORFLOW_PLATNFORM_CLOUD_DNS_CACHE_H_ diff --git a/tensorflow/core/platform/cloud/oauth_client.h b/tensorflow/core/platform/cloud/oauth_client.h index 1614c7b315..519d69acf9 100644 --- a/tensorflow/core/platform/cloud/oauth_client.h +++ b/tensorflow/core/platform/cloud/oauth_client.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_OAUTH_CLIENT_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_OAUTH_CLIENT_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_CLOUD_OAUTH_CLIENT_H_ +#define TENSORFLOW_CORE_PLATFORM_CLOUD_OAUTH_CLIENT_H_ #include #include "include/json/json.h" @@ -59,4 +59,4 @@ class OAuthClient { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_OAUTH_CLIENT_H_ +#endif // TENSORFLOW_CORE_PLATFORM_CLOUD_OAUTH_CLIENT_H_ diff --git a/tensorflow/core/platform/cloud/retrying_utils.h b/tensorflow/core/platform/cloud/retrying_utils.h index 99ab216e97..546b8d1c4a 100644 --- a/tensorflow/core/platform/cloud/retrying_utils.h +++ b/tensorflow/core/platform/cloud/retrying_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_RETRYING_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_RETRYING_UTILS_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_CLOUD_RETRYING_UTILS_H_ +#define TENSORFLOW_CORE_PLATFORM_CLOUD_RETRYING_UTILS_H_ #include #include "tensorflow/core/lib/core/status.h" @@ -47,4 +47,4 @@ class RetryingUtils { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_RETRYING_UTILS_H_ +#endif // TENSORFLOW_CORE_PLATFORM_CLOUD_RETRYING_UTILS_H_ diff --git a/tensorflow/core/platform/cloud/time_util.h b/tensorflow/core/platform/cloud/time_util.h index b1bb7f1119..d6d4bc499f 100644 --- a/tensorflow/core/platform/cloud/time_util.h +++ b/tensorflow/core/platform/cloud/time_util.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ +#define TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ #include "tensorflow/core/lib/core/status.h" @@ -26,4 +26,4 @@ Status ParseRfc3339Time(const string& time, int64* mtime_nsec); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ +#endif // TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ diff --git a/tensorflow/core/platform/cuda_libdevice_path.h b/tensorflow/core/platform/cuda_libdevice_path.h index 601d0db6d4..6ef565ecd3 100644 --- a/tensorflow/core/platform/cuda_libdevice_path.h +++ b/tensorflow/core/platform/cuda_libdevice_path.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CUDA_LIBDEVICE_PATH_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CUDA_LIBDEVICE_PATH_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_CUDA_LIBDEVICE_PATH_H_ +#define TENSORFLOW_CORE_PLATFORM_CUDA_LIBDEVICE_PATH_H_ #include "tensorflow/core/platform/types.h" @@ -29,4 +29,4 @@ string LibdeviceRoot(); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CUDA_LIBDEVICE_PATH_H_ +#endif // TENSORFLOW_CORE_PLATFORM_CUDA_LIBDEVICE_PATH_H_ diff --git a/tensorflow/core/platform/cupti_wrapper.h b/tensorflow/core/platform/cupti_wrapper.h index c909dcd35b..9a17ab60c0 100644 --- a/tensorflow/core/platform/cupti_wrapper.h +++ b/tensorflow/core/platform/cupti_wrapper.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CUPTI_WRAPPER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CUPTI_WRAPPER_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_CUPTI_WRAPPER_H_ +#define TENSORFLOW_CORE_PLATFORM_CUPTI_WRAPPER_H_ #include "tensorflow/core/platform/platform.h" @@ -24,4 +24,4 @@ limitations under the License. #include "tensorflow/core/platform/default/gpu/cupti_wrapper.h" #endif -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CUPTI_WRAPPER_H_ +#endif // TENSORFLOW_CORE_PLATFORM_CUPTI_WRAPPER_H_ diff --git a/tensorflow/core/platform/default/gpu/cupti_wrapper.h b/tensorflow/core/platform/default/gpu/cupti_wrapper.h index 38e01cefad..acd889e474 100644 --- a/tensorflow/core/platform/default/gpu/cupti_wrapper.h +++ b/tensorflow/core/platform/default/gpu/cupti_wrapper.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_DEFAULT_CUPTI_WRAPPER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_DEFAULT_CUPTI_WRAPPER_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_DEFAULT_CUPTI_WRAPPER_H_ +#define TENSORFLOW_CORE_PLATFORM_DEFAULT_CUPTI_WRAPPER_H_ #if GOOGLE_CUDA @@ -76,4 +76,4 @@ class CuptiWrapper { #endif // GOOGLE_CUDA -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_DEFAULT_CUPTI_WRAPPER_H_ +#endif // TENSORFLOW_CORE_PLATFORM_DEFAULT_CUPTI_WRAPPER_H_ diff --git a/tensorflow/core/platform/demangle.h b/tensorflow/core/platform/demangle.h index c2def217a1..ce33be2e68 100644 --- a/tensorflow/core/platform/demangle.h +++ b/tensorflow/core/platform/demangle.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_DEMANGLE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_DEMANGLE_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_DEMANGLE_H_ +#define TENSORFLOW_CORE_PLATFORM_DEMANGLE_H_ #include "tensorflow/core/platform/types.h" @@ -28,4 +28,4 @@ string Demangle(const char* mangled); } // namespace port } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_DEMANGLE_H_ +#endif // TENSORFLOW_CORE_PLATFORM_DEMANGLE_H_ diff --git a/tensorflow/core/platform/file_statistics.h b/tensorflow/core/platform/file_statistics.h index 7629db6ef9..9e3489b1ad 100644 --- a/tensorflow/core/platform/file_statistics.h +++ b/tensorflow/core/platform/file_statistics.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_FILE_STATISTICS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_FILE_STATISTICS_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_FILE_STATISTICS_H_ +#define TENSORFLOW_CORE_PLATFORM_FILE_STATISTICS_H_ #include "tensorflow/core/platform/types.h" @@ -36,4 +36,4 @@ struct FileStatistics { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_FILE_STATISTICS_H_ +#endif // TENSORFLOW_CORE_PLATFORM_FILE_STATISTICS_H_ diff --git a/tensorflow/core/platform/hadoop/hadoop_file_system.h b/tensorflow/core/platform/hadoop/hadoop_file_system.h index 447e83158a..5f2b222622 100644 --- a/tensorflow/core/platform/hadoop/hadoop_file_system.h +++ b/tensorflow/core/platform/hadoop/hadoop_file_system.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_HADOOP_HADOOP_FILE_SYSTEM_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_HADOOP_HADOOP_FILE_SYSTEM_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_HADOOP_HADOOP_FILE_SYSTEM_H_ +#define TENSORFLOW_CORE_PLATFORM_HADOOP_HADOOP_FILE_SYSTEM_H_ #include "tensorflow/core/platform/env.h" @@ -70,4 +70,4 @@ class HadoopFileSystem : public FileSystem { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_HADOOP_HADOOP_FILE_SYSTEM_H_ +#endif // TENSORFLOW_CORE_PLATFORM_HADOOP_HADOOP_FILE_SYSTEM_H_ diff --git a/tensorflow/core/platform/stacktrace_handler.h b/tensorflow/core/platform/stacktrace_handler.h index d36c82c9ba..a52970fdaa 100644 --- a/tensorflow/core/platform/stacktrace_handler.h +++ b/tensorflow/core/platform/stacktrace_handler.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_BACKTRACE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_BACKTRACE_H_ +#ifndef TENSORFLOW_CORE_PLATFORM_BACKTRACE_H_ +#define TENSORFLOW_CORE_PLATFORM_BACKTRACE_H_ namespace tensorflow { namespace testing { @@ -25,4 +25,4 @@ void InstallStacktraceHandler(); } // namespace testing } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_BACKTRACE_H_ +#endif // TENSORFLOW_CORE_PLATFORM_BACKTRACE_H_ diff --git a/tensorflow/core/profiler/internal/advisor/accelerator_utilization_checker.h b/tensorflow/core/profiler/internal/advisor/accelerator_utilization_checker.h index c6544fe0b0..25766668d8 100644 --- a/tensorflow/core/profiler/internal/advisor/accelerator_utilization_checker.h +++ b/tensorflow/core/profiler/internal/advisor/accelerator_utilization_checker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ // This checker checks the accelerator's utilization. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_ACCELERATOR_UTILIZATION_CHECKER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_ACCELERATOR_UTILIZATION_CHECKER_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_ACCELERATOR_UTILIZATION_CHECKER_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_ACCELERATOR_UTILIZATION_CHECKER_H_ #include "tensorflow/core/profiler/internal/advisor/checker.h" @@ -106,4 +106,4 @@ class AcceleratorUtilizationChecker : public Checker { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_ACCELERATOR_UTILIZATION_CHECKER_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_ACCELERATOR_UTILIZATION_CHECKER_H_ diff --git a/tensorflow/core/profiler/internal/advisor/checker.h b/tensorflow/core/profiler/internal/advisor/checker.h index 4b5ebcf9e8..5d7da39e6b 100644 --- a/tensorflow/core/profiler/internal/advisor/checker.h +++ b/tensorflow/core/profiler/internal/advisor/checker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_CHECKER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_CHECKER_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_CHECKER_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_CHECKER_H_ #include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/core/profiler/internal/tfprof_stats.h" @@ -49,4 +49,4 @@ class Checker { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_CHECKER_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_CHECKER_H_ diff --git a/tensorflow/core/profiler/internal/advisor/expensive_operation_checker.h b/tensorflow/core/profiler/internal/advisor/expensive_operation_checker.h index 145782c7bd..f5ac5c9c5a 100644 --- a/tensorflow/core/profiler/internal/advisor/expensive_operation_checker.h +++ b/tensorflow/core/profiler/internal/advisor/expensive_operation_checker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ // This checker checks the most expensive operations. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OPERATION_CHECKER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OPERATION_CHECKER_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OPERATION_CHECKER_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OPERATION_CHECKER_H_ #include "tensorflow/core/profiler/internal/advisor/checker.h" @@ -137,4 +137,4 @@ class ExpensiveOperationChecker : public Checker { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OP_CHECKER_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OP_CHECKER_H_ diff --git a/tensorflow/core/profiler/internal/advisor/internal_checker_runner.h b/tensorflow/core/profiler/internal/advisor/internal_checker_runner.h index ec52741b19..6fc16cf903 100644 --- a/tensorflow/core/profiler/internal/advisor/internal_checker_runner.h +++ b/tensorflow/core/profiler/internal/advisor/internal_checker_runner.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_INTERNAL_CHECKER_RUNNER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_INTERNAL_CHECKER_RUNNER_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_INTERNAL_CHECKER_RUNNER_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_INTERNAL_CHECKER_RUNNER_H_ #include "tensorflow/core/profiler/internal/tfprof_utils.h" #include "tensorflow/core/profiler/tfprof_options.pb.h" @@ -31,4 +31,4 @@ AdviceProto RunInternalCheckers(const AdvisorOptionsProto& options, } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_INTERNAL_CHECKER_RUNNER_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_INTERNAL_CHECKER_RUNNER_H_ diff --git a/tensorflow/core/profiler/internal/advisor/operation_checker.h b/tensorflow/core/profiler/internal/advisor/operation_checker.h index f0bd72fa40..6c1d5cd670 100644 --- a/tensorflow/core/profiler/internal/advisor/operation_checker.h +++ b/tensorflow/core/profiler/internal/advisor/operation_checker.h @@ -14,8 +14,8 @@ limitations under the License. ==============================================================================*/ // This checker checks common wrong configurations of operations. // -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_OPERATION_CHECKER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_OPERATION_CHECKER_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_OPERATION_CHECKER_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_OPERATION_CHECKER_H_ #include "tensorflow/core/profiler/internal/advisor/checker.h" @@ -74,4 +74,4 @@ class OperationChecker : public Checker { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_OPERATION_CHECKER_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_OPERATION_CHECKER_H_ diff --git a/tensorflow/core/profiler/internal/advisor/tfprof_advisor.h b/tensorflow/core/profiler/internal/advisor/tfprof_advisor.h index 42bd6d5438..270662bd4a 100644 --- a/tensorflow/core/profiler/internal/advisor/tfprof_advisor.h +++ b/tensorflow/core/profiler/internal/advisor/tfprof_advisor.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_TFPROF_ADVICE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_TFPROF_ADVICE_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_TFPROF_ADVICE_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_TFPROF_ADVICE_H_ #include "tensorflow/core/profiler/internal/advisor/accelerator_utilization_checker.h" #include "tensorflow/core/profiler/internal/advisor/checker.h" @@ -78,4 +78,4 @@ class Advisor { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_TFPROF_ADVICE_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_TFPROF_ADVICE_H_ diff --git a/tensorflow/core/profiler/internal/print_model_analysis.h b/tensorflow/core/profiler/internal/print_model_analysis.h index 90166aa7d5..29666ab936 100644 --- a/tensorflow/core/profiler/internal/print_model_analysis.h +++ b/tensorflow/core/profiler/internal/print_model_analysis.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_PRINT_MODEL_ANALYSIS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_PRINT_MODEL_ANALYSIS_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_PRINT_MODEL_ANALYSIS_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_PRINT_MODEL_ANALYSIS_H_ #include @@ -63,4 +63,4 @@ string PrintModelAnalysis(const string* graph, const string* run_meta, } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_PRINT_MODEL_ANALYSIS_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_PRINT_MODEL_ANALYSIS_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_code.h b/tensorflow/core/profiler/internal/tfprof_code.h index bcbdc1b48c..38395f967c 100644 --- a/tensorflow/core/profiler/internal/tfprof_code.h +++ b/tensorflow/core/profiler/internal/tfprof_code.h @@ -16,8 +16,8 @@ limitations under the License. // Build a tree structure based on the TensorFlow model's python code stacks. // Stats are aggregated from descendants to ancestors. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CODE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CODE_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CODE_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CODE_H_ #include #include @@ -94,4 +94,4 @@ class TFCode : public TFMultiShow { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CODE_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CODE_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_constants.h b/tensorflow/core/profiler/internal/tfprof_constants.h index 6a4eaaa890..d4a47931a2 100644 --- a/tensorflow/core/profiler/internal/tfprof_constants.h +++ b/tensorflow/core/profiler/internal/tfprof_constants.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CONSTANTS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CONSTANTS_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CONSTANTS_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CONSTANTS_H_ namespace tensorflow { namespace tfprof { @@ -34,4 +34,4 @@ static const char* const kCkptVarType = "_checkpoint_variables"; } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CONSTANTS_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_CONSTANTS_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_graph.h b/tensorflow/core/profiler/internal/tfprof_graph.h index f7eef9c835..356a459a65 100644 --- a/tensorflow/core/profiler/internal/tfprof_graph.h +++ b/tensorflow/core/profiler/internal/tfprof_graph.h @@ -16,8 +16,8 @@ limitations under the License. // Build a graph structure based on op inputs/outputs. The graph is a directed // acyclic graph pointing *from outputs to inputs*. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_GRAPH_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_GRAPH_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_GRAPH_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_GRAPH_H_ #include #include @@ -86,4 +86,4 @@ class TFGraph : public TFShow { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_GRAPH_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_GRAPH_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_node.h b/tensorflow/core/profiler/internal/tfprof_node.h index 255a0987e6..0a97b1cb0f 100644 --- a/tensorflow/core/profiler/internal/tfprof_node.h +++ b/tensorflow/core/profiler/internal/tfprof_node.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_H_ #include #include @@ -915,4 +915,4 @@ bool IsCanonicalDevice(const string& device); } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_node_show.h b/tensorflow/core/profiler/internal/tfprof_node_show.h index ca6f9bca5e..517da67d74 100644 --- a/tensorflow/core/profiler/internal/tfprof_node_show.h +++ b/tensorflow/core/profiler/internal/tfprof_node_show.h @@ -21,8 +21,8 @@ limitations under the License. // ScopeNode and GraphNode each maps to one TFGraphNode. // CodeNode and OpNode each maps to one TFMultiGraphNode. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_SHOW_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_SHOW_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_SHOW_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_SHOW_H_ #include #include @@ -156,4 +156,4 @@ class OpNode : public ShowMultiNode { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_SHOW_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_NODE_SHOW_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_op.h b/tensorflow/core/profiler/internal/tfprof_op.h index fcc5e68f47..fe1c3b2ae8 100644 --- a/tensorflow/core/profiler/internal/tfprof_op.h +++ b/tensorflow/core/profiler/internal/tfprof_op.h @@ -15,8 +15,8 @@ limitations under the License. // Build a flat structure of ops. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OP_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OP_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OP_H_ #include #include @@ -76,4 +76,4 @@ class TFOp : public TFMultiShow { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OP_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OP_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_scope.h b/tensorflow/core/profiler/internal/tfprof_scope.h index bb847c0866..235dfde803 100644 --- a/tensorflow/core/profiler/internal/tfprof_scope.h +++ b/tensorflow/core/profiler/internal/tfprof_scope.h @@ -17,8 +17,8 @@ limitations under the License. // For example, 'name1/name2' is a child of 'name1'. // Stats are aggregated from descendants to ancestors. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SCOPE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SCOPE_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SCOPE_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SCOPE_H_ #include #include @@ -74,4 +74,4 @@ class TFScope : public TFShow { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SCOPE_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SCOPE_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_show.h b/tensorflow/core/profiler/internal/tfprof_show.h index 2067ea3b73..4d6de06070 100644 --- a/tensorflow/core/profiler/internal/tfprof_show.h +++ b/tensorflow/core/profiler/internal/tfprof_show.h @@ -15,8 +15,8 @@ limitations under the License. // Parent class and utilities for tfprof_graph and tfprof_scope. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_H_ #include #include @@ -151,4 +151,4 @@ string FormatAcceleratorExecTime(const T* node, const Options& opts) { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_show_multi.h b/tensorflow/core/profiler/internal/tfprof_show_multi.h index ac0ada0449..2a2208d8e7 100644 --- a/tensorflow/core/profiler/internal/tfprof_show_multi.h +++ b/tensorflow/core/profiler/internal/tfprof_show_multi.h @@ -15,8 +15,8 @@ limitations under the License. // Parent class and utilities for tfprof_code. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_MULTI_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_MULTI_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_MULTI_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_MULTI_H_ #include #include @@ -127,4 +127,4 @@ class TFMultiShow { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_MULTI_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_SHOW_MULTI_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_stats.h b/tensorflow/core/profiler/internal/tfprof_stats.h index d78abda588..0790cb0ca6 100644 --- a/tensorflow/core/profiler/internal/tfprof_stats.h +++ b/tensorflow/core/profiler/internal/tfprof_stats.h @@ -20,8 +20,8 @@ limitations under the License. // 3. Accept command and options to selectively aggregate stats for analysis // and print out the results. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_STATS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_STATS_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_STATS_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_STATS_H_ #include #include @@ -125,4 +125,4 @@ class TFStats { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_STATS_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_STATS_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_tensor.h b/tensorflow/core/profiler/internal/tfprof_tensor.h index 9f72e081c9..7a08857720 100644 --- a/tensorflow/core/profiler/internal/tfprof_tensor.h +++ b/tensorflow/core/profiler/internal/tfprof_tensor.h @@ -19,8 +19,8 @@ limitations under the License. // is not supported by TensorFlow CheckPointReader library, though it is // supported in current code. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TENSOR_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TENSOR_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TENSOR_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TENSOR_H_ #include @@ -173,4 +173,4 @@ class TFProfTensor { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TENSOR_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TENSOR_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_timeline.h b/tensorflow/core/profiler/internal/tfprof_timeline.h index b8174cdecb..4428ab571f 100644 --- a/tensorflow/core/profiler/internal/tfprof_timeline.h +++ b/tensorflow/core/profiler/internal/tfprof_timeline.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_ #include "include/json/json.h" #include "tensorflow/core/framework/graph.pb.h" @@ -191,4 +191,4 @@ class Timeline { } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_ diff --git a/tensorflow/core/profiler/internal/tfprof_utils.h b/tensorflow/core/profiler/internal/tfprof_utils.h index afca3df7f8..d4f80afce0 100644 --- a/tensorflow/core/profiler/internal/tfprof_utils.h +++ b/tensorflow/core/profiler/internal/tfprof_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_UTILS_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_UTILS_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_UTILS_H_ #include #include @@ -72,4 +72,4 @@ string QueryDoc(const string& cmd, const Options& opts); } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_UTILS_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_UTILS_H_ diff --git a/tensorflow/core/profiler/tfprof_options.h b/tensorflow/core/profiler/tfprof_options.h index 463f5b3c3a..d61deb72ac 100644 --- a/tensorflow/core/profiler/tfprof_options.h +++ b/tensorflow/core/profiler/tfprof_options.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OPTIONS_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OPTIONS_H_ +#ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OPTIONS_H_ +#define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OPTIONS_H_ #include #include @@ -183,4 +183,4 @@ tensorflow::Status ParseOutput(const string& output_opt, string* output_type, } // namespace tfprof } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OPTIONS_H_ +#endif // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_OPTIONS_H_ diff --git a/tensorflow/core/util/command_line_flags.h b/tensorflow/core/util/command_line_flags.h index 121c7063c9..928ae8a4e9 100644 --- a/tensorflow/core/util/command_line_flags.h +++ b/tensorflow/core/util/command_line_flags.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_UTIL_COMMAND_LINE_FLAGS_H -#define THIRD_PARTY_TENSORFLOW_CORE_UTIL_COMMAND_LINE_FLAGS_H +#ifndef TENSORFLOW_CORE_UTIL_COMMAND_LINE_FLAGS_H +#define TENSORFLOW_CORE_UTIL_COMMAND_LINE_FLAGS_H #include #include @@ -134,4 +134,4 @@ class Flags { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_UTIL_COMMAND_LINE_FLAGS_H +#endif // TENSORFLOW_CORE_UTIL_COMMAND_LINE_FLAGS_H diff --git a/tensorflow/core/util/example_proto_fast_parsing.h b/tensorflow/core/util/example_proto_fast_parsing.h index fe59ec77ca..1b08f02267 100644 --- a/tensorflow/core/util/example_proto_fast_parsing.h +++ b/tensorflow/core/util/example_proto_fast_parsing.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ +#ifndef TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ +#define TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ #include #include @@ -94,4 +94,4 @@ bool TestFastParse(const string& serialized, Example* example); } // namespace example } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ +#endif // TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ diff --git a/tensorflow/core/util/example_proto_helper.h b/tensorflow/core/util/example_proto_helper.h index 8b3c6c5a3f..e511704962 100644 --- a/tensorflow/core/util/example_proto_helper.h +++ b/tensorflow/core/util/example_proto_helper.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_HELPER_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_HELPER_H_ +#ifndef TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_HELPER_H_ +#define TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_HELPER_H_ #include #include @@ -314,4 +314,4 @@ class ParseSingleSequenceExampleAttrs { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_HELPER_H_ +#endif // TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_HELPER_H_ diff --git a/tensorflow/core/util/matmul_autotune.h b/tensorflow/core/util/matmul_autotune.h index 5366623883..5846cae2fc 100644 --- a/tensorflow/core/util/matmul_autotune.h +++ b/tensorflow/core/util/matmul_autotune.h @@ -15,8 +15,8 @@ limitations under the License. // The utility to check matmul autotune related flags. -#ifndef THIRD_PARTY_TENSORFLOW_CORE_UTIL_MATMUL_AUTOTUNE_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_UTIL_MATMUL_AUTOTUNE_H_ +#ifndef TENSORFLOW_CORE_UTIL_MATMUL_AUTOTUNE_H_ +#define TENSORFLOW_CORE_UTIL_MATMUL_AUTOTUNE_H_ namespace tensorflow { @@ -25,4 +25,4 @@ bool MatmulDoFP32ComputationFP16Input(); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_UTIL_MATMUL_AUTOTUNE_H_ +#endif // TENSORFLOW_CORE_UTIL_MATMUL_AUTOTUNE_H_ diff --git a/tensorflow/core/util/strided_slice_op.h b/tensorflow/core/util/strided_slice_op.h index abca98f27b..25ecccd285 100644 --- a/tensorflow/core/util/strided_slice_op.h +++ b/tensorflow/core/util/strided_slice_op.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_CORE_UTIL_STRIDED_SLICE_OP_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_UTIL_STRIDED_SLICE_OP_H_ +#ifndef TENSORFLOW_CORE_UTIL_STRIDED_SLICE_OP_H_ +#define TENSORFLOW_CORE_UTIL_STRIDED_SLICE_OP_H_ #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/framework/tensor_shape.h" @@ -62,4 +62,4 @@ Status ValidateStridedSliceOp( } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_UTIL_STRIDED_SLICE_OP_H_ +#endif // TENSORFLOW_CORE_UTIL_STRIDED_SLICE_OP_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/config.h b/tensorflow/examples/android/jni/object_tracking/config.h index 86e9fc71b6..47de2d2c15 100644 --- a/tensorflow/examples/android/jni/object_tracking/config.h +++ b/tensorflow/examples/android/jni/object_tracking/config.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_CONFIG_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_CONFIG_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_CONFIG_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_CONFIG_H_ #include @@ -297,4 +297,4 @@ struct TrackerConfig { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_CONFIG_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_CONFIG_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/flow_cache.h b/tensorflow/examples/android/jni/object_tracking/flow_cache.h index 8813ab6d71..b62e334ecd 100644 --- a/tensorflow/examples/android/jni/object_tracking/flow_cache.h +++ b/tensorflow/examples/android/jni/object_tracking/flow_cache.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FLOW_CACHE_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FLOW_CACHE_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FLOW_CACHE_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FLOW_CACHE_H_ #include "tensorflow/examples/android/jni/object_tracking/geom.h" #include "tensorflow/examples/android/jni/object_tracking/utils.h" @@ -303,4 +303,4 @@ class FlowCache { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FLOW_CACHE_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FLOW_CACHE_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/frame_pair.h b/tensorflow/examples/android/jni/object_tracking/frame_pair.h index 8f409fe806..6c8ac9be98 100644 --- a/tensorflow/examples/android/jni/object_tracking/frame_pair.h +++ b/tensorflow/examples/android/jni/object_tracking/frame_pair.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FRAME_PAIR_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FRAME_PAIR_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FRAME_PAIR_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FRAME_PAIR_H_ #include "tensorflow/examples/android/jni/object_tracking/keypoint.h" @@ -100,4 +100,4 @@ class FramePair { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FRAME_PAIR_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_FRAME_PAIR_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/geom.h b/tensorflow/examples/android/jni/object_tracking/geom.h index 2819063616..c975e40144 100644 --- a/tensorflow/examples/android/jni/object_tracking/geom.h +++ b/tensorflow/examples/android/jni/object_tracking/geom.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GEOM_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GEOM_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GEOM_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GEOM_H_ #include "tensorflow/examples/android/jni/object_tracking/logging.h" #include "tensorflow/examples/android/jni/object_tracking/utils.h" @@ -316,4 +316,4 @@ inline BoundingSquare GetCenteredSquare(const BoundingBox& original_box) { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GEOM_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GEOM_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/gl_utils.h b/tensorflow/examples/android/jni/object_tracking/gl_utils.h index bd5c233f4f..a29e677d3c 100755 --- a/tensorflow/examples/android/jni/object_tracking/gl_utils.h +++ b/tensorflow/examples/android/jni/object_tracking/gl_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GL_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GL_UTILS_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GL_UTILS_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GL_UTILS_H_ #include #include @@ -52,4 +52,4 @@ inline static void MapWorldSquareToUnitSquare(const BoundingSquare& square) { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GL_UTILS_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_GL_UTILS_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/image-inl.h b/tensorflow/examples/android/jni/object_tracking/image-inl.h index 9c4c389aa7..61d69908b5 100644 --- a/tensorflow/examples/android/jni/object_tracking/image-inl.h +++ b/tensorflow/examples/android/jni/object_tracking/image-inl.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_INL_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_INL_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_INL_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_INL_H_ #include @@ -641,4 +641,4 @@ inline void Image::FromArray(const T* const pixels, const int stride, } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_INL_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_INL_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/image.h b/tensorflow/examples/android/jni/object_tracking/image.h index b7a2301f5e..a436f0e0a1 100644 --- a/tensorflow/examples/android/jni/object_tracking/image.h +++ b/tensorflow/examples/android/jni/object_tracking/image.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_H_ #include @@ -338,4 +338,4 @@ inline std::ostream& operator<<(std::ostream& stream, const Image& image) { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/image_data.h b/tensorflow/examples/android/jni/object_tracking/image_data.h index 445cdb57a3..c4f91d8cbd 100644 --- a/tensorflow/examples/android/jni/object_tracking/image_data.h +++ b/tensorflow/examples/android/jni/object_tracking/image_data.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_DATA_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_DATA_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_DATA_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_DATA_H_ #include #include @@ -261,4 +261,4 @@ class ImageData { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_DATA_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_DATA_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/image_utils.h b/tensorflow/examples/android/jni/object_tracking/image_utils.h index ac9ffd90f8..b4ad7000b3 100644 --- a/tensorflow/examples/android/jni/object_tracking/image_utils.h +++ b/tensorflow/examples/android/jni/object_tracking/image_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_UTILS_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_UTILS_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_UTILS_H_ #include @@ -295,4 +295,4 @@ inline void NormalizeImage(Image* const image) { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_UTILS_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_IMAGE_UTILS_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/integral_image.h b/tensorflow/examples/android/jni/object_tracking/integral_image.h index 8e82334abf..caf9b7d2ab 100755 --- a/tensorflow/examples/android/jni/object_tracking/integral_image.h +++ b/tensorflow/examples/android/jni/object_tracking/integral_image.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_INTEGRAL_IMAGE_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_INTEGRAL_IMAGE_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_INTEGRAL_IMAGE_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_INTEGRAL_IMAGE_H_ #include "tensorflow/examples/android/jni/object_tracking/geom.h" #include "tensorflow/examples/android/jni/object_tracking/image-inl.h" @@ -184,4 +184,4 @@ class IntegralImage : public Image { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_INTEGRAL_IMAGE_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_INTEGRAL_IMAGE_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/jni_utils.h b/tensorflow/examples/android/jni/object_tracking/jni_utils.h index 21fbabb521..b81d9e0c12 100644 --- a/tensorflow/examples/android/jni/object_tracking/jni_utils.h +++ b/tensorflow/examples/android/jni/object_tracking/jni_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_JNI_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_JNI_UTILS_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_JNI_UTILS_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_JNI_UTILS_H_ #include diff --git a/tensorflow/examples/android/jni/object_tracking/keypoint.h b/tensorflow/examples/android/jni/object_tracking/keypoint.h index 719f9aff3f..93405a5b2a 100644 --- a/tensorflow/examples/android/jni/object_tracking/keypoint.h +++ b/tensorflow/examples/android/jni/object_tracking/keypoint.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_H_ #include "tensorflow/examples/android/jni/object_tracking/geom.h" #include "tensorflow/examples/android/jni/object_tracking/image-inl.h" @@ -45,4 +45,4 @@ inline std::ostream& operator<<(std::ostream& stream, const Keypoint keypoint) { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/keypoint_detector.h b/tensorflow/examples/android/jni/object_tracking/keypoint_detector.h index 33d228128d..2e85b835a7 100644 --- a/tensorflow/examples/android/jni/object_tracking/keypoint_detector.h +++ b/tensorflow/examples/android/jni/object_tracking/keypoint_detector.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_DETECTOR_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_DETECTOR_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_DETECTOR_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_DETECTOR_H_ #include #include @@ -125,4 +125,4 @@ class KeypointDetector { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_DETECTOR_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_KEYPOINT_DETECTOR_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/logging.h b/tensorflow/examples/android/jni/object_tracking/logging.h index dbc89af2f7..852a749399 100644 --- a/tensorflow/examples/android/jni/object_tracking/logging.h +++ b/tensorflow/examples/android/jni/object_tracking/logging.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_LOG_STREAMING_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_LOG_STREAMING_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_LOG_STREAMING_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_LOG_STREAMING_H_ #include #include @@ -118,4 +118,4 @@ void LogPrintF(const int severity, const char* format, ...); #endif -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_LOG_STREAMING_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_LOG_STREAMING_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/object_detector.h b/tensorflow/examples/android/jni/object_tracking/object_detector.h index 2525567678..a65c7b0db7 100644 --- a/tensorflow/examples/android/jni/object_tracking/object_detector.h +++ b/tensorflow/examples/android/jni/object_tracking/object_detector.h @@ -20,8 +20,8 @@ limitations under the License. // Defines the ObjectDetector class that is the main interface for detecting // ObjectModelBases in frames. -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_DETECTOR_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_DETECTOR_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_DETECTOR_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_DETECTOR_H_ #include #include @@ -227,4 +227,4 @@ class ObjectDetector : public ObjectDetectorBase { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_DETECTOR_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_DETECTOR_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/object_model.h b/tensorflow/examples/android/jni/object_tracking/object_model.h index be33aea638..5e81c49080 100644 --- a/tensorflow/examples/android/jni/object_tracking/object_model.h +++ b/tensorflow/examples/android/jni/object_tracking/object_model.h @@ -19,8 +19,8 @@ limitations under the License. // Contains ObjectModelBase declaration. -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_DETECTION_OBJECT_MODEL_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_DETECTION_OBJECT_MODEL_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_DETECTION_OBJECT_MODEL_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_DETECTION_OBJECT_MODEL_H_ #ifdef __RENDER_OPENGL__ #include @@ -99,4 +99,4 @@ class ObjectModel : public ObjectModelBase { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_DETECTION_OBJECT_MODEL_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_DETECTION_OBJECT_MODEL_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/object_tracker.h b/tensorflow/examples/android/jni/object_tracking/object_tracker.h index eb281fad37..20c7627fc5 100644 --- a/tensorflow/examples/android/jni/object_tracking/object_tracker.h +++ b/tensorflow/examples/android/jni/object_tracking/object_tracker.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_TRACKER_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_TRACKER_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_TRACKER_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_TRACKER_H_ #include #include @@ -267,4 +267,4 @@ inline std::ostream& operator<<(std::ostream& stream, } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_TRACKER_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OBJECT_TRACKER_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/optical_flow.h b/tensorflow/examples/android/jni/object_tracking/optical_flow.h index 2206375beb..f98ae22bd6 100644 --- a/tensorflow/examples/android/jni/object_tracking/optical_flow.h +++ b/tensorflow/examples/android/jni/object_tracking/optical_flow.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OPTICAL_FLOW_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OPTICAL_FLOW_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OPTICAL_FLOW_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OPTICAL_FLOW_H_ #include "tensorflow/examples/android/jni/object_tracking/geom.h" #include "tensorflow/examples/android/jni/object_tracking/image-inl.h" @@ -97,4 +97,4 @@ class OpticalFlow { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OPTICAL_FLOW_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_OPTICAL_FLOW_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/sprite.h b/tensorflow/examples/android/jni/object_tracking/sprite.h index 05a13fea11..b54a68458f 100755 --- a/tensorflow/examples/android/jni/object_tracking/sprite.h +++ b/tensorflow/examples/android/jni/object_tracking/sprite.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_ #include #include @@ -199,4 +199,4 @@ class Sprite { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/time_log.h b/tensorflow/examples/android/jni/object_tracking/time_log.h index 60911da396..0073e11596 100644 --- a/tensorflow/examples/android/jni/object_tracking/time_log.h +++ b/tensorflow/examples/android/jni/object_tracking/time_log.h @@ -15,8 +15,8 @@ limitations under the License. // Utility functions for performance profiling. -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_ #include @@ -134,4 +134,4 @@ inline static void TimeLog(const char* const str) { inline static void PrintTimeLog() {} #endif -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TIME_LOG_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/tracked_object.h b/tensorflow/examples/android/jni/object_tracking/tracked_object.h index cda14e19d2..d7f1a7019b 100644 --- a/tensorflow/examples/android/jni/object_tracking/tracked_object.h +++ b/tensorflow/examples/android/jni/object_tracking/tracked_object.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TRACKED_OBJECT_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TRACKED_OBJECT_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TRACKED_OBJECT_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TRACKED_OBJECT_H_ #ifdef __RENDER_OPENGL__ #include "tensorflow/examples/android/jni/object_tracking/gl_utils.h" @@ -183,4 +183,4 @@ inline std::ostream& operator<<(std::ostream& stream, } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TRACKED_OBJECT_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_TRACKED_OBJECT_H_ diff --git a/tensorflow/examples/android/jni/object_tracking/utils.h b/tensorflow/examples/android/jni/object_tracking/utils.h index 51cdfcdcfb..2e98734ec4 100644 --- a/tensorflow/examples/android/jni/object_tracking/utils.h +++ b/tensorflow/examples/android/jni/object_tracking/utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ +#ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ +#define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ #include #include @@ -378,4 +378,4 @@ inline bool Invert2x2(const T* const a, float* const a_inv) { } // namespace tf_tracking -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ +#endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ diff --git a/tensorflow/examples/speech_commands/accuracy_utils.h b/tensorflow/examples/speech_commands/accuracy_utils.h index 8d918cb64b..eea048365b 100644 --- a/tensorflow/examples/speech_commands/accuracy_utils.h +++ b/tensorflow/examples/speech_commands/accuracy_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_ACCURACY_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_ACCURACY_UTILS_H_ +#ifndef TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_ACCURACY_UTILS_H_ +#define TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_ACCURACY_UTILS_H_ #include @@ -57,4 +57,4 @@ void PrintAccuracyStats(const StreamingAccuracyStats& stats); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_ACCURACY_UTILS_H_ +#endif // TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_ACCURACY_UTILS_H_ diff --git a/tensorflow/examples/speech_commands/recognize_commands.h b/tensorflow/examples/speech_commands/recognize_commands.h index 7f8041f9ed..a7cd194bec 100644 --- a/tensorflow/examples/speech_commands/recognize_commands.h +++ b/tensorflow/examples/speech_commands/recognize_commands.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_RECOGNIZE_COMMANDS_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_RECOGNIZE_COMMANDS_H_ +#ifndef TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_RECOGNIZE_COMMANDS_H_ +#define TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_RECOGNIZE_COMMANDS_H_ #include #include @@ -76,4 +76,4 @@ class RecognizeCommands { } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_RECOGNIZE_COMMANDS_H_ +#endif // TENSORFLOW_EXAMPLES_SPEECH_COMMANDS_RECOGNIZE_COMMANDS_H_ diff --git a/tensorflow/examples/wav_to_spectrogram/wav_to_spectrogram.h b/tensorflow/examples/wav_to_spectrogram/wav_to_spectrogram.h index fa8cb0abe9..eada07e06f 100644 --- a/tensorflow/examples/wav_to_spectrogram/wav_to_spectrogram.h +++ b/tensorflow/examples/wav_to_spectrogram/wav_to_spectrogram.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_EXAMPLES_WAV_TO_SPECTROGRAM_WAV_TO_SPECTROGRAM_H_ -#define THIRD_PARTY_TENSORFLOW_EXAMPLES_WAV_TO_SPECTROGRAM_WAV_TO_SPECTROGRAM_H_ +#ifndef TENSORFLOW_EXAMPLES_WAV_TO_SPECTROGRAM_WAV_TO_SPECTROGRAM_H_ +#define TENSORFLOW_EXAMPLES_WAV_TO_SPECTROGRAM_WAV_TO_SPECTROGRAM_H_ #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/platform/types.h" @@ -28,4 +28,4 @@ tensorflow::Status WavToSpectrogram(const tensorflow::string& input_wav, tensorflow::int32 stride, float brightness, const tensorflow::string& output_image); -#endif // THIRD_PARTY_TENSORFLOW_EXAMPLES_WAV_TO_SPECTROGRAM_WAV_TO_SPECTROGRAM_H_ +#endif // TENSORFLOW_EXAMPLES_WAV_TO_SPECTROGRAM_WAV_TO_SPECTROGRAM_H_ diff --git a/tensorflow/python/eager/python_eager_op_gen.h b/tensorflow/python/eager/python_eager_op_gen.h index f9dfdf0408..d27b00139d 100644 --- a/tensorflow/python/eager/python_eager_op_gen.h +++ b/tensorflow/python/eager/python_eager_op_gen.h @@ -12,8 +12,8 @@ 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 THIRD_PARTY_TENSORFLOW_PYTHON_EAGER_PYTHON_EAGER_OP_GEN_H_ -#define THIRD_PARTY_TENSORFLOW_PYTHON_EAGER_PYTHON_EAGER_OP_GEN_H_ +#ifndef TENSORFLOW_PYTHON_EAGER_PYTHON_EAGER_OP_GEN_H_ +#define TENSORFLOW_PYTHON_EAGER_PYTHON_EAGER_OP_GEN_H_ #include #include @@ -40,4 +40,4 @@ string GetEagerPythonWrappers(const char* op_list_buf, size_t op_list_len); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PYTHON_EAGER_PYTHON_EAGER_OP_GEN_H_ +#endif // TENSORFLOW_PYTHON_EAGER_PYTHON_EAGER_OP_GEN_H_ diff --git a/tensorflow/python/framework/cpp_shape_inference.h b/tensorflow/python/framework/cpp_shape_inference.h index afca7277c7..c6ab6b106f 100644 --- a/tensorflow/python/framework/cpp_shape_inference.h +++ b/tensorflow/python/framework/cpp_shape_inference.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ -#define THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ +#ifndef TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ +#define TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ // Must be included first #include "tensorflow/python/lib/core/numpy.h" @@ -51,4 +51,4 @@ std::vector RunCppShapeInference( } // namespace swig } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ +#endif // TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ diff --git a/tensorflow/python/framework/python_op_gen_internal.h b/tensorflow/python/framework/python_op_gen_internal.h index 6b53825a6d..d09b36a3e8 100644 --- a/tensorflow/python/framework/python_op_gen_internal.h +++ b/tensorflow/python/framework/python_op_gen_internal.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_PYTHON_OP_GEN_INTERNAL_H_ -#define THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_PYTHON_OP_GEN_INTERNAL_H_ +#ifndef TENSORFLOW_PYTHON_FRAMEWORK_PYTHON_OP_GEN_INTERNAL_H_ +#define TENSORFLOW_PYTHON_FRAMEWORK_PYTHON_OP_GEN_INTERNAL_H_ #include @@ -112,4 +112,4 @@ class GenPythonOp { } // namespace python_op_gen_internal } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_PYTHON_OP_GEN_INTERNAL_H_ +#endif // TENSORFLOW_PYTHON_FRAMEWORK_PYTHON_OP_GEN_INTERNAL_H_ diff --git a/tensorflow/python/lib/core/ndarray_tensor.h b/tensorflow/python/lib/core/ndarray_tensor.h index 5172d504bd..b2cd4133ca 100644 --- a/tensorflow/python/lib/core/ndarray_tensor.h +++ b/tensorflow/python/lib/core/ndarray_tensor.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_NDARRAY_TENSOR_H_ -#define THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_NDARRAY_TENSOR_H_ +#ifndef TENSORFLOW_PYTHON_LIB_CORE_NDARRAY_TENSOR_H_ +#define TENSORFLOW_PYTHON_LIB_CORE_NDARRAY_TENSOR_H_ // Must be included first. #include "tensorflow/python/lib/core/numpy.h" @@ -45,4 +45,4 @@ Status TensorToNdarray(const Tensor& t, PyObject** ret); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_NDARRAY_TENSOR_H_ +#endif // TENSORFLOW_PYTHON_LIB_CORE_NDARRAY_TENSOR_H_ diff --git a/tensorflow/python/lib/core/py_seq_tensor.h b/tensorflow/python/lib/core/py_seq_tensor.h index 6dc4d9c777..c6e5080c62 100644 --- a/tensorflow/python/lib/core/py_seq_tensor.h +++ b/tensorflow/python/lib/core/py_seq_tensor.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_PY_SEQ_TENSOR_H_ -#define THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_PY_SEQ_TENSOR_H_ +#ifndef TENSORFLOW_PYTHON_LIB_CORE_PY_SEQ_TENSOR_H_ +#define TENSORFLOW_PYTHON_LIB_CORE_PY_SEQ_TENSOR_H_ #include @@ -34,4 +34,4 @@ Status PySeqToTensor(PyObject* obj, PyObject* dtype, Tensor* ret); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_PY_SEQ_TENSOR_H_ +#endif // TENSORFLOW_PYTHON_LIB_CORE_PY_SEQ_TENSOR_H_ diff --git a/tensorflow/python/lib/core/safe_ptr.h b/tensorflow/python/lib/core/safe_ptr.h index 80db840aeb..32d2868886 100644 --- a/tensorflow/python/lib/core/safe_ptr.h +++ b/tensorflow/python/lib/core/safe_ptr.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_SAFE_PTR_H_ -#define THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_SAFE_PTR_H_ +#ifndef TENSORFLOW_PYTHON_LIB_CORE_SAFE_PTR_H_ +#define TENSORFLOW_PYTHON_LIB_CORE_SAFE_PTR_H_ #include @@ -66,4 +66,4 @@ Safe_TF_StatusPtr make_safe(TF_Status* status); } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PYTHON_LIB_CORE_SAFE_PTR_H_ +#endif // TENSORFLOW_PYTHON_LIB_CORE_SAFE_PTR_H_ diff --git a/tensorflow/python/util/kernel_registry.h b/tensorflow/python/util/kernel_registry.h index c00b60d91b..1ba76f020b 100644 --- a/tensorflow/python/util/kernel_registry.h +++ b/tensorflow/python/util/kernel_registry.h @@ -14,8 +14,8 @@ limitations under the License. ==============================================================================*/ // Functions for getting information about kernels registered in the binary. -#ifndef THIRD_PARTY_TENSORFLOW_PYTHON_UTIL_KERNEL_REGISTRY_H_ -#define THIRD_PARTY_TENSORFLOW_PYTHON_UTIL_KERNEL_REGISTRY_H_ +#ifndef TENSORFLOW_PYTHON_UTIL_KERNEL_REGISTRY_H_ +#define TENSORFLOW_PYTHON_UTIL_KERNEL_REGISTRY_H_ #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/platform/types.h" @@ -31,4 +31,4 @@ string TryFindKernelClass(const string& serialized_node_def); } // namespace swig } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PYTHON_UTIL_KERNEL_REGISTRY_H_ +#endif // TENSORFLOW_PYTHON_UTIL_KERNEL_REGISTRY_H_ diff --git a/tensorflow/python/util/util.h b/tensorflow/python/util/util.h index 493d26b497..2af71dc753 100644 --- a/tensorflow/python/util/util.h +++ b/tensorflow/python/util/util.h @@ -14,8 +14,8 @@ limitations under the License. ==============================================================================*/ // Functions for getting information about kernels registered in the binary. -#ifndef THIRD_PARTY_TENSORFLOW_PYTHON_UTIL_UTIL_H_ -#define THIRD_PARTY_TENSORFLOW_PYTHON_UTIL_UTIL_H_ +#ifndef TENSORFLOW_PYTHON_UTIL_UTIL_H_ +#define TENSORFLOW_PYTHON_UTIL_UTIL_H_ #include @@ -71,4 +71,4 @@ void RegisterSequenceClass(PyObject* sequence_class); } // namespace swig } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_PYTHON_UTIL_UTIL_H_ +#endif // TENSORFLOW_PYTHON_UTIL_UTIL_H_ diff --git a/tensorflow/tools/graph_transforms/file_utils.h b/tensorflow/tools/graph_transforms/file_utils.h index 4737e95abc..a3723f5cd3 100644 --- a/tensorflow/tools/graph_transforms/file_utils.h +++ b/tensorflow/tools/graph_transforms/file_utils.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_TOOLS_GRAPH_TRANSFORMS_FILE_UTILS_H_ -#define THIRD_PARTY_TENSORFLOW_TOOLS_GRAPH_TRANSFORMS_FILE_UTILS_H_ +#ifndef TENSORFLOW_TOOLS_GRAPH_TRANSFORMS_FILE_UTILS_H_ +#define TENSORFLOW_TOOLS_GRAPH_TRANSFORMS_FILE_UTILS_H_ #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/lib/core/status.h" @@ -29,4 +29,4 @@ Status LoadTextOrBinaryGraphFile(const string& file_name, GraphDef* graph_def); } // namespace graph_transforms } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_TOOLS_GRAPH_TRANSFORMS_FILE_UTILS_H_ +#endif // TENSORFLOW_TOOLS_GRAPH_TRANSFORMS_FILE_UTILS_H_ diff --git a/tensorflow/tools/proto_text/gen_proto_text_functions_lib.h b/tensorflow/tools/proto_text/gen_proto_text_functions_lib.h index 44387bbd4d..e18d749cff 100644 --- a/tensorflow/tools/proto_text/gen_proto_text_functions_lib.h +++ b/tensorflow/tools/proto_text/gen_proto_text_functions_lib.h @@ -13,8 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#ifndef THIRD_PARTY_TENSORFLOW_CORE_UTIL_CREATE_PROTO_DEBUG_STRING_LIB_H_ -#define THIRD_PARTY_TENSORFLOW_CORE_UTIL_CREATE_PROTO_DEBUG_STRING_LIB_H_ +#ifndef TENSORFLOW_CORE_UTIL_CREATE_PROTO_DEBUG_STRING_LIB_H_ +#define TENSORFLOW_CORE_UTIL_CREATE_PROTO_DEBUG_STRING_LIB_H_ #include "tensorflow/core/platform/protobuf.h" #include "tensorflow/core/platform/types.h" @@ -50,4 +50,4 @@ ProtoTextFunctionCode GetProtoTextFunctionCode( } // namespace tensorflow -#endif // THIRD_PARTY_TENSORFLOW_CORE_UTIL_CREATE_PROTO_DEBUG_STRING_LIB_H_ +#endif // TENSORFLOW_CORE_UTIL_CREATE_PROTO_DEBUG_STRING_LIB_H_ diff --git a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/PacketMathAVX2.h b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/PacketMathAVX2.h index c210b1712c..cb1636256d 100644 --- a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/PacketMathAVX2.h +++ b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/PacketMathAVX2.h @@ -1,5 +1,5 @@ -#ifndef THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX2_H_ -#define THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX2_H_ +#ifndef EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX2_H_ +#define EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX2_H_ #ifdef _MSC_VER @@ -502,4 +502,4 @@ struct functor_traits> { } // end namespace internal } // end namespace Eigen -#endif // THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX2_H_ +#endif // EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX2_H_ diff --git a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/PacketMathAVX512.h b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/PacketMathAVX512.h index 7a222fddc1..8f9906dbf9 100644 --- a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/PacketMathAVX512.h +++ b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/PacketMathAVX512.h @@ -1,5 +1,5 @@ -#ifndef THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX512_H_ -#define THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX512_H_ +#ifndef EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX512_H_ +#define EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX512_H_ #include "PacketMathAVX2.h" @@ -542,4 +542,4 @@ EIGEN_STRONG_INLINE QInt8 predux_max(const Packet64q8i& a) { } // end namespace internal } // end namespace Eigen -#endif // THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX512_H_ +#endif // EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_PACKETMATHAVX512_H_ diff --git a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/TypeCastingAVX2.h b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/TypeCastingAVX2.h index 045384d7fc..7b4ecc752f 100644 --- a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/TypeCastingAVX2.h +++ b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/TypeCastingAVX2.h @@ -1,5 +1,5 @@ -#ifndef THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX2_H_ -#define THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX2_H_ +#ifndef EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX2_H_ +#define EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX2_H_ namespace Eigen { namespace internal { @@ -63,4 +63,4 @@ pcast(const Packet8q32i& a, const Packet8q32i& b, } // end namespace internal } // end namespace Eigen -#endif // THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX2_H_ +#endif // EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX2_H_ diff --git a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/TypeCastingAVX512.h b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/TypeCastingAVX512.h index cd7120ec00..26735743d4 100644 --- a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/TypeCastingAVX512.h +++ b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/TypeCastingAVX512.h @@ -1,5 +1,5 @@ -#ifndef THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX512_H_ -#define THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX512_H_ +#ifndef EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX512_H_ +#define EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX512_H_ namespace Eigen { namespace internal { @@ -177,4 +177,4 @@ pcast(const Packet16q32i& a, } // end namespace internal } // end namespace Eigen -#endif // THIRD_PARTY_EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX512_H_ +#endif // EIGEN3_UNSUPPORTED_EIGEN_CXX11_SRC_FIXEDPOINT_TYPECASTINGAVX512_H_ diff --git a/third_party/fft2d/fft.h b/third_party/fft2d/fft.h index 252cc01fec..31b4935089 100644 --- a/third_party/fft2d/fft.h +++ b/third_party/fft2d/fft.h @@ -15,8 +15,8 @@ limitations under the License. // Declarations for 1D FFT routines in third_party/fft2d/fft. -#ifndef THIRD_PARTY_FFT2D_FFT_H__ -#define THIRD_PARTY_FFT2D_FFT_H__ +#ifndef FFT2D_FFT_H__ +#define FFT2D_FFT_H__ #ifdef __cplusplus extern "C" { @@ -33,4 +33,4 @@ extern void dfst(int, double *, double *, int *, double *); } #endif -#endif // THIRD_PARTY_FFT2D_FFT_H__ +#endif // FFT2D_FFT_H__ -- GitLab From 98809980c420bb5db4759ce796d6b6dcc8877b73 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 14:41:35 -0800 Subject: [PATCH 214/258] [XLA] Enable F16 for the CPU and GPU backends. Enhance the IR emitter to handle mathematics operations with F16 types. Add tests for F16 mathematics operations. PiperOrigin-RevId: 183144087 --- .../xla/service/cpu/elemental_ir_emitter.cc | 32 ++- .../xla/service/gpu/elemental_ir_emitter.cc | 41 ++- .../compiler/xla/service/llvm_ir/llvm_util.cc | 7 + tensorflow/compiler/xla/tests/BUILD | 24 ++ .../xla/tests/client_library_test_base.h | 5 + tensorflow/compiler/xla/tests/half_test.cc | 257 ++++++++++++++++++ .../compiler/xla/tests/literal_test_util.cc | 12 + 7 files changed, 362 insertions(+), 16 deletions(-) create mode 100644 tensorflow/compiler/xla/tests/half_test.cc diff --git a/tensorflow/compiler/xla/service/cpu/elemental_ir_emitter.cc b/tensorflow/compiler/xla/service/cpu/elemental_ir_emitter.cc index ebd96c4c42..99c5e16db7 100644 --- a/tensorflow/compiler/xla/service/cpu/elemental_ir_emitter.cc +++ b/tensorflow/compiler/xla/service/cpu/elemental_ir_emitter.cc @@ -33,8 +33,14 @@ StatusOr CpuElementalIrEmitter::EmitFloatUnaryOp( switch (op->opcode()) { case HloOpcode::kTanh: { PrimitiveType element_type = op->shape().element_type(); + bool cast_result_to_fp16 = false; string function_name; switch (element_type) { + case F16: + cast_result_to_fp16 = true; + operand_value = ir_builder_->CreateFPCast(operand_value, + ir_builder_->getFloatTy()); + TF_FALLTHROUGH_INTENDED; case F32: function_name = "tanhf"; break; @@ -44,7 +50,7 @@ StatusOr CpuElementalIrEmitter::EmitFloatUnaryOp( default: return Unimplemented("tanh"); } - // Create function declaration for 'tanhf'. + // Create a function declaration. llvm::Function* function = llvm::cast(module_->getOrInsertFunction( llvm_ir::AsStringRef(function_name), operand_value->getType(), @@ -52,8 +58,12 @@ StatusOr CpuElementalIrEmitter::EmitFloatUnaryOp( function->setCallingConv(llvm::CallingConv::C); function->setDoesNotThrow(); function->setDoesNotAccessMemory(); - // Create instruction to call 'tanhf'. - return ir_builder_->CreateCall(function, operand_value); + // Create an instruction to call the function. + llvm::Value* result = ir_builder_->CreateCall(function, operand_value); + if (cast_result_to_fp16) { + result = ir_builder_->CreateFPCast(result, ir_builder_->getHalfTy()); + } + return result; } default: return ElementalIrEmitter::EmitFloatUnaryOp(op, operand_value); @@ -63,7 +73,13 @@ StatusOr CpuElementalIrEmitter::EmitFloatUnaryOp( StatusOr CpuElementalIrEmitter::EmitAtan2( PrimitiveType prim_type, llvm::Value* lhs, llvm::Value* rhs) const { string function_name; + bool cast_result_to_fp16 = false; switch (prim_type) { + case F16: + cast_result_to_fp16 = true; + lhs = ir_builder_->CreateFPCast(lhs, ir_builder_->getFloatTy()); + rhs = ir_builder_->CreateFPCast(rhs, ir_builder_->getFloatTy()); + TF_FALLTHROUGH_INTENDED; case F32: function_name = "atan2f"; break; @@ -73,7 +89,7 @@ StatusOr CpuElementalIrEmitter::EmitAtan2( default: return Unimplemented("atan2"); } - // Create function declaration for 'atan2'. + // Create a function declaration. llvm::Function* function = llvm::cast(module_->getOrInsertFunction( llvm_ir::AsStringRef(function_name), lhs->getType(), lhs->getType(), @@ -81,8 +97,12 @@ StatusOr CpuElementalIrEmitter::EmitAtan2( function->setCallingConv(llvm::CallingConv::C); function->setDoesNotThrow(); function->setDoesNotAccessMemory(); - // Create instruction to call 'atan2'. - return ir_builder_->CreateCall(function, {lhs, rhs}); + // Create an instruction to call the function. + llvm::Value* result = ir_builder_->CreateCall(function, {lhs, rhs}); + if (cast_result_to_fp16) { + result = ir_builder_->CreateFPCast(result, ir_builder_->getHalfTy()); + } + return result; } llvm_ir::ElementGenerator CpuElementalIrEmitter::MakeElementGenerator( diff --git a/tensorflow/compiler/xla/service/gpu/elemental_ir_emitter.cc b/tensorflow/compiler/xla/service/gpu/elemental_ir_emitter.cc index 4b511cb4bb..5af7a77ea8 100644 --- a/tensorflow/compiler/xla/service/gpu/elemental_ir_emitter.cc +++ b/tensorflow/compiler/xla/service/gpu/elemental_ir_emitter.cc @@ -72,9 +72,27 @@ StatusOr GpuElementalIrEmitter::EmitLibdeviceMathCall( tensorflow::gtl::ArraySlice input_types, PrimitiveType output_type) const { // The libdevice math functions differentiate between "double" and "float" by - // appending an 'f' to the function's name. + // appending an 'f' to the function's name. libdevice doesn't have f16 math + // functions, so we convert the operands to f32 before calling the function + // and then convert the result back to f16. string munged_callee = callee_name; + bool cast_result_to_fp16 = false; + std::vector converted_operands(operands.begin(), + operands.end()); + std::vector converted_input_types(input_types.begin(), + input_types.end()); switch (output_type) { + case F16: + cast_result_to_fp16 = true; + for (int64 i = 0; i < operands.size(); ++i) { + if (input_types[i] == F16) { + converted_operands[i] = ir_builder_->CreateFPCast( + converted_operands[i], ir_builder_->getFloatTy()); + converted_input_types[i] = F32; + } + } + output_type = F32; + TF_FALLTHROUGH_INTENDED; case F32: StrAppend(&munged_callee, "f"); break; @@ -84,7 +102,13 @@ StatusOr GpuElementalIrEmitter::EmitLibdeviceMathCall( return Unimplemented("Bad type for libdevice math call: %s", PrimitiveType_Name(output_type).c_str()); } - return EmitMathCall(munged_callee, operands, input_types, output_type); + llvm::Value* result = EmitMathCall(munged_callee, converted_operands, + converted_input_types, output_type) + .ValueOrDie(); + if (cast_result_to_fp16) { + result = ir_builder_->CreateFPCast(result, ir_builder_->getHalfTy()); + } + return result; } StatusOr GpuElementalIrEmitter::EmitLlvmIntrinsicMathCall( @@ -92,10 +116,13 @@ StatusOr GpuElementalIrEmitter::EmitLlvmIntrinsicMathCall( tensorflow::gtl::ArraySlice operands, tensorflow::gtl::ArraySlice input_types, PrimitiveType output_type) const { - // llvm intrinsics differentiate between float/double functions via the ".f32" - // and ".f64" suffixes. + // llvm intrinsics differentiate between half/float/double functions via + // the suffixes ".f16", ".f32" and ".f64". string munged_callee = callee_name; switch (output_type) { + case F16: + StrAppend(&munged_callee, ".f16"); + break; case F32: StrAppend(&munged_callee, ".f32"); break; @@ -233,12 +260,6 @@ StatusOr GpuElementalIrEmitter::EmitFloatUnaryOp( PrimitiveType input_type = op->operand(0)->shape().element_type(); PrimitiveType output_type = op->shape().element_type(); switch (op->opcode()) { - case HloOpcode::kFloor: - return EmitLibdeviceMathCall("__nv_floor", {operand_value}, {input_type}, - output_type); - case HloOpcode::kCeil: - return EmitLibdeviceMathCall("__nv_ceil", {operand_value}, {input_type}, - output_type); case HloOpcode::kTanh: return EmitLibdeviceMathCall("__nv_tanh", {operand_value}, {input_type}, output_type); diff --git a/tensorflow/compiler/xla/service/llvm_ir/llvm_util.cc b/tensorflow/compiler/xla/service/llvm_ir/llvm_util.cc index d2bcb38d09..8d1e6338e1 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/llvm_util.cc +++ b/tensorflow/compiler/xla/service/llvm_ir/llvm_util.cc @@ -150,6 +150,8 @@ llvm::Type* PrimitiveTypeToIrType(PrimitiveType element_type, // addition to an addition on this type (int16) - this is just the type // used for storage. return llvm::Type::getInt16Ty(module->getContext()); + case F16: + return llvm::Type::getHalfTy(module->getContext()); case S32: case U32: return llvm::Type::getInt32Ty(module->getContext()); @@ -292,6 +294,11 @@ llvm::Constant* LiteralToConstant(const Literal& literal, int64 dimension_index, ir_element_type, tensorflow::bit_cast(literal.Get(*multi_index))); break; + case F16: + value = llvm::ConstantFP::get( + ir_element_type, + static_cast(literal.Get(*multi_index))); + break; case F64: value = llvm::ConstantFP::get(ir_element_type, literal.Get(*multi_index)); diff --git a/tensorflow/compiler/xla/tests/BUILD b/tensorflow/compiler/xla/tests/BUILD index 84e7c1770b..6ab406d6c3 100644 --- a/tensorflow/compiler/xla/tests/BUILD +++ b/tensorflow/compiler/xla/tests/BUILD @@ -844,6 +844,30 @@ xla_test( ], ) +xla_test( + name = "half_test", + srcs = ["half_test.cc"], + backends = [ + "cpu", + "gpu", + ], + deps = [ + ":test_utils", + "//tensorflow/compiler/xla:literal_util", + "//tensorflow/compiler/xla:statusor", + "//tensorflow/compiler/xla:test", + "//tensorflow/compiler/xla:test_helpers", + "//tensorflow/compiler/xla/client:computation", + "//tensorflow/compiler/xla/client:computation_builder", + "//tensorflow/compiler/xla/tests:client_library_test_base", + "//tensorflow/compiler/xla/tests:hlo_test_base", + "//tensorflow/compiler/xla/tests:literal_test_util", + "//tensorflow/compiler/xla/tests:xla_internal_test_main", + "//tensorflow/core:lib", + "//tensorflow/core:test", + ], +) + xla_test( name = "slice_test", srcs = ["slice_test.cc"], diff --git a/tensorflow/compiler/xla/tests/client_library_test_base.h b/tensorflow/compiler/xla/tests/client_library_test_base.h index a559a653df..ba0319990b 100644 --- a/tensorflow/compiler/xla/tests/client_library_test_base.h +++ b/tensorflow/compiler/xla/tests/client_library_test_base.h @@ -431,6 +431,7 @@ void ClientLibraryTestBase::ComputeAndCompareR0( static_assert(std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value, "Float or complex type required when specifying an ErrorSpec"); std::unique_ptr expected_literal = @@ -456,6 +457,7 @@ void ClientLibraryTestBase::ComputeAndCompareR1( static_assert(std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value, "Float or complex type required when specifying an ErrorSpec"); std::unique_ptr expected_literal = @@ -481,6 +483,7 @@ void ClientLibraryTestBase::ComputeAndCompareR2( static_assert(std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value, "Float or complex type required when specifying an ErrorSpec"); std::unique_ptr expected_literal = @@ -506,6 +509,7 @@ void ClientLibraryTestBase::ComputeAndCompareR3( static_assert(std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value, "Float or complex type required when specifying an ErrorSpec"); std::unique_ptr expected_literal = @@ -531,6 +535,7 @@ void ClientLibraryTestBase::ComputeAndCompareR4( static_assert(std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value, "Float or complex type required when specifying an ErrorSpec"); std::unique_ptr expected_literal = diff --git a/tensorflow/compiler/xla/tests/half_test.cc b/tensorflow/compiler/xla/tests/half_test.cc new file mode 100644 index 0000000000..ec2f49d43b --- /dev/null +++ b/tensorflow/compiler/xla/tests/half_test.cc @@ -0,0 +1,257 @@ +/* Copyright 2018 The TensorFlow Authors. 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 +#include + +#include "tensorflow/compiler/xla/client/computation.h" +#include "tensorflow/compiler/xla/client/computation_builder.h" +#include "tensorflow/compiler/xla/literal_util.h" +#include "tensorflow/compiler/xla/statusor.h" +#include "tensorflow/compiler/xla/test.h" +#include "tensorflow/compiler/xla/test_helpers.h" +#include "tensorflow/compiler/xla/tests/client_library_test_base.h" +#include "tensorflow/compiler/xla/tests/test_macros.h" +#include "tensorflow/compiler/xla/tests/test_utils.h" + +// Tests the handling of the basic mathematics operations with F16 operands. + +namespace xla { +namespace { + +class HalfTestBase : public ClientLibraryTestBase { + protected: + const ErrorSpec error_spec_{0.001, 0.001}; + // Number of elements in the input buffers. + static const int kNumElements = 4; +}; + +using UnaryBuildFuncTy = + std::function; + +struct UnaryOpTestParam { + std::function compute_func; + UnaryBuildFuncTy build_func; +}; + +class UnaryOpTest : public HalfTestBase, + public ::testing::WithParamInterface {}; + +XLA_TEST_P(UnaryOpTest, Ops) { + std::vector x({half(1.4), half(-2.3), half(3.2), half(-4.1)}); + ComputationBuilder builder(client_, TestName()); + ComputationDataHandle x_opnd; + auto x_data = CreateR1Parameter(x, /*parameter_number=*/0, "x", + &builder, &x_opnd); + + std::function compute_func = GetParam().compute_func; + std::vector expected; + for (int64 i = 0; i < x.size(); ++i) { + expected.push_back(compute_func(x[i])); + } + + UnaryBuildFuncTy build_func = GetParam().build_func; + build_func(&builder, x_opnd); + + ComputeAndCompareR1(&builder, expected, {x_data.get()}, error_spec_); +} + +half sign_imp(half value) { + const float x(std::move(value)); + return half((x < .0) ? -1 : (x > .0)); +} + +half round_imp(half value) { + return half(round(static_cast(std::move(value)))); +} + +INSTANTIATE_TEST_CASE_P( + half, UnaryOpTest, + ::testing::Values(UnaryOpTestParam{[](half x) { return abs(x); }, + &ComputationBuilder::Abs}, + UnaryOpTestParam{[](half x) { return round_imp(x); }, + &ComputationBuilder::Round}, + UnaryOpTestParam{[](half x) { return ceil(x); }, + &ComputationBuilder::Ceil}, + UnaryOpTestParam{[](half x) { return cos(x); }, + &ComputationBuilder::Cos}, + UnaryOpTestParam{[](half x) { return exp(x); }, + &ComputationBuilder::Exp}, + UnaryOpTestParam{[](half x) { return floor(x); }, + &ComputationBuilder::Floor}, + UnaryOpTestParam{[](half x) { return log(x); }, + &ComputationBuilder::Log}, + UnaryOpTestParam{[](half x) { return -x; }, + &ComputationBuilder::Neg}, + UnaryOpTestParam{[](half x) { return sign_imp(x); }, + &ComputationBuilder::Sign}, + UnaryOpTestParam{[](half x) { return sin(x); }, + &ComputationBuilder::Sin}, + UnaryOpTestParam{[](half x) { return tanh(x); }, + &ComputationBuilder::Tanh} + + )); + +struct UnaryPredTestParam { + std::function compute_func; + UnaryBuildFuncTy build_func; +}; + +class UnaryPredTest : public HalfTestBase, + public ::testing::WithParamInterface { +}; + +XLA_TEST_P(UnaryPredTest, Ops) { + std::vector x({half(1.4), half(-2.3), half(3.2), half(-4.1)}); + ComputationBuilder builder(client_, TestName()); + ComputationDataHandle x_opnd; + auto x_data = CreateR1Parameter(x, /*parameter_number=*/0, "x", + &builder, &x_opnd); + + std::function compute_func = GetParam().compute_func; + CHECK_EQ(kNumElements, x.size()); + bool expected[kNumElements]; + for (int64 i = 0; i < x.size(); ++i) { + expected[i] = compute_func(x[i]); + } + + UnaryBuildFuncTy build_func = GetParam().build_func; + build_func(&builder, x_opnd); + + ComputeAndCompareR1(&builder, expected, {x_data.get()}); +} + +INSTANTIATE_TEST_CASE_P(half, UnaryPredTest, + ::testing::Values(UnaryPredTestParam{ + [](half x) { return isfinite(x); }, + &ComputationBuilder::IsFinite})); + +using BinaryBuildFuncTy = std::function)>; + +struct BinaryOpTestParam { + std::function compute_func; + BinaryBuildFuncTy build_func; +}; + +class BinaryOpTest : public HalfTestBase, + public ::testing::WithParamInterface {}; + +XLA_TEST_P(BinaryOpTest, Ops) { + std::vector x({half(1.0), half(2.0), half(3.0), half(-4.0)}); + std::vector y({half(0.4), half(-0.3), half(0.2), half(0.1)}); + ComputationBuilder builder(client_, TestName()); + ComputationDataHandle x_opnd; + auto x_data = CreateR1Parameter(x, /*parameter_number=*/0, "x", + &builder, &x_opnd); + + ComputationDataHandle y_opnd; + auto y_data = CreateR1Parameter(y, /*parameter_number=*/1, "y", + &builder, &y_opnd); + + std::function compute_func = GetParam().compute_func; + std::vector expected; + for (int64 i = 0; i < x.size(); ++i) { + expected.push_back(compute_func(x[i], y[i])); + } + + BinaryBuildFuncTy build_func = GetParam().build_func; + build_func(&builder, x_opnd, y_opnd, {}); + + ComputeAndCompareR1(&builder, expected, {x_data.get(), y_data.get()}, + error_spec_); +} + +half atan2_imp(half x, half y) { + return half(atan2(static_cast(std::move(x)), + static_cast(std::move(y)))); +} + +INSTANTIATE_TEST_CASE_P( + half, BinaryOpTest, + ::testing::Values( + BinaryOpTestParam{[](half x, half y) { return x + y; }, + &ComputationBuilder::Add}, + BinaryOpTestParam{[](half x, half y) { return atan2_imp(x, y); }, + &ComputationBuilder::Atan2}, + BinaryOpTestParam{[](half x, half y) { return x / y; }, + &ComputationBuilder::Div}, + BinaryOpTestParam{[](half x, half y) { return max(x, y); }, + &ComputationBuilder::Max}, + BinaryOpTestParam{[](half x, half y) { return min(x, y); }, + &ComputationBuilder::Min}, + BinaryOpTestParam{[](half x, half y) { return x * y; }, + &ComputationBuilder::Mul}, + BinaryOpTestParam{[](half x, half y) { return pow(x, y); }, + &ComputationBuilder::Pow}, + BinaryOpTestParam{[](half x, half y) { return x - y; }, + &ComputationBuilder::Sub} + + )); + +struct BinaryPredTestParam { + std::function compute_func; + BinaryBuildFuncTy build_func; +}; + +class BinaryPredTest + : public HalfTestBase, + public ::testing::WithParamInterface {}; + +XLA_TEST_P(BinaryPredTest, Ops) { + std::vector x({half(1.0), half(2.0), half(0.2), half(-4.0)}); + std::vector y({half(0.4), half(-0.3), half(0.2), half(0.1)}); + ComputationBuilder builder(client_, TestName()); + ComputationDataHandle x_opnd; + auto x_data = CreateR1Parameter(x, /*parameter_number=*/0, "x", + &builder, &x_opnd); + + ComputationDataHandle y_opnd; + auto y_data = CreateR1Parameter(y, /*parameter_number=*/1, "y", + &builder, &y_opnd); + + std::function compute_func = GetParam().compute_func; + CHECK_EQ(kNumElements, x.size()); + bool expected[kNumElements]; + for (int64 i = 0; i < x.size(); ++i) { + expected[i] = compute_func(x[i], y[i]); + } + + BinaryBuildFuncTy build_func = GetParam().build_func; + build_func(&builder, x_opnd, y_opnd, {}); + + ComputeAndCompareR1(&builder, expected, {x_data.get(), y_data.get()}); +} + +INSTANTIATE_TEST_CASE_P( + half, BinaryPredTest, + ::testing::Values(BinaryPredTestParam{[](half x, half y) { return x == y; }, + &ComputationBuilder::Eq}, + BinaryPredTestParam{[](half x, half y) { return x != y; }, + &ComputationBuilder::Ne}, + BinaryPredTestParam{[](half x, half y) { return x >= y; }, + &ComputationBuilder::Ge}, + BinaryPredTestParam{[](half x, half y) { return x > y; }, + &ComputationBuilder::Gt}, + BinaryPredTestParam{[](half x, half y) { return x <= y; }, + &ComputationBuilder::Le}, + BinaryPredTestParam{[](half x, half y) { return x < y; }, + &ComputationBuilder::Lt} + + )); + +} // namespace +} // namespace xla diff --git a/tensorflow/compiler/xla/tests/literal_test_util.cc b/tensorflow/compiler/xla/tests/literal_test_util.cc index 975feaa050..f8205de702 100644 --- a/tensorflow/compiler/xla/tests/literal_test_util.cc +++ b/tensorflow/compiler/xla/tests/literal_test_util.cc @@ -301,6 +301,9 @@ bool ExpectLiteralsEqual(const Literal& expected, const Literal& actual, case BF16: match = ExpectLiteralsEqual(expected, actual, &multi_index, 0); break; + case F16: + match = ExpectLiteralsEqual(expected, actual, &multi_index, 0); + break; case F32: match = ExpectLiteralsEqual(expected, actual, &multi_index, 0); break; @@ -380,6 +383,9 @@ class NearComparator { case BF16: ExpectLiteralsNear(expected, actual, 0); break; + case F16: + ExpectLiteralsNear(expected, actual, 0); + break; case F32: ExpectLiteralsNear(expected, actual, 0); break; @@ -572,6 +578,12 @@ bool NearComparator::ExpectValuesNear(bfloat16 expected, static_cast(actual)); } +template <> +bool NearComparator::ExpectValuesNear(half expected, half actual) { + return ExpectValuesNear(static_cast(std::move(expected)), + static_cast(std::move(actual))); +} + } // namespace /* static */ ::testing::AssertionResult LiteralTestUtil::Near( -- GitLab From 170246dadb4926fb35000bba8beffb73f2299968 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 14:56:16 -0800 Subject: [PATCH 215/258] Go: Update generated wrapper functions for TensorFlow ops. PiperOrigin-RevId: 183146357 --- tensorflow/go/op/wrappers.go | 132 +++++++++++++++++------------------ 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/tensorflow/go/op/wrappers.go b/tensorflow/go/op/wrappers.go index 7873201f3e..5b19c90238 100644 --- a/tensorflow/go/op/wrappers.go +++ b/tensorflow/go/op/wrappers.go @@ -5486,6 +5486,72 @@ func QuantizedReluX(scope *Scope, features tf.Output, max_value tf.Output, min_f return op.Output(0), op.Output(1), op.Output(2) } +// SummaryWriterAttr is an optional argument to SummaryWriter. +type SummaryWriterAttr func(optionalAttr) + +// SummaryWriterSharedName sets the optional shared_name attribute to value. +// If not specified, defaults to "" +func SummaryWriterSharedName(value string) SummaryWriterAttr { + return func(m optionalAttr) { + m["shared_name"] = value + } +} + +// SummaryWriterContainer sets the optional container attribute to value. +// If not specified, defaults to "" +func SummaryWriterContainer(value string) SummaryWriterAttr { + return func(m optionalAttr) { + m["container"] = value + } +} + +// Returns a handle to be used to access a summary writer. +// +// The summary writer is an in-graph resource which can be used by ops to write +// summaries to event files. +// +// Returns the summary writer resource. Scalar handle. +func SummaryWriter(scope *Scope, optional ...SummaryWriterAttr) (writer tf.Output) { + if scope.Err() != nil { + return + } + attrs := map[string]interface{}{} + for _, a := range optional { + a(attrs) + } + opspec := tf.OpSpec{ + Type: "SummaryWriter", + + Attrs: attrs, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + +// Computes gradients for SparseSegmentMean. +// +// Returns tensor "output" with same shape as grad, except for dimension 0 whose +// value is output_dim0. +// +// Arguments: +// grad: gradient propagated to the SparseSegmentMean op. +// indices: indices passed to the corresponding SparseSegmentMean op. +// segment_ids: segment_ids passed to the corresponding SparseSegmentMean op. +// output_dim0: dimension 0 of "data" passed to SparseSegmentMean op. +func SparseSegmentMeanGrad(scope *Scope, grad tf.Output, indices tf.Output, segment_ids tf.Output, output_dim0 tf.Output) (output tf.Output) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "SparseSegmentMeanGrad", + Input: []tf.Input{ + grad, indices, segment_ids, output_dim0, + }, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + // Applies softmax to a batched N-D `SparseTensor`. // // The inputs represent an N-D SparseTensor with logical shape `[..., B, C]` @@ -18597,72 +18663,6 @@ func MatchingFiles(scope *Scope, pattern tf.Output) (filenames tf.Output) { return op.Output(0) } -// Computes gradients for SparseSegmentMean. -// -// Returns tensor "output" with same shape as grad, except for dimension 0 whose -// value is output_dim0. -// -// Arguments: -// grad: gradient propagated to the SparseSegmentMean op. -// indices: indices passed to the corresponding SparseSegmentMean op. -// segment_ids: segment_ids passed to the corresponding SparseSegmentMean op. -// output_dim0: dimension 0 of "data" passed to SparseSegmentMean op. -func SparseSegmentMeanGrad(scope *Scope, grad tf.Output, indices tf.Output, segment_ids tf.Output, output_dim0 tf.Output) (output tf.Output) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "SparseSegmentMeanGrad", - Input: []tf.Input{ - grad, indices, segment_ids, output_dim0, - }, - } - op := scope.AddOperation(opspec) - return op.Output(0) -} - -// SummaryWriterAttr is an optional argument to SummaryWriter. -type SummaryWriterAttr func(optionalAttr) - -// SummaryWriterSharedName sets the optional shared_name attribute to value. -// If not specified, defaults to "" -func SummaryWriterSharedName(value string) SummaryWriterAttr { - return func(m optionalAttr) { - m["shared_name"] = value - } -} - -// SummaryWriterContainer sets the optional container attribute to value. -// If not specified, defaults to "" -func SummaryWriterContainer(value string) SummaryWriterAttr { - return func(m optionalAttr) { - m["container"] = value - } -} - -// Returns a handle to be used to access a summary writer. -// -// The summary writer is an in-graph resource which can be used by ops to write -// summaries to event files. -// -// Returns the summary writer resource. Scalar handle. -func SummaryWriter(scope *Scope, optional ...SummaryWriterAttr) (writer tf.Output) { - if scope.Err() != nil { - return - } - attrs := map[string]interface{}{} - for _, a := range optional { - a(attrs) - } - opspec := tf.OpSpec{ - Type: "SummaryWriter", - - Attrs: attrs, - } - op := scope.AddOperation(opspec) - return op.Output(0) -} - // ResizeBicubicGradAttr is an optional argument to ResizeBicubicGrad. type ResizeBicubicGradAttr func(optionalAttr) -- GitLab From b3294d74c73d8f01412ffeeac616d0b8a2f4e18e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 15:07:21 -0800 Subject: [PATCH 216/258] When a device list API such as TF_DeviceListName() succeeds, set the output status to OK. PiperOrigin-RevId: 183148319 --- tensorflow/c/c_api.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/c/c_api.cc b/tensorflow/c/c_api.cc index 92c9adbec7..3c7f041b39 100644 --- a/tensorflow/c/c_api.cc +++ b/tensorflow/c/c_api.cc @@ -927,6 +927,7 @@ int TF_DeviceListCount(const TF_DeviceList* list) { status->status = InvalidArgument("index out of bounds"); \ return err_val; \ } \ + status->status = Status::OK(); \ return list->response[index].accessor; \ } -- GitLab From 2d78a128d67b7469e0da1143fab51d96ab9aa3aa Mon Sep 17 00:00:00 2001 From: Amit Patankar Date: Wed, 24 Jan 2018 15:10:19 -0800 Subject: [PATCH 217/258] Parameterized docker build now supports a local pip whl file path. PiperOrigin-RevId: 183148798 --- .../docker/parameterized_docker_build.sh | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tensorflow/tools/docker/parameterized_docker_build.sh b/tensorflow/tools/docker/parameterized_docker_build.sh index fa867b65db..b4fba5b8f5 100755 --- a/tensorflow/tools/docker/parameterized_docker_build.sh +++ b/tensorflow/tools/docker/parameterized_docker_build.sh @@ -34,6 +34,11 @@ # If set to a non-empty string, will use it as the URL from which the # pip wheel file will be downloaded (instead of building the pip locally). # +# TF_DOCKER_BUILD_CENTRAL_PIP_IS_LOCAL +# (Optional) +# If set to a non-empty string, we will treat TF_DOCKER_BUILD_CENTRAL_PIP +# as a path rather than a url. +# # TF_DOCKER_BUILD_IMAGE_NAME: # (Optional) # If set to any non-empty value, will use it as the image of the @@ -234,6 +239,32 @@ if [[ "${TF_DOCKER_BUILD_IS_DEVEL}" == "no" ]]; then "COPY ${PIP_WHL} /\n"\ "RUN pip --no-cache-dir install /${PIP_WHL}" "${ORIG_DOCKERFILE}" \ > "${DOCKERFILE}" + + # Build from a local whl file path rather than an URL + elif [[ ! -z "${TF_DOCKER_BUILD_CENTRAL_PIP_IS_LOCAL}" ]]; then + PIP_WHL="${TF_DOCKER_BUILD_CENTRAL_PIP}" + if [[ -z "${PIP_WHL}" ]]; then + die "ERROR: Cannot locate the specified pip whl file" + fi + echo "Specified PIP whl file is at: ${PIP_WHL}" + + # Copy the pip file to tmp directory + cp "${PIP_WHL}" "${TMP_DIR}/" || \ + die "ERROR: Failed to copy wheel file: ${PIP_WHL}" + + # Use string replacement to put the correct file name into the Dockerfile + PIP_WHL=$(basename "${PIP_WHL}") + + # Modify the non-devel Dockerfile to point to the correct pip whl file + # location + sed -e "/# --- DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/,"\ +"/# --- ~ DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/c"\ +"COPY ${PIP_WHL} /\n"\ +"RUN pip --no-cache-dir install /${PIP_WHL}" "${ORIG_DOCKERFILE}" \ + > "${DOCKERFILE}" + echo "Using local pip wheel from: ${TF_DOCKER_BUILD_CENTRAL_PIP}" + echo + else echo "Downloading pip wheel from: ${TF_DOCKER_BUILD_CENTRAL_PIP}" echo -- GitLab From a5eaaf5996fc8a802e8d15de95447c849067c94f Mon Sep 17 00:00:00 2001 From: Eugene Brevdo Date: Wed, 24 Jan 2018 15:10:28 -0800 Subject: [PATCH 218/258] Modify dynamic_rnn to use max_seq_length for its while_loop. This is especially important with XLA compilation, which will usually have a maximum time dimension on the input that is (sometimes much larger than) max(sequence_length). In these cases, a lot of compute can be saved. PiperOrigin-RevId: 183148831 --- tensorflow/python/ops/rnn.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/tensorflow/python/ops/rnn.py b/tensorflow/python/ops/rnn.py index a079b4485f..a1008f1c83 100644 --- a/tensorflow/python/ops/rnn.py +++ b/tensorflow/python/ops/rnn.py @@ -35,7 +35,6 @@ from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops -from tensorflow.python.ops import control_flow_util from tensorflow.python.ops import math_ops from tensorflow.python.ops import rnn_cell_impl from tensorflow.python.ops import tensor_array_ops @@ -726,6 +725,8 @@ def _dynamic_rnn_loop(cell, if sequence_length is not None: min_sequence_length = math_ops.reduce_min(sequence_length) max_sequence_length = math_ops.reduce_max(sequence_length) + else: + max_sequence_length = time_steps time = array_ops.constant(0, dtype=dtypes.int32, name="time") @@ -810,28 +811,18 @@ def _dynamic_rnn_loop(cell, return (time + 1, output_ta_t, new_state) - # TODO(pbar) `loop_bound` can be reduced to `max_sequence_length` once - # TensorArray shape inference is working. When sequence lengths are highly - # variable, this will reduce the performance overheads of padding to a fixed - # maximum length. - loop_bound = time_steps - - # This is a workaround since we cannot currently use maximum_iterations if - # time_steps is defined inside control flow, see the comment in - # control_flow_ops.py. - if (context.in_eager_mode() or - not (control_flow_util.IsInWhileLoop(time_steps.op) or - control_flow_util.IsInCond(time_steps.op))): - maximum_iterations = time_steps + if in_graph_mode: + loop_bound = max_sequence_length else: - maximum_iterations = None + # Using max_sequence_length isn't currently supported in the Eager branch. + loop_bound = time_steps _, output_final_ta, final_state = control_flow_ops.while_loop( cond=lambda time, *_: time < loop_bound, body=_time_step, loop_vars=(time, output_ta, state), parallel_iterations=parallel_iterations, - maximum_iterations=maximum_iterations, + maximum_iterations=time_steps, swap_memory=swap_memory) # Unpack final output if not using output tuples. -- GitLab From bf83571eb14d57ce32320bf8f49134458659a441 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 15:10:52 -0800 Subject: [PATCH 219/258] internal change PiperOrigin-RevId: 183148922 --- tensorflow/contrib/tpu/profiler/dump_tpu_profile.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow/contrib/tpu/profiler/dump_tpu_profile.cc b/tensorflow/contrib/tpu/profiler/dump_tpu_profile.cc index 0ed5b2fad3..b842951eb2 100644 --- a/tensorflow/contrib/tpu/profiler/dump_tpu_profile.cc +++ b/tensorflow/contrib/tpu/profiler/dump_tpu_profile.cc @@ -171,7 +171,6 @@ Status WriteTensorboardTPUProfile(const string& logdir, const string& run, DumpToolDataToLogDirectory(profile_run_dir, tool_data, os)); } } - TF_RETURN_IF_ERROR(DumpGraphEvents(logdir, run, response, os)); return Status::OK(); } -- GitLab From 1df1544aeb8a6311c98a0d9ee9b6946e035fdbeb Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Wed, 24 Jan 2018 15:23:12 -0800 Subject: [PATCH 220/258] Make tensor_util_test.py work with the C API enabled. Some of the shape inference error messages have changed. We also need to wrap an InvalidArgumentError as a ValueError for backwards compat. PiperOrigin-RevId: 183150857 --- .../python/framework/tensor_util_test.py | 15 +++++++++++++-- tensorflow/python/framework/ops.py | 18 +++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/tensorflow/contrib/framework/python/framework/tensor_util_test.py b/tensorflow/contrib/framework/python/framework/tensor_util_test.py index 2effe8eb26..8cdb340f2d 100644 --- a/tensorflow/contrib/framework/python/framework/tensor_util_test.py +++ b/tensorflow/contrib/framework/python/framework/tensor_util_test.py @@ -30,6 +30,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import variables as variables_lib from tensorflow.python.platform import test @@ -77,6 +78,7 @@ class AssertScalarIntTest(test.TestCase): [3, 4], dtype=dtypes.int32)) +@test_util.with_c_api class WithShapeTest(test.TestCase): def _assert_with_shape(self, tensor, expected_value, expected_shape, @@ -213,16 +215,25 @@ class WithShapeTest(test.TestCase): tensor_partial_shape.set_shape([None, 2]) for incompatible_shape in [[0], [1]]: + if ops._USE_C_API: + error_message = "Shapes must be equal rank, but are 2 and 1" + else: + error_message = r"Shapes \(\?, 2\) and \([01],\) are not compatible" self.assertRaisesRegexp( - ValueError, r"Shapes \(\?, 2\) and \([01],\) are not compatible", + ValueError, error_message, tensor_util.with_shape, incompatible_shape, tensor_partial_shape) for incompatible_shape in [[1, 2, 1]]: self.assertRaisesRegexp(ValueError, "Dimensions must be equal", tensor_util.with_shape, incompatible_shape, tensor_partial_shape) for incompatible_shape in [[2, 1]]: + if ops._USE_C_API: + error_message = (r"Dimension 1 in both shapes must be equal, but are " + r"2 and 1. Shapes are \[\?,2\] and \[2,1\].") + else: + error_message = r"Shapes \(\?, 2\) and \(2, 1\) are not compatible" self.assertRaisesRegexp( - ValueError, r"Shapes \(\?, 2\) and \(2, 1\) are not compatible", + ValueError, error_message, tensor_util.with_shape, incompatible_shape, tensor_partial_shape) compatible_shape = [2, 2] diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index a1c2e07e94..b107670275 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -481,13 +481,17 @@ class Tensor(_TensorLike): dim_list.append(-1) else: dim_list.append(dim.value) - with errors.raise_exception_on_not_ok_status() as status: - c_api.TF_GraphSetTensorShape_wrapper( - self._op._graph._c_graph, # pylint: disable=protected-access - self._as_tf_output(), - dim_list, - unknown_shape, - status) + try: + with errors.raise_exception_on_not_ok_status() as status: + c_api.TF_GraphSetTensorShape_wrapper( + self._op._graph._c_graph, # pylint: disable=protected-access + self._as_tf_output(), + dim_list, + unknown_shape, + status) + except errors.InvalidArgumentError as e: + # Convert to ValueError for backwards compatibility. + raise ValueError(str(e)) @property def value_index(self): -- GitLab From 7bf8ccdb4ef5b0b28c1cf0d5084e07ffbf0e2703 Mon Sep 17 00:00:00 2001 From: Yutaka Leon Date: Wed, 24 Jan 2018 15:45:55 -0800 Subject: [PATCH 221/258] Set export_outs in KMeans' EstimatorSpec. PiperOrigin-RevId: 183154542 --- .../contrib/factorization/python/ops/kmeans.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tensorflow/contrib/factorization/python/ops/kmeans.py b/tensorflow/contrib/factorization/python/ops/kmeans.py index 9a5413fc3f..4d0f9b2424 100644 --- a/tensorflow/contrib/factorization/python/ops/kmeans.py +++ b/tensorflow/contrib/factorization/python/ops/kmeans.py @@ -25,6 +25,7 @@ import time from tensorflow.contrib.factorization.python.ops import clustering_ops from tensorflow.python.estimator import estimator from tensorflow.python.estimator import model_fn as model_fn_lib +from tensorflow.python.estimator.export import export_output from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops @@ -32,6 +33,7 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops import metrics from tensorflow.python.ops import state_ops from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.saved_model import signature_constants from tensorflow.python.summary import summary from tensorflow.python.training import session_run_hook from tensorflow.python.training import training_util @@ -207,6 +209,15 @@ class _ModelFn(object): training_hooks.append( _LossRelativeChangeHook(loss, self._relative_tolerance)) + export_outputs = { + KMeansClustering.ALL_DISTANCES: + export_output.PredictOutput(all_distances[0]), + KMeansClustering.CLUSTER_INDEX: + export_output.PredictOutput(model_predictions[0]), + signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: + export_output.PredictOutput(model_predictions[0]) + } + return model_fn_lib.EstimatorSpec( mode=mode, predictions={ @@ -216,7 +227,8 @@ class _ModelFn(object): loss=loss, train_op=training_op, eval_metric_ops={KMeansClustering.SCORE: metrics.mean(loss)}, - training_hooks=training_hooks) + training_hooks=training_hooks, + export_outputs=export_outputs) # TODO(agarwal,ands): support sharded input. -- GitLab From ffa63e57bdd703ae051ae849af5b5a272fca2223 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 24 Jan 2018 16:10:12 -0800 Subject: [PATCH 222/258] [TF:XLA] Replace most of HloProfilePrinter by a protocol buffer This change replaces the meat of HloProfilePrinter with a protobuf HloProfilePrinterData. The original plan was to serialize HloProfilePrinter into C++ source code and put that in a .cc file along with the string for the xla::ProgramShape. However, since we now directly serialize xla::ProgramShape into a .o file, for consistency I think we should do the same thing for HloProfilePrinter (instead of adding yet another output file to tfcompile). The change itself is fairly simple, it is large mostly due to the mass renaming I had to do. PiperOrigin-RevId: 183158192 --- .../tf2xla/xla_compiled_cpu_function.cc | 2 +- .../tf2xla/xla_compiled_cpu_function.h | 20 +-- .../tf2xla/xla_jit_compiled_cpu_function.cc | 6 +- tensorflow/compiler/xla/service/BUILD | 6 + .../compiler/xla/service/cpu/cpu_compiler.cc | 10 +- .../xla/service/cpu/cpu_executable.cc | 4 +- .../compiler/xla/service/cpu/cpu_executable.h | 2 +- .../service/cpu/parallel_cpu_executable.cc | 4 +- .../xla/service/cpu/parallel_cpu_executable.h | 2 +- tensorflow/compiler/xla/service/executable.cc | 2 +- tensorflow/compiler/xla/service/executable.h | 21 ++-- .../compiler/xla/service/gpu/gpu_compiler.cc | 4 +- .../xla/service/gpu/gpu_executable.cc | 4 +- .../compiler/xla/service/gpu/gpu_executable.h | 2 +- .../xla/service/hlo_execution_profile.cc | 118 ++++++++---------- .../xla/service/hlo_execution_profile.h | 15 ++- .../xla/service/hlo_execution_profile_test.cc | 4 +- .../xla/service/hlo_profile_printer.cc | 45 ++++--- .../xla/service/hlo_profile_printer.h | 79 +----------- .../service/hlo_profile_printer_data.proto | 60 +++++++++ tensorflow/compiler/xla/service/service.cc | 2 +- .../xla/tests/xla_hlo_profile_test.cc | 3 +- tensorflow/compiler/xla/util.h | 8 +- 23 files changed, 208 insertions(+), 215 deletions(-) create mode 100644 tensorflow/compiler/xla/service/hlo_profile_printer_data.proto diff --git a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc index 79da701fd2..672e19bd93 100644 --- a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc +++ b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc @@ -29,7 +29,7 @@ XlaCompiledCpuFunction::XlaCompiledCpuFunction(const StaticData& static_data, arg_names_(static_data.arg_names), result_names_(static_data.result_names), program_shape_(static_data.program_shape), - hlo_profile_printer_(static_data.hlo_profile_printer) { + hlo_profile_printer_data_(static_data.hlo_profile_printer_data) { // Allocate arg and temp buffers. if (alloc_mode == AllocMode::ARGS_RESULTS_PROFILES_AND_TEMPS) { alloc_args_ = tensorflow::tfcompile::runtime::MallocContiguousBuffers( diff --git a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h index e0ae3ed9a8..48a8c083ca 100644 --- a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h +++ b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h @@ -26,7 +26,7 @@ limitations under the License. // never use this functionality. namespace xla { class ProgramShape; -class HloProfilePrinter; +class HloProfilePrinterData; } namespace tensorflow { @@ -77,12 +77,14 @@ class XlaCompiledCpuFunction { // [Optional] Arg and result shapes. const xla::ProgramShape* program_shape = nullptr; - // [Optional] Profile printer. Null if profiling is disabled. - const xla::HloProfilePrinter* hlo_profile_printer = nullptr; + // [Optional] Profile printer data. Null if profiling is disabled. + const xla::HloProfilePrinterData* hlo_profile_printer_data = nullptr; // [Optional] The number of profile counters expected in the profile counter // buffer by the generated code and hlo_profile_printer. 0 if profiling is - // disabled. + // disabled. This information is already present in + // hlo_profile_printer_data but xla::HloProfilePrinterData is forward + // declared so we don't have access to that information here. int64 profile_counters_size = 0; }; @@ -205,10 +207,12 @@ class XlaCompiledCpuFunction { // program shape isn't available. const xla::ProgramShape* ProgramShape() const { return program_shape_; } - bool hlo_profiling_enabled() const { return hlo_profile_printer_ != nullptr; } - const xla::HloProfilePrinter& hlo_profile_printer() const { + bool hlo_profiling_enabled() const { + return hlo_profile_printer_data_ != nullptr; + } + const xla::HloProfilePrinterData& hlo_profile_printer_data() const { assert(hlo_profiling_enabled()); - return *hlo_profile_printer_; + return *hlo_profile_printer_data_; } private: @@ -234,7 +238,7 @@ class XlaCompiledCpuFunction { const char** arg_names_ = nullptr; const char** result_names_ = nullptr; const xla::ProgramShape* program_shape_ = nullptr; - const xla::HloProfilePrinter* hlo_profile_printer_ = nullptr; + const xla::HloProfilePrinterData* hlo_profile_printer_data_ = nullptr; }; } // namespace tensorflow diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc index 584417bc72..1fe6e69ff2 100644 --- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc +++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc @@ -182,10 +182,10 @@ XlaJitCompiledCpuFunction::Compile( jit->static_data_.program_shape = jit->program_shape_.get(); if (cpu_executable->hlo_profiling_enabled()) { - jit->static_data_.hlo_profile_printer = - &cpu_executable->hlo_profile_printer(); + jit->static_data_.hlo_profile_printer_data = + &cpu_executable->hlo_profile_printer_data(); jit->static_data_.profile_counters_size = - cpu_executable->hlo_profile_printer().profile_counters_size(); + cpu_executable->hlo_profile_printer_data().profile_counters_size(); } return std::move(jit_unique_ptr); diff --git a/tensorflow/compiler/xla/service/BUILD b/tensorflow/compiler/xla/service/BUILD index d0e2dc88ea..2c5f3ea1dd 100644 --- a/tensorflow/compiler/xla/service/BUILD +++ b/tensorflow/compiler/xla/service/BUILD @@ -29,6 +29,11 @@ xla_proto_library( deps = ["//tensorflow/compiler/xla:xla_data_proto"], ) +xla_proto_library( + name = "hlo_profile_printer_data", + srcs = ["hlo_profile_printer_data.proto"], +) + # Filegroup used to collect source files for dependency checking. filegroup( name = "c_srcs", @@ -2267,6 +2272,7 @@ cc_library( srcs = ["hlo_profile_printer.cc"], hdrs = ["hlo_profile_printer.h"], deps = [ + ":hlo_profile_printer_data", ":human_readable_profile_builder", "//tensorflow/compiler/xla:types", ], diff --git a/tensorflow/compiler/xla/service/cpu/cpu_compiler.cc b/tensorflow/compiler/xla/service/cpu/cpu_compiler.cc index f0507982b3..33af77e1a8 100644 --- a/tensorflow/compiler/xla/service/cpu/cpu_compiler.cc +++ b/tensorflow/compiler/xla/service/cpu/cpu_compiler.cc @@ -485,7 +485,7 @@ StatusOr> CpuCompiler::RunBackend( std::unordered_map instruction_to_profile_idx; std::unordered_map computation_to_profile_idx; std::unique_ptr hlo_profile_index_map; - std::unique_ptr hlo_profile_printer; + std::unique_ptr hlo_profile_printer_data; if (module->config().hlo_profiling_enabled()) { hlo_profile_index_map = MakeUnique(*module); @@ -505,8 +505,8 @@ StatusOr> CpuCompiler::RunBackend( HloCostAnalysis cost_analysis(shape_size_bytes); TF_RETURN_IF_ERROR(entry_computation->Accept(&cost_analysis)); - hlo_profile_printer = - CreateHloProfilePrinter(*hlo_profile_index_map, cost_analysis); + hlo_profile_printer_data = + CreateHloProfilePrinterData(*hlo_profile_index_map, cost_analysis); computation_to_profile_idx = hlo_profile_index_map->computation_to_profile_idx(); } @@ -619,7 +619,7 @@ StatusOr> CpuCompiler::RunBackend( cpu_executable.reset(new ParallelCpuExecutable( std::move(jit), std::move(assignment), std::move(module), std::move(function_names), std::move(aligned_constants), - std::move(hlo_profile_printer), std::move(hlo_profile_index_map))); + std::move(hlo_profile_printer_data), std::move(hlo_profile_index_map))); if (embed_ir_in_executable) { static_cast(*cpu_executable) @@ -698,7 +698,7 @@ StatusOr> CpuCompiler::RunBackend( jit->AddModule(std::move(llvm_module)); cpu_executable.reset(new CpuExecutable( std::move(jit), std::move(assignment), std::move(module), function_name, - std::move(hlo_profile_printer), std::move(hlo_profile_index_map))); + std::move(hlo_profile_printer_data), std::move(hlo_profile_index_map))); if (embed_ir_in_executable) { static_cast(*cpu_executable) diff --git a/tensorflow/compiler/xla/service/cpu/cpu_executable.cc b/tensorflow/compiler/xla/service/cpu/cpu_executable.cc index f335bd1bbc..802d0a6fb4 100644 --- a/tensorflow/compiler/xla/service/cpu/cpu_executable.cc +++ b/tensorflow/compiler/xla/service/cpu/cpu_executable.cc @@ -55,9 +55,9 @@ CpuExecutable::CpuExecutable( std::unique_ptr assignment, std::unique_ptr hlo_module, const string& entry_function_name, - std::unique_ptr hlo_profile_printer, + std::unique_ptr hlo_profile_printer_data, std::unique_ptr hlo_profile_index_map) - : Executable(std::move(hlo_module), std::move(hlo_profile_printer), + : Executable(std::move(hlo_module), std::move(hlo_profile_printer_data), std::move(hlo_profile_index_map)), jit_(std::move(jit)), assignment_(std::move(assignment)) { diff --git a/tensorflow/compiler/xla/service/cpu/cpu_executable.h b/tensorflow/compiler/xla/service/cpu/cpu_executable.h index 50443a5995..267b89a10b 100644 --- a/tensorflow/compiler/xla/service/cpu/cpu_executable.h +++ b/tensorflow/compiler/xla/service/cpu/cpu_executable.h @@ -51,7 +51,7 @@ class CpuExecutable : public Executable { std::unique_ptr assignment, std::unique_ptr hlo_module, const string& entry_function_name, - std::unique_ptr hlo_profile_printer, + std::unique_ptr hlo_profile_printer_data, std::unique_ptr hlo_profile_index_map); ~CpuExecutable() override {} diff --git a/tensorflow/compiler/xla/service/cpu/parallel_cpu_executable.cc b/tensorflow/compiler/xla/service/cpu/parallel_cpu_executable.cc index d1b88b27f0..cd997f0789 100644 --- a/tensorflow/compiler/xla/service/cpu/parallel_cpu_executable.cc +++ b/tensorflow/compiler/xla/service/cpu/parallel_cpu_executable.cc @@ -61,9 +61,9 @@ ParallelCpuExecutable::ParallelCpuExecutable( std::unique_ptr> function_names, std::unordered_map> aligned_constants, - std::unique_ptr hlo_profile_printer, + std::unique_ptr hlo_profile_printer_data, std::unique_ptr hlo_profile_index_map) - : Executable(std::move(hlo_module), std::move(hlo_profile_printer), + : Executable(std::move(hlo_module), std::move(hlo_profile_printer_data), std::move(hlo_profile_index_map)), jit_(std::move(jit)), assignment_(std::move(assignment)), diff --git a/tensorflow/compiler/xla/service/cpu/parallel_cpu_executable.h b/tensorflow/compiler/xla/service/cpu/parallel_cpu_executable.h index 90ac94ef92..c393e9b8ea 100644 --- a/tensorflow/compiler/xla/service/cpu/parallel_cpu_executable.h +++ b/tensorflow/compiler/xla/service/cpu/parallel_cpu_executable.h @@ -55,7 +55,7 @@ class ParallelCpuExecutable : public Executable { std::unordered_map> aligned_constants, - std::unique_ptr hlo_profile_printer, + std::unique_ptr hlo_profile_printer_data, std::unique_ptr hlo_profile_index_map); ~ParallelCpuExecutable() override {} diff --git a/tensorflow/compiler/xla/service/executable.cc b/tensorflow/compiler/xla/service/executable.cc index 21e7fbea29..90481c7a88 100644 --- a/tensorflow/compiler/xla/service/executable.cc +++ b/tensorflow/compiler/xla/service/executable.cc @@ -73,7 +73,7 @@ StatusOr> Executable::ExecuteOnStreamWrapper( std::unique_ptr profile_ptr = module_config().debug_options().xla_hlo_profile() && hlo_profiling_enabled() - ? MakeUnique(&hlo_profile_printer(), + ? MakeUnique(&hlo_profile_printer_data(), &hlo_profile_index_map()) : nullptr; diff --git a/tensorflow/compiler/xla/service/executable.h b/tensorflow/compiler/xla/service/executable.h index 5ecfdffe21..0aee535ee7 100644 --- a/tensorflow/compiler/xla/service/executable.h +++ b/tensorflow/compiler/xla/service/executable.h @@ -44,13 +44,14 @@ namespace xla { // interface that is used for launching compiled programs across platforms. class Executable { public: - explicit Executable(std::unique_ptr hlo_module, - std::unique_ptr hlo_profile_printer, - std::unique_ptr hlo_profile_index_map) + explicit Executable( + std::unique_ptr hlo_module, + std::unique_ptr hlo_profile_printer_data, + std::unique_ptr hlo_profile_index_map) : hlo_module_(std::move(hlo_module)), - hlo_profile_printer_(std::move(hlo_profile_printer)), + hlo_profile_printer_data_(std::move(hlo_profile_printer_data)), hlo_profile_index_map_(std::move(hlo_profile_index_map)) { - CHECK_EQ(hlo_profile_printer_.get() == nullptr, + CHECK_EQ(hlo_profile_printer_data_.get() == nullptr, hlo_profile_index_map_.get() == nullptr); } virtual ~Executable() {} @@ -116,9 +117,9 @@ class Executable { "Equality test on this executable is not implemented."); } - const HloProfilePrinter& hlo_profile_printer() const { + const HloProfilePrinterData& hlo_profile_printer_data() const { CHECK(hlo_profiling_enabled()); - return *hlo_profile_printer_; + return *hlo_profile_printer_data_; } const HloProfileIndexMap& hlo_profile_index_map() const { @@ -129,7 +130,9 @@ class Executable { // Returns whether this executable was compiled with HLO profilings support // enabled. If not, the caller should not expect an hlo_execution_profile // passed to ExecuteOnStream above to be populated during execution. - bool hlo_profiling_enabled() const { return hlo_profile_printer_ != nullptr; } + bool hlo_profiling_enabled() const { + return hlo_profile_printer_data_ != nullptr; + } const HloModule& module() const { return *hlo_module_; } @@ -179,7 +182,7 @@ class Executable { // execution. int64 execution_count_ = 0; - std::unique_ptr hlo_profile_printer_; + std::unique_ptr hlo_profile_printer_data_; std::unique_ptr hlo_profile_index_map_; }; diff --git a/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc b/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc index 21798ed606..0cca3ca092 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_compiler.cc @@ -593,14 +593,14 @@ StatusOr> GpuCompiler::RunBackend( XLA_VLOG_LINES(2, thunk_schedule->ToString()); std::unique_ptr profile_index_map; - std::unique_ptr profile_printer; + std::unique_ptr profile_printer; if (module->config().hlo_profiling_enabled()) { HloCostAnalysis cost_analysis(ShapeSizeBytesFunction()); TF_RETURN_IF_ERROR(module->entry_computation()->Accept(&cost_analysis)); profile_index_map = MakeUnique(*module); profile_printer = - CreateHloProfilePrinter(*profile_index_map, cost_analysis); + CreateHloProfilePrinterData(*profile_index_map, cost_analysis); } auto* gpu_executable = new GpuExecutable( diff --git a/tensorflow/compiler/xla/service/gpu/gpu_executable.cc b/tensorflow/compiler/xla/service/gpu/gpu_executable.cc index 51d164cdf4..f5d67b9ea9 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_executable.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_executable.cc @@ -116,9 +116,9 @@ GpuExecutable::GpuExecutable( std::unique_ptr thunk_schedule, std::unique_ptr hlo_module, std::unique_ptr assignment, - std::unique_ptr hlo_profile_printer, + std::unique_ptr hlo_profile_printer_data, std::unique_ptr hlo_profile_index_map) - : Executable(std::move(hlo_module), std::move(hlo_profile_printer), + : Executable(std::move(hlo_module), std::move(hlo_profile_printer_data), std::move(hlo_profile_index_map)), ptx_(ptx), cubin_(cubin), diff --git a/tensorflow/compiler/xla/service/gpu/gpu_executable.h b/tensorflow/compiler/xla/service/gpu/gpu_executable.h index 00da64dfad..b19cfd43de 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_executable.h +++ b/tensorflow/compiler/xla/service/gpu/gpu_executable.h @@ -54,7 +54,7 @@ class GpuExecutable : public Executable { std::unique_ptr thunk_schedule, std::unique_ptr hlo_module, std::unique_ptr assignment, - std::unique_ptr hlo_profile_printer, + std::unique_ptr hlo_profile_printer_data, std::unique_ptr hlo_profile_index_map); // This should be called after set_ir_module_string. diff --git a/tensorflow/compiler/xla/service/hlo_execution_profile.cc b/tensorflow/compiler/xla/service/hlo_execution_profile.cc index 849aac0b12..f0df93b61d 100644 --- a/tensorflow/compiler/xla/service/hlo_execution_profile.cc +++ b/tensorflow/compiler/xla/service/hlo_execution_profile.cc @@ -40,83 +40,75 @@ HloProfileIndexMap::HloProfileIndexMap(const HloModule& module) { } } -std::unique_ptr CreateHloProfilePrinter( +std::unique_ptr CreateHloProfilePrinterData( const HloProfileIndexMap& hlo_profile_index_map, const HloCostAnalysis& cost_analysis) { - using HloComputationInfo = HloProfilePrinter::HloComputationInfo; - using HloInstructionInfo = HloProfilePrinter::HloInstructionInfo; - - HloComputationInfo* computation_infos = - new HloComputationInfo[hlo_profile_index_map.computation_count()]; - - // There are two "indices" in play here. The first one is the index of the - // HloComputationInfo or HloInstructionInfo in the array that contains said - // HloComputationInfo or HloInstructionInfo. The second index is the index of - // the HloComputationInfo or HloInstructionInfo in the profile counters array, - // as decided by hlo_profile_index_map. The latter index is always referred - // to as "profile_index". - - size_t computation_index_in_static_data = 0; - size_t max_profile_index = hlo_profile_index_map.total_count(); - for (const auto& pair : hlo_profile_index_map.computation_to_profile_idx()) { - CHECK_LT(pair.second, max_profile_index); + using HloComputationInfo = HloProfilePrinterData::HloComputationInfo; + using HloInstructionInfo = HloProfilePrinterData::HloInstructionInfo; + + size_t profile_counters_size = hlo_profile_index_map.total_count(); + + std::unique_ptr profile_printer_data = + MakeUnique(); + profile_printer_data->set_profile_counters_size(profile_counters_size); + profile_printer_data->mutable_computation_infos()->Reserve( + hlo_profile_index_map.computation_count()); + + const auto& computation_to_profile_idx_map = + hlo_profile_index_map.computation_to_profile_idx(); + + // computation_to_profile_idx_map's order is not deterministic so create a + // deterministic computation_and_profile_idx_list so that we end up with a + // deterministic HloProfilePrinterData protobuf. + + std::vector> + computation_and_profile_idx_list(computation_to_profile_idx_map.begin(), + computation_to_profile_idx_map.end()); + + // The profile indices were computed deterministically in + // HloProfileIndexMap::HloProfileIndexMap. + c_sort(computation_and_profile_idx_list, + [](const std::pair& left, + const std::pair& right) { + return left.second < right.second; + }); + + for (const auto& pair : computation_and_profile_idx_list) { + CHECK_LT(pair.second, profile_counters_size); const HloComputation* computation = pair.first; - size_t current_computation_index = computation_index_in_static_data++; HloComputationInfo* computation_info = - &computation_infos[current_computation_index]; + profile_printer_data->add_computation_infos(); - computation_info->name = strdup(computation->name().c_str()); - computation_info->profile_index = pair.second; - computation_info->instructions = - new HloInstructionInfo[computation->instruction_count()]; - computation_info->instructions_size = computation->instruction_count(); + computation_info->set_name(computation->name()); + computation_info->set_profile_index(pair.second); + computation_info->mutable_instruction_infos()->Reserve( + computation->instruction_count()); - size_t instruction_index_in_static_data = 0; for (const HloInstruction* hlo : computation->instructions()) { - HloProfilePrinter::HloInstructionInfo* instruction_info = - &computation_info->instructions[instruction_index_in_static_data++]; - instruction_info->long_name = strdup(hlo->ToString().c_str()); - instruction_info->short_name = strdup( - hlo->ToString(HloPrintOptions().set_compact_operands(true)).c_str()); - instruction_info->category = strdup(hlo->ToCategory().c_str()); - instruction_info->flop_count = cost_analysis.flop_count(*hlo); - instruction_info->transcendental_count = - cost_analysis.transcendental_count(*hlo); - instruction_info->bytes_accessed = cost_analysis.bytes_accessed(*hlo); - instruction_info->optimal_seconds = cost_analysis.optimal_seconds(*hlo); - instruction_info->profile_index = - hlo_profile_index_map.GetProfileIndexFor(*hlo); - CHECK_LT(instruction_info->profile_index, max_profile_index); + HloInstructionInfo* instruction_info = + computation_info->add_instruction_infos(); + instruction_info->set_long_name(hlo->ToString()); + instruction_info->set_short_name( + hlo->ToString(HloPrintOptions().set_compact_operands(true))); + instruction_info->set_category(hlo->ToCategory()); + instruction_info->set_flop_count(cost_analysis.flop_count(*hlo)); + instruction_info->set_transcendental_count( + cost_analysis.transcendental_count(*hlo)); + instruction_info->set_bytes_accessed(cost_analysis.bytes_accessed(*hlo)); + instruction_info->set_optimal_seconds( + cost_analysis.optimal_seconds(*hlo)); + instruction_info->set_profile_index( + hlo_profile_index_map.GetProfileIndexFor(*hlo)); } } - auto deleter = [](HloProfilePrinter::HloComputationInfo* computation_infos, - int64 computation_infos_size) { - for (int64 i = 0; i < computation_infos_size; i++) { - HloInstructionInfo* instruction_infos = computation_infos[i].instructions; - for (int64 j = 0; j < computation_infos[i].instructions_size; j++) { - // We can't make instruction_infos[j].long_name etc. non-const pointers - // since they may point into static storage, so we have a const_cast - // here. - free(const_cast(instruction_infos[j].long_name)); - free(const_cast(instruction_infos[j].short_name)); - free(const_cast(instruction_infos[j].category)); - } - delete[] instruction_infos; - free(const_cast(computation_infos[i].name)); - } - delete[] computation_infos; - }; - - return MakeUnique( - computation_infos, hlo_profile_index_map.computation_count(), - /*profile_counters_size=*/max_profile_index, deleter); + return profile_printer_data; } HloExecutionProfile::HloExecutionProfile( - const HloProfilePrinter* hlo_profile_printer, + const HloProfilePrinterData* hlo_profile_printer_data, const HloProfileIndexMap* hlo_profile_index_map) - : hlo_profile_printer_(*hlo_profile_printer), + : hlo_profile_printer_data_(*hlo_profile_printer_data), hlo_profile_index_map_(*hlo_profile_index_map), profile_counters_( /*count*/ hlo_profile_index_map_.total_count(), diff --git a/tensorflow/compiler/xla/service/hlo_execution_profile.h b/tensorflow/compiler/xla/service/hlo_execution_profile.h index 1a6b069609..6fb91b9bef 100644 --- a/tensorflow/compiler/xla/service/hlo_execution_profile.h +++ b/tensorflow/compiler/xla/service/hlo_execution_profile.h @@ -77,8 +77,8 @@ class HloProfileIndexMap { std::unordered_map computation_to_profile_idx_; }; -// Create an instance of `HloProfilePrinter` that owns its memory. -std::unique_ptr CreateHloProfilePrinter( +// Create an instance of `HloProfilePrinterData`. +std::unique_ptr CreateHloProfilePrinterData( const HloProfileIndexMap& hlo_profile_index_map, const HloCostAnalysis& cost_analysis); @@ -90,7 +90,7 @@ class HloExecutionProfile { public: using DeviceDescription = perftools::gputools::DeviceDescription; - HloExecutionProfile(const HloProfilePrinter* hlo_profile_printer, + HloExecutionProfile(const HloProfilePrinterData* hlo_profile_printer_data, const HloProfileIndexMap* hlo_profile_index_map); // Record how many cycles this HLO took to execute. @@ -117,11 +117,10 @@ class HloExecutionProfile { // debugging; e.g. emits cycle counts, execution time at the nominal device // frequency, and the effective throughput given the provided cost_analysis // for the operations in a given computation. Returns an empty string if it - // wasn't possible to generate a printable version. cost_analysis should be a - // clean analysis that can be used to visit the computation. + // wasn't possible to generate a printable version. string ToString(const DeviceDescription& device_description) const { - return hlo_profile_printer_.ToString(profile_counters_.data(), - device_description.clock_rate_ghz()); + return PrintHloProfile(hlo_profile_printer_data_, profile_counters_.data(), + device_description.clock_rate_ghz()); } std::vector* mutable_profile_counters() { return &profile_counters_; } @@ -130,7 +129,7 @@ class HloExecutionProfile { } private: - const HloProfilePrinter& hlo_profile_printer_; + const HloProfilePrinterData& hlo_profile_printer_data_; const HloProfileIndexMap& hlo_profile_index_map_; // Stores per-Hlo profile counters. This is the only thing that changes when diff --git a/tensorflow/compiler/xla/service/hlo_execution_profile_test.cc b/tensorflow/compiler/xla/service/hlo_execution_profile_test.cc index b1e6729e2b..a0cb28246d 100644 --- a/tensorflow/compiler/xla/service/hlo_execution_profile_test.cc +++ b/tensorflow/compiler/xla/service/hlo_execution_profile_test.cc @@ -73,8 +73,8 @@ TEST_F(HloExecutionProfileTest, Basic) { HloCostAnalysis cost_analysis(shape_size_function); HloProfileIndexMap profile_index_map(*hlo_module); - std::unique_ptr profile_printer = - CreateHloProfilePrinter(profile_index_map, cost_analysis); + std::unique_ptr profile_printer = + CreateHloProfilePrinterData(profile_index_map, cost_analysis); HloExecutionProfile execution_profile(profile_printer.get(), &profile_index_map); diff --git a/tensorflow/compiler/xla/service/hlo_profile_printer.cc b/tensorflow/compiler/xla/service/hlo_profile_printer.cc index e944ad1513..dcc2279301 100644 --- a/tensorflow/compiler/xla/service/hlo_profile_printer.cc +++ b/tensorflow/compiler/xla/service/hlo_profile_printer.cc @@ -18,20 +18,20 @@ limitations under the License. #include "tensorflow/compiler/xla/service/human_readable_profile_builder.h" namespace xla { -string HloProfilePrinter::ToString(const int64* counters, - double clock_rate_ghz) const { +string PrintHloProfile(const HloProfilePrinterData& hlo_profile_printer_data, + const int64* counters, double clock_rate_ghz) { + using HloComputationInfo = HloProfilePrinterData::HloComputationInfo; + using HloInstructionInfo = HloProfilePrinterData::HloInstructionInfo; + string result; - for (int computation_idx = 0; computation_idx < computation_infos_size_; - computation_idx++) { - const HloComputationInfo& computation = computation_infos_[computation_idx]; - const HloInstructionInfo* instructions_begin = computation.instructions; - const HloInstructionInfo* instructions_end = - computation.instructions + computation.instructions_size; + for (const HloComputationInfo& computation_info : + hlo_profile_printer_data.computation_infos()) { + const auto& instruction_infos = computation_info.instruction_infos(); bool any_instruction_profiled = - std::any_of(instructions_begin, instructions_end, + std::any_of(instruction_infos.begin(), instruction_infos.end(), [&](const HloInstructionInfo& instruction_info) { - return counters[instruction_info.profile_index] != 0; + return counters[instruction_info.profile_index()] != 0; }); if (!any_instruction_profiled) { @@ -41,16 +41,19 @@ string HloProfilePrinter::ToString(const int64* counters, // Once we start using this in AOT for real, we will probably need a more // minimal version of HumanReadableProfileBuilder. HumanReadableProfileBuilder builder( - computation.name, counters[computation.profile_index], clock_rate_ghz); + computation_info.name(), counters[computation_info.profile_index()], + clock_rate_ghz); - for (const auto* instruction = instructions_begin; - instruction != instructions_end; instruction++) { + for (const auto& instruction_info : instruction_infos) { builder.AddOp( - /*op_name=*/instruction->long_name, - /*short_name=*/instruction->short_name, instruction->category, - counters[instruction->profile_index], instruction->flop_count, - instruction->transcendental_count, instruction->bytes_accessed, - instruction->optimal_seconds); + /*op_name=*/instruction_info.long_name(), + /*short_name=*/instruction_info.short_name(), + instruction_info.category(), + counters[instruction_info.profile_index()], + instruction_info.flop_count(), + instruction_info.transcendental_count(), + instruction_info.bytes_accessed(), + instruction_info.optimal_seconds()); } result += builder.ToString(); @@ -58,10 +61,4 @@ string HloProfilePrinter::ToString(const int64* counters, return result; } - -HloProfilePrinter::~HloProfilePrinter() { - if (deleter_) { - deleter_(computation_infos_, computation_infos_size_); - } -} } // namespace xla diff --git a/tensorflow/compiler/xla/service/hlo_profile_printer.h b/tensorflow/compiler/xla/service/hlo_profile_printer.h index 35152e744d..b72325c755 100644 --- a/tensorflow/compiler/xla/service/hlo_profile_printer.h +++ b/tensorflow/compiler/xla/service/hlo_profile_printer.h @@ -20,84 +20,13 @@ limitations under the License. #include #include +#include "tensorflow/compiler/xla/service/hlo_profile_printer_data.pb.h" #include "tensorflow/compiler/xla/types.h" namespace xla { -// Instances of this class can pretty-print profile counters gathered from -// running an XLA computation without having access to the backing module. -class HloProfilePrinter { - public: - // Holds meta information about an HloInstruction. - // - // The pointer-typed fields can be owning or non-owning -- this decision is - // manifested as the deleter_ function in the containing HloProfilePrinter. - struct HloInstructionInfo { - // Textual information for pretty printing. - const char* long_name; - const char* short_name; - const char* category; - - // Metrics computed by HloCostAnalysis. - float flop_count; - float transcendental_count; - float bytes_accessed; - float optimal_seconds; - - // The index into the profile counters array for the HloInstruction - // corresponding to this HloInstructionInfo. - int64 profile_index; - }; - - // Holds meta information about an HloComputation. - // - // The pointer-typed fields can be owning or non-owning -- this decision is - // manifested as the deleter_ function in the containing HloProfilePrinter. - struct HloComputationInfo { - const char* name; - - // The index into the profile counters array for the HloInstruction - // corresponding to this HloComputationInfo. - int64 profile_index; - - HloInstructionInfo* instructions; - int64 instructions_size; - }; - - HloProfilePrinter( - HloComputationInfo* computation_infos, int64 computation_infos_size, - int64 profile_counters_size, - std::function deleter = nullptr) - : computation_infos_(computation_infos), - computation_infos_size_(computation_infos_size), - profile_counters_size_(profile_counters_size), - deleter_(std::move(deleter)) {} - - HloProfilePrinter(HloProfilePrinter&& other) { - std::swap(other.computation_infos_, computation_infos_); - std::swap(other.computation_infos_size_, computation_infos_size_); - std::swap(other.deleter_, deleter_); - } - - HloProfilePrinter(const HloProfilePrinter&) = delete; - HloProfilePrinter& operator=(const HloProfilePrinter&) = delete; - - // Converts the profile counter sequence `counters` to a human readable string - // representation. - string ToString(const int64* counters, double clock_rate_ghz) const; - - // Returns the size of the profile buffer expected by this printer. - int64 profile_counters_size() const { return profile_counters_size_; } - - ~HloProfilePrinter(); - - private: - // The `computation_infos_` field can be owning or non-owning -- this decision - // is manifested as the deleter_ function. - HloComputationInfo* computation_infos_ = nullptr; - int64 computation_infos_size_ = 0; - int64 profile_counters_size_ = 0; - std::function deleter_; -}; +// Pretty-print an array of profile counters using hlo_profile_printer_data. +string PrintHloProfile(const HloProfilePrinterData& hlo_profile_printer_data, + const int64* counters, double clock_rate_ghz); } // namespace xla #endif // TENSORFLOW_COMPILER_XLA_SERVICE_HLO_PROFILE_PRINTER_H_ diff --git a/tensorflow/compiler/xla/service/hlo_profile_printer_data.proto b/tensorflow/compiler/xla/service/hlo_profile_printer_data.proto new file mode 100644 index 0000000000..9f22b733fe --- /dev/null +++ b/tensorflow/compiler/xla/service/hlo_profile_printer_data.proto @@ -0,0 +1,60 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +syntax = "proto3"; + +package xla; + +option cc_enable_arenas = true; + +// Describes how to pretty-print a profile counter array gathered for a specific +// HloModule. +message HloProfilePrinterData { + // Pretty-printer information about an HloInstruction. + message HloInstructionInfo { + string long_name = 1; + string short_name = 2; + string category = 3; + + // Metrics computed by HloCostAnalysis. + float flop_count = 4; + float transcendental_count = 5; + float bytes_accessed = 6; + float optimal_seconds = 7; + + // The index into the profile counters array for the HloInstruction + // corresponding to this HloInstructionInfo. + int64 profile_index = 8; + } + + // Pretty-printer information about an HloComputation. + message HloComputationInfo { + string name = 1; + + // The index into the profile counters array for the HloComputation + // corresponding to this HloComputationInfo. + int64 profile_index = 2; + + // HloInstructionInfos for every HloInstruction in the HloComputation for + // corresponding to this HloComputattionInfo. + repeated HloInstructionInfo instruction_infos = 3; + } + + // HloComputationInfos for every HloComputation in the HloModule. + repeated HloComputationInfo computation_infos = 1; + + // The size of the profile counters array we will pretty-print. + int64 profile_counters_size = 2; +} diff --git a/tensorflow/compiler/xla/service/service.cc b/tensorflow/compiler/xla/service/service.cc index e230d25f1e..926ebbe314 100644 --- a/tensorflow/compiler/xla/service/service.cc +++ b/tensorflow/compiler/xla/service/service.cc @@ -569,7 +569,7 @@ Service::ExecuteParallelAndRegisterResult( se::Stream* stream = index_to_profiled_stream.second; Executable* executable = executables[device]; const HloModule& module = executable->module(); - HloExecutionProfile hlo_profile(&executable->hlo_profile_printer(), + HloExecutionProfile hlo_profile(&executable->hlo_profile_printer_data(), &executable->hlo_profile_index_map()); TF_RETURN_IF_ERROR( executable->PopulateExecutionProfile(&hlo_profile, stream->parent())); diff --git a/tensorflow/compiler/xla/tests/xla_hlo_profile_test.cc b/tensorflow/compiler/xla/tests/xla_hlo_profile_test.cc index 146fbadcb6..1d2f436194 100644 --- a/tensorflow/compiler/xla/tests/xla_hlo_profile_test.cc +++ b/tensorflow/compiler/xla/tests/xla_hlo_profile_test.cc @@ -110,7 +110,8 @@ void ExecuteAndFetchProfile(string* profile_output, LocalClient* client, Executable* executable = local_executable->executable(); HloExecutionProfile hlo_execution_profile( - &executable->hlo_profile_printer(), &executable->hlo_profile_index_map()); + &executable->hlo_profile_printer_data(), + &executable->hlo_profile_index_map()); TF_ASSERT_OK_AND_ASSIGN( Backend::StreamPtr stream_ptr, diff --git a/tensorflow/compiler/xla/util.h b/tensorflow/compiler/xla/util.h index bb2db2010c..1d7dd34449 100644 --- a/tensorflow/compiler/xla/util.h +++ b/tensorflow/compiler/xla/util.h @@ -398,13 +398,11 @@ std::vector> CommonFactors( // Removes illegal characters from filenames. string SanitizeFileName(string file_name); -// Simple wrapper around std::all_of. template bool c_all_of(Container container, Predicate predicate) { return std::all_of(std::begin(container), std::end(container), predicate); } -// Simple wrapper around std::transform. template OutputIterator c_transform(InputContainer input_container, @@ -414,7 +412,6 @@ OutputIterator c_transform(InputContainer input_container, output_iterator, unary_op); } -// Simple wrapper around std::copy_if. template OutputIterator c_copy_if(InputContainer input_container, OutputIterator output_iterator, @@ -423,6 +420,11 @@ OutputIterator c_copy_if(InputContainer input_container, output_iterator, predicate); } +template +void c_sort(InputContainer& input_container, Comparator comparator) { + std::sort(input_container.begin(), input_container.end(), comparator); +} + } // namespace xla #define XLA_LOG_LINES(SEV, STRING) \ -- GitLab From e76a7a7c8bccb1fb67559160c9a06ba3a722fd54 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 24 Jan 2018 16:10:37 -0800 Subject: [PATCH 223/258] [TF:XLA:CPU] Fix an issue with explicitly vectorized reductions The explicitly vectorized reduction kernel assumes that the input and the output layouts are "same" (not identical which is not possible, but have the same ordering of the un-reduced dimensions). This change makes IrEmitter check this precondition. PiperOrigin-RevId: 183158249 --- .../compiler/xla/service/cpu/ir_emitter.cc | 51 +++++++ tensorflow/compiler/xla/tests/BUILD | 13 ++ .../compiler/xla/tests/reduce_hlo_test.cc | 132 ++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 tensorflow/compiler/xla/tests/reduce_hlo_test.cc diff --git a/tensorflow/compiler/xla/service/cpu/ir_emitter.cc b/tensorflow/compiler/xla/service/cpu/ir_emitter.cc index b03a9f9aa5..71e8133189 100644 --- a/tensorflow/compiler/xla/service/cpu/ir_emitter.cc +++ b/tensorflow/compiler/xla/service/cpu/ir_emitter.cc @@ -62,6 +62,7 @@ limitations under the License. #include "tensorflow/core/lib/core/bits.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/gtl/array_slice.h" +#include "tensorflow/core/lib/gtl/flatmap.h" #include "tensorflow/core/lib/gtl/flatset.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/lib/strings/stringprintf.h" @@ -1271,6 +1272,52 @@ Status IrEmitter::HandleParameter(HloInstruction* parameter) { return Status::OK(); } +// Returns true if the relative order of the unreduced dimensions stays the same +// through the reduce operation. +static bool ReductionPreservesLayout(const HloInstruction& reduce) { + DCHECK_EQ(reduce.opcode(), HloOpcode::kReduce); + + // Maps dimensions that were not reduced from their dimension numbers in the + // source shape to their dimensions numbers in the destination shape. + // + // So if we reduce f32[A,B,C,D] on dimensions 1 and 2, this map contains + // [0->0, 3->1]. + gtl::FlatMap unreduced_dim_map; + + gtl::FlatSet reduced_dims(reduce.dimensions().begin(), + reduce.dimensions().end()); + + const Shape& operand_shape = reduce.operand(0)->shape(); + const Shape& result_shape = reduce.shape(); + + int64 delta = 0; + for (int64 i = 0; i < operand_shape.dimensions_size(); i++) { + if (reduced_dims.count(i)) { + delta++; + } else { + InsertOrDie(&unreduced_dim_map, i, i - delta); + } + } + + // Iterate dimensions minor to major and check that the corresponding + // dimensions in the source and target shapes are equivalent. + int64 result_dim_idx = 0; + for (int64 operand_dim_idx = 0; + operand_dim_idx < operand_shape.dimensions_size(); operand_dim_idx++) { + int64 operand_dim = operand_shape.layout().minor_to_major(operand_dim_idx); + if (!reduced_dims.count(operand_dim)) { + if (FindOrDie(unreduced_dim_map, operand_dim) != + result_shape.layout().minor_to_major(result_dim_idx++)) { + return false; + } + } + } + + CHECK_EQ(result_dim_idx, result_shape.dimensions_size()); + + return true; +} + IrEmitter::ReductionGenerator IrEmitter::MatchReductionGenerator( HloComputation* function, string* failure_reason) const { CHECK_EQ(function->num_parameters(), 2); @@ -1540,6 +1587,10 @@ StatusOr IrEmitter::EmitVectorizedReduce( HloInstruction* reduce, HloInstruction* arg, HloInstruction* init_value, gtl::ArraySlice dimensions, HloComputation* function, string* failure_reason) { + if (!ReductionPreservesLayout(*reduce)) { + return false; + } + ReductionGenerator reduction_generator = MatchReductionGenerator(function, failure_reason); if (!reduction_generator) { diff --git a/tensorflow/compiler/xla/tests/BUILD b/tensorflow/compiler/xla/tests/BUILD index 6ab406d6c3..bc15bd9593 100644 --- a/tensorflow/compiler/xla/tests/BUILD +++ b/tensorflow/compiler/xla/tests/BUILD @@ -1072,6 +1072,19 @@ xla_test( ], ) +xla_test( + name = "reduce_hlo_test", + srcs = ["reduce_hlo_test.cc"], + deps = [ + ":client_library_test_base", + "//tensorflow/compiler/xla/tests:hlo_test_base", + "//tensorflow/compiler/xla/tests:xla_internal_test_main", + "//tensorflow/compiler/xla/tools/parser:hlo_parser", + "//tensorflow/core:lib", + "//tensorflow/core:test", + ], +) + xla_test( name = "call_test", srcs = ["call_test.cc"], diff --git a/tensorflow/compiler/xla/tests/reduce_hlo_test.cc b/tensorflow/compiler/xla/tests/reduce_hlo_test.cc new file mode 100644 index 0000000000..c0a2c0ca4c --- /dev/null +++ b/tensorflow/compiler/xla/tests/reduce_hlo_test.cc @@ -0,0 +1,132 @@ +/* Copyright 2017 The TensorFlow Authors. 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 + +#include "tensorflow/compiler/xla/tests/hlo_test_base.h" +#include "tensorflow/compiler/xla/tests/test_macros.h" +#include "tensorflow/compiler/xla/tools/parser/hlo_parser.h" +#include "tensorflow/core/lib/strings/str_util.h" +#include "tensorflow/core/lib/strings/strcat.h" +#include "tensorflow/core/platform/test.h" +#include "tensorflow/core/platform/types.h" + +// Tests the Reduce HLO in ways that can't be done using the ComputationBuilder +// API. + +namespace xla { +namespace { + +namespace str_util = tensorflow::str_util; +namespace strings = tensorflow::strings; + +struct ReduceLayout { + std::array input_minor_to_major; + std::array output_minor_to_major; + + string ToString() const { + return strings::StrCat(str_util::Join(input_minor_to_major, "x"), "_", + str_util::Join(output_minor_to_major, "x")); + } +}; + +string PrintReduceLayout( + ::testing::TestParamInfo reduce_layout_param) { + return reduce_layout_param.param.ToString(); +} + +void PrintTo(const ReduceLayout& reduce_layout, ::std::ostream* os) { + *os << reduce_layout.ToString(); +} + +class ReduceWithLayoutTest + : public HloTestBase, + public ::testing::WithParamInterface {}; + +StatusOr> GetParsedModule() { + const char* const hlo_string = R"( +HloModule BadReduce + +Sum { + x.1 = f32[] parameter(0) + y.1 = f32[] parameter(1) + ROOT add.1 = f32[] add(x.1, y.1) +} + +ENTRY reduce.1 { + parameter = f32[2,2,2,3]{3,2,1,0} parameter(0) + init_value = f32[] constant(0) + reduce = f32[2,2,3]{2,1,0} reduce(parameter, init_value), dimensions={1}, to_apply=Sum + ROOT copy = f32[2,2,3]{2,1,0} copy(reduce) +} +)"; + + return tools::Parse(hlo_string); +} + +// TODO(b/72454718): XLA:GPU does not support executing code compiled without +// optimizations. +XLA_TEST_P(ReduceWithLayoutTest, DISABLED_ON_GPU(Reduce)) { + TF_ASSERT_OK_AND_ASSIGN(std::unique_ptr module, GetParsedModule()); + HloInstruction* reduce_instruction = + module->entry_computation()->root_instruction()->mutable_operand(0); + ASSERT_EQ(reduce_instruction->opcode(), HloOpcode::kReduce); + + const ReduceLayout& reduce_layout = GetParam(); + + Shape* reduce_output_shape = reduce_instruction->mutable_shape(); + *reduce_output_shape->mutable_layout() = + LayoutUtil::MakeLayout(reduce_layout.output_minor_to_major); + + Shape* reduce_input_shape = + reduce_instruction->mutable_operand(0)->mutable_shape(); + *reduce_input_shape->mutable_layout() = + LayoutUtil::MakeLayout(reduce_layout.input_minor_to_major); + + std::unique_ptr reduce_input = + Literal::CreateR4({{ /*i0=0*/ + {/*i1=0*/ + {-0.246092796, -0.179497838, -0.161181688}, + {-0.151643038, -0.240213156, -0.198156}}, + {/*i1=1*/ + {-0.14222312, -0.162200093, -0.193907976}, + {-0.239411, -0.198166847, -0.172471642}}}, + { /*i0=1*/ + {/*i1=0*/ + {-0.22965157, -0.218723893, -0.129257083}, + {-0.188762426, -0.16123569, -0.181166649}}, + {/*i1=1*/ + {-0.241772294, -0.245131493, -0.160247207}, + {-0.179881215, -0.23383224, -0.121976733}}}}); + + EXPECT_TRUE(RunAndCompareNoHloPasses(std::move(module), ErrorSpec(1e-5))); +} + +INSTANTIATE_TEST_CASE_P(ReduceWithLayoutTest_Instantiation, + ReduceWithLayoutTest, + ::testing::Values( // + ReduceLayout{{3, 2, 1, 0}, {0, 1, 2}}, // + ReduceLayout{{3, 2, 1, 0}, {0, 2, 1}}, // + ReduceLayout{{3, 2, 1, 0}, {1, 2, 0}}, // + ReduceLayout{{3, 2, 1, 0}, {1, 0, 2}}, // + ReduceLayout{{3, 2, 1, 0}, {2, 0, 1}}, // + ReduceLayout{{3, 2, 1, 0}, {2, 1, 0}}, // + ReduceLayout{{3, 1, 2, 0}, {1, 2, 0}}, // + ReduceLayout{{1, 2, 3, 0}, {1, 0, 2}}, // + ReduceLayout{{0, 2, 1, 3}, {2, 0, 1}}), // + PrintReduceLayout); + +} // namespace +} // namespace xla -- GitLab From dc0511e51a8f2af8b0f053d7f04352f0b0be58fa Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 16:23:09 -0800 Subject: [PATCH 224/258] Basic AddN support in toco PiperOrigin-RevId: 183160197 --- tensorflow/contrib/lite/toco/BUILD | 1 + .../contrib/lite/toco/export_tensorflow.cc | 15 ++++++ .../convert_trivial_addn_to_add.cc | 51 +++++++++++++++++++ .../graph_transformations.h | 1 + .../propagate_fixed_sizes.cc | 25 +++++++++ .../contrib/lite/toco/import_tensorflow.cc | 15 ++++++ tensorflow/contrib/lite/toco/model.h | 11 ++++ .../contrib/lite/toco/tflite/operator.cc | 2 + tensorflow/contrib/lite/toco/toco_tooling.cc | 1 + tensorflow/contrib/lite/toco/tooling_util.cc | 11 ++++ 10 files changed, 133 insertions(+) create mode 100644 tensorflow/contrib/lite/toco/graph_transformations/convert_trivial_addn_to_add.cc diff --git a/tensorflow/contrib/lite/toco/BUILD b/tensorflow/contrib/lite/toco/BUILD index ad8f0e4a47..041e248790 100644 --- a/tensorflow/contrib/lite/toco/BUILD +++ b/tensorflow/contrib/lite/toco/BUILD @@ -172,6 +172,7 @@ cc_library( "graph_transformations/convert_expanddims_to_reshape.cc", "graph_transformations/convert_pure_conv_to_depthwise.cc", "graph_transformations/convert_reorder_axes.cc", + "graph_transformations/convert_trivial_addn_to_add.cc", "graph_transformations/convert_trivial_transpose_to_reshape.cc", "graph_transformations/create_im2col_arrays.cc", "graph_transformations/dequantize.cc", diff --git a/tensorflow/contrib/lite/toco/export_tensorflow.cc b/tensorflow/contrib/lite/toco/export_tensorflow.cc index 4fc01dbc20..529df3cd2e 100644 --- a/tensorflow/contrib/lite/toco/export_tensorflow.cc +++ b/tensorflow/contrib/lite/toco/export_tensorflow.cc @@ -519,6 +519,18 @@ void ConvertAddOperator(const Model& model, const AddOperator& src_op, (*add_op->mutable_attr())["T"].set_type(DT_FLOAT); } +void ConvertAddNOperator(const Model& model, const AddNOperator& src_op, + GraphDef* tensorflow_graph) { + auto* add_op = tensorflow_graph->add_node(); + add_op->set_op("AddN"); + add_op->set_name(src_op.outputs[0]); + for (const auto& input : src_op.inputs) { + *add_op->add_input() = input; + } + (*add_op->mutable_attr())["N"].set_i(src_op.inputs.size()); + (*add_op->mutable_attr())["T"].set_type(DT_FLOAT); +} + void ConvertMulOperator(const Model& model, const MulOperator& src_op, GraphDef* tensorflow_graph) { auto* add_op = tensorflow_graph->add_node(); @@ -1406,6 +1418,9 @@ void ConvertOperator(const Model& model, const Operator& src_op, } else if (src_op.type == OperatorType::kAdd) { ConvertAddOperator(model, static_cast(src_op), tensorflow_graph); + } else if (src_op.type == OperatorType::kAddN) { + ConvertAddNOperator(model, static_cast(src_op), + tensorflow_graph); } else if (src_op.type == OperatorType::kMul) { ConvertMulOperator(model, static_cast(src_op), tensorflow_graph); diff --git a/tensorflow/contrib/lite/toco/graph_transformations/convert_trivial_addn_to_add.cc b/tensorflow/contrib/lite/toco/graph_transformations/convert_trivial_addn_to_add.cc new file mode 100644 index 0000000000..dcaaddbf3b --- /dev/null +++ b/tensorflow/contrib/lite/toco/graph_transformations/convert_trivial_addn_to_add.cc @@ -0,0 +1,51 @@ +/* Copyright 2017 The TensorFlow Authors. 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/contrib/lite/toco/graph_transformations/graph_transformations.h" +#include "tensorflow/contrib/lite/toco/model.h" +#include "tensorflow/core/platform/logging.h" + +namespace toco { + +// This pass will convert an AddN operator with only 2 inputs into a regular Add +// operator, to which more optimizations may apply. +bool ConvertTrivialAddNToAdd::Run(Model* model, std::size_t op_index) { + auto addn_it = model->operators.begin() + op_index; + if (addn_it->get()->type != OperatorType::kAddN) { + return false; + } + AddNOperator* addn_op = static_cast(addn_it->get()); + CHECK_GE(addn_op->inputs.size(), 2); + CHECK_EQ(addn_op->outputs.size(), 1); + + // We only reduce AddN with N=2 to a regular Add. + if (addn_op->inputs.size() != 2) { + return false; + } + + // Copy inputs & outputs to regular Add. + auto* add_op = new AddOperator; + add_op->inputs.push_back(addn_op->inputs[0]); + add_op->inputs.push_back(addn_op->inputs[1]); + add_op->outputs = addn_op->outputs; + + // Replace the AddN operator in the graph. + const auto add_it = model->operators.emplace(addn_it, add_op); + addn_it = add_it + 1; + CHECK_EQ(addn_it->get(), addn_op); + model->operators.erase(addn_it); + return true; +} + +} // namespace toco diff --git a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h index 4ac2265be9..e11bebcd4e 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h +++ b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h @@ -114,6 +114,7 @@ void RunGraphTransformations(Model* model, const string& message, // List of all graph transformations DECLARE_GRAPH_TRANSFORMATION(ConvertExpandDimsToReshape) DECLARE_GRAPH_TRANSFORMATION(ConvertPureConvToDepthwise) +DECLARE_GRAPH_TRANSFORMATION(ConvertTrivialAddNToAdd) DECLARE_GRAPH_TRANSFORMATION(ConvertTrivialTransposeToReshape) DECLARE_GRAPH_TRANSFORMATION(ConvertReorderAxes) DECLARE_GRAPH_TRANSFORMATION(EnsureBiasVectors) diff --git a/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc b/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc index ff0a3bd881..4fb3b6ae7a 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/propagate_fixed_sizes.cc @@ -406,6 +406,28 @@ void ProcessSimpleBinaryOperator(Model* model, Operator* op) { &output_array); } +void ProcessAddNOperator(Model* model, Operator* op) { + // Yield until all input dims have been resolved. + // + // TODO(myenik): Since AddN does not support broadcasting, maybe we could + // actually use this to improve shape propagation by propagating the shape of + // one input to all other inputs once it is resolved instead of just the + // output, since all inputs must be the same size and shape for a well-formed + // graph. + for (const auto& input : op->inputs) { + const auto& input_array = model->GetArray(input); + if (!input_array.has_shape()) { + return; + } + } + + // AddN does not support broadcasting, all inputs must be the same shape, so + // we just take the first input shape and apply it to the output. + const auto& input0_array = model->GetArray(op->inputs[0]); + auto& output_array = model->GetArray(op->outputs[0]); + output_array.copy_shape(input0_array.shape()); +} + bool KeepDims(const Operator& op) { switch (op.type) { case OperatorType::kTensorFlowMin: @@ -1282,6 +1304,9 @@ bool PropagateFixedSizes::Run(Model* model, std::size_t op_index) { case OperatorType::kTensorFlowGreaterEqual: ProcessSimpleBinaryOperator(model, op); break; + case OperatorType::kAddN: + ProcessAddNOperator(model, op); + break; case OperatorType::kConv: ProcessConvOperator(model, static_cast(op)); break; diff --git a/tensorflow/contrib/lite/toco/import_tensorflow.cc b/tensorflow/contrib/lite/toco/import_tensorflow.cc index e8f318cd43..ca378af4c5 100644 --- a/tensorflow/contrib/lite/toco/import_tensorflow.cc +++ b/tensorflow/contrib/lite/toco/import_tensorflow.cc @@ -696,6 +696,19 @@ void ConvertAddOperator(const NodeDef& node, model->operators.emplace_back(op); } +void ConvertAddNOperator(const NodeDef& node, + const TensorFlowImportFlags& tf_import_flags, + Model* model) { + CHECK_EQ(node.op(), "AddN"); + const int num_inputs = GetInputsCount(node, tf_import_flags); + auto* op = new AddNOperator; + for (int i = 0; i < num_inputs; ++i) { + op->inputs.push_back(node.input(i)); + } + op->outputs.push_back(node.name()); + model->operators.emplace_back(op); +} + void ConvertMulOperator(const NodeDef& node, const TensorFlowImportFlags& tf_import_flags, Model* model) { @@ -1862,6 +1875,8 @@ std::unique_ptr ImportTensorFlowGraphDef( ConvertSquareOperator(node, tf_import_flags, model); } else if (node.op() == "Add") { ConvertAddOperator(node, tf_import_flags, model); + } else if (node.op() == "AddN") { + ConvertAddNOperator(node, tf_import_flags, model); } else if (node.op() == "Mul") { ConvertMulOperator(node, tf_import_flags, model); } else if (node.op() == "Sub") { diff --git a/tensorflow/contrib/lite/toco/model.h b/tensorflow/contrib/lite/toco/model.h index b1b9b718bb..d1af371fd4 100644 --- a/tensorflow/contrib/lite/toco/model.h +++ b/tensorflow/contrib/lite/toco/model.h @@ -32,6 +32,7 @@ enum class OperatorType { kNone, // General-purpose neural network operators. kAdd, + kAddN, kAveragePool, kBatchNormalization, kConv, @@ -559,6 +560,16 @@ struct AddOperator : Operator { AddOperator() : Operator(OperatorType::kAdd) {} }; +// Element-wise addition operator for N inputs. +// +// Inputs: +// inputs[i]: The i-th array to add together to form the output. +// +// TensorFlow equivalent: AddN +struct AddNOperator : Operator { + AddNOperator() : Operator(OperatorType::kAddN) {} +}; + // Concatenation operator: concatenates its inputs // along the axis. // diff --git a/tensorflow/contrib/lite/toco/tflite/operator.cc b/tensorflow/contrib/lite/toco/tflite/operator.cc index d75d1fcc5b..298f49025f 100644 --- a/tensorflow/contrib/lite/toco/tflite/operator.cc +++ b/tensorflow/contrib/lite/toco/tflite/operator.cc @@ -807,6 +807,8 @@ std::vector> BuildOperatorList() { // There operators are supported by Toco, but not by TF Lite, and has no // attributes. + ops.emplace_back( + new SimpleOperator("ADDN", OperatorType::kAddN)); ops.emplace_back(new SimpleOperator("NEG", OperatorType::kNeg)); ops.emplace_back(new SimpleOperator( "RSQRT", OperatorType::kTensorFlowRsqrt)); diff --git a/tensorflow/contrib/lite/toco/toco_tooling.cc b/tensorflow/contrib/lite/toco/toco_tooling.cc index f2753c84e9..720c33777d 100644 --- a/tensorflow/contrib/lite/toco/toco_tooling.cc +++ b/tensorflow/contrib/lite/toco/toco_tooling.cc @@ -52,6 +52,7 @@ void MakeGeneralGraphTransformationsSet( GraphTransformationsSet* transformations) { CHECK(transformations->empty()); transformations->Add(new ConvertExpandDimsToReshape); + transformations->Add(new ConvertTrivialAddNToAdd); transformations->Add(new ConvertTrivialTransposeToReshape); transformations->Add(new ConvertReorderAxes); transformations->Add(new ResolveReshapeAttributes); diff --git a/tensorflow/contrib/lite/toco/tooling_util.cc b/tensorflow/contrib/lite/toco/tooling_util.cc index 8543ba4742..99a54a300b 100644 --- a/tensorflow/contrib/lite/toco/tooling_util.cc +++ b/tensorflow/contrib/lite/toco/tooling_util.cc @@ -197,6 +197,7 @@ const char* OperatorTypeName(OperatorType type) { case OperatorType::k##c: \ return #c; HANDLE_OPERATORTYPENAME_CASE(Add) + HANDLE_OPERATORTYPENAME_CASE(AddN) HANDLE_OPERATORTYPENAME_CASE(AveragePool) HANDLE_OPERATORTYPENAME_CASE(BatchNormalization) HANDLE_OPERATORTYPENAME_CASE(Conv) @@ -1396,6 +1397,16 @@ bool EstimateArithmeticOpsCount(const Model& model, int64* result) { total += RequiredBufferSizeForShape(output_array.shape()); break; } + case OperatorType::kAddN: { + const auto& output_array = model.GetArray(op->outputs[0]); + if (!output_array.has_shape()) { + return false; + } + // AddN cost is roughly the same cost as N-1 Adds. + const int num_adds = op->inputs.size() - 1; + total += num_adds * RequiredBufferSizeForShape(output_array.shape()); + break; + } case OperatorType::kLogistic: case OperatorType::kSoftmax: case OperatorType::kTanh: { -- GitLab From 7b44779ff2031e73ea46ecc7cf2a73405d22a57a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 16:28:20 -0800 Subject: [PATCH 225/258] Prepare internal kernels for BroadcastMul and BroadcastAdd PiperOrigin-RevId: 183160907 --- .../internal/optimized/optimized_ops.h | 48 ++++++++++++--- .../internal/reference/reference_ops.h | 60 ++++++++++++++----- 2 files changed, 86 insertions(+), 22 deletions(-) diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h b/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h index c35b9da938..8163c76cfd 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h @@ -1538,9 +1538,10 @@ void Add(const int32* input1_data, const Dims<4>& input1_dims, // reference_ops.h. Once an optimized version is implemented and NdArrayDesc // is no longer referenced in this file, move NdArrayDesc from types.h to // reference_ops.h. -template +template void BroadcastAdd(const T* input1_data, const Dims<4>& input1_dims, const T* input2_data, const Dims<4>& input2_dims, + T output_activation_min, T output_activation_max, T* output_data, const Dims<4>& output_dims) { gemmlowp::ScopedProfilingLabel label("BroadcastAdd"); @@ -1563,15 +1564,30 @@ void BroadcastAdd(const T* input1_data, const Dims<4>& input1_dims, for (int y = 0; y < ArraySize(output_dims, 2); ++y) { for (int x = 0; x < ArraySize(output_dims, 1); ++x) { for (int c = 0; c < ArraySize(output_dims, 0); ++c) { - output_data[Offset(output_dims, c, x, y, b)] = ActivationFunction( - input1_data[SubscriptToIndex(desc1, c, x, y, b)] + - input2_data[SubscriptToIndex(desc2, c, x, y, b)]); + output_data[Offset(output_dims, c, x, y, b)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, c, x, y, b)] + + input2_data[SubscriptToIndex(desc2, c, x, y, b)], + output_activation_min, output_activation_max); } } } } } +// legacy, for compatibility with old checked-in code +template +void BroadcastAdd(const T* input1_data, const Dims<4>& input1_dims, + const T* input2_data, const Dims<4>& input2_dims, + T* output_data, const Dims<4>& output_dims) { + T output_activation_min, output_activation_max; + GetActivationMinMax(Ac, &output_activation_min, &output_activation_max); + + BroadcastAdd(input1_data, input1_dims, input2_data, input2_dims, + output_activation_min, output_activation_max, output_data, + output_dims); +} + inline void BroadcastAdd(int left_shift, const uint8* input1_data, const Dims<4>& input1_dims, int32 input1_offset, int32 input1_multiplier, int input1_shift, @@ -1772,9 +1788,10 @@ void Mul(const int32* input1_data, const Dims<4>& input1_dims, // reference_ops.h. Once an optimized version is implemented and NdArrayDesc // is no longer referenced in this file, move NdArrayDesc from types.h to // reference_ops.h. -template +template void BroadcastMul(const T* input1_data, const Dims<4>& input1_dims, const T* input2_data, const Dims<4>& input2_dims, + T output_activation_min, T output_activation_max, T* output_data, const Dims<4>& output_dims) { gemmlowp::ScopedProfilingLabel label("BroadcastMul"); @@ -1797,15 +1814,30 @@ void BroadcastMul(const T* input1_data, const Dims<4>& input1_dims, for (int y = 0; y < ArraySize(output_dims, 2); ++y) { for (int x = 0; x < ArraySize(output_dims, 1); ++x) { for (int c = 0; c < ArraySize(output_dims, 0); ++c) { - output_data[Offset(output_dims, c, x, y, b)] = ActivationFunction( - input1_data[SubscriptToIndex(desc1, c, x, y, b)] * - input2_data[SubscriptToIndex(desc2, c, x, y, b)]); + output_data[Offset(output_dims, c, x, y, b)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, c, x, y, b)] * + input2_data[SubscriptToIndex(desc2, c, x, y, b)], + output_activation_min, output_activation_max); } } } } } +// legacy, for compatibility with old checked-in code +template +void BroadcastMul(const T* input1_data, const Dims<4>& input1_dims, + const T* input2_data, const Dims<4>& input2_dims, + T* output_data, const Dims<4>& output_dims) { + T output_activation_min, output_activation_max; + GetActivationMinMax(Ac, &output_activation_min, &output_activation_max); + + BroadcastMul(input1_data, input1_dims, input2_data, input2_dims, + output_activation_min, output_activation_max, output_data, + output_dims); +} + inline void BroadcastMul(const uint8* input1_data, const Dims<4>& input1_dims, int32 input1_offset, const uint8* input2_data, const Dims<4>& input2_dims, int32 input2_offset, diff --git a/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h b/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h index 64651d8348..31bade26f9 100644 --- a/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h @@ -889,10 +889,11 @@ inline void Add(int left_shift, const uint8* input1_data, // dimensionality if the runtime code does a single loop over one dimension // that handles broadcasting as the base case. The code generator would then // generate max(D1, D2) nested for loops. -template -void BroadcastAdd(const float* input1_data, const Dims<4>& input1_dims, - const float* input2_data, const Dims<4>& input2_dims, - float* output_data, const Dims<4>& output_dims) { +template +void BroadcastAdd(const T* input1_data, const Dims<4>& input1_dims, + const T* input2_data, const Dims<4>& input2_dims, + T output_activation_min, T output_activation_max, + T* output_data, const Dims<4>& output_dims) { gemmlowp::ScopedProfilingLabel label("BroadcastAdd"); NdArrayDesc<4> desc1; @@ -914,15 +915,30 @@ void BroadcastAdd(const float* input1_data, const Dims<4>& input1_dims, for (int y = 0; y < ArraySize(output_dims, 2); ++y) { for (int x = 0; x < ArraySize(output_dims, 1); ++x) { for (int c = 0; c < ArraySize(output_dims, 0); ++c) { - output_data[Offset(output_dims, c, x, y, b)] = ActivationFunction( - input1_data[SubscriptToIndex(desc1, c, x, y, b)] + - input2_data[SubscriptToIndex(desc2, c, x, y, b)]); + output_data[Offset(output_dims, c, x, y, b)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, c, x, y, b)] + + input2_data[SubscriptToIndex(desc2, c, x, y, b)], + output_activation_min, output_activation_max); } } } } } +// legacy, for compatibility with old checked-in code +template +void BroadcastAdd(const T* input1_data, const Dims<4>& input1_dims, + const T* input2_data, const Dims<4>& input2_dims, + T* output_data, const Dims<4>& output_dims) { + T output_activation_min, output_activation_max; + GetActivationMinMax(Ac, &output_activation_min, &output_activation_max); + + BroadcastAdd(input1_data, input1_dims, input2_data, input2_dims, + output_activation_min, output_activation_max, output_data, + output_dims); +} + inline void BroadcastAdd(int left_shift, const uint8* input1_data, const Dims<4>& input1_dims, int32 input1_offset, int32 input1_multiplier, int input1_shift, @@ -1053,10 +1069,11 @@ void Mul(const float* input1_data, const Dims<4>& input1_dims, // dimensionality if the runtime code does a single loop over one dimension // that handles broadcasting as the base case. The code generator would then // generate max(D1, D2) nested for loops. -template -void BroadcastMul(const float* input1_data, const Dims<4>& input1_dims, - const float* input2_data, const Dims<4>& input2_dims, - float* output_data, const Dims<4>& output_dims) { +template +void BroadcastMul(const T* input1_data, const Dims<4>& input1_dims, + const T* input2_data, const Dims<4>& input2_dims, + T output_activation_min, T output_activation_max, + T* output_data, const Dims<4>& output_dims) { gemmlowp::ScopedProfilingLabel label("BroadcastMul"); NdArrayDesc<4> desc1; @@ -1078,15 +1095,30 @@ void BroadcastMul(const float* input1_data, const Dims<4>& input1_dims, for (int y = 0; y < ArraySize(output_dims, 2); ++y) { for (int x = 0; x < ArraySize(output_dims, 1); ++x) { for (int c = 0; c < ArraySize(output_dims, 0); ++c) { - output_data[Offset(output_dims, c, x, y, b)] = ActivationFunction( - input1_data[SubscriptToIndex(desc1, c, x, y, b)] * - input2_data[SubscriptToIndex(desc2, c, x, y, b)]); + output_data[Offset(output_dims, c, x, y, b)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, c, x, y, b)] * + input2_data[SubscriptToIndex(desc2, c, x, y, b)], + output_activation_min, output_activation_max); } } } } } +// legacy, for compatibility with old checked-in code +template +void BroadcastMul(const T* input1_data, const Dims<4>& input1_dims, + const T* input2_data, const Dims<4>& input2_dims, + T* output_data, const Dims<4>& output_dims) { + T output_activation_min, output_activation_max; + GetActivationMinMax(Ac, &output_activation_min, &output_activation_max); + + BroadcastMul(input1_data, input1_dims, input2_data, input2_dims, + output_activation_min, output_activation_max, output_data, + output_dims); +} + inline void BroadcastMul(const uint8* input1_data, const Dims<4>& input1_dims, int32 input1_offset, const uint8* input2_data, const Dims<4>& input2_dims, int32 input2_offset, -- GitLab From 0454180a47bdbe7174a2f51ecbe76b2aed2ce719 Mon Sep 17 00:00:00 2001 From: Russell Power Date: Wed, 24 Jan 2018 16:41:50 -0800 Subject: [PATCH 226/258] Defer logging infeed error messages for a short time to see if the main session returns. PiperOrigin-RevId: 183162866 --- .../contrib/tpu/python/tpu/tpu_estimator.py | 457 ++++++++++-------- 1 file changed, 249 insertions(+), 208 deletions(-) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index b6d685b3fc..2ae3a26a85 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # =================================================================== - """TPUEstimator class.""" from __future__ import absolute_import @@ -24,6 +23,7 @@ from contextlib import contextmanager import copy import threading import time +import traceback import six from six.moves import queue as Queue # pylint: disable=redefined-builtin @@ -60,7 +60,6 @@ from tensorflow.python.training import session_run_hook from tensorflow.python.training import training from tensorflow.python.training import training_util - _INITIAL_LOSS = 1e7 _ZERO_LOSS = 0. _TPU_ESTIMATOR = 'tpu_estimator' @@ -86,8 +85,7 @@ def _create_global_step(graph): initializer=init_ops.zeros_initializer(), trainable=False, use_resource=True, - collections=[ops.GraphKeys.GLOBAL_VARIABLES, - ops.GraphKeys.GLOBAL_STEP]) + collections=[ops.GraphKeys.GLOBAL_VARIABLES, ops.GraphKeys.GLOBAL_STEP]) def _create_or_get_iterations_per_loop(): @@ -100,8 +98,8 @@ def _create_or_get_iterations_per_loop(): raise RuntimeError('Multiple iterations_per_loop_var in collection.') with ops.colocate_with(training_util.get_global_step()): - with variable_scope.variable_scope(_TPU_ESTIMATOR, - reuse=variable_scope.AUTO_REUSE): + with variable_scope.variable_scope( + _TPU_ESTIMATOR, reuse=variable_scope.AUTO_REUSE): return variable_scope.get_variable( _ITERATIONS_PER_LOOP_VAR, initializer=init_ops.zeros_initializer(), @@ -242,9 +240,9 @@ class _TPUContext(object): return self._eval_batch_size return None - global_batch_size = (self._train_batch_size if - mode == model_fn_lib.ModeKeys.TRAIN - else self._eval_batch_size) + global_batch_size = ( + self._train_batch_size + if mode == model_fn_lib.ModeKeys.TRAIN else self._eval_batch_size) # On TPU if self.is_input_sharded_per_core(): return global_batch_size // self.num_cores @@ -291,8 +289,9 @@ class _TPUContext(object): # The tpu job is determined by the run_config. Right now, this method is # required as tpu_config is not part of the RunConfig. mode = self._assert_mode() - master = (run_config.evaluation_master if mode == model_fn_lib.ModeKeys.EVAL - else run_config.master) + master = ( + run_config.evaluation_master + if mode == model_fn_lib.ModeKeys.EVAL else run_config.master) if master in _LOCAL_MASTERS: return None @@ -319,6 +318,7 @@ class _TPUContext(object): def tpu_host_placement_function(self): """Returns the TPU host place function.""" master = self.master_job + def _placement_function(_sentinal=None, core_id=None, host_id=None): # pylint: disable=invalid-name assert _sentinal is None if core_id is not None and host_id is not None: @@ -333,19 +333,23 @@ class _TPUContext(object): if core_id is not None: host_id = core_id / 8 return '/job:%s/task:%d/device:CPU:0' % (master, host_id) + return _placement_function @property def tpu_device_placement_function(self): master = self.master_job job_device = '' if master is None else ('/job:%s' % master) + def _placement_function(i): return '%s/task:%d/device:TPU:%d' % (job_device, i / 8, i % 8) + return _placement_function @property def tpu_ordinal_function(self): """Returns the TPU ordinal fn.""" + def _tpu_ordinal_function(index): """Return the TPU ordinal associated with a shard. @@ -358,6 +362,7 @@ class _TPUContext(object): The ordinal of the TPU device the shard's infeed should be placed on. """ return index % 8 + return _tpu_ordinal_function @@ -371,14 +376,16 @@ class _SIGNAL(object): STOP = -2 -class TPUEstimatorSpec(collections.namedtuple('TPUEstimatorSpec', [ - 'mode', - 'predictions', - 'loss', - 'train_op', - 'eval_metrics', - 'export_outputs', - 'scaffold_fn'])): +class TPUEstimatorSpec( + collections.namedtuple('TPUEstimatorSpec', [ + 'mode', + 'predictions', + 'loss', + 'train_op', + 'eval_metrics', + 'export_outputs', + 'scaffold_fn' + ])): """Ops and objects returned from a `model_fn` and passed to `TPUEstimator`. See `EstimatorSpec` for `mode`, 'predictions, 'loss', 'train_op', and @@ -416,111 +423,116 @@ class TPUEstimatorSpec(collections.namedtuple('TPUEstimatorSpec', [ """Creates a validated `TPUEstimatorSpec` instance.""" if eval_metrics is not None: _EvalMetrics.validate(eval_metrics) - return super(TPUEstimatorSpec, cls).__new__(cls, - mode=mode, - predictions=predictions, - loss=loss, - train_op=train_op, - eval_metrics=eval_metrics, - export_outputs=export_outputs, - scaffold_fn=scaffold_fn) + return super(TPUEstimatorSpec, cls).__new__( + cls, + mode=mode, + predictions=predictions, + loss=loss, + train_op=train_op, + eval_metrics=eval_metrics, + export_outputs=export_outputs, + scaffold_fn=scaffold_fn) def as_estimator_spec(self): """Creates an equivalent `EstimatorSpec` used by CPU train/eval.""" eval_metric_ops = _EvalMetrics.to_metric_metric_ops_for_cpu( self.eval_metrics) scaffold = self.scaffold_fn() if self.scaffold_fn else None - return model_fn_lib.EstimatorSpec(mode=self.mode, - predictions=self.predictions, - loss=self.loss, - train_op=self.train_op, - eval_metric_ops=eval_metric_ops, - export_outputs=self.export_outputs, - scaffold=scaffold) + return model_fn_lib.EstimatorSpec( + mode=self.mode, + predictions=self.predictions, + loss=self.loss, + train_op=self.train_op, + eval_metric_ops=eval_metric_ops, + export_outputs=self.export_outputs, + scaffold=scaffold) + + +class _OpQueueContext(object): + """Manages work queue and thread for a infeed/outfeed thread.""" + + def __init__(self, name, target, args): + self._name = name + self._queue = Queue.Queue() + args = (self,) + args + self._thread = threading.Thread(name=name, target=target, args=args) + self._thread.daemon = True + self._thread.start() + + def stop(self): + self._queue.put(_SIGNAL.STOP) + + def send_next_batch_signal(self, iterations): + self._queue.put(iterations) + + def read_iteration_counts(self): + while True: + signal = self._queue.get(block=True) + logging.debug('%s read signal %s', self._name, signal) + if signal == _SIGNAL.STOP: + logging.info('%s received signal, stopping.', self._name) + return + yield signal + def join(self): + logging.info('Shutting down %s thread.' % self._name) + self.stop() + self._thread.join() -class _InfeedOutfeedThreadBaseController(object): - """This wraps the infeed/outfeed thread and stops when Estimator finishes.""" - def __init__(self, thd): - self._signal_queue = Queue.Queue() - thd.daemon = True - thd.start() - self._thd = thd +class TPUInfeedOutfeedSessionHook(session_run_hook.SessionRunHook): + """A Session hook setting up the TPU initialization, infeed, and outfeed. - def block_and_get_signal(self): - return self._signal_queue.get() + This hook does two major things: + 1. initialize and shutdown TPU system. + 2. launch and join the threads for infeed enqueue and (optional) outfeed + dequeue. + """ - def send_next_batch_signal(self, signal=_SIGNAL.NEXT_BATCH): - self._signal_queue.put(signal) + def __init__(self, ctx, enqueue_ops, dequeue_ops=None): + self._master_job = ctx.master_job + self._enqueue_ops = enqueue_ops + self._dequeue_ops = dequeue_ops + self._initial_infeed_sleep_secs = ( + ctx.config.tpu_config.initial_infeed_sleep_secs) + self._session_cancel_timer = None - def join(self): - self._signal_queue.put(_SIGNAL.STOP) - self._thd.join() + self._feed_error = None + self._finished = False + def begin(self): + logging.info('TPU job name %s', self._master_job) + self._iterations_per_loop_var = _create_or_get_iterations_per_loop() + self._init_op = [tpu.initialize_system(job=self._master_job)] + self._finalize_op = [tpu.shutdown_system(job=self._master_job)] -class _OutfeedThreadController(_InfeedOutfeedThreadBaseController): - """This wraps the outfeed thread and stops when Estimator finishes.""" + def _log_error(self, session, error): + """Log an infeed or outfeed error. - def __init__(self, session, dequeue_ops): - super(_OutfeedThreadController, self).__init__( - threading.Thread(target=self._execute_dequeue_ops, - args=(session, dequeue_ops))) + This logs a short error message immediately, and schedules a timer to + emit the full stack trace and error message after a short period of time. + If the main session has terminated by the time the timer triggers, we + assume the real source of the error was from the main session and avoid + emitting a stack trace for the infeed. - def _execute_dequeue_ops(self, session, dequeue_ops): - count = 0 - while True: - signal = self.block_and_get_signal() - if signal == _SIGNAL.STOP: - logging.info('Stop outfeed thread.') - return + Args: + session: `tf.Session`, session to be terminated + error: exception that triggered logging. + """ + logging.warning( + '\n\n' + 'Error occurred during infeed/outfeed. This may be due to a compile ' + 'error in the main session. Waiting for a short time for the main ' + 'session to come back.\n\n%s', error) - iterations = signal - for i in range(iterations): - logging.debug('Outfeed dequeue for iteration (%d, %d)', count, i) - session.run(dequeue_ops) - count += 1 + self._feed_error = traceback.format_exc() - def join(self): - logging.info('Waiting for Outfeed Thread to exit.') - super(_OutfeedThreadController, self).join() - - -class _InfeedThreadController(_InfeedOutfeedThreadBaseController): - """This wraps the infeed thread and stops when Estimator finishes.""" - - def __init__(self, session, enqueue_ops, initial_infeed_sleep_secs): - super(_InfeedThreadController, self).__init__( - threading.Thread( - target=self._input_thread_fn_for_loading, - args=(session, enqueue_ops, initial_infeed_sleep_secs))) - - def _input_thread_fn_for_loading(self, session, enqueue_ops, - initial_infeed_sleep_secs): - count = 0 - if initial_infeed_sleep_secs: - logging.info('Infeed thread sleeping for %d seconds.', - initial_infeed_sleep_secs) - time.sleep(initial_infeed_sleep_secs) - logging.info('Infeed thread starting after sleep') - try: - while True: - signal = self._signal_queue.get() - if signal == _SIGNAL.STOP: - logging.info('Stop Infeed input thread.') - return - - if _WRAP_INPUT_FN_INTO_WHILE_LOOP: - # Enqueue batches for next loop. - session.run(enqueue_ops) - else: - iterations = signal - for i in range(iterations): - logging.debug('Infeed enqueue for iteration (%d, %d)', count, i) - session.run(enqueue_ops) - count += 1 + # If we've already encountered a feed error, don't schedule another + # cancellation op. + if self._session_cancel_timer: + return - except Exception: # pylint: disable=broad-except + def _cancel_session(): # Close the session to avoid the main thread from hanging. If input # pipeline triggers any error, the infeed thread dies but the main thread # for TPU computation waits for the infeed enqueue forever. Close the @@ -535,77 +547,94 @@ class _InfeedThreadController(_InfeedOutfeedThreadBaseController): # exception in the main thread, instead of the expected compile error. # User code that depends on having the proper exception type will # therefore be confused. - logging.error( - 'Failed running infeed, closing session.\n' - 'You may see an exception from your main session after this. ' - 'Sleep for 2 minutes before close Session from infeed thread to ' - 'allow the main thread returning an error first, if any.', - exc_info=1 - ) - time.sleep(120) - logging.error('Closing the failed session.') - session.close() - - def join(self): - logging.info('Waiting for Infeed Thread to exit.') - super(_InfeedThreadController, self).join() - - -class TPUInfeedOutfeedSessionHook(session_run_hook.SessionRunHook): - """A Session hook setting up the TPU initialization, infeed, and outfeed. - - This hook does two major things: - 1. initialize and shutdown TPU system. - 2. launch and join the threads for infeed enqueue and (optional) outfeed - dequeue. - """ + time.sleep(5) + + # If the main session is still running, the infeed/outfeed errors are + # legitimate, and should be logged. + if not self._finished: + logging.error('Feed error: %s', self._feed_error) + logging.error('Closing session. A RuntimeError should follow.') + session.close() + + self._session_cancel_timer = threading.Thread(target=_cancel_session) + self._session_cancel_timer.daemon = True + self._session_cancel_timer.start() + + def _run_infeed(self, queue_ctx, session): + logging.info('Starting infeed thread controller.') + if self._initial_infeed_sleep_secs: + logging.info('%s thread sleeping for %d seconds.', self._name, + self._initial_infeed_sleep_secs) + time.sleep(self._initial_infeed_sleep_secs) + logging.info('%s thread starting after sleep', self._name) - def __init__(self, ctx, enqueue_ops, dequeue_ops=None): - self._master_job = ctx.master_job - self._enqueue_ops = enqueue_ops - self._dequeue_ops = dequeue_ops - self._initial_infeed_sleep_secs = ( - ctx.config.tpu_config.initial_infeed_sleep_secs) + try: + if _WRAP_INPUT_FN_INTO_WHILE_LOOP: + for _ in queue_ctx.read_iteration_counts(): + session.run(self._enqueue_ops) + else: + for count, steps in enumerate(queue_ctx.read_iteration_counts()): + for i in xrange(steps): + logging.debug('Infeed enqueue for iteration (%d, %d)', count, i) + session.run(self._enqueue_ops) + logging.debug('Infeed thread finished, shutting down.') + except Exception as e: # pylint: disable=broad-except + self._log_error(session, e) - def begin(self): - logging.info('TPU job name %s', self._master_job) - self._iterations_per_loop_var = _create_or_get_iterations_per_loop() - self._init_op = [tpu.initialize_system(job=self._master_job)] - self._finalize_op = [tpu.shutdown_system(job=self._master_job)] + def _run_outfeed(self, queue_ctx, session): + logging.info('Starting outfeed thread controller.') + try: + for count, steps in enumerate(queue_ctx.read_iteration_counts()): + for i in xrange(steps): + logging.debug('Outfeed dequeue for iteration (%d, %d)', count, i) + session.run(self._dequeue_ops) + except Exception as e: # pylint: disable=broad-except + self._log_error(session, e) def after_create_session(self, session, coord): logging.info('Init TPU system') - session.run(self._init_op, - options=config_pb2.RunOptions(timeout_in_ms=5*60*1000)) + session.run( + self._init_op, + options=config_pb2.RunOptions(timeout_in_ms=5 * 60 * 1000)) logging.info('Start infeed thread controller') - self._infeed_thd_controller = _InfeedThreadController( - session, self._enqueue_ops, self._initial_infeed_sleep_secs) + self._infeed_controller = _OpQueueContext( + name='InfeedController', target=self._run_infeed, args=(session,)) if self._dequeue_ops is not None: logging.info('Start outfeed thread controller') - self._outfeed_thd_controller = _OutfeedThreadController( - session, self._dequeue_ops) + self._outfeed_controller = _OpQueueContext( + name='OutfeedController', target=self._run_outfeed, args=(session,)) def before_run(self, run_context): + if self._feed_error: + logging.warning('Feed error occurred, terminating session.') + run_context.request_stop() + return + iterations = run_context.session.run(self._iterations_per_loop_var) logging.info('Enqueue next (%d) batch(es) of data to infeed.', iterations) + self._infeed_controller.send_next_batch_signal(iterations) - self._infeed_thd_controller.send_next_batch_signal(iterations) if self._dequeue_ops is not None: # TODO(xiejw): Refactor the outfeed dequeue into tf.while_loop. - logging.info( - 'Dequeue next (%d) batch(es) of data from outfeed.', iterations) - self._outfeed_thd_controller.send_next_batch_signal(iterations) + logging.info('Dequeue next (%d) batch(es) of data from outfeed.', + iterations) + self._outfeed_controller.send_next_batch_signal(iterations) def end(self, session): + if self._session_cancel_timer: + logging.warning('Feed error occurred; waiting for message.') + self._session_cancel_timer.join() + + self._finished = True logging.info('Stop infeed thread controller') - self._infeed_thd_controller.join() + self._infeed_controller.join() if self._dequeue_ops is not None: logging.info('Stop output thread controller') - self._outfeed_thd_controller.join() + self._outfeed_controller.join() logging.info('Shutdown TPU system.') session.run(self._finalize_op) @@ -676,8 +705,8 @@ class _TPUStopAtStepHook(session_run_hook.SessionRunHook): run_context.request_stop() else: iterations = self._next_iterations(global_step, self._last_step) - self._iterations_per_loop_var.load(iterations, - session=run_context.session) + self._iterations_per_loop_var.load( + iterations, session=run_context.session) class _SetEvalIterationsHook(session_run_hook.SessionRunHook): @@ -698,8 +727,8 @@ class _SetEvalIterationsHook(session_run_hook.SessionRunHook): self._iterations_per_loop_var.load(self._num_steps, session=session) -def generate_per_core_enqueue_ops_fn_for_host( - ctx, input_fn, inputs_structure_recorder): +def generate_per_core_enqueue_ops_fn_for_host(ctx, input_fn, + inputs_structure_recorder): """Generates infeed enqueue ops for per-core input_fn on a single host.""" captured_infeed_queue = _CapturedObject() @@ -729,9 +758,9 @@ def generate_per_core_enqueue_ops_fn_for_host( per_host_sharded_inputs) per_host_enqueue_ops = infeed_queue.generate_enqueue_ops( - per_host_sharded_inputs, - tpu_ordinal_function=ctx.tpu_ordinal_function) + per_host_sharded_inputs, tpu_ordinal_function=ctx.tpu_ordinal_function) return per_host_enqueue_ops + return enqueue_ops_fn, captured_infeed_queue @@ -748,8 +777,7 @@ def generate_per_host_enqueue_ops_fn_for_host( features, labels = inputs else: features, labels = inputs, None - inputs_structure_recorder.validate_and_record_structure( - features, labels) + inputs_structure_recorder.validate_and_record_structure(features, labels) unsharded_tensor_list = ( inputs_structure_recorder.flatten_features_and_labels( features, labels)) @@ -763,9 +791,9 @@ def generate_per_host_enqueue_ops_fn_for_host( per_host_enqueue_ops = ( infeed_queue.split_inputs_and_generate_enqueue_ops( - unsharded_tensor_list, - placement_function=lambda x: device)) + unsharded_tensor_list, placement_function=lambda x: device)) return per_host_enqueue_ops + return enqueue_ops_fn, captured_infeed_queue @@ -815,6 +843,7 @@ class _InputPipeline(object): def validate_and_record_structure(self, features, labels): """Validates and records the structure of features` and `labels`.""" + def _extract_key_names(tensor_or_dict): if tensor_or_dict is None: return [] @@ -842,8 +871,8 @@ class _InputPipeline(object): flattened_inputs = [] if self._feature_names: # We need a fixed ordering for enqueueing and dequeueing. - flattened_inputs.extend([features[name] - for name in self._feature_names]) + flattened_inputs.extend( + [features[name] for name in self._feature_names]) else: flattened_inputs.append(features) @@ -870,11 +899,11 @@ class _InputPipeline(object): ValueError: If the number of expected tensors from `flattened_inputs` mismatches the recorded structure. """ - expected_num_features = (len(self._feature_names) if self._feature_names - else 1) + expected_num_features = ( + len(self._feature_names) if self._feature_names else 1) if self._has_labels: - expected_num_labels = (len(self._label_names) if self._label_names - else 1) + expected_num_labels = ( + len(self._label_names) if self._label_names else 1) else: expected_num_labels = 0 @@ -895,8 +924,8 @@ class _InputPipeline(object): if expected_num_labels == 0: unflattened_label = None elif self._label_names: - unflattened_label = dict(zip(self._label_names, - flattened_inputs[expected_num_features:])) + unflattened_label = dict( + zip(self._label_names, flattened_inputs[expected_num_features:])) else: # Single tensor case. unflattened_label = flattened_inputs[expected_num_features] @@ -961,8 +990,9 @@ class _InputPipeline(object): self._ctx, self._input_fn, self._inputs_structure_recorder)) if _WRAP_INPUT_FN_INTO_WHILE_LOOP: - enqueue_ops.append(_wrap_computation_in_while_loop( - device=host_device, op_fn=enqueue_ops_fn)) + enqueue_ops.append( + _wrap_computation_in_while_loop( + device=host_device, op_fn=enqueue_ops_fn)) else: enqueue_ops.append(enqueue_ops_fn()) # Infeed_queue_getter must be called after enqueue_ops_fn is called. @@ -979,8 +1009,9 @@ class _InputPipeline(object): self._batch_axis, host_device)) if _WRAP_INPUT_FN_INTO_WHILE_LOOP: - enqueue_ops.append(_wrap_computation_in_while_loop( - device=host_device, op_fn=enqueue_ops_fn)) + enqueue_ops.append( + _wrap_computation_in_while_loop( + device=host_device, op_fn=enqueue_ops_fn)) else: enqueue_ops.append(enqueue_ops_fn()) infeed_queues.append(captured_infeed_queue.get()) @@ -1066,6 +1097,7 @@ class _ModelFnWrapper(object): with ops.control_dependencies([train_op]): return array_ops.identity(loss) + return train_step, captured_scaffold_fn def convert_to_single_tpu_eval_step(self, dequeue_fn): @@ -1114,6 +1146,7 @@ class _ModelFnWrapper(object): with ops.control_dependencies([outfeed_ops]): return math_ops.add(total_loss, loss) + return eval_step, eval_metrics, captured_scaffold_fn def _call_model_fn(self, features, labels): @@ -1138,10 +1171,9 @@ class _ModelFnWrapper(object): kwargs['params'] = params if 'params' not in model_fn_args: - raise ValueError( - 'model_fn ({}) does not include params argument, ' - 'required by TPUEstimator to pass batch size as ' - 'params[\'batch_size\']'.format(self._model_fn)) + raise ValueError('model_fn ({}) does not include params argument, ' + 'required by TPUEstimator to pass batch size as ' + 'params[\'batch_size\']'.format(self._model_fn)) batch_size_for_model_fn = self._ctx.batch_size_for_model_fn if batch_size_for_model_fn is not None: @@ -1348,8 +1380,9 @@ class ExamplesPerSecondHook(basic_session_run_hooks.StepCounterHook): def _log_and_record(self, elapsed_steps, elapsed_time, global_step): examples_per_sec = self._batch_size * elapsed_steps / elapsed_time if self._summary_writer is not None: - example_summary = Summary(value=[Summary.Value( - tag='examples_sec', simple_value=examples_per_sec)]) + example_summary = Summary(value=[ + Summary.Value(tag='examples_sec', simple_value=examples_per_sec) + ]) self._summary_writer.add_summary(example_summary, global_step) logging.info('examples/sec: %g', examples_per_sec) @@ -1488,9 +1521,8 @@ class TPUEstimator(estimator_lib.Estimator): '`config` must be provided with type `tpu_config.RunConfig`') if params is not None and any(k in params for k in _RESERVED_PARAMS_KEYS): - raise ValueError( - '{} are reserved keys but existed in params {}.'.format( - _RESERVED_PARAMS_KEYS, params)) + raise ValueError('{} are reserved keys but existed in params {}.'.format( + _RESERVED_PARAMS_KEYS, params)) if use_tpu: if train_batch_size is None: @@ -1571,8 +1603,9 @@ class TPUEstimator(estimator_lib.Estimator): if max_steps is not None: util_lib.check_positive_integer(max_steps, 'Train max_steps') - return [_TPUStopAtStepHook(self._iterations_per_training_loop, steps, - max_steps)] + return [ + _TPUStopAtStepHook(self._iterations_per_training_loop, steps, max_steps) + ] def _convert_eval_steps_to_hooks(self, steps): with self._ctx.with_mode(model_fn_lib.ModeKeys.EVAL) as ctx: @@ -1640,6 +1673,7 @@ class TPUEstimator(estimator_lib.Estimator): # `features` in `model_fn` signature. def _input_fn(): return input_fn(**kwargs) + return _input_fn def _augment_model_fn(self, model_fn, batch_axis): @@ -1695,9 +1729,10 @@ class TPUEstimator(estimator_lib.Estimator): total_loss, eval_metric_ops, scaffold = _eval_on_tpu_system( ctx, model_fn_wrapper, dequeue_fn) iterations_per_loop_var = _create_or_get_iterations_per_loop() - mean_loss = math_ops.div( - total_loss, - math_ops.cast(iterations_per_loop_var, dtype=total_loss.dtype)) + mean_loss = math_ops.div(total_loss, + math_ops.cast( + iterations_per_loop_var, + dtype=total_loss.dtype)) # Creates a dummy metric update_op for all metrics. Estimator expects # all metrics in eval_metric_ops have update_op and calls them one by @@ -1725,6 +1760,7 @@ class TPUEstimator(estimator_lib.Estimator): evaluation_hooks=hooks, eval_metric_ops=eval_metric_ops, scaffold=scaffold) + return _model_fn @@ -1737,15 +1773,16 @@ def _eval_on_tpu_system(ctx, model_fn_wrapper, dequeue_fn): model_fn_wrapper.convert_to_single_tpu_eval_step(dequeue_fn)) def multi_tpu_eval_steps_on_single_shard(): - return training_loop.repeat(iterations_per_loop_var, - single_tpu_eval_step, - [_ZERO_LOSS], - name='loop') + return training_loop.repeat( + iterations_per_loop_var, + single_tpu_eval_step, [_ZERO_LOSS], + name='loop') - (loss,) = tpu.shard(multi_tpu_eval_steps_on_single_shard, - inputs=[], - num_shards=num_cores, - outputs_from_all_shards=False) + (loss,) = tpu.shard( + multi_tpu_eval_steps_on_single_shard, + inputs=[], + num_shards=num_cores, + outputs_from_all_shards=False) scaffold = _get_scaffold(captured_scaffold_fn) return loss, eval_metric_ops, scaffold @@ -1762,14 +1799,14 @@ def _train_on_tpu_system(ctx, model_fn_wrapper, dequeue_fn): def multi_tpu_train_steps_on_single_shard(): return training_loop.repeat( iterations_per_loop_var, - single_tpu_train_step, - [_INITIAL_LOSS], + single_tpu_train_step, [_INITIAL_LOSS], name=b'loop') - (loss,) = tpu.shard(multi_tpu_train_steps_on_single_shard, - inputs=[], - num_shards=num_cores, - outputs_from_all_shards=False) + (loss,) = tpu.shard( + multi_tpu_train_steps_on_single_shard, + inputs=[], + num_shards=num_cores, + outputs_from_all_shards=False) scaffold = _get_scaffold(captured_scaffold_fn) return loss, scaffold @@ -1777,6 +1814,7 @@ def _train_on_tpu_system(ctx, model_fn_wrapper, dequeue_fn): def _wrap_computation_in_while_loop(device, op_fn): """Wraps the ops generated by `op_fn` in tf.while_loop.""" + def computation(i): with ops.control_dependencies(op_fn()): return i + 1 @@ -1788,7 +1826,8 @@ def _wrap_computation_in_while_loop(device, op_fn): iterations = array_ops.identity(iterations_per_loop_var) return control_flow_ops.while_loop( lambda i: i < iterations, - computation, [constant_op.constant(0)], parallel_iterations=1) + computation, [constant_op.constant(0)], + parallel_iterations=1) def _validate_tpu_training_graph(): @@ -1801,8 +1840,9 @@ def _validate_tpu_training_graph(): # Check if there is atleast one CrossReplicaSum operation in the graph # This should be introduced by using the CrossShardOptimizer wrapper - cross_replica_sum_ops = [o for o in operations - if o.type == _CROSS_REPLICA_SUM_OP] + cross_replica_sum_ops = [ + o for o in operations if o.type == _CROSS_REPLICA_SUM_OP + ] if not cross_replica_sum_ops: raise ValueError( 'CrossShardOptimizer must be used for model training on TPUs.') @@ -1849,9 +1889,11 @@ def _get_scaffold(captured_scaffold_fn): if scaffold: wrapped_finalize = scaffold.finalize + def _finalize(): with _CapturingContext('Inside Scaffold.finalize'): wrapped_finalize() + scaffold.finalize = _finalize return scaffold @@ -1866,9 +1908,8 @@ class _CapturingContext(control_flow_ops.ControlFlowContext): def AddOp(self, op): # pylint: disable=invalid-name for c in op.inputs: if tpu._TPU_REPLICATE_ATTR in c.op.node_def.attr: # pylint: disable=protected-access - raise ValueError( - '{}: Op {} depends on TPU computation {}, ' - 'which is not allowed.'.format(self._message, op, c)) + raise ValueError('{}: Op {} depends on TPU computation {}, ' + 'which is not allowed.'.format(self._message, op, c)) def __enter__(self): # pylint: disable=protected-access -- GitLab From 5e3ed99469d32e494869b8d044620b2ef8e96a40 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 17:11:42 -0800 Subject: [PATCH 227/258] Dedup control dependencies where the node already depends on the source as a non-control input. PiperOrigin-RevId: 183166819 --- .../grappler/optimizers/dependency_optimizer.cc | 6 +----- tensorflow/python/framework/function_test.py | 17 +++++++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/dependency_optimizer.cc b/tensorflow/core/grappler/optimizers/dependency_optimizer.cc index 1f68ecbade..d2da125236 100644 --- a/tensorflow/core/grappler/optimizers/dependency_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/dependency_optimizer.cc @@ -58,11 +58,7 @@ void PruneControlInputs(NodeDef* node) { int pos = 0; while (pos < node->input_size()) { const string& input = node->input(pos); - // TODO(rmlarsen): Remove control inputs that also appears as a regular - // inputs. Currently, doing so breaks testControlFlowStrictness in - // python/framework/function_test. - // if (!inputs.insert(NodeName(input)).second && IsControlInput(input)) { - if (IsControlInput(input) && !inputs.insert(input).second) { + if (!inputs.insert(NodeName(input)).second && IsControlInput(input)) { VLOG(1) << "**** Removing duplicate control input: " << input << " from node " << node->DebugString(); node->mutable_input()->SwapElements(pos, node->input_size() - 1); diff --git a/tensorflow/python/framework/function_test.py b/tensorflow/python/framework/function_test.py index 57e5a724c9..a4ca3f9a89 100644 --- a/tensorflow/python/framework/function_test.py +++ b/tensorflow/python/framework/function_test.py @@ -26,6 +26,7 @@ import numpy as np from tensorflow.core.framework import function_pb2 from tensorflow.core.protobuf import config_pb2 +from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes @@ -451,13 +452,17 @@ class FunctionTest(test.TestCase): lambda y: AssertFail(y), [x]) # pylint: enable=unnecessary-lambda + rewriter_config = rewriter_config_pb2.RewriterConfig( + dependency_optimization=rewriter_config_pb2.RewriterConfig.OFF) # Enables inlining. - config = config_pb2.ConfigProto(graph_options=config_pb2.GraphOptions( - optimizer_options=config_pb2.OptimizerOptions( - opt_level=config_pb2.OptimizerOptions.L0, - do_common_subexpression_elimination=True, - do_function_inlining=True, - do_constant_folding=True))) + config = config_pb2.ConfigProto( + graph_options=config_pb2.GraphOptions( + optimizer_options=config_pb2.OptimizerOptions( + opt_level=config_pb2.OptimizerOptions.L0, + do_common_subexpression_elimination=True, + do_function_inlining=True, + do_constant_folding=True), + rewrite_options=rewriter_config)) with session.Session(config=config) as sess: # Since the 'False' branch is not taken, the assertion should not fire. -- GitLab From 65aa9ee2500b0108d89f5fd1368ec3b73b273082 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 17:16:58 -0800 Subject: [PATCH 228/258] Fix comparison bug in remove_trivial_binary PiperOrigin-RevId: 183167508 --- .../toco/graph_transformations/remove_trivial_binary.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_binary.cc b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_binary.cc index 8512e6bb5a..95a50c6179 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_binary.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/remove_trivial_binary.cc @@ -89,14 +89,14 @@ bool RemoveTrivialBinaryOperator::Run(Model* model, std::size_t op_index) { const auto& constant_input_float_data = constant_input_array.GetBuffer().data; bool is_trivial = false; - if (binary_op->type != OperatorType::kAdd) { + if (binary_op->type == OperatorType::kAdd) { is_trivial = AreAllBufferElementsEqualTo(constant_input_float_data, 0.f); - } else if (binary_op->type != OperatorType::kSub) { + } else if (binary_op->type == OperatorType::kSub) { is_trivial = index_of_constant_input == 1 && AreAllBufferElementsEqualTo(constant_input_float_data, 0.f); - } else if (binary_op->type != OperatorType::kMul) { + } else if (binary_op->type == OperatorType::kMul) { is_trivial = AreAllBufferElementsEqualTo(constant_input_float_data, 1.f); - } else if (binary_op->type != OperatorType::kDiv) { + } else if (binary_op->type == OperatorType::kDiv) { is_trivial = index_of_constant_input == 1 && AreAllBufferElementsEqualTo(constant_input_float_data, 1.f); } -- GitLab From 10eab61afb2292b4b8ad82426b7650c77e483d7a Mon Sep 17 00:00:00 2001 From: Jerome Date: Thu, 25 Jan 2018 09:21:51 +0800 Subject: [PATCH 229/258] Created dense_to_sparse in contrib.layers (#16119) * Added ctc_loss_dense_labels. This does the conversion of dense labels into sparse ones to be passed into the core ctc_loss function. * Removed constant_op from the import. * Matched ctc_loss_dense_labels with the other layers ops. * Added ctc_loss_dense_labels to contrib.layers __init__.py file * Added missing comma to list of ops. * Reordred arguments for ctc_loss_dense_labels Labels should be first then inputs for ctc_loss. * Removed ctc_loss_dense_labels. Replaced it with dense_to_sparse instead so that there'll be only one ctc_loss function. * Replaced ctc_loss_dense_labels with dense_to_sparse * Fixed dense_to_sparse. Some of the names of the variables did not match with that of the parameters. * Updated documentation for dense_to_sparse since it can accept a tensor of any shape. * Added test case for dense_to_sparse. * Updated documentation. Dense to sparse accepts int tensors. * Fixed testDenseFromConstantToSparse. The sparse_to_dense order of arguments in the test are wrong and the expected constant should be of int64. --- tensorflow/contrib/layers/__init__.py | 1 + .../contrib/layers/python/layers/layers.py | 27 ++++++++++++++++++- .../layers/python/layers/layers_test.py | 12 +++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/tensorflow/contrib/layers/__init__.py b/tensorflow/contrib/layers/__init__.py index 6c624929f2..ef419862b4 100644 --- a/tensorflow/contrib/layers/__init__.py +++ b/tensorflow/contrib/layers/__init__.py @@ -27,6 +27,7 @@ See the @{$python/contrib.layers} guide. @@convolution2d_transpose @@conv3d_transpose @@convolution3d_transpose +@@dense_to_sparse @@dropout @@elu @@embedding_lookup_unique diff --git a/tensorflow/contrib/layers/python/layers/layers.py b/tensorflow/contrib/layers/python/layers/layers.py index 7c52da7b49..c8e3307ee8 100644 --- a/tensorflow/contrib/layers/python/layers/layers.py +++ b/tensorflow/contrib/layers/python/layers/layers.py @@ -29,6 +29,7 @@ from tensorflow.contrib.framework.python.ops import variables from tensorflow.contrib.layers.python.layers import initializers from tensorflow.contrib.layers.python.layers import utils from tensorflow.python.eager import context +from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import function from tensorflow.python.framework import ops @@ -58,7 +59,8 @@ __all__ = [ 'avg_pool2d', 'avg_pool3d', 'batch_norm', 'bias_add', 'conv2d', 'conv3d', 'conv2d_in_plane', 'conv2d_transpose', 'conv3d_transpose', 'convolution', 'convolution2d', 'convolution2d_in_plane', 'convolution2d_transpose', - 'convolution3d', 'convolution3d_transpose', 'dropout', 'elu', 'flatten', + 'convolution3d', 'convolution3d_transpose', 'dense_to_sparse', + 'dropout', 'elu', 'flatten', 'fully_connected', 'GDN', 'gdn', 'layer_norm', 'linear', 'pool', 'max_pool2d', 'max_pool3d', 'one_hot_encoding', 'relu', 'relu6', 'repeat', 'scale_gradient', 'separable_conv2d', 'separable_convolution2d', 'softmax', @@ -1400,6 +1402,29 @@ def convolution3d_transpose( return utils.collect_named_outputs(outputs_collections, sc.name, outputs) +@add_arg_scope +def dense_to_sparse(tensor, eos_token=0, outputs_collections=None, scope=None): + """Converts a dense tensor into a sparse tensor. + An example use would be to convert dense labels to sparse ones + so that they can be fed to the ctc_loss. + + Args: + tensor: An `int` `Tensor` to be converted to a `Sparse`. + eos_token: An integer. + It is part of the target label that signfies the end of a sentence. + outputs_collections: Collection to add the outputs. + scope: Optional scope for name_scope. + """ + with variable_scope.variable_scope( + scope, 'dense_to_sparse', [tensor]) as sc: + tensor = ops.convert_to_tensor(tensor) + indices = array_ops.where(math_ops.not_equal(tensor, constant_op.constant(eos_token, tensor.dtype))) + values = array_ops.gather_nd(tensor, indices) + shape = array_ops.shape(tensor, out_type=dtypes.int64) + outputs = sparse_tensor.SparseTensor(indices, values, shape) + return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + + @add_arg_scope def dropout(inputs, keep_prob=0.5, diff --git a/tensorflow/contrib/layers/python/layers/layers_test.py b/tensorflow/contrib/layers/python/layers/layers_test.py index a9bdbe0138..c5790c7622 100644 --- a/tensorflow/contrib/layers/python/layers/layers_test.py +++ b/tensorflow/contrib/layers/python/layers/layers_test.py @@ -44,6 +44,7 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn_ops from tensorflow.python.ops import partitioned_variables from tensorflow.python.ops import random_ops +from tensorflow.python.ops import sparse_ops from tensorflow.python.ops import state_ops from tensorflow.python.ops import template from tensorflow.python.ops import variable_scope @@ -1292,6 +1293,17 @@ class ConvolutionInPlaneTest(test.TestCase): self.assertAllClose(result, expected, rtol=1e-5, atol=1e-5) +class DenseToSparseTest(test.TestCase): + + def testDenseFromConstantToSparse(self): + expected_constant = np.reshape(np.arange(24, dtype=np.int64), (3, 4, 2)) + tensor = constant_op.constant(expected_constant) + sparse = _layers.dense_to_sparse(tensor) + dense = sparse_ops.sparse_to_dense(sparse.indices, sparse.dense_shape, sparse.values) + with self.test_session() as sess: + constant = sess.run(dense) + self.assertAllEqual(expected_constant, constant) + class DropoutTest(test.TestCase): def testCreateDropout(self): -- GitLab From e2b93e6c45fc9e0745ec4b70a7ba0d1b86f42c94 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Wed, 24 Jan 2018 17:22:27 -0800 Subject: [PATCH 230/258] Fix sample_distorted_bounding_box where min_object_covered could be None (#15531) * Fix sample_distorted_bounding_box where min_object_covered could be None This fix tried to address the issue raised in 15529 where not providing min_object_covered a value will result in a ValueError. In the docstring, however, min_object_covered has been described as default to 0.1. The reason for the issue is that when sample_distorted_bounding_box switched to V2, min_object_covered has been changed form an attr to an input. As input could not have a default value, min_object_covered=None will result in an error. This fix adds the check so that a default value 0.1 will be provided if min_object_covered=None. This fix fixes 15529. Signed-off-by: Yong Tang * Add test case for min_object_covered=None with sample_distorted_bounding_box. Signed-off-by: Yong Tang * Move min_object_covered = 0.1 to the args Signed-off-by: Yong Tang * Update golden API with ``` bazel-bin/tensorflow/tools/api/tests/api_compatibility_test --update_goldens True ``` Signed-off-by: Yong Tang --- tensorflow/python/ops/image_ops_impl.py | 2 +- tensorflow/python/ops/image_ops_test.py | 19 +++++++++++++++++++ .../tools/api/golden/tensorflow.image.pbtxt | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 76da3bed31..9bd452155c 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -1507,7 +1507,7 @@ def sample_distorted_bounding_box(image_size, bounding_boxes, seed=None, seed2=None, - min_object_covered=None, + min_object_covered=0.1, aspect_ratio_range=None, area_range=None, max_attempts=None, diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index 80911ffe07..0c5ed2150d 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -1857,6 +1857,25 @@ class SelectDistortedCropBoxTest(test_util.TensorFlowTestCase): self.assertAllEqual([3], end.get_shape().as_list()) self.assertAllEqual([1, 1, 4], bbox_for_drawing.get_shape().as_list()) + def testDefaultMinObjectCovered(self): + # By default min_object_covered=0.1 if not provided + with self.test_session(use_gpu=True): + image_size = constant_op.constant( + [40, 50, 1], shape=[3], dtype=dtypes.int32) + bounding_box = constant_op.constant( + [0.0, 0.0, 1.0, 1.0], + shape=[4], + dtype=dtypes.float32,) + begin, end, bbox_for_drawing = image_ops.sample_distorted_bounding_box( + image_size=image_size, + bounding_boxes=bounding_box, + aspect_ratio_range=(0.75, 1.33), + area_range=(0.05, 1.0)) + + self.assertAllEqual([3], begin.get_shape().as_list()) + self.assertAllEqual([3], end.get_shape().as_list()) + self.assertAllEqual([1, 1, 4], bbox_for_drawing.get_shape().as_list()) + class ResizeImagesTest(test_util.TensorFlowTestCase): diff --git a/tensorflow/tools/api/golden/tensorflow.image.pbtxt b/tensorflow/tools/api/golden/tensorflow.image.pbtxt index f32353c957..441621a2a0 100644 --- a/tensorflow/tools/api/golden/tensorflow.image.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.image.pbtxt @@ -174,7 +174,7 @@ tf_module { } member_method { name: "sample_distorted_bounding_box" - argspec: "args=[\'image_size\', \'bounding_boxes\', \'seed\', \'seed2\', \'min_object_covered\', \'aspect_ratio_range\', \'area_range\', \'max_attempts\', \'use_image_if_no_bounding_boxes\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'image_size\', \'bounding_boxes\', \'seed\', \'seed2\', \'min_object_covered\', \'aspect_ratio_range\', \'area_range\', \'max_attempts\', \'use_image_if_no_bounding_boxes\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'0.1\', \'None\', \'None\', \'None\', \'None\', \'None\'], " } member_method { name: "total_variation" -- GitLab From 6743031da633d1ce284a606c49eb00e793c1d729 Mon Sep 17 00:00:00 2001 From: Mohamed Aly Date: Wed, 24 Jan 2018 17:23:10 -0800 Subject: [PATCH 231/258] Changes to fix a bug in ResolveConstantConcat whereby shared tensors are removed without checking if they are used in other operators in the graph (#16012) --- .../toco/graph_transformations/graph_transformations.cc | 1 + .../resolve_constant_concatenation.cc | 5 ++++- tensorflow/contrib/lite/toco/tooling_util.cc | 7 +++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc index 2340f0e850..6961e23690 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc @@ -132,6 +132,7 @@ bool GraphTransformationsPass(int increment, Model* model, CHECK(increment == 1 || increment == -1); bool changed = false; if (model->operators.empty()) { + LOG(INFO) << "Model is empty!!!"; return false; } int op_index = increment == 1 ? 0 : model->operators.size() - 1; diff --git a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_concatenation.cc b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_concatenation.cc index 833c97c758..5ac449749a 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_concatenation.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/resolve_constant_concatenation.cc @@ -189,7 +189,10 @@ bool ResolveConstantConcatenation::Run(Model* model, std::size_t op_index) { // Remove all the resolved arrays. for (const string& input_name : concat_op->inputs) { - model->EraseArray(input_name); + // Check to prevent removal of shared tensors + if(CountOpsWithInput(*model, input_name) == 1) { + model->EraseArray(input_name); + } } // Remove concatenate operator diff --git a/tensorflow/contrib/lite/toco/tooling_util.cc b/tensorflow/contrib/lite/toco/tooling_util.cc index 8543ba4742..69187bb142 100644 --- a/tensorflow/contrib/lite/toco/tooling_util.cc +++ b/tensorflow/contrib/lite/toco/tooling_util.cc @@ -652,10 +652,13 @@ void CheckNonExistentIOArrays(const Model& model) { void CheckNoMissingArray(const Model& model) { for (const auto& op : model.operators) { for (const auto& input : op->inputs) { - CHECK(model.HasArray(input) || model.optional_arrays.count(input)); + CHECK(model.HasArray(input) || model.optional_arrays.count(input)) + << "Input: " << input << " missing for op: " + << op->outputs[0] << "."; } for (const auto& output : op->outputs) { - CHECK(model.HasArray(output)); + CHECK(model.HasArray(output)) << "Output: " << output + << " missing."; } } CheckNonExistentIOArrays(model); -- GitLab From 7c4f482a851d12a3b0187bbf31db65ff6b7a7ad3 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 17:18:47 -0800 Subject: [PATCH 232/258] Add copy method to EagerVariableStore. EagerVariableStore.copy creates a new EagerVariableStore instance containing new variables so that they can be modified without affecting the variables in the old store. PiperOrigin-RevId: 183167776 --- .../kernel_tests/variable_scope_test.py | 24 ++++++++++++++ tensorflow/python/ops/variable_scope.py | 31 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index 238d4b58d5..8527f116f9 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -131,6 +131,30 @@ class VariableScopeTest(test.TestCase): self.assertFalse(v in store.non_trainable_variables()) self.assertTrue(w in store.non_trainable_variables()) + # Test copying. + new_store = store.copy() + with new_store.as_default(): + new_v = variable_scope.get_variable("v") + new_w = variable_scope.get_variable("w") + self.assertEqual(new_v.numpy(), v.numpy()) + self.assertEqual(new_w.numpy(), w.numpy()) + self.assertTrue(new_v in new_store.variables()) + self.assertTrue(new_w in new_store.variables()) + self.assertTrue(new_v in new_store.trainable_variables()) + self.assertFalse(new_w in new_store.trainable_variables()) + self.assertFalse(new_v in new_store.non_trainable_variables()) + self.assertTrue(new_w in new_store.non_trainable_variables()) + + # Check that variables are separate instances. + for v in store.variables(): + v.assign(-1) + for v in new_store.variables(): + v.assign(1) + for v in store.variables(): + self.assertEqual(v.numpy(), -1) + for v in new_store.variables(): + self.assertEqual(v.numpy(), 1) + @test_util.run_in_graph_and_eager_modes() def testInitFromNonTensorValue(self): v = variable_scope.get_variable("v4", initializer=4, dtype=dtypes.int32) diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index c52d5fff5d..db594ac6a0 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -27,6 +27,7 @@ import sys import traceback import six +from six import iteritems from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.eager import context @@ -1242,6 +1243,36 @@ class EagerVariableStore(object): key=lambda x: x.name) # pylint: enable=protected-access + def copy(self): + """Copy this variable store and all of its contents. + + Variables contained in this store will be copied over to the new variable + store, meaning that they can be modified without affecting the variables in + this store. + + Returns: + A new EagerVariableStore instance containing copied variables. + """ + # pylint: disable=protected-access + new_store = EagerVariableStore() + for key, var in iteritems(self._store._vars): + # Strip device out of variable name. + try: + index = var.name.index(":") + except ValueError: + stripped_var_name = var.name + else: + stripped_var_name = var.name[:index] + + # Create new variable with same value, name, and "trainable" flag. + new_var = resource_variable_ops.ResourceVariable( + var.read_value(), + name=stripped_var_name, + trainable=var._trainable) + new_store._store._vars[key] = new_var + return new_store + # pylint: enable=protected-access + @tf_export("get_variable") def get_variable(name, -- GitLab From 0412e0946bdd2765d5c3dba0cc9b12b8650f564a Mon Sep 17 00:00:00 2001 From: Yunxing Dai Date: Wed, 24 Jan 2018 17:24:50 -0800 Subject: [PATCH 233/258] Add R3 and R5 tests to select and scatter. - Added evaluator support so that we can test S&S in arbitrary dimensions. RELNOTES: n/a PiperOrigin-RevId: 183168473 --- .../compiler/xla/service/hlo_evaluator.cc | 189 +++++++++++++++--- tensorflow/compiler/xla/tests/BUILD | 1 + .../xla/tests/select_and_scatter_test.cc | 189 +++++++++++------- 3 files changed, 276 insertions(+), 103 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_evaluator.cc b/tensorflow/compiler/xla/service/hlo_evaluator.cc index 2112cf57c7..e3f5c17e35 100644 --- a/tensorflow/compiler/xla/service/hlo_evaluator.cc +++ b/tensorflow/compiler/xla/service/hlo_evaluator.cc @@ -43,6 +43,7 @@ limitations under the License. #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/core/stringpiece.h" +#include "tensorflow/core/lib/gtl/optional.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/protobuf.h" #include "tensorflow/core/platform/types.h" @@ -166,6 +167,34 @@ StatusOr> ElementWiseUnaryOpImpl( return std::move(result); } +// For one particular placement of a window in a base shape (the placement is +// represented as `window_count_index`), iterates inside the window. Translates +// the window index into base index. If the base index is within bound, call `f` +// with the base index. +void IterateThroughWindow( + const Shape& window_shape, const Window& window, const Shape& base_shape, + const tensorflow::gtl::ArraySlice& window_count_index, + const std::function&)>& f) { + const int64 rank = ShapeUtil::Rank(base_shape); + DimensionVector window_index(rank); + std::fill(window_index.begin(), window_index.end(), 0); + do { + std::vector base_index(rank); + bool out_of_bound = false; + for (int64 i = 0; i < rank; ++i) { + base_index[i] = window_count_index[i] * window.dimensions(i).stride() + + window_index[i] - window.dimensions(i).padding_low(); + if (base_index[i] < 0 || base_index[i] >= base_shape.dimensions(i)) { + out_of_bound = true; + break; + } + } + if (!out_of_bound) { + f(base_index); + } + } while (IndexUtil::BumpIndices(window_shape, &window_index)); +} + } // namespace template @@ -1420,6 +1449,111 @@ class HloEvaluator::TypedVisitor : public DfsHloVisitorWithDefault { return Status::OK(); } + Status HandleSelectAndScatter(HloInstruction* select_and_scatter) override { + auto operand = select_and_scatter->operand(0); + auto source = select_and_scatter->operand(1); + const Window& window = select_and_scatter->window(); + + const Literal& init_literal = + parent_->GetEvaluatedLiteralFor(select_and_scatter->operand(2)); + TF_RET_CHECK(ShapeUtil::IsScalar(init_literal.shape())); + auto init_scalar = init_literal.Get({}); + + auto result = Literal::CreateFromShape(select_and_scatter->shape()); + + // Initialize result array with the init value. + TF_RETURN_IF_ERROR(result->Populate( + [&](tensorflow::gtl::ArraySlice output_index) { + return init_scalar; + })); + + std::vector window_dimension_sizes; + for (const auto& window_dimension : window.dimensions()) { + window_dimension_sizes.push_back(window_dimension.size()); + } + const Shape window_shape = ShapeUtil::MakeShape( + operand->shape().element_type(), window_dimension_sizes); + + HloComputation* select = select_and_scatter->select(); + HloComputation* scatter = select_and_scatter->scatter(); + + const Literal& operand_literal = parent_->GetEvaluatedLiteralFor(operand); + const Literal& source_literal = parent_->GetEvaluatedLiteralFor(source); + + int64 rank = ShapeUtil::Rank(operand_literal.shape()); + + HloEvaluator embedded_evaluator; + DimensionVector source_index(rank); + + std::fill(source_index.begin(), source_index.end(), 0); + do { + // For each element in `source`, we place a window in `operand`. For each + // window placement, we iterate inside the window twice: + // + // 1. Find the selected index by applying `select` function to all + // elements. E.g., If the `select` function is GreaterEqual, the first + // iteration through the window finds the biggest value and returns its + // index. + // + // 2. Using the selected index, scatter value from `source` to result. We + // do this by iterating through the window, and compare each index with + // the selected index. + tensorflow::gtl::optional selected_val; + tensorflow::gtl::optional> selected_index; + + IterateThroughWindow( + window_shape, window, operand_literal.shape(), source_index, + [&](const std::vector& operand_index) { + auto curr_val = operand_literal.Get(operand_index); + if (!selected_val) { + selected_val = curr_val; + selected_index = operand_index; + } + const auto curr_val_literal = Literal::CreateR0(curr_val); + const auto selected_val_literal = + Literal::CreateR0(*selected_val); + + const std::vector args = { + curr_val_literal.get(), selected_val_literal.get()}; + std::unique_ptr computed_result = + embedded_evaluator.Evaluate(*select, args) + .ConsumeValueOrDie(); + bool selected = computed_result->Get({}); + if (selected) { + selected_val = curr_val; + selected_index = operand_index; + } + embedded_evaluator.ResetVisitStates(); + }); + + IterateThroughWindow( + window_shape, window, operand_literal.shape(), source_index, + [&](const std::vector& operand_index) { + if (std::equal(operand_index.begin(), operand_index.end(), + selected_index->begin())) { + auto source = source_literal.Get(source_index); + auto scattered = result->Get(operand_index); + const auto source_literal = Literal::CreateR0(source); + const auto scattered_literal = + Literal::CreateR0(scattered); + + const std::vector args = { + source_literal.get(), scattered_literal.get()}; + std::unique_ptr computed_result = + embedded_evaluator.Evaluate(*scatter, args) + .ConsumeValueOrDie(); + result->Set(operand_index, computed_result->Get({})); + // Clear visit states so that the we can use the evaluator again + // on the same computation. + embedded_evaluator.ResetVisitStates(); + } + }); + } while (IndexUtil::BumpIndices(source->shape(), &source_index)); + + parent_->evaluated_[select_and_scatter] = std::move(result); + return Status::OK(); + } + Status HandleReduceWindow(HloInstruction* reduce_window) override { auto operand = reduce_window->operand(0); const Window& window = reduce_window->window(); @@ -1468,39 +1602,28 @@ class HloEvaluator::TypedVisitor : public DfsHloVisitorWithDefault { std::fill(window_index.begin(), window_index.end(), 0); std::fill(operand_index.begin(), operand_index.end(), 0); - do { - bool out_of_bound = false; - for (int i = 0; i < operand_index.size(); ++i) { - operand_index[i] = - output_index[i] * window.dimensions(i).stride() + - window_index[i] - window.dimensions(i).padding_low(); - if (operand_index[i] < 0 || - operand_index[i] >= operand_literal.shape().dimensions(i)) { - out_of_bound = true; - break; - } - } - if (!out_of_bound) { - auto curr_val = operand_literal.Get(operand_index); - - // Evaluate computation with specified literal operands. - const auto curr_val_literal = - Literal::CreateR0(curr_val); - const auto result_val_literal = - Literal::CreateR0(result_val); - const std::vector args = { - curr_val_literal.get(), result_val_literal.get()}; - std::unique_ptr computed_result = - embedded_evaluator.Evaluate(*function, args) - .ConsumeValueOrDie(); - - // Clear visit states so that the we can use the evaluate again on - // the same computation. - embedded_evaluator.ResetVisitStates(); - - result_val = computed_result->Get({}); - } - } while (IndexUtil::BumpIndices(window_shape, &window_index)); + IterateThroughWindow( + window_shape, window, operand_literal.shape(), output_index, + [&](const std::vector& operand_index) { + auto curr_val = operand_literal.Get(operand_index); + + // Evaluate computation with specified literal operands. + const auto curr_val_literal = + Literal::CreateR0(curr_val); + const auto result_val_literal = + Literal::CreateR0(result_val); + const std::vector args = { + curr_val_literal.get(), result_val_literal.get()}; + std::unique_ptr computed_result = + embedded_evaluator.Evaluate(*function, args) + .ConsumeValueOrDie(); + + // Clear visit states so that the we can use the evaluate again + // on the same computation. + embedded_evaluator.ResetVisitStates(); + + result_val = computed_result->Get({}); + }); return result_val; })); diff --git a/tensorflow/compiler/xla/tests/BUILD b/tensorflow/compiler/xla/tests/BUILD index bc15bd9593..3afd52b6b2 100644 --- a/tensorflow/compiler/xla/tests/BUILD +++ b/tensorflow/compiler/xla/tests/BUILD @@ -1034,6 +1034,7 @@ xla_test( name = "select_and_scatter_test", timeout = "long", srcs = ["select_and_scatter_test.cc"], + tags = ["enable_for_xla_interpreter"], deps = [ "//tensorflow/compiler/xla:array2d", "//tensorflow/compiler/xla:literal_util", diff --git a/tensorflow/compiler/xla/tests/select_and_scatter_test.cc b/tensorflow/compiler/xla/tests/select_and_scatter_test.cc index 62ff349e9c..9ee94b8571 100644 --- a/tensorflow/compiler/xla/tests/select_and_scatter_test.cc +++ b/tensorflow/compiler/xla/tests/select_and_scatter_test.cc @@ -39,8 +39,8 @@ namespace xla { namespace { struct SelectAndScatterTestParam { - Array4D operand_shape; - Array4D source_shape; + std::vector operand_shape; + std::vector source_shape; Padding padding_type; tensorflow::gtl::ArraySlice window_dimensions; tensorflow::gtl::ArraySlice window_strides; @@ -69,83 +69,132 @@ class SelectAndScatterTest Computation min_f32_; }; -XLA_TEST_P(SelectAndScatterTest, R4Randomized) { - Array4D o(GetParam().operand_shape); +XLA_TEST_P(SelectAndScatterTest, ParamTest) { + auto operand_shape = GetParam().operand_shape; + Array o(operand_shape); o.FillRandom(1.5f); - auto operand = builder_.ConstantR4FromArray4D(o); + auto operand = builder_.ConstantFromArray(o); - Array4D s(GetParam().source_shape); + auto source_shape = GetParam().source_shape; + Array s(source_shape); s.FillRandom(12.0f); - auto source = builder_.ConstantR4FromArray4D(s); - - builder_.SelectAndScatter(operand, ge_f32_, GetParam().window_dimensions, - GetParam().window_strides, GetParam().padding_type, - source, builder_.ConstantR0(0.0f), add_f32_); + auto source = builder_.ConstantFromArray(s); - auto e = ReferenceUtil::SelectAndScatter4DGePlus( - o, s, 0.0f, GetParam().window_dimensions, GetParam().window_strides, - GetParam().padding_type == Padding::kSame); + auto select_and_scatter = builder_.SelectAndScatter( + operand, ge_f32_, GetParam().window_dimensions, GetParam().window_strides, + GetParam().padding_type, source, builder_.ConstantR0(0.0f), + add_f32_); - ComputeAndCompareR4(&builder_, *e, {}, ErrorSpec(1e-5)); + ComputeAndCompare(&builder_, select_and_scatter, {}, ErrorSpec(1e-5)); } INSTANTIATE_TEST_CASE_P( SelectAndScatterTest_Instantiation, SelectAndScatterTest, - ::testing::Values(SelectAndScatterTestParam{{6, 6, 256, 128}, - {3, 3, 256, 128}, - Padding::kSame, - {3, 3, 1, 1}, - {2, 2, 1, 1}}, - SelectAndScatterTestParam{{7, 7, 256, 128}, - {3, 3, 256, 128}, - Padding::kValid, - {3, 3, 1, 1}, - {2, 2, 1, 1}}, - SelectAndScatterTestParam{{6, 7, 256, 128}, - {3, 3, 256, 128}, - Padding::kValid, - {2, 3, 1, 1}, - {2, 2, 1, 1}}, - SelectAndScatterTestParam{{6, 7, 256, 128}, - {2, 3, 256, 128}, - Padding::kValid, - {2, 3, 1, 1}, - {3, 2, 1, 1}}, - SelectAndScatterTestParam{{9, 9, 16, 128}, - {3, 3, 16, 128}, - Padding::kValid, - {3, 3, 1, 1}, - {3, 3, 1, 1}}, - SelectAndScatterTestParam{{3, 3, 4, 4}, - {1, 1, 4, 4}, - Padding::kValid, - {3, 3, 1, 1}, - {3, 3, 1, 1}}, - SelectAndScatterTestParam{{3, 3, 4, 4}, - {1, 1, 4, 4}, - Padding::kValid, - {3, 3, 1, 1}, - {3, 3, 1, 1}}, - SelectAndScatterTestParam{{9, 3, 4, 4}, - {3, 1, 4, 4}, - Padding::kValid, - {3, 3, 1, 1}, - {3, 3, 1, 1}}, - SelectAndScatterTestParam{{7, 3, 4, 4}, - {3, 1, 4, 4}, - Padding::kValid, - {3, 3, 1, 1}, - {2, 3, 1, 1}}, - SelectAndScatterTestParam{{1, 1, 5, 5}, - {1, 1, 5, 5}, - Padding::kSame, - {3, 3, 1, 1}, - {3, 3, 1, 1}}, - SelectAndScatterTestParam{{7, 7, 8, 256}, - {4, 4, 8, 256}, - Padding::kSame, - {2, 2, 1, 1}, - {2, 2, 1, 1}})); + ::testing::Values( + SelectAndScatterTestParam{{6, 6, 6, 4, 4}, + {3, 3, 3, 4, 4}, + Padding::kSame, + {3, 3, 3, 1, 1}, + {2, 2, 2, 1, 1}}, + SelectAndScatterTestParam{{7, 7, 7, 4, 4}, + {3, 3, 3, 4, 4}, + Padding::kValid, + {3, 3, 3, 1, 1}, + {2, 2, 2, 1, 1}}, + + SelectAndScatterTestParam{{8, 8, 8, 4, 4}, + {1, 3, 3, 4, 4}, + Padding::kValid, + {8, 4, 4, 1, 1}, + {1, 2, 2, 1, 1}}, + SelectAndScatterTestParam{{6, 6, 256, 128}, + {3, 3, 256, 128}, + Padding::kSame, + {3, 3, 1, 1}, + {2, 2, 1, 1}}, + SelectAndScatterTestParam{{7, 7, 256, 128}, + {3, 3, 256, 128}, + Padding::kValid, + {3, 3, 1, 1}, + {2, 2, 1, 1}}, + SelectAndScatterTestParam{{6, 7, 256, 128}, + {3, 3, 256, 128}, + Padding::kValid, + {2, 3, 1, 1}, + {2, 2, 1, 1}}, + SelectAndScatterTestParam{{6, 7, 256, 128}, + {2, 3, 256, 128}, + Padding::kValid, + {2, 3, 1, 1}, + {3, 2, 1, 1}}, + SelectAndScatterTestParam{{9, 9, 16, 128}, + {3, 3, 16, 128}, + Padding::kValid, + {3, 3, 1, 1}, + {3, 3, 1, 1}}, + SelectAndScatterTestParam{{3, 3, 4, 4}, + {1, 1, 4, 4}, + Padding::kValid, + {3, 3, 1, 1}, + {3, 3, 1, 1}}, + SelectAndScatterTestParam{{3, 3, 4, 4}, + {1, 1, 4, 4}, + Padding::kValid, + {3, 3, 1, 1}, + {3, 3, 1, 1}}, + SelectAndScatterTestParam{{9, 3, 4, 4}, + {3, 1, 4, 4}, + Padding::kValid, + {3, 3, 1, 1}, + {3, 3, 1, 1}}, + SelectAndScatterTestParam{{7, 3, 4, 4}, + {3, 1, 4, 4}, + Padding::kValid, + {3, 3, 1, 1}, + {2, 3, 1, 1}}, + SelectAndScatterTestParam{{1, 1, 5, 5}, + {1, 1, 5, 5}, + Padding::kSame, + {3, 3, 1, 1}, + {3, 3, 1, 1}}, + SelectAndScatterTestParam{{7, 7, 8, 256}, + {4, 4, 8, 256}, + Padding::kSame, + {2, 2, 1, 1}, + {2, 2, 1, 1}}, + SelectAndScatterTestParam{ + {6, 4, 4}, {3, 4, 4}, Padding::kSame, {3, 1, 1}, {2, 1, 1}}, + SelectAndScatterTestParam{ + {6, 256, 128}, {3, 256, 128}, Padding::kSame, {3, 1, 1}, {2, 1, 1}}, + SelectAndScatterTestParam{{7, 256, 128}, + {3, 256, 128}, + Padding::kValid, + {3, 1, 1}, + {2, 1, 1}}, + SelectAndScatterTestParam{{6, 256, 128}, + {3, 256, 128}, + Padding::kValid, + {2, 1, 1}, + {2, 1, 1}}, + SelectAndScatterTestParam{{6, 256, 128}, + {2, 256, 128}, + Padding::kValid, + {2, 1, 1}, + {3, 1, 1}}, + SelectAndScatterTestParam{ + {9, 16, 128}, {3, 16, 128}, Padding::kValid, {3, 1, 1}, {3, 1, 1}}, + SelectAndScatterTestParam{ + {3, 4, 4}, {1, 4, 4}, Padding::kValid, {3, 1, 1}, {3, 1, 1}}, + SelectAndScatterTestParam{ + {3, 4, 4}, {1, 4, 4}, Padding::kValid, {3, 1, 1}, {3, 1, 1}}, + SelectAndScatterTestParam{ + {9, 4, 4}, {3, 4, 4}, Padding::kValid, {3, 1, 1}, {3, 1, 1}}, + SelectAndScatterTestParam{ + {7, 4, 4}, {3, 4, 4}, Padding::kValid, {3, 1, 1}, {2, 1, 1}}, + SelectAndScatterTestParam{ + {1, 5, 5}, {1, 5, 5}, Padding::kSame, {3, 1, 1}, {3, 1, 1}}, + SelectAndScatterTestParam{ + {7, 8, 256}, {4, 8, 256}, Padding::kSame, {2, 1, 1}, {2, 1, 1}})); // Test for F32 1D array, with a zero-element input. XLA_TEST_F(SelectAndScatterTest, R1S0F32) { -- GitLab From 8a5b0f457c89e3ae77f67628654c1b64c4e65000 Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Wed, 24 Jan 2018 17:49:28 -0800 Subject: [PATCH 234/258] Make resource_variable_ops_test.py work with the C API enabled. PiperOrigin-RevId: 183171341 --- tensorflow/python/kernel_tests/resource_variable_ops_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/kernel_tests/resource_variable_ops_test.py b/tensorflow/python/kernel_tests/resource_variable_ops_test.py index 7b131a5b8c..b4b555591d 100644 --- a/tensorflow/python/kernel_tests/resource_variable_ops_test.py +++ b/tensorflow/python/kernel_tests/resource_variable_ops_test.py @@ -38,6 +38,7 @@ from tensorflow.python.ops import variables from tensorflow.python.platform import test +@test_util.with_c_api class ResourceVariableOpsTest(test_util.TensorFlowTestCase): def tearDown(self): @@ -342,14 +343,14 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): v = resource_variable_ops.ResourceVariable( 2.0, caching_device="/job:localhost") self.assertEqual("/job:localhost", v.value().device) - with self.assertRaisesRegexp(ValueError, "No attr named '_class'"): + with self.assertRaises(ValueError): _ = v.value().op.get_attr("_class") with ops.colocate_with(v.op): w = resource_variable_ops.ResourceVariable( 2.0, caching_device="/job:localhost") self.assertEqual("/job:localhost", w.value().device) - with self.assertRaisesRegexp(ValueError, "No attr named '_class'"): + with self.assertRaises(ValueError): _ = w.value().op.get_attr("_class") def testSharedName(self): -- GitLab From f76387a10f5188b059bc13223c5e9040a3bb7143 Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Wed, 24 Jan 2018 17:52:19 -0800 Subject: [PATCH 235/258] Make batch_sequences_with_states_test.py work with C API enabled. PiperOrigin-RevId: 183171572 --- .../batch_sequences_with_states_test.py | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tensorflow/contrib/training/python/training/batch_sequences_with_states_test.py b/tensorflow/contrib/training/python/training/batch_sequences_with_states_test.py index 2a0ef0e6b3..04538405e4 100644 --- a/tensorflow/contrib/training/python/training/batch_sequences_with_states_test.py +++ b/tensorflow/contrib/training/python/training/batch_sequences_with_states_test.py @@ -320,6 +320,18 @@ class BatchSequencesWithStatesTest(test.TestCase): def testNotAMultiple(self): num_unroll = 3 # Not a divisor of value_length - # so padding would have been necessary. + + # Use placeholder_with_default in sequences to make sure we get runtime + # error instead of shape inference error + sequences = { + "seq1": array_ops.placeholder_with_default(self.sequences["seq1"], + shape=(None, 5)), + "seq2": array_ops.placeholder_with_default(self.sequences["seq2"], + shape=(None, 4, 2)), + "seq3": self.sequences["seq3"], + "seq4": self.sequences["seq4"], + } + with self.test_session() as sess: with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, ".*should be a multiple of: 3, but saw " @@ -330,7 +342,7 @@ class BatchSequencesWithStatesTest(test.TestCase): with coord.stop_on_exception(): next_batch = sqss.batch_sequences_with_states( input_key=self.key, - input_sequences=self.sequences, + input_sequences=sequences, input_context=self.context, input_length=3, initial_states=self.initial_states, @@ -493,6 +505,18 @@ class BatchSequencesWithStatesTest(test.TestCase): expected_seq4_batch2=expected_seq4_batch2) +class BatchSequencesWithStatesTestWithCApi(BatchSequencesWithStatesTest): + + def setUp(self): + self._prev_value = ops._USE_C_API + ops._USE_C_API = True + super(BatchSequencesWithStatesTestWithCApi, self).setUp() + + def tearDown(self): + super(BatchSequencesWithStatesTestWithCApi, self).tearDown() + ops._USE_C_API = self._prev_value + + class PaddingTest(test.TestCase): def testPaddingInvalidLengths(self): -- GitLab From 4aacd356fe7354b044d7c5787fb2366219294658 Mon Sep 17 00:00:00 2001 From: Ian Langmore Date: Wed, 24 Jan 2018 17:56:55 -0800 Subject: [PATCH 236/258] VISIBILITY_FIX: Add 'auto_correlation' to _allowed_symbols. PiperOrigin-RevId: 183171955 --- tensorflow/contrib/distributions/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/contrib/distributions/__init__.py b/tensorflow/contrib/distributions/__init__.py index 59cc5eae06..60a187e541 100644 --- a/tensorflow/contrib/distributions/__init__.py +++ b/tensorflow/contrib/distributions/__init__.py @@ -85,6 +85,7 @@ from tensorflow.python.ops.distributions.uniform import * from tensorflow.python.util.all_util import remove_undocumented _allowed_symbols = [ + 'auto_correlation', 'bijectors', 'Cauchy', 'ConditionalDistribution', -- GitLab From cbd1ee59d28f94c369738cbba8b6a4faed1e5fad Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Wed, 24 Jan 2018 17:56:57 -0800 Subject: [PATCH 237/258] Don't close session in debug_gradients_test.py. PiperOrigin-RevId: 183171960 --- tensorflow/python/debug/lib/debug_gradients_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/debug/lib/debug_gradients_test.py b/tensorflow/python/debug/lib/debug_gradients_test.py index 6fd89e018a..b6c7280a41 100644 --- a/tensorflow/python/debug/lib/debug_gradients_test.py +++ b/tensorflow/python/debug/lib/debug_gradients_test.py @@ -39,7 +39,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): def setUp(self): self.sess = session.Session() - with self.sess: + with self.sess.as_default(): self.u = variables.Variable(2.0, name="u") self.v = variables.Variable(3.0, name="v") self.w = math_ops.multiply(self.u.value(), self.v.value(), name="w") -- GitLab From 4153e7afff4e17bbef866bd4811b0392ddb25b53 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 18:23:18 -0800 Subject: [PATCH 238/258] Refactoring pass. Add a container context class to shorten argument lists and expose context information in a more organized manner. Clean up names, docs and tests. Rename submodule to avoid clashing with the new @covert decorator. PiperOrigin-RevId: 183174971 --- tensorflow/BUILD | 2 +- tensorflow/contrib/py2tf/BUILD | 4 +- tensorflow/contrib/py2tf/api.py | 66 ++++---- tensorflow/contrib/py2tf/config.py | 1 + tensorflow/contrib/py2tf/conversion.py | 145 +++++++++--------- tensorflow/contrib/py2tf/conversion_test.py | 15 +- .../py2tf/{convert => converters}/BUILD | 43 +++--- .../py2tf/{convert => converters}/__init__.py | 0 .../break_canonicalization.py | 0 .../break_canonicalization_test.py | 20 +-- .../builtin_functions.py | 0 .../builtin_functions_test.py | 18 +-- .../{convert => converters}/call_trees.py | 0 .../call_trees_test.py | 20 +-- .../continue_canonicalization.py | 0 .../continue_canonicalization_test.py | 20 +-- .../{convert => converters}/control_flow.py | 0 .../control_flow_test.py | 24 +-- .../py2tf/converters/converter_test_base.py | 48 ++++++ .../{convert => converters}/decorators.py | 0 .../for_canonicalization.py | 0 .../for_canonicalization_test.py | 16 +- .../logical_expressions.py | 0 .../logical_expressions_test.py | 10 +- .../print_functions.py | 0 .../print_functions_test.py | 18 +-- .../side_effect_guards.py | 0 .../side_effect_guards_test.py | 18 +-- tensorflow/contrib/py2tf/pyct/BUILD | 1 + tensorflow/contrib/py2tf/pyct/context.py | 42 +++++ .../py2tf/pyct/static_analysis/type_info.py | 16 +- .../pyct/static_analysis/type_info_test.py | 61 +++----- tensorflow/contrib/py2tf/pyct/transformer.py | 18 ++- tensorflow/tools/pip_package/BUILD | 3 +- 34 files changed, 328 insertions(+), 301 deletions(-) rename tensorflow/contrib/py2tf/{convert => converters}/BUILD (79%) rename tensorflow/contrib/py2tf/{convert => converters}/__init__.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/break_canonicalization.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/break_canonicalization_test.py (84%) rename tensorflow/contrib/py2tf/{convert => converters}/builtin_functions.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/builtin_functions_test.py (68%) rename tensorflow/contrib/py2tf/{convert => converters}/call_trees.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/call_trees_test.py (78%) rename tensorflow/contrib/py2tf/{convert => converters}/continue_canonicalization.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/continue_canonicalization_test.py (83%) rename tensorflow/contrib/py2tf/{convert => converters}/control_flow.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/control_flow_test.py (79%) create mode 100644 tensorflow/contrib/py2tf/converters/converter_test_base.py rename tensorflow/contrib/py2tf/{convert => converters}/decorators.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/for_canonicalization.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/for_canonicalization_test.py (75%) rename tensorflow/contrib/py2tf/{convert => converters}/logical_expressions.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/logical_expressions_test.py (85%) rename tensorflow/contrib/py2tf/{convert => converters}/print_functions.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/print_functions_test.py (65%) rename tensorflow/contrib/py2tf/{convert => converters}/side_effect_guards.py (100%) rename tensorflow/contrib/py2tf/{convert => converters}/side_effect_guards_test.py (72%) create mode 100644 tensorflow/contrib/py2tf/pyct/context.py diff --git a/tensorflow/BUILD b/tensorflow/BUILD index 2ea0e38c78..9099463c4f 100644 --- a/tensorflow/BUILD +++ b/tensorflow/BUILD @@ -527,7 +527,7 @@ filegroup( "//tensorflow/contrib/periodic_resample:all_files", "//tensorflow/contrib/predictor:all_files", "//tensorflow/contrib/py2tf:all_files", - "//tensorflow/contrib/py2tf/convert:all_files", + "//tensorflow/contrib/py2tf/converters:all_files", "//tensorflow/contrib/py2tf/pyct:all_files", "//tensorflow/contrib/py2tf/pyct/static_analysis:all_files", "//tensorflow/contrib/quantize:all_files", diff --git a/tensorflow/contrib/py2tf/BUILD b/tensorflow/contrib/py2tf/BUILD index 7358822ef5..d395de986d 100644 --- a/tensorflow/contrib/py2tf/BUILD +++ b/tensorflow/contrib/py2tf/BUILD @@ -26,7 +26,7 @@ py_library( srcs_version = "PY2AND3", visibility = ["//visibility:public"], deps = [ - "//tensorflow/contrib/py2tf/convert", + "//tensorflow/contrib/py2tf/converters", "//tensorflow/contrib/py2tf/pyct", "//tensorflow/contrib/py2tf/pyct/static_analysis", "@gast_archive//:gast", @@ -46,7 +46,7 @@ py_library( srcs_version = "PY2AND3", visibility = ["//tensorflow:__subpackages__"], deps = [ - "//tensorflow/contrib/py2tf/convert", + "//tensorflow/contrib/py2tf/converters", "//tensorflow/contrib/py2tf/pyct", "//tensorflow/contrib/py2tf/pyct/static_analysis", "@gast_archive//:gast", diff --git a/tensorflow/contrib/py2tf/api.py b/tensorflow/contrib/py2tf/api.py index 9a2b70c53c..1f250d5f57 100644 --- a/tensorflow/contrib/py2tf/api.py +++ b/tensorflow/contrib/py2tf/api.py @@ -83,7 +83,7 @@ def convert_inline(f, *args, **kwargs): return convert(arg_value_hints)(f)(*args, **kwargs) -def convert(recursive=False, arg_value_hints=None): +def convert(recursive=False, arg_types=None): """Decorator that compiles a function to graph mode. The decorator is dynamic - invoking compilation whenever the decorated fuction @@ -92,8 +92,7 @@ def convert(recursive=False, arg_value_hints=None): Args: recursive: Whether to recusrively convert any functions that the decorator function may call. - arg_value_hints: A dict mapping parameter names to objects that can hint - at the type of those parameters. + arg_types: See to_graph. Returns: A decorator that compiles the given function to graph mode. @@ -101,8 +100,8 @@ def convert(recursive=False, arg_value_hints=None): Raises: ValueError: If any of the arguments are illegal. """ - if arg_value_hints is None: - arg_value_hints = {} + if arg_types is None: + arg_types = {} def decorator(f): """Decorator implementation.""" @@ -111,22 +110,23 @@ def convert(recursive=False, arg_value_hints=None): def wrapper(*args, **kwargs): """Wrapper that calls the compiled version of the wrapped function.""" partial_types = () + arg_values = {} arg_names = tf_inspect.getargspec(f)[0] for name, arg in zip(arg_names, args): + arg_values[name] = arg arg_class = arg.__class__ - if tf_inspect.isclass(arg_class): - # If arg_value_hints specifies any name, use that instead. - # TODO(mdan): Shouldn't this just be in the func's globals? - if name not in arg_value_hints: - arg_value_hints[name] = (arg_class.__name__, arg_class) + # If arg_value_hints specifies any name, use that instead. + if name not in arg_types: + arg_types[name] = (arg_class.__name__, arg_class) + if name == 'self' and tf_inspect.isclass(arg_class): # Annotated methods need to specify that their owner type is partial, # otherwise other members they call will not be converted. - if name == 'self': - partial_types = (arg_class,) + partial_types = (arg_class,) wrapped = to_graph( f, recursive=recursive, - arg_value_hints=arg_value_hints, + arg_values=arg_values, + arg_types=arg_types, partial_types=partial_types) return wrapped(*args, **kwargs) @@ -138,7 +138,11 @@ def convert(recursive=False, arg_value_hints=None): return decorator -def to_graph(o, recursive=True, arg_value_hints=None, partial_types=None): +def to_graph(e, + recursive=True, + arg_values=None, + arg_types=None, + partial_types=None): """Compile a Python entity into equivalent TensorFlow code. Currently supported entities: @@ -148,11 +152,13 @@ def to_graph(o, recursive=True, arg_value_hints=None, partial_types=None): Classes are handled by converting all their methods into a new class. Args: - o: A Python function or class. + e: A Python entity. recursive: Whether to recusrively convert any functions that the decorator function may call. - arg_value_hints: A dict mapping parameter names to objects that can hint - at the type of those parameters. + arg_values: A dict containing value hints for symbols like function + parameters. + arg_types: A dict containing type hints for symbols like function + parameters. partial_types: A set of types (e.g. classes) that will not be converted entirely. Calls to member functions for these types will be renamed independently. @@ -165,7 +171,7 @@ def to_graph(o, recursive=True, arg_value_hints=None, partial_types=None): recursive=recursive, nocompile_decorators=(convert, graph_ready, convert_inline), partial_types=partial_types) - _, name = conversion.object_to_graph(o, conversion_map, arg_value_hints) + _, name = conversion.entity_to_graph(e, conversion_map, arg_values, arg_types) module = gast.Module([]) for import_line in config.COMPILED_IMPORT_STATEMENTS: @@ -176,16 +182,17 @@ def to_graph(o, recursive=True, arg_value_hints=None, partial_types=None): # The compiled code should see everything the entry function saw. # TODO(mdan): This might not work well if the call tree spans modules? - if tf_inspect.isfunction(o): - compiled_node.__dict__.update(six.get_function_globals(o)) + if tf_inspect.isfunction(e): + compiled_node.__dict__.update(six.get_function_globals(e)) compiled_fn = getattr(compiled_node, name) return compiled_fn -def to_code(o, +def to_code(e, recursive=True, - arg_value_hints=None, + arg_values=None, + arg_types=None, partial_types=None, indentation=' '): """Return the equivalent of an entity in TensorFlow code. @@ -193,14 +200,11 @@ def to_code(o, See `to_graph` for more details. Args: - o: A Python function or class. - recursive: Whether to recusrively convert any functions that the decorator - function may call. - arg_value_hints: A dict mapping parameter names to objects that can hint - at the type of those parameters. - partial_types: A set of types (e.g. classes) that will not be converted - entirely. Calls to member functions for these types will be renamed - independently. + e: A Python entity. + recursive: See to_graph. + arg_values: See to_graph. + arg_types: See to_graph. + partial_types: See to_graph. indentation: String, when to use for each level of indentation. Returns: @@ -210,7 +214,7 @@ def to_code(o, recursive=recursive, nocompile_decorators=(convert, graph_ready, convert_inline), partial_types=partial_types) - conversion.object_to_graph(o, conversion_map, arg_value_hints) + conversion.entity_to_graph(e, conversion_map, arg_values, arg_types) imports = '\n'.join(config.COMPILED_IMPORT_STATEMENTS) code = '\n'.join( diff --git a/tensorflow/contrib/py2tf/config.py b/tensorflow/contrib/py2tf/config.py index 0a9d52136e..8c502a7a9e 100644 --- a/tensorflow/contrib/py2tf/config.py +++ b/tensorflow/contrib/py2tf/config.py @@ -22,6 +22,7 @@ PYTHON_LITERALS = { 'None': None, 'False': False, 'True': True, + 'float': float, } DEFAULT_UNCOMPILED_MODULES = set(( diff --git a/tensorflow/contrib/py2tf/conversion.py b/tensorflow/contrib/py2tf/conversion.py index 38f1c0a14a..b484eebbd5 100644 --- a/tensorflow/contrib/py2tf/conversion.py +++ b/tensorflow/contrib/py2tf/conversion.py @@ -23,16 +23,17 @@ import six from tensorflow.contrib.py2tf import config from tensorflow.contrib.py2tf import naming -from tensorflow.contrib.py2tf.convert import break_canonicalization -from tensorflow.contrib.py2tf.convert import builtin_functions -from tensorflow.contrib.py2tf.convert import call_trees -from tensorflow.contrib.py2tf.convert import continue_canonicalization -from tensorflow.contrib.py2tf.convert import control_flow -from tensorflow.contrib.py2tf.convert import decorators -from tensorflow.contrib.py2tf.convert import for_canonicalization -from tensorflow.contrib.py2tf.convert import logical_expressions -from tensorflow.contrib.py2tf.convert import print_functions -from tensorflow.contrib.py2tf.convert import side_effect_guards +from tensorflow.contrib.py2tf.converters import break_canonicalization +from tensorflow.contrib.py2tf.converters import builtin_functions +from tensorflow.contrib.py2tf.converters import call_trees +from tensorflow.contrib.py2tf.converters import continue_canonicalization +from tensorflow.contrib.py2tf.converters import control_flow +from tensorflow.contrib.py2tf.converters import decorators +from tensorflow.contrib.py2tf.converters import for_canonicalization +from tensorflow.contrib.py2tf.converters import logical_expressions +from tensorflow.contrib.py2tf.converters import print_functions +from tensorflow.contrib.py2tf.converters import side_effect_guards +from tensorflow.contrib.py2tf.pyct import context from tensorflow.contrib.py2tf.pyct import parser from tensorflow.contrib.py2tf.pyct.static_analysis import access from tensorflow.contrib.py2tf.pyct.static_analysis import live_values @@ -51,9 +52,9 @@ class ConversionMap(object): function may call. nocompile_decorators: tuple of decorator functions that toggle compilation off. - dependency_cache: dict[object]: ast; maps original objects to their + dependency_cache: dict[object]: ast; maps original entities to their converted AST - name_map: dict[string]: string; maps original objects to the name of + name_map: dict[string]: string; maps original entities to the name of their converted counterparts """ @@ -66,8 +67,8 @@ class ConversionMap(object): self.dependency_cache = {} self.name_map = {} - def new_namer(self, global_symbols): - return naming.Namer(global_symbols, self.recursive, self.name_map, + def new_namer(self, namespace): + return naming.Namer(namespace, self.recursive, self.name_map, self.partial_types) def update_name_map(self, namer): @@ -76,48 +77,47 @@ class ConversionMap(object): if self.name_map[o] != name: raise ValueError( 'Calls to %s were converted using multiple names (%s). This is ' - 'possible when an object with one of these names already ' + 'possible when an entity with one of these names already ' 'existed. To fix, avoid using any of these names.') else: self.name_map[o] = name - def add_to_cache(self, original_object, converted_ast): - self.dependency_cache[original_object] = converted_ast + def add_to_cache(self, original_entity, converted_ast): + self.dependency_cache[original_entity] = converted_ast -def object_to_graph(o, conversion_map, value_hints): - """Compile a Python object into equivalent TensorFlow. +def entity_to_graph(o, conversion_map, arg_values, arg_types): + """Compile a Python entity into equivalent TensorFlow. - The function will also recursively compile all the objects that `o` + The function will also recursively compile all the entities that `o` references, updating `dependency_cache`. This function is reentrant, and relies on dependency_cache to avoid generating duplicate code. Args: - o: A Python object. + o: A Python entity. conversion_map: A ConversionMap object. - value_hints: A dict containing value hints for symbols like function + arg_values: A dict containing value hints for symbols like function + parameters. + arg_types: A dict containing type hints for symbols like function parameters. Returns: A tuple (ast, new_name): - * ast: An AST representing an object with interface equivalent to `o`, + * ast: An AST representing an entity with interface equivalent to `o`, but which when executed it creates TF a graph. - * new_name: The symbol name under which the new object can be found. + * new_name: The symbol name under which the new entity can be found. Raises: - ValueError: if the object is not supported. + ValueError: if the entity type is not supported. """ - if value_hints is None: - value_hints = {} - if tf_inspect.isclass(o): - node, new_name = class_to_graph(o, conversion_map, value_hints) + node, new_name = class_to_graph(o, conversion_map) elif tf_inspect.isfunction(o): - node, new_name = function_to_graph(o, conversion_map, value_hints) + node, new_name = function_to_graph(o, conversion_map, arg_values, arg_types) elif tf_inspect.ismethod(o): - node, new_name = function_to_graph(o, conversion_map, value_hints) + node, new_name = function_to_graph(o, conversion_map, arg_values, arg_types) else: raise ValueError( 'Entity "%s" has unsupported type "%s". Only functions and classes are ' @@ -132,25 +132,26 @@ def object_to_graph(o, conversion_map, value_hints): # Class members are converted with their objects, unless they're # only converted partially. continue - object_to_graph(obj, conversion_map, None) + entity_to_graph(obj, conversion_map, {}, {}) return node, new_name -def class_to_graph(c, conversion_map, param_value_hints): - """Specialization of `object_to_graph` for classes.""" +def class_to_graph(c, conversion_map): + """Specialization of `entity_to_graph` for classes.""" converted_members = {} members = tf_inspect.getmembers(c, predicate=tf_inspect.ismethod) if not members: raise ValueError('Cannot convert %s: it has no member methods.') - if 'self' in param_value_hints: - raise ValueError('Hints may not be provided for reserved name "self".') - param_value_hints['self'] = (c.__name__, c) - class_globals = None for _, m in members: - node, _ = function_to_graph(m, conversion_map, param_value_hints, c) + node, _ = function_to_graph( + m, + conversion_map=conversion_map, + arg_values={}, + arg_types={'self': (c.__name__, c)}, + owner_type=c) # TODO(mdan): Do not assume all members have the same view of globals. if class_globals is None: class_globals = six.get_function_globals(m) @@ -167,10 +168,11 @@ def class_to_graph(c, conversion_map, param_value_hints): return node, class_name -def function_to_graph(f, conversion_map, param_value_hints, owner_type=None): - """Specialization of `object_to_graph` for callable functions.""" +def function_to_graph(f, conversion_map, arg_values, arg_types, + owner_type=None): + """Specialization of `entity_to_graph` for callable functions.""" node = parser.parse_object(f).body[0] - node_globals = six.get_function_globals(f) + namespace = six.get_function_globals(f) # This is needed for non-global functions. closure = six.get_function_closure(f) @@ -178,12 +180,17 @@ def function_to_graph(f, conversion_map, param_value_hints, owner_type=None): for e in closure: if callable(e.cell_contents): fn = e.cell_contents - node_globals[fn.__name__] = fn - - namer = conversion_map.new_namer(node_globals) - node = node_to_graph(node, tf_inspect.getsource(f), tf_inspect.getfile(f), - namer, node_globals, param_value_hints, - conversion_map.nocompile_decorators) + namespace[fn.__name__] = fn + + namer = conversion_map.new_namer(namespace) + ctx = context.EntityContext( + namer=namer, + source_code=tf_inspect.getsource(f), + source_file=tf_inspect.getfile(f), + namespace=namespace, + arg_values=arg_values, + arg_types=arg_types) + node = node_to_graph(node, ctx, conversion_map.nocompile_decorators) # Simulate a rename to ensure the top level is in the name map. This is needed # for top level functions, and it also helps the consistency verification made @@ -197,34 +204,26 @@ def function_to_graph(f, conversion_map, param_value_hints, owner_type=None): return node, conversion_map.name_map[f] -def _static_analysis_pass(node, source, f, namespace, value_hints): +def _static_analysis_pass(node, ctx): node = access.resolve(node) - node = live_values.resolve(node, namespace, config.PYTHON_LITERALS) - node = type_info.resolve(node, source, f, value_hints) + node = live_values.resolve(node, ctx.namespace, config.PYTHON_LITERALS) + node = type_info.resolve(node, ctx) return node -def node_to_graph(node, source, f, namer, namespace, value_hints, - nocompile_decorators): +def node_to_graph(node, ctx, nocompile_decorators): """Convert Python code to equivalent TF graph mode code. Args: node: A Python AST node representing the code to convert. - source: Optional string containing the source code of the node. Used in - error messages. - f: Optional string indicating the file where the node originated. None if - unknown. Used in error messages. - namer: A naming.Namer object. - namespace: Dict mapping symbol names to their corresponding live objects. - value_hints: A dict containing value hints for symbols like function - parameters. + ctx: An EntityContext object. nocompile_decorators: A tuple containing decorators to be stripped from functions during conversion. Returns: A tuple (node, deps): * node: A Python ast node, representing the converted code. - * deps: A set of strings, the fully qualified names of object + * deps: A set of strings, the fully qualified names of entity dependencies that this node has. """ # TODO(mdan): Verify arguments for correctness. @@ -241,30 +240,30 @@ def node_to_graph(node, source, f, namer, namespace, value_hints, # tree, which must be accounted. Although less efficient, it is most robust # to re-run the analysis. - node = _static_analysis_pass(node, source, f, namespace, value_hints) + node = _static_analysis_pass(node, ctx) node = decorators.transform(node, nocompile_decorators) - node = break_canonicalization.transform(node, namer) + node = break_canonicalization.transform(node, ctx.namer) # Note: sequencing continue canonicalization before for loop one avoids # dealing with the extra loop increment operation that the for # canonicalization creates. - node = continue_canonicalization.transform(node, namer) - namespace['len'] = len + node = continue_canonicalization.transform(node, ctx.namer) + ctx.namespace['len'] = len - node = _static_analysis_pass(node, None, None, namespace, value_hints) - node = for_canonicalization.transform(node, namer) + node = _static_analysis_pass(node, ctx) + node = for_canonicalization.transform(node, ctx.namer) # for_canonicalization may insert new global references. node = builtin_functions.transform(node) # builtin_functions may insert new global references. - namespace['print'] = print + ctx.namespace['print'] = print - node = _static_analysis_pass(node, None, None, namespace, value_hints) + node = _static_analysis_pass(node, ctx) node = print_functions.transform(node) - node = call_trees.transform(node, namer, namespace, + node = call_trees.transform(node, ctx.namer, ctx.namespace, config.DEFAULT_UNCOMPILED_MODULES, nocompile_decorators) - node = control_flow.transform(node, namer) + node = control_flow.transform(node, ctx.namer) node = logical_expressions.transform(node) - node = side_effect_guards.transform(node, namer) + node = side_effect_guards.transform(node, ctx.namer) return node diff --git a/tensorflow/contrib/py2tf/conversion_test.py b/tensorflow/contrib/py2tf/conversion_test.py index e48bfe4464..26f915f4f4 100644 --- a/tensorflow/contrib/py2tf/conversion_test.py +++ b/tensorflow/contrib/py2tf/conversion_test.py @@ -26,20 +26,23 @@ from tensorflow.python.platform import test class ConversionTest(test.TestCase): - def test_object_to_graph_unsupported_types(self): + def test_entity_to_graph_unsupported_types(self): with self.assertRaises(ValueError): - conversion.object_to_graph('dummy', None, {}) + conversion_map = conversion.ConversionMap(True, (), ()) + conversion.entity_to_graph('dummy', conversion_map, None, None) + + def test_entity_to_graph_callable(self): - def test_object_to_graph_callable(self): def f(a): return a conversion_map = conversion.ConversionMap(True, (), ()) - ast, new_name = conversion.object_to_graph(f, conversion_map, {}) + ast, new_name = conversion.entity_to_graph(f, conversion_map, None, None) self.assertTrue(isinstance(ast, gast.FunctionDef), ast) self.assertEqual('tf__f', new_name) - def test_object_to_graph_call_tree(self): + def test_entity_to_graph_call_tree(self): + def g(a): return a @@ -47,7 +50,7 @@ class ConversionTest(test.TestCase): return g(a) conversion_map = conversion.ConversionMap(True, (), ()) - conversion.object_to_graph(f, conversion_map, {}) + conversion.entity_to_graph(f, conversion_map, None, None) self.assertTrue(f in conversion_map.dependency_cache) self.assertTrue(g in conversion_map.dependency_cache) diff --git a/tensorflow/contrib/py2tf/convert/BUILD b/tensorflow/contrib/py2tf/converters/BUILD similarity index 79% rename from tensorflow/contrib/py2tf/convert/BUILD rename to tensorflow/contrib/py2tf/converters/BUILD index 050e2ef108..2b0a1234e6 100644 --- a/tensorflow/contrib/py2tf/convert/BUILD +++ b/tensorflow/contrib/py2tf/converters/BUILD @@ -15,7 +15,7 @@ filegroup( ) py_library( - name = "convert", + name = "converters", srcs = [ "break_canonicalization.py", "builtin_functions.py", @@ -35,13 +35,26 @@ py_library( ], ) +py_library( + name = "test_lib", + srcs = [ + "converter_test_base.py", + ], + srcs_version = "PY2AND3", + visibility = ["//tensorflow:__subpackages__"], + deps = [ + ":converters", + "//tensorflow/contrib/py2tf/pyct/static_analysis", + "@gast_archive//:gast", + ], +) + py_test( name = "break_canonicalization_test", srcs = ["break_canonicalization_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", ], ) @@ -50,9 +63,8 @@ py_test( name = "call_trees_test", srcs = ["call_trees_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", ], ) @@ -61,9 +73,8 @@ py_test( name = "continue_canonicalization_test", srcs = ["continue_canonicalization_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", ], ) @@ -72,9 +83,8 @@ py_test( name = "control_flow_test", srcs = ["control_flow_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", ], ) @@ -83,9 +93,8 @@ py_test( name = "builtin_functions_test", srcs = ["builtin_functions_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", ], ) @@ -94,9 +103,8 @@ py_test( name = "for_canonicalization_test", srcs = ["for_canonicalization_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", ], ) @@ -105,9 +113,8 @@ py_test( name = "logical_expressions_test", srcs = ["logical_expressions_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", ], ) @@ -116,9 +123,8 @@ py_test( name = "print_functions_test", srcs = ["print_functions_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", "@gast_archive//:gast", ], @@ -128,9 +134,8 @@ py_test( name = "side_effect_guards_test", srcs = ["side_effect_guards_test.py"], deps = [ - ":convert", + ":test_lib", "//tensorflow/contrib/py2tf/pyct", - "//tensorflow/contrib/py2tf/pyct/static_analysis", "//tensorflow/python:client_testlib", ], ) diff --git a/tensorflow/contrib/py2tf/convert/__init__.py b/tensorflow/contrib/py2tf/converters/__init__.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/__init__.py rename to tensorflow/contrib/py2tf/converters/__init__.py diff --git a/tensorflow/contrib/py2tf/convert/break_canonicalization.py b/tensorflow/contrib/py2tf/converters/break_canonicalization.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/break_canonicalization.py rename to tensorflow/contrib/py2tf/converters/break_canonicalization.py diff --git a/tensorflow/contrib/py2tf/convert/break_canonicalization_test.py b/tensorflow/contrib/py2tf/converters/break_canonicalization_test.py similarity index 84% rename from tensorflow/contrib/py2tf/convert/break_canonicalization_test.py rename to tensorflow/contrib/py2tf/converters/break_canonicalization_test.py index 23c4c4d3e2..b5ba2ad923 100644 --- a/tensorflow/contrib/py2tf/convert/break_canonicalization_test.py +++ b/tensorflow/contrib/py2tf/converters/break_canonicalization_test.py @@ -18,11 +18,10 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.py2tf.convert import break_canonicalization -from tensorflow.contrib.py2tf.convert import control_flow +from tensorflow.contrib.py2tf.converters import break_canonicalization +from tensorflow.contrib.py2tf.converters import control_flow +from tensorflow.contrib.py2tf.converters import converter_test_base from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser -from tensorflow.contrib.py2tf.pyct.static_analysis import access from tensorflow.python.platform import test @@ -32,12 +31,7 @@ class TestNamer(control_flow.SymbolNamer): return name_root -class BreakCanonicalizationTest(test.TestCase): - - def _parse_and_analyze(self, test_fn, namespace): - node = parser.parse_object(test_fn) - node = access.resolve(node) - return node +class BreakCanonicalizationTest(converter_test_base.TestCase): def test_basic_break(self): @@ -50,7 +44,7 @@ class BreakCanonicalizationTest(test.TestCase): v.append(x) return v - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}, include_type_analysis=False) node = break_canonicalization.transform(node, TestNamer()) result = compiler.ast_to_object(node) @@ -82,7 +76,7 @@ class BreakCanonicalizationTest(test.TestCase): v.append(x) return v - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}, include_type_analysis=False) node = break_canonicalization.transform(node, TestNamer()) result = compiler.ast_to_object(node) @@ -110,7 +104,7 @@ class BreakCanonicalizationTest(test.TestCase): v.append(x) return v, u, w - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}, include_type_analysis=False) node = break_canonicalization.transform(node, TestNamer()) result = compiler.ast_to_object(node) diff --git a/tensorflow/contrib/py2tf/convert/builtin_functions.py b/tensorflow/contrib/py2tf/converters/builtin_functions.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/builtin_functions.py rename to tensorflow/contrib/py2tf/converters/builtin_functions.py diff --git a/tensorflow/contrib/py2tf/convert/builtin_functions_test.py b/tensorflow/contrib/py2tf/converters/builtin_functions_test.py similarity index 68% rename from tensorflow/contrib/py2tf/convert/builtin_functions_test.py rename to tensorflow/contrib/py2tf/converters/builtin_functions_test.py index ab02b362aa..b5358da6bc 100644 --- a/tensorflow/contrib/py2tf/convert/builtin_functions_test.py +++ b/tensorflow/contrib/py2tf/converters/builtin_functions_test.py @@ -18,32 +18,22 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.py2tf.convert import builtin_functions +from tensorflow.contrib.py2tf.converters import builtin_functions +from tensorflow.contrib.py2tf.converters import converter_test_base from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser -from tensorflow.contrib.py2tf.pyct.static_analysis import access -from tensorflow.contrib.py2tf.pyct.static_analysis import live_values -from tensorflow.contrib.py2tf.pyct.static_analysis import type_info from tensorflow.python.framework import constant_op from tensorflow.python.ops import array_ops from tensorflow.python.platform import test -class BuiltinFunctionsTest(test.TestCase): - - def _parse_and_analyze(self, test_fn, namespace): - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, None, None, {}) - return node +class BuiltinFunctionsTest(converter_test_base.TestCase): def test_len(self): def test_fn(a): return len(a) - node = self._parse_and_analyze(test_fn, {'len': len}) + node = self.parse_and_analyze(test_fn, {'len': len}) node = builtin_functions.transform(node) result = compiler.ast_to_object(node) setattr(result, 'tf', array_ops) diff --git a/tensorflow/contrib/py2tf/convert/call_trees.py b/tensorflow/contrib/py2tf/converters/call_trees.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/call_trees.py rename to tensorflow/contrib/py2tf/converters/call_trees.py diff --git a/tensorflow/contrib/py2tf/convert/call_trees_test.py b/tensorflow/contrib/py2tf/converters/call_trees_test.py similarity index 78% rename from tensorflow/contrib/py2tf/convert/call_trees_test.py rename to tensorflow/contrib/py2tf/converters/call_trees_test.py index 78a6b53910..8cb8d7be0f 100644 --- a/tensorflow/contrib/py2tf/convert/call_trees_test.py +++ b/tensorflow/contrib/py2tf/converters/call_trees_test.py @@ -18,12 +18,9 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.py2tf.convert import call_trees +from tensorflow.contrib.py2tf.converters import call_trees +from tensorflow.contrib.py2tf.converters import converter_test_base from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser -from tensorflow.contrib.py2tf.pyct.static_analysis import access -from tensorflow.contrib.py2tf.pyct.static_analysis import live_values -from tensorflow.contrib.py2tf.pyct.static_analysis import type_info from tensorflow.python.framework import constant_op from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -35,14 +32,7 @@ class TestNamer(call_trees.FunctionNamer): return 'renamed_%s' % original_name -class CallTreesTest(test.TestCase): - - def _parse_and_analyze(self, test_fn, namespace): - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, None, None, {}) - return node +class CallTreesTest(converter_test_base.TestCase): def test_basic(self): @@ -55,7 +45,7 @@ class CallTreesTest(test.TestCase): def test_fn_2(a): return test_fn_1(a) + 1 - node = self._parse_and_analyze(test_fn_2, {'test_fn_1': test_fn_1}) + node = self.parse_and_analyze(test_fn_2, {'test_fn_1': test_fn_1}) node = call_trees.transform(node, TestNamer(), {}, (), ()) result = compiler.ast_to_object(node) # Only test_fn_2 is transformed, so we'll insert renamed_test_fn_1 manually. @@ -70,7 +60,7 @@ class CallTreesTest(test.TestCase): a = math_ops.add(a, constant_op.constant(1)) return a - node = self._parse_and_analyze(test_fn, { + node = self.parse_and_analyze(test_fn, { 'math_ops': math_ops, 'constant_op': constant_op }) diff --git a/tensorflow/contrib/py2tf/convert/continue_canonicalization.py b/tensorflow/contrib/py2tf/converters/continue_canonicalization.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/continue_canonicalization.py rename to tensorflow/contrib/py2tf/converters/continue_canonicalization.py diff --git a/tensorflow/contrib/py2tf/convert/continue_canonicalization_test.py b/tensorflow/contrib/py2tf/converters/continue_canonicalization_test.py similarity index 83% rename from tensorflow/contrib/py2tf/convert/continue_canonicalization_test.py rename to tensorflow/contrib/py2tf/converters/continue_canonicalization_test.py index a041ff4641..c1fe903a2d 100644 --- a/tensorflow/contrib/py2tf/convert/continue_canonicalization_test.py +++ b/tensorflow/contrib/py2tf/converters/continue_canonicalization_test.py @@ -18,11 +18,10 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.py2tf.convert import continue_canonicalization -from tensorflow.contrib.py2tf.convert import control_flow +from tensorflow.contrib.py2tf.converters import continue_canonicalization +from tensorflow.contrib.py2tf.converters import control_flow +from tensorflow.contrib.py2tf.converters import converter_test_base from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser -from tensorflow.contrib.py2tf.pyct.static_analysis import access from tensorflow.python.platform import test @@ -32,12 +31,7 @@ class TestNamer(control_flow.SymbolNamer): return name_root -class ContinueCanonicalizationTest(test.TestCase): - - def _parse_and_analyze(self, test_fn, namespace): - node = parser.parse_object(test_fn) - node = access.resolve(node) - return node +class ContinueCanonicalizationTest(converter_test_base.TestCase): def test_basic_continue(self): @@ -50,7 +44,7 @@ class ContinueCanonicalizationTest(test.TestCase): v.append(x) return v - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}, include_type_analysis=False) node = continue_canonicalization.transform(node, TestNamer()) result = compiler.ast_to_object(node) @@ -71,7 +65,7 @@ class ContinueCanonicalizationTest(test.TestCase): v.append(x) return v - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}, include_type_analysis=False) node = continue_canonicalization.transform(node, TestNamer()) result = compiler.ast_to_object(node) @@ -97,7 +91,7 @@ class ContinueCanonicalizationTest(test.TestCase): v.append(x) return v, u, w - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}, include_type_analysis=False) node = continue_canonicalization.transform(node, TestNamer()) result = compiler.ast_to_object(node) diff --git a/tensorflow/contrib/py2tf/convert/control_flow.py b/tensorflow/contrib/py2tf/converters/control_flow.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/control_flow.py rename to tensorflow/contrib/py2tf/converters/control_flow.py diff --git a/tensorflow/contrib/py2tf/convert/control_flow_test.py b/tensorflow/contrib/py2tf/converters/control_flow_test.py similarity index 79% rename from tensorflow/contrib/py2tf/convert/control_flow_test.py rename to tensorflow/contrib/py2tf/converters/control_flow_test.py index 64a317ee9c..054e33750d 100644 --- a/tensorflow/contrib/py2tf/convert/control_flow_test.py +++ b/tensorflow/contrib/py2tf/converters/control_flow_test.py @@ -18,12 +18,9 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.py2tf.convert import control_flow +from tensorflow.contrib.py2tf.converters import control_flow +from tensorflow.contrib.py2tf.converters import converter_test_base from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser -from tensorflow.contrib.py2tf.pyct.static_analysis import access -from tensorflow.contrib.py2tf.pyct.static_analysis import live_values -from tensorflow.contrib.py2tf.pyct.static_analysis import type_info from tensorflow.python.framework import constant_op from tensorflow.python.ops import control_flow_ops from tensorflow.python.platform import test @@ -40,14 +37,7 @@ class TestNamer(control_flow.SymbolNamer): i += 1 -class ControlFlowTest(test.TestCase): - - def _parse_and_analyze(self, test_fn, namespace): - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, None, None, {}) - return node +class ControlFlowTest(converter_test_base.TestCase): def test_simple_while(self): @@ -59,7 +49,7 @@ class ControlFlowTest(test.TestCase): i += 1 return s, i, n - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}) node = control_flow.transform(node, TestNamer()) result = compiler.ast_to_object(node) setattr(result, 'tf', control_flow_ops) @@ -75,7 +65,7 @@ class ControlFlowTest(test.TestCase): n -= 1 return n - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}) node = control_flow.transform(node, TestNamer()) result = compiler.ast_to_object(node) setattr(result, 'tf', control_flow_ops) @@ -94,7 +84,7 @@ class ControlFlowTest(test.TestCase): b = 2 * n return a, b - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}) node = control_flow.transform(node, TestNamer()) result = compiler.ast_to_object(node) setattr(result, 'tf', control_flow_ops) @@ -112,7 +102,7 @@ class ControlFlowTest(test.TestCase): n = -n return n - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}) node = control_flow.transform(node, TestNamer()) result = compiler.ast_to_object(node) setattr(result, 'tf', control_flow_ops) diff --git a/tensorflow/contrib/py2tf/converters/converter_test_base.py b/tensorflow/contrib/py2tf/converters/converter_test_base.py new file mode 100644 index 0000000000..ed006bad6d --- /dev/null +++ b/tensorflow/contrib/py2tf/converters/converter_test_base.py @@ -0,0 +1,48 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Base class for tests in this module.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.contrib.py2tf.pyct import context +from tensorflow.contrib.py2tf.pyct import parser +from tensorflow.contrib.py2tf.pyct.static_analysis import access +from tensorflow.contrib.py2tf.pyct.static_analysis import live_values +from tensorflow.contrib.py2tf.pyct.static_analysis import type_info +from tensorflow.python.platform import test + + +class TestCase(test.TestCase): + + def parse_and_analyze(self, + test_fn, + namespace, + arg_types=None, + include_type_analysis=True): + ctx = context.EntityContext( + namer=None, + source_code=None, + source_file=None, + namespace=namespace, + arg_values=None, + arg_types=arg_types) + node = parser.parse_object(test_fn) + node = access.resolve(node) + node = live_values.resolve(node, namespace, {}) + if include_type_analysis: + node = type_info.resolve(node, ctx) + return node diff --git a/tensorflow/contrib/py2tf/convert/decorators.py b/tensorflow/contrib/py2tf/converters/decorators.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/decorators.py rename to tensorflow/contrib/py2tf/converters/decorators.py diff --git a/tensorflow/contrib/py2tf/convert/for_canonicalization.py b/tensorflow/contrib/py2tf/converters/for_canonicalization.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/for_canonicalization.py rename to tensorflow/contrib/py2tf/converters/for_canonicalization.py diff --git a/tensorflow/contrib/py2tf/convert/for_canonicalization_test.py b/tensorflow/contrib/py2tf/converters/for_canonicalization_test.py similarity index 75% rename from tensorflow/contrib/py2tf/convert/for_canonicalization_test.py rename to tensorflow/contrib/py2tf/converters/for_canonicalization_test.py index 8de2d1a0f8..a6e6350fd4 100644 --- a/tensorflow/contrib/py2tf/convert/for_canonicalization_test.py +++ b/tensorflow/contrib/py2tf/converters/for_canonicalization_test.py @@ -18,11 +18,10 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.py2tf.convert import control_flow -from tensorflow.contrib.py2tf.convert import for_canonicalization +from tensorflow.contrib.py2tf.converters import control_flow +from tensorflow.contrib.py2tf.converters import converter_test_base +from tensorflow.contrib.py2tf.converters import for_canonicalization from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser -from tensorflow.contrib.py2tf.pyct.static_analysis import access from tensorflow.python.platform import test @@ -32,12 +31,7 @@ class TestNamer(control_flow.SymbolNamer): return name_root -class ControlFlowTest(test.TestCase): - - def _parse_and_analyze(self, test_fn, namespace): - node = parser.parse_object(test_fn) - node = access.resolve(node) - return node +class ControlFlowTest(converter_test_base.TestCase): def test_basic_for(self): @@ -47,7 +41,7 @@ class ControlFlowTest(test.TestCase): s += e return s - node = self._parse_and_analyze(test_fn, {}) + node = self.parse_and_analyze(test_fn, {}) node = for_canonicalization.transform(node, TestNamer()) result = compiler.ast_to_object(node) diff --git a/tensorflow/contrib/py2tf/convert/logical_expressions.py b/tensorflow/contrib/py2tf/converters/logical_expressions.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/logical_expressions.py rename to tensorflow/contrib/py2tf/converters/logical_expressions.py diff --git a/tensorflow/contrib/py2tf/convert/logical_expressions_test.py b/tensorflow/contrib/py2tf/converters/logical_expressions_test.py similarity index 85% rename from tensorflow/contrib/py2tf/convert/logical_expressions_test.py rename to tensorflow/contrib/py2tf/converters/logical_expressions_test.py index f07fa017b9..d711065099 100644 --- a/tensorflow/contrib/py2tf/convert/logical_expressions_test.py +++ b/tensorflow/contrib/py2tf/converters/logical_expressions_test.py @@ -18,21 +18,21 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.py2tf.convert import logical_expressions +from tensorflow.contrib.py2tf.converters import converter_test_base +from tensorflow.contrib.py2tf.converters import logical_expressions from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser from tensorflow.python.ops import math_ops from tensorflow.python.platform import test -class GradientsFunctionTest(test.TestCase): +class GradientsFunctionTest(converter_test_base.TestCase): def test_equals(self): def test_fn(a, b): return a == b - node = parser.parse_object(test_fn) + node = self.parse_and_analyze(test_fn, {}) node = logical_expressions.transform(node) result = compiler.ast_to_object(node) setattr(result, 'tf', math_ops) @@ -46,7 +46,7 @@ class GradientsFunctionTest(test.TestCase): def test_fn(a, b, c): return (a or b) and (a or b or c) - node = parser.parse_object(test_fn) + node = self.parse_and_analyze(test_fn, {}) node = logical_expressions.transform(node) result = compiler.ast_to_object(node) setattr(result, 'tf', math_ops) diff --git a/tensorflow/contrib/py2tf/convert/print_functions.py b/tensorflow/contrib/py2tf/converters/print_functions.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/print_functions.py rename to tensorflow/contrib/py2tf/converters/print_functions.py diff --git a/tensorflow/contrib/py2tf/convert/print_functions_test.py b/tensorflow/contrib/py2tf/converters/print_functions_test.py similarity index 65% rename from tensorflow/contrib/py2tf/convert/print_functions_test.py rename to tensorflow/contrib/py2tf/converters/print_functions_test.py index 8b6c238aa4..475196ce10 100644 --- a/tensorflow/contrib/py2tf/convert/print_functions_test.py +++ b/tensorflow/contrib/py2tf/converters/print_functions_test.py @@ -20,30 +20,20 @@ from __future__ import print_function import gast -from tensorflow.contrib.py2tf.convert import print_functions +from tensorflow.contrib.py2tf.converters import converter_test_base +from tensorflow.contrib.py2tf.converters import print_functions from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser -from tensorflow.contrib.py2tf.pyct.static_analysis import access -from tensorflow.contrib.py2tf.pyct.static_analysis import live_values -from tensorflow.contrib.py2tf.pyct.static_analysis import type_info from tensorflow.python.platform import test -class PrintFunctionsTest(test.TestCase): - - def _parse_and_analyze(self, test_fn, namespace): - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, None, None, {}) - return node +class PrintFunctionsTest(converter_test_base.TestCase): def test_transform(self): def test_fn(a): print(a) - node = self._parse_and_analyze(test_fn, {'print': print}) + node = self.parse_and_analyze(test_fn, {'print': print}) node = print_functions.transform(node) result = compiler.ast_to_object(node) diff --git a/tensorflow/contrib/py2tf/convert/side_effect_guards.py b/tensorflow/contrib/py2tf/converters/side_effect_guards.py similarity index 100% rename from tensorflow/contrib/py2tf/convert/side_effect_guards.py rename to tensorflow/contrib/py2tf/converters/side_effect_guards.py diff --git a/tensorflow/contrib/py2tf/convert/side_effect_guards_test.py b/tensorflow/contrib/py2tf/converters/side_effect_guards_test.py similarity index 72% rename from tensorflow/contrib/py2tf/convert/side_effect_guards_test.py rename to tensorflow/contrib/py2tf/converters/side_effect_guards_test.py index 1715e9eb95..5c56973dc2 100644 --- a/tensorflow/contrib/py2tf/convert/side_effect_guards_test.py +++ b/tensorflow/contrib/py2tf/converters/side_effect_guards_test.py @@ -18,12 +18,9 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.py2tf.convert import side_effect_guards +from tensorflow.contrib.py2tf.converters import converter_test_base +from tensorflow.contrib.py2tf.converters import side_effect_guards from tensorflow.contrib.py2tf.pyct import compiler -from tensorflow.contrib.py2tf.pyct import parser -from tensorflow.contrib.py2tf.pyct.static_analysis import access -from tensorflow.contrib.py2tf.pyct.static_analysis import live_values -from tensorflow.contrib.py2tf.pyct.static_analysis import type_info from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import state_ops @@ -37,14 +34,7 @@ class TestNamer(side_effect_guards.SymbolNamer): return name_root -class SideEffectGuardsTest(test.TestCase): - - def _parse_and_analyze(self, test_fn, namespace): - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, namespace, {}) - node = type_info.resolve(node, None, None, {}) - return node +class SideEffectGuardsTest(converter_test_base.TestCase): def test_transform(self): @@ -52,7 +42,7 @@ class SideEffectGuardsTest(test.TestCase): state_ops.assign(a, a + 1) return a - node = self._parse_and_analyze(test_fn, {'state_ops': state_ops}) + node = self.parse_and_analyze(test_fn, {'state_ops': state_ops}) node = side_effect_guards.transform(node, TestNamer()) result = compiler.ast_to_object(node) setattr(result, 'state_ops', state_ops) diff --git a/tensorflow/contrib/py2tf/pyct/BUILD b/tensorflow/contrib/py2tf/pyct/BUILD index 9dd564cb9f..e0331dbc97 100644 --- a/tensorflow/contrib/py2tf/pyct/BUILD +++ b/tensorflow/contrib/py2tf/pyct/BUILD @@ -20,6 +20,7 @@ py_library( "__init__.py", "anno.py", "compiler.py", + "context.py", "parser.py", "pretty_printer.py", "templates.py", diff --git a/tensorflow/contrib/py2tf/pyct/context.py b/tensorflow/contrib/py2tf/pyct/context.py new file mode 100644 index 0000000000..73f3613d09 --- /dev/null +++ b/tensorflow/contrib/py2tf/pyct/context.py @@ -0,0 +1,42 @@ +# Copyright 2016 The TensorFlow Authors. 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. +# ============================================================================== +"""Conversion context containers.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +class EntityContext(object): + """Contains information about an entity, like source code. + + Attributes: + namer: Namer that matches the contract of all converters. + source_code: The entity's source code. + source_file: The entity's source file. + namespace: Dict[str->*], containing symbols visible to the entity + (excluding parameters). + arg_values: Dict[str->*], containing parameter values, if known. + arg_types: Dict[str->*], containing parameter types, if known. + """ + + def __init__(self, namer, source_code, source_file, namespace, arg_values, + arg_types): + self.namer = namer + self.source_code = source_code + self.source_file = source_file + self.namespace = namespace + self.arg_values = {} if arg_values is None else arg_values + self.arg_types = {} if arg_types is None else arg_types diff --git a/tensorflow/contrib/py2tf/pyct/static_analysis/type_info.py b/tensorflow/contrib/py2tf/pyct/static_analysis/type_info.py index b17af5d844..0042aa90ed 100644 --- a/tensorflow/contrib/py2tf/pyct/static_analysis/type_info.py +++ b/tensorflow/contrib/py2tf/pyct/static_analysis/type_info.py @@ -78,10 +78,9 @@ class TypeInfoResolver(transformer.Base): * Attribute (helps resolve object methods) """ - def __init__(self, value_hints, source, f): - super(TypeInfoResolver, self).__init__(source, f) + def __init__(self, context): + super(TypeInfoResolver, self).__init__(context) self.scope = Scope(None) - self.value_hints = value_hints self.function_level = 0 def visit_FunctionDef(self, node): @@ -122,13 +121,11 @@ class TypeInfoResolver(transformer.Base): self.generic_visit(node) if isinstance(node.ctx, gast.Param): self.scope.setval(node.id, gast.Name(node.id, gast.Load(), None)) - # TODO(mdan): Member functions should not need type hints. - # We could attemp to extract im_class from the live_val annotation. - if self.function_level == 1 and node.id in self.value_hints: + if self.function_level == 1 and node.id in self.context.arg_types: # Forge a node to hold the type information, so that method calls on # it can resolve the type. type_holder = gast.Name(node.id, gast.Load(), None) - type_string, type_obj = self.value_hints[node.id] + type_string, type_obj = self.context.arg_types[node.id] anno.setanno(type_holder, 'type', type_obj) anno.setanno(type_holder, 'type_fqn', tuple(type_string.split('.'))) self.scope.setval(node.id, type_holder) @@ -208,6 +205,5 @@ class TypeInfoResolver(transformer.Base): return node -def resolve(node, source, f, value_hints): - assert value_hints is not None - return TypeInfoResolver(value_hints, source, f).visit(node) +def resolve(node, context): + return TypeInfoResolver(context).visit(node) diff --git a/tensorflow/contrib/py2tf/pyct/static_analysis/type_info_test.py b/tensorflow/contrib/py2tf/pyct/static_analysis/type_info_test.py index 98dc7bf50f..a491f49ca3 100644 --- a/tensorflow/contrib/py2tf/pyct/static_analysis/type_info_test.py +++ b/tensorflow/contrib/py2tf/pyct/static_analysis/type_info_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function from tensorflow.contrib.py2tf.pyct import anno +from tensorflow.contrib.py2tf.pyct import context from tensorflow.contrib.py2tf.pyct import parser from tensorflow.contrib.py2tf.pyct import transformer from tensorflow.contrib.py2tf.pyct.static_analysis import access @@ -55,17 +56,27 @@ class ScopeTest(test.TestCase): class TypeInfoResolverTest(test.TestCase): + def _parse_and_analyze(self, test_fn, namespace, arg_types=None): + ctx = context.EntityContext( + namer=None, + source_code=None, + source_file=None, + namespace=namespace, + arg_values=None, + arg_types=arg_types) + node = parser.parse_object(test_fn) + node = access.resolve(node) + node = live_values.resolve(node, namespace, {}) + node = type_info.resolve(node, ctx) + return node + def test_constructor_detection(self): def test_fn(): opt = training.GradientDescentOptimizer(0.1) return opt - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, {'training': training}, {}) - node = type_info.resolve(node, None, None, {}) - + node = self._parse_and_analyze(test_fn, {'training': training}) call_node = node.body[0].body[0].value self.assertEquals(training.GradientDescentOptimizer, anno.getanno(call_node, 'type')) @@ -78,11 +89,7 @@ class TypeInfoResolverTest(test.TestCase): opt = training.GradientDescentOptimizer(0.1) opt.minimize(0) - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, {'training': training}, {}) - node = type_info.resolve(node, None, None, {}) - + node = self._parse_and_analyze(test_fn, {'training': training}) attr_call_node = node.body[0].body[1].value.func self.assertEquals((training.__name__, 'GradientDescentOptimizer'), anno.getanno(attr_call_node, 'type_fqn')) @@ -93,11 +100,7 @@ class TypeInfoResolverTest(test.TestCase): with session.Session() as sess: sess.run(x) - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, {'session': session}, {}) - node = type_info.resolve(node, None, None, {}) - + node = self._parse_and_analyze(test_fn, {'session': session}) constructor_call = node.body[0].body[0].items[0].context_expr self.assertEquals(session.Session, anno.getanno(constructor_call, 'type')) self.assertEquals((session.__name__, 'Session'), @@ -116,33 +119,25 @@ class TypeInfoResolverTest(test.TestCase): opt = training.GradientDescentOptimizer(0.01) opt.minimize(0) - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, {'training': training}, {}) with self.assertRaises(transformer.PyFlowParseError): - node = type_info.resolve(node, None, None, {}) + self._parse_and_analyze(test_fn, {'training': training}) def test_parameter_class_members(self): def test_fn(opt): opt.minimize(0) - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, {'training': training}, {}) with self.assertRaises(transformer.PyFlowParseError): - node = type_info.resolve(node, None, None, {}) + self._parse_and_analyze(test_fn, {'training': training}) def test_parameter_class_members_with_value_hints(self): def test_fn(opt): opt.minimize(0) - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, {'training': training}, {}) - node = type_info.resolve( - node, None, None, { + node = self._parse_and_analyze( + test_fn, {'training': training}, + arg_types={ 'opt': (('%s.GradientDescentOptimizer' % training.__name__), training.GradientDescentOptimizer(0.1)) }) @@ -161,11 +156,8 @@ class TypeInfoResolverTest(test.TestCase): foo = bar foo() - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, {'bar': bar}, {}) with self.assertRaises(transformer.PyFlowParseError): - node = type_info.resolve(node, None, None, {}) + self._parse_and_analyze(test_fn, {'bar': bar}) def test_nested_members(self): @@ -173,11 +165,8 @@ class TypeInfoResolverTest(test.TestCase): foo = training.GradientDescentOptimizer(0.1) foo.bar.baz() - node = parser.parse_object(test_fn) - node = access.resolve(node) - node = live_values.resolve(node, {'training': training}, {}) with self.assertRaises(transformer.PyFlowParseError): - node = type_info.resolve(node, None, None, {}) + self._parse_and_analyze(test_fn, {'training': training}) if __name__ == '__main__': diff --git a/tensorflow/contrib/py2tf/pyct/transformer.py b/tensorflow/contrib/py2tf/pyct/transformer.py index 1658a1b694..d5aa23eaeb 100644 --- a/tensorflow/contrib/py2tf/pyct/transformer.py +++ b/tensorflow/contrib/py2tf/pyct/transformer.py @@ -30,23 +30,29 @@ class PyFlowParseError(SyntaxError): class Base(gast.NodeTransformer): """Base class for specialized transformers.""" - def __init__(self, source, f): + def __init__(self, context): + """Initialize the transformer. Subclasses should call this. + + Args: + context: An EntityContext. + """ self._lineno = 0 self._col_offset = 0 - self._source = source - self._file = f + self.context = context def visit(self, node): try: - if self._source and hasattr(node, 'lineno'): + source_code = self.context.source_code + source_file = self.context.source_file + if source_code and hasattr(node, 'lineno'): self._lineno = node.lineno self._col_offset = node.col_offset return super(Base, self).visit(node) except ValueError as e: msg = '%s\nOccurred at node:\n%s' % (str(e), pretty_printer.fmt(node)) - if self._source: + if source_code: line = self._source.splitlines()[self._lineno - 1] else: line = '' raise PyFlowParseError( - msg, (self._file, self._lineno, self._col_offset + 1, line)) + msg, (source_file, self._lineno, self._col_offset + 1, line)) diff --git a/tensorflow/tools/pip_package/BUILD b/tensorflow/tools/pip_package/BUILD index c789e2ba0c..598080ed27 100644 --- a/tensorflow/tools/pip_package/BUILD +++ b/tensorflow/tools/pip_package/BUILD @@ -152,7 +152,8 @@ sh_binary( "//tensorflow/contrib/nn:nn_py", "//tensorflow/contrib/predictor:predictor_pip", "//tensorflow/contrib/py2tf:py2tf_internal", - "//tensorflow/contrib/py2tf/convert:convert", + "//tensorflow/contrib/py2tf/converters:converters", + "//tensorflow/contrib/py2tf/converters:test_lib", "//tensorflow/contrib/py2tf/pyct:pyct", "//tensorflow/contrib/py2tf/pyct/static_analysis:static_analysis", "//tensorflow/contrib/receptive_field:receptive_field_pip", -- GitLab From faf3547da8bde4aa05ac65562250901f1784e562 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Wed, 24 Jan 2018 19:01:16 -0800 Subject: [PATCH 239/258] [XLA] Allow buffers for CustomCalls to be reused. PiperOrigin-RevId: 183177944 --- tensorflow/compiler/xla/service/buffer_assignment.cc | 9 ++++----- tensorflow/compiler/xla/tests/local_client_aot_test.cc | 3 +-- .../compiler/xla/tests/local_client_aot_test_helper.cc | 3 +-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tensorflow/compiler/xla/service/buffer_assignment.cc b/tensorflow/compiler/xla/service/buffer_assignment.cc index 33fe11b81d..323620c131 100644 --- a/tensorflow/compiler/xla/service/buffer_assignment.cc +++ b/tensorflow/compiler/xla/service/buffer_assignment.cc @@ -846,14 +846,13 @@ Status BufferAssigner::AssignBuffersForComputation( continue; } - if (is_thread_local || instruction->opcode() == HloOpcode::kCustomCall) { - // Custom call operations never have reusable buffers. Also we do not - // reuse thread-local buffers for now, because they are dynamically - // allocated and their lifetimes are hard to compute. + if (is_thread_local) { + // We do not reuse thread-local buffers for now, because they are + // dynamically allocated and their lifetimes are hard to compute. BufferAllocation* allocation = assignment->NewAllocation( *buffer, buffer_size, is_thread_local, /*is_reusable=*/false); VLOG(3) << "New allocation #" << allocation->index() - << " for thread-local/CustomCall: " << *buffer; + << " for thread-local: " << *buffer; continue; } diff --git a/tensorflow/compiler/xla/tests/local_client_aot_test.cc b/tensorflow/compiler/xla/tests/local_client_aot_test.cc index 569d5944ca..47cab79604 100644 --- a/tensorflow/compiler/xla/tests/local_client_aot_test.cc +++ b/tensorflow/compiler/xla/tests/local_client_aot_test.cc @@ -44,8 +44,7 @@ TEST_F(LocalClientAotTest, Constant) { OpaqueData opaque_data{100, 20, 3}; void* parameters[] = {&opaque_data}; float out = 0; - char tmp[4] = {0}; - void* temporary_buffers[] = {nullptr, &out, &tmp}; + void* temporary_buffers[] = {nullptr, &out}; SumAndDouble(&out, &run_options, parameters, temporary_buffers); EXPECT_EQ(out, 246.0f); diff --git a/tensorflow/compiler/xla/tests/local_client_aot_test_helper.cc b/tensorflow/compiler/xla/tests/local_client_aot_test_helper.cc index 4d3b513b09..3704ddd801 100644 --- a/tensorflow/compiler/xla/tests/local_client_aot_test_helper.cc +++ b/tensorflow/compiler/xla/tests/local_client_aot_test_helper.cc @@ -87,10 +87,9 @@ int main(int argc, char** argv) { // It's lame to hard-code the buffer assignments, but we need // local_client_aot_test.cc to be able to easily invoke the function. CHECK_EQ(result->result_buffer_index(), 1); - CHECK_EQ(result->buffer_sizes().size(), 3); + CHECK_EQ(result->buffer_sizes().size(), 2); CHECK_EQ(result->buffer_sizes()[0], -1); // param buffer CHECK_EQ(result->buffer_sizes()[1], sizeof(float)); // result buffer - CHECK_EQ(result->buffer_sizes()[2], sizeof(float)); // temp buffer if (triple.isOSBinFormatELF()) { // Check the ELF magic. CHECK_EQ(result->object_file_data()[0], 0x7F); -- GitLab From b25e892311fbdb308f89605ede30fce1b138c7f6 Mon Sep 17 00:00:00 2001 From: Rui Zhao Date: Wed, 24 Jan 2018 19:32:10 -0800 Subject: [PATCH 240/258] Allow passing candidate sampling seed in to sampled_softmax_loss for testing. PiperOrigin-RevId: 183180196 --- tensorflow/python/ops/nn_impl.py | 16 ++++++++++++---- tensorflow/tools/api/golden/tensorflow.nn.pbtxt | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/ops/nn_impl.py b/tensorflow/python/ops/nn_impl.py index 3268fd0e0a..55fcd176d6 100644 --- a/tensorflow/python/ops/nn_impl.py +++ b/tensorflow/python/ops/nn_impl.py @@ -969,7 +969,8 @@ def _compute_sampled_logits(weights, subtract_log_q=True, remove_accidental_hits=False, partition_strategy="mod", - name=None): + name=None, + seed=None): """Helper function for nce_loss and sampled_softmax_loss functions. Computes sampled output training logits and labels suitable for implementing @@ -1007,6 +1008,8 @@ def _compute_sampled_logits(weights, if `len(weights) > 1`. Currently `"div"` and `"mod"` are supported. Default is `"mod"`. See `tf.nn.embedding_lookup` for more details. name: A name for the operation (optional). + seed: random seed for candidate sampling. Default to None, which doesn't set + the op-level random seed for candidate sampling. Returns: out_logits: `Tensor` object with shape `[batch_size, num_true + num_sampled]`, for passing to either @@ -1036,7 +1039,8 @@ def _compute_sampled_logits(weights, num_true=num_true, num_sampled=num_sampled, unique=True, - range_max=num_classes) + range_max=num_classes, + seed=seed) # NOTE: pylint cannot tell that 'sampled_values' is a sequence # pylint: disable=unpacking-non-sequence sampled, true_expected_count, sampled_expected_count = ( @@ -1255,7 +1259,8 @@ def sampled_softmax_loss(weights, sampled_values=None, remove_accidental_hits=True, partition_strategy="mod", - name="sampled_softmax_loss"): + name="sampled_softmax_loss", + seed=None): """Computes and returns the sampled softmax training loss. This is a faster way to train a softmax classifier over a huge number of @@ -1316,6 +1321,8 @@ def sampled_softmax_loss(weights, if `len(weights) > 1`. Currently `"div"` and `"mod"` are supported. Default is `"mod"`. See `tf.nn.embedding_lookup` for more details. name: A name for the operation (optional). + seed: random seed for candidate sampling. Default to None, which doesn't set + the op-level random seed for candidate sampling. Returns: A `batch_size` 1-D tensor of per-example sampled softmax losses. @@ -1333,7 +1340,8 @@ def sampled_softmax_loss(weights, subtract_log_q=True, remove_accidental_hits=remove_accidental_hits, partition_strategy=partition_strategy, - name=name) + name=name, + seed=seed) sampled_losses = nn_ops.softmax_cross_entropy_with_logits( labels=labels, logits=logits) # sampled_losses is a [batch_size] tensor. diff --git a/tensorflow/tools/api/golden/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/tensorflow.nn.pbtxt index 8ce022e454..455590d866 100644 --- a/tensorflow/tools/api/golden/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.nn.pbtxt @@ -262,7 +262,7 @@ tf_module { } member_method { name: "sampled_softmax_loss" - argspec: "args=[\'weights\', \'biases\', \'labels\', \'inputs\', \'num_sampled\', \'num_classes\', \'num_true\', \'sampled_values\', \'remove_accidental_hits\', \'partition_strategy\', \'name\'], varargs=None, keywords=None, defaults=[\'1\', \'None\', \'True\', \'mod\', \'sampled_softmax_loss\'], " + argspec: "args=[\'weights\', \'biases\', \'labels\', \'inputs\', \'num_sampled\', \'num_classes\', \'num_true\', \'sampled_values\', \'remove_accidental_hits\', \'partition_strategy\', \'name\', \'seed\'], varargs=None, keywords=None, defaults=[\'1\', \'None\', \'True\', \'mod\', \'sampled_softmax_loss\', \'None\'], " } member_method { name: "selu" -- GitLab From 1a6216e61e804019cd64732d6f95d4d9bbedb594 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 19:47:58 -0800 Subject: [PATCH 241/258] [XLA] Fix HloModule clone. Currently the cloning of an instruction is usually "shallow": the called computations of the instruction are reused in the clone. This mechanism is useful when the hlo graph need to be modified in place (e.g. inliner, and some hlo passes). One exception is the fusion instruction: it's always "deep" copied, which means the fused computation is copied as well. So when we deep cloning an HLO module, don't re-copy the fused computation, and do let the instruction's clone function know where to put the copied fused computation. PiperOrigin-RevId: 183181206 --- tensorflow/compiler/xla/service/hlo_module.cc | 21 ++++++++-- .../compiler/xla/service/hlo_module_test.cc | 42 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_module.cc b/tensorflow/compiler/xla/service/hlo_module.cc index 58bb942211..99d8dd04e5 100644 --- a/tensorflow/compiler/xla/service/hlo_module.cc +++ b/tensorflow/compiler/xla/service/hlo_module.cc @@ -523,7 +523,15 @@ std::unique_ptr HloModule::Clone(const string& suffix) const { std::unordered_map clone_map; for (auto& computation : computations_) { - auto cloned_computation = computation->Clone(suffix); + if (computation->IsFusionComputation()) { + // Cloning of a fused computation is handled by its fusion instruction. + continue; + } + + // When cloning a computation, pass in the new module, so that for any + // fusion instruction in this computation, the fused computation will be + // deep cloned to the new module. + auto cloned_computation = computation->Clone(suffix, module.get()); InsertOrDie(&clone_map, computation.get(), cloned_computation.get()); if (entry_computation_ == computation.get()) { @@ -537,8 +545,15 @@ std::unique_ptr HloModule::Clone(const string& suffix) const { for (auto* instruction : cloned_computation->instructions()) { // Rewrite instruction's called_computation to point to the cloned // computations. - instruction->ReplaceCalledComputations( - [&](HloComputation* hlo) { return FindOrDie(clone_map, hlo); }); + instruction->ReplaceCalledComputations([&](HloComputation* hlo) { + if (hlo->IsFusionComputation()) { + // Cloning of a fused computation has already been handled when its + // fusion instruction is cloned. So this hlo computation is already + // the cloned one. + return hlo; + } + return FindOrDie(clone_map, hlo); + }); } } return module; diff --git a/tensorflow/compiler/xla/service/hlo_module_test.cc b/tensorflow/compiler/xla/service/hlo_module_test.cc index 0f5d3dccb7..cd51fa4e85 100644 --- a/tensorflow/compiler/xla/service/hlo_module_test.cc +++ b/tensorflow/compiler/xla/service/hlo_module_test.cc @@ -105,6 +105,48 @@ TEST_F(HloModuleTest, CloneTest) { } } +TEST_F(HloModuleTest, CloneHasFusion) { + auto module = CreateNewModule(); + + // Create the fused computation. + HloComputation* fused_computation; + { + auto b = HloComputation::Builder("Fused"); + auto x = b.AddInstruction(HloInstruction::CreateParameter(0, r0f32_, "x")); + b.AddInstruction( + HloInstruction::CreateBinary(r0f32_, HloOpcode::kAdd, x, x)); + fused_computation = module->AddEmbeddedComputation(b.Build()); + } + + // Create the entry computation. + { + auto b = HloComputation::Builder("Entry"); + auto input = b.AddInstruction( + HloInstruction::CreateConstant(Literal::CreateR0(42.0f))); + b.AddInstruction( + HloInstruction::CreateFusion(r0f32_, HloInstruction::FusionKind::kInput, + /*operands=*/{input}, fused_computation)); + module->AddEntryComputation(b.Build()); + } + + auto post_order = module->MakeComputationPostOrder(); + auto cloned_module = module->Clone("copy"); + auto post_order_copied = cloned_module->MakeComputationPostOrder(); + + EXPECT_EQ(post_order.size(), post_order_copied.size()); + for (auto origin = post_order.begin(), copied = post_order_copied.begin(); + origin != post_order.end() && copied != post_order_copied.end(); + ++origin, ++copied) { + if ((*origin)->name() == "Fused") { + // Clone of the fused computation is handled when its fusion instruction + // is cloned, which always use suffix ".clone". + EXPECT_EQ((*origin)->name() + ".clone", (*copied)->name()); + } else { + EXPECT_EQ((*origin)->name() + ".copy", (*copied)->name()); + } + } +} + TEST_F(HloModuleTest, DiamondComputationsPostOrder) { // Create a module with a diamond call graph of computations. auto module = CreateNewModule(); -- GitLab From 0d11ed25e49e9dfbb45c15c1af9a5892e9146768 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 20:13:14 -0800 Subject: [PATCH 242/258] Make the graph generation for TFBT deterministic. PiperOrigin-RevId: 183183086 --- tensorflow/contrib/boosted_trees/python/ops/batch_ops_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/boosted_trees/python/ops/batch_ops_utils.py b/tensorflow/contrib/boosted_trees/python/ops/batch_ops_utils.py index 23168bf493..b281a4c6d1 100644 --- a/tensorflow/contrib/boosted_trees/python/ops/batch_ops_utils.py +++ b/tensorflow/contrib/boosted_trees/python/ops/batch_ops_utils.py @@ -104,7 +104,7 @@ def run_handler_scheduled_ops(per_handler_ops, stamp, worker_device): batched_ops = collections.defaultdict(list) # Group the ops by their batching_key. Ops that share the same batching key # can be executed together. - for handler in per_handler_ops.keys(): + for handler in sorted(per_handler_ops.keys()): for op in per_handler_ops[handler]: batched_ops[(op.batching_key(), op.batch_runner_fn())].append(op) op_results = {} -- GitLab From b986f8944d22b922e9a5feb5b7234b9a0b1087ce Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Wed, 24 Jan 2018 20:51:33 -0800 Subject: [PATCH 243/258] [XLA] Add more tests for ConvertElementType. PiperOrigin-RevId: 183185601 --- tensorflow/compiler/xla/tests/unary_op_test.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tensorflow/compiler/xla/tests/unary_op_test.cc b/tensorflow/compiler/xla/tests/unary_op_test.cc index fa4192e928..835e2d7e55 100644 --- a/tensorflow/compiler/xla/tests/unary_op_test.cc +++ b/tensorflow/compiler/xla/tests/unary_op_test.cc @@ -215,5 +215,23 @@ XLA_TEST_F(UnaryOpTest, SignAbsTestR2) { ComputeAndCompareR2(&builder, {{0, 0}, {0, 0}}, {}); } +XLA_TEST_F(UnaryOpTest, ConvertElementTypePredToS32) { + ComputationBuilder builder(client_, TestName()); + auto lhs = builder.ConstantR1({0, 1}); + auto rhs = builder.ConstantR1({1, 1}); + builder.ConvertElementType(builder.Eq(lhs, rhs), S32); + + ComputeAndCompareR1(&builder, {0, 1}, {}); +} + +XLA_TEST_F(UnaryOpTest, ConvertElementTypePredToF32) { + ComputationBuilder builder(client_, TestName()); + auto lhs = builder.ConstantR1({0, 1}); + auto rhs = builder.ConstantR1({1, 1}); + builder.ConvertElementType(builder.Eq(lhs, rhs), F32); + + ComputeAndCompareR1(&builder, {0.0, 1.0}, {}); +} + } // namespace } // namespace xla -- GitLab From 72c420a32702f7a7638c0130a7d7dc1db4469840 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 24 Jan 2018 22:33:14 -0800 Subject: [PATCH 244/258] Automated g4 rollback of changelist 183171572 PiperOrigin-RevId: 183192221 --- .../batch_sequences_with_states_test.py | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/tensorflow/contrib/training/python/training/batch_sequences_with_states_test.py b/tensorflow/contrib/training/python/training/batch_sequences_with_states_test.py index 04538405e4..2a0ef0e6b3 100644 --- a/tensorflow/contrib/training/python/training/batch_sequences_with_states_test.py +++ b/tensorflow/contrib/training/python/training/batch_sequences_with_states_test.py @@ -320,18 +320,6 @@ class BatchSequencesWithStatesTest(test.TestCase): def testNotAMultiple(self): num_unroll = 3 # Not a divisor of value_length - # so padding would have been necessary. - - # Use placeholder_with_default in sequences to make sure we get runtime - # error instead of shape inference error - sequences = { - "seq1": array_ops.placeholder_with_default(self.sequences["seq1"], - shape=(None, 5)), - "seq2": array_ops.placeholder_with_default(self.sequences["seq2"], - shape=(None, 4, 2)), - "seq3": self.sequences["seq3"], - "seq4": self.sequences["seq4"], - } - with self.test_session() as sess: with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, ".*should be a multiple of: 3, but saw " @@ -342,7 +330,7 @@ class BatchSequencesWithStatesTest(test.TestCase): with coord.stop_on_exception(): next_batch = sqss.batch_sequences_with_states( input_key=self.key, - input_sequences=sequences, + input_sequences=self.sequences, input_context=self.context, input_length=3, initial_states=self.initial_states, @@ -505,18 +493,6 @@ class BatchSequencesWithStatesTest(test.TestCase): expected_seq4_batch2=expected_seq4_batch2) -class BatchSequencesWithStatesTestWithCApi(BatchSequencesWithStatesTest): - - def setUp(self): - self._prev_value = ops._USE_C_API - ops._USE_C_API = True - super(BatchSequencesWithStatesTestWithCApi, self).setUp() - - def tearDown(self): - super(BatchSequencesWithStatesTestWithCApi, self).tearDown() - ops._USE_C_API = self._prev_value - - class PaddingTest(test.TestCase): def testPaddingInvalidLengths(self): -- GitLab From 86967885684433c86d4764d82e5d975e3ef4ab8e Mon Sep 17 00:00:00 2001 From: Francois Chollet Date: Wed, 24 Jan 2018 23:36:20 -0800 Subject: [PATCH 245/258] Fix eager Pooling1D unit test for data_format='channels_first' PiperOrigin-RevId: 183196050 --- tensorflow/python/layers/pooling_test.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/layers/pooling_test.py b/tensorflow/python/layers/pooling_test.py index e4d4ed4a2a..7533674e5a 100644 --- a/tensorflow/python/layers/pooling_test.py +++ b/tensorflow/python/layers/pooling_test.py @@ -96,33 +96,41 @@ class PoolingTest(test.TestCase): def testCreateMaxPooling1D(self): width = 7 - images = random_ops.random_uniform((5, width, 4)) + channels = 3 + images = random_ops.random_uniform((5, width, channels)) layer = pooling_layers.MaxPooling1D(2, strides=2) output = layer.apply(images) - self.assertListEqual(output.get_shape().as_list(), [5, 3, 4]) + self.assertListEqual(output.get_shape().as_list(), + [5, width // 2, channels]) def testCreateAveragePooling1D(self): width = 7 - images = random_ops.random_uniform((5, width, 4)) + channels = 3 + images = random_ops.random_uniform((5, width, channels)) layer = pooling_layers.AveragePooling1D(2, strides=2) output = layer.apply(images) - self.assertListEqual(output.get_shape().as_list(), [5, 3, 4]) + self.assertListEqual(output.get_shape().as_list(), + [5, width // 2, channels]) def testCreateMaxPooling1DChannelsFirst(self): width = 7 - images = random_ops.random_uniform((5, 4, width)) + channels = 3 + images = random_ops.random_uniform((5, channels, width)) layer = pooling_layers.MaxPooling1D( 2, strides=2, data_format='channels_first') output = layer.apply(images) - self.assertListEqual(output.get_shape().as_list(), [5, 4, 3]) + self.assertListEqual(output.get_shape().as_list(), + [5, channels, width // 2]) def testCreateAveragePooling1DChannelsFirst(self): width = 7 - images = random_ops.random_uniform((5, 4, width)) + channels = 3 + images = random_ops.random_uniform((5, channels, width)) layer = pooling_layers.AveragePooling1D( 2, strides=2, data_format='channels_first') output = layer.apply(images) - self.assertListEqual(output.get_shape().as_list(), [5, 4, 3]) + self.assertListEqual(output.get_shape().as_list(), + [5, channels, width // 2]) def testCreateMaxPooling3D(self): depth, height, width = 6, 7, 9 -- GitLab From 9814329d58a392af905266a38f68e7212db6eecf Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 25 Jan 2018 00:05:16 -0800 Subject: [PATCH 246/258] Add WarmStartSettings configuration for all Estimators. PiperOrigin-RevId: 183197945 --- tensorflow/python/estimator/canned/dnn.py | 31 +++++------------ .../estimator/canned/dnn_linear_combined.py | 31 +++++------------ tensorflow/python/estimator/canned/linear.py | 31 +++++------------ tensorflow/python/estimator/estimator.py | 34 ++++++++++++++++++- tensorflow/python/estimator/estimator_test.py | 28 +++++++++++++++ .../python/estimator/warm_starting_util.py | 6 ++-- .../tensorflow.estimator.-estimator.pbtxt | 2 +- 7 files changed, 89 insertions(+), 74 deletions(-) diff --git a/tensorflow/python/estimator/canned/dnn.py b/tensorflow/python/estimator/canned/dnn.py index ba96d738ae..0f274a23c0 100644 --- a/tensorflow/python/estimator/canned/dnn.py +++ b/tensorflow/python/estimator/canned/dnn.py @@ -22,7 +22,6 @@ import six from tensorflow.python.estimator import estimator from tensorflow.python.estimator import model_fn -from tensorflow.python.estimator import warm_starting_util from tensorflow.python.estimator.canned import head as head_lib from tensorflow.python.estimator.canned import optimizers from tensorflow.python.feature_column import feature_column as feature_column_lib @@ -340,8 +339,8 @@ class DNNClassifier(estimator.Estimator): loss_reduction=loss_reduction) def _model_fn(features, labels, mode, config): - """Call the defined shared _dnn_model_fn and possibly warm-start.""" - estimator_spec = _dnn_model_fn( + """Call the defined shared _dnn_model_fn.""" + return _dnn_model_fn( features=features, labels=labels, mode=mode, @@ -353,17 +352,10 @@ class DNNClassifier(estimator.Estimator): dropout=dropout, input_layer_partitioner=input_layer_partitioner, config=config) - # pylint: disable=protected-access - warm_start_settings = warm_starting_util._get_default_warm_start_settings( - warm_start_from) - if warm_start_settings: - warm_starting_util._warm_start(warm_start_settings) - # pylint: enable=protected-access - - return estimator_spec super(DNNClassifier, self).__init__( - model_fn=_model_fn, model_dir=model_dir, config=config) + model_fn=_model_fn, model_dir=model_dir, config=config, + warm_start_from=warm_start_from) class DNNRegressor(estimator.Estimator): @@ -490,8 +482,8 @@ class DNNRegressor(estimator.Estimator): """ def _model_fn(features, labels, mode, config): - """Call the defined shared _dnn_model_fn and possibly warm-start.""" - estimator_spec = _dnn_model_fn( + """Call the defined shared _dnn_model_fn.""" + return _dnn_model_fn( features=features, labels=labels, mode=mode, @@ -506,14 +498,7 @@ class DNNRegressor(estimator.Estimator): dropout=dropout, input_layer_partitioner=input_layer_partitioner, config=config) - # pylint: disable=protected-access - warm_start_settings = warm_starting_util._get_default_warm_start_settings( - warm_start_from) - if warm_start_settings: - warm_starting_util._warm_start(warm_start_settings) - # pylint: enable=protected-access - - return estimator_spec super(DNNRegressor, self).__init__( - model_fn=_model_fn, model_dir=model_dir, config=config) + model_fn=_model_fn, model_dir=model_dir, config=config, + warm_start_from=warm_start_from) diff --git a/tensorflow/python/estimator/canned/dnn_linear_combined.py b/tensorflow/python/estimator/canned/dnn_linear_combined.py index d29c892662..1a0f4c5c39 100644 --- a/tensorflow/python/estimator/canned/dnn_linear_combined.py +++ b/tensorflow/python/estimator/canned/dnn_linear_combined.py @@ -23,7 +23,6 @@ import math import six from tensorflow.python.estimator import estimator -from tensorflow.python.estimator import warm_starting_util from tensorflow.python.estimator.canned import dnn from tensorflow.python.estimator.canned import head as head_lib from tensorflow.python.estimator.canned import linear @@ -385,8 +384,8 @@ class DNNLinearCombinedClassifier(estimator.Estimator): loss_reduction=loss_reduction) def _model_fn(features, labels, mode, config): - """Call the _dnn_linear_combined_model_fn and possibly warm-start.""" - estimator_spec = _dnn_linear_combined_model_fn( + """Call the _dnn_linear_combined_model_fn.""" + return _dnn_linear_combined_model_fn( features=features, labels=labels, mode=mode, @@ -400,17 +399,10 @@ class DNNLinearCombinedClassifier(estimator.Estimator): dnn_dropout=dnn_dropout, input_layer_partitioner=input_layer_partitioner, config=config) - # pylint: disable=protected-access - warm_start_settings = warm_starting_util._get_default_warm_start_settings( - warm_start_from) - if warm_start_settings: - warm_starting_util._warm_start(warm_start_settings) - # pylint: enable=protected-access - - return estimator_spec super(DNNLinearCombinedClassifier, self).__init__( - model_fn=_model_fn, model_dir=model_dir, config=config) + model_fn=_model_fn, model_dir=model_dir, config=config, + warm_start_from=warm_start_from) class DNNLinearCombinedRegressor(estimator.Estimator): @@ -554,8 +546,8 @@ class DNNLinearCombinedRegressor(estimator.Estimator): 'must be defined.') def _model_fn(features, labels, mode, config): - """Call the _dnn_linear_combined_model_fn and possibly warm-start.""" - estimator_spec = _dnn_linear_combined_model_fn( + """Call the _dnn_linear_combined_model_fn.""" + return _dnn_linear_combined_model_fn( features=features, labels=labels, mode=mode, @@ -572,14 +564,7 @@ class DNNLinearCombinedRegressor(estimator.Estimator): dnn_dropout=dnn_dropout, input_layer_partitioner=input_layer_partitioner, config=config) - # pylint: disable=protected-access - warm_start_settings = warm_starting_util._get_default_warm_start_settings( - warm_start_from) - if warm_start_settings: - warm_starting_util._warm_start(warm_start_settings) - # pylint: enable=protected-access - - return estimator_spec super(DNNLinearCombinedRegressor, self).__init__( - model_fn=_model_fn, model_dir=model_dir, config=config) + model_fn=_model_fn, model_dir=model_dir, config=config, + warm_start_from=warm_start_from) diff --git a/tensorflow/python/estimator/canned/linear.py b/tensorflow/python/estimator/canned/linear.py index 7a80dfacc2..a5b1172e72 100644 --- a/tensorflow/python/estimator/canned/linear.py +++ b/tensorflow/python/estimator/canned/linear.py @@ -23,7 +23,6 @@ import math import six from tensorflow.python.estimator import estimator -from tensorflow.python.estimator import warm_starting_util from tensorflow.python.estimator.canned import head as head_lib from tensorflow.python.estimator.canned import optimizers from tensorflow.python.feature_column import feature_column as feature_column_lib @@ -305,8 +304,8 @@ class LinearClassifier(estimator.Estimator): loss_reduction=loss_reduction) def _model_fn(features, labels, mode, config): - """Call the defined shared _linear_model_fn and possibly warm-start.""" - estimator_spec = _linear_model_fn( + """Call the defined shared _linear_model_fn.""" + return _linear_model_fn( features=features, labels=labels, mode=mode, @@ -315,19 +314,12 @@ class LinearClassifier(estimator.Estimator): optimizer=optimizer, partitioner=partitioner, config=config) - # pylint: disable=protected-access - warm_start_settings = warm_starting_util._get_default_warm_start_settings( - warm_start_from) - if warm_start_settings: - warm_starting_util._warm_start(warm_start_settings) - # pylint: enable=protected-access - - return estimator_spec super(LinearClassifier, self).__init__( model_fn=_model_fn, model_dir=model_dir, - config=config) + config=config, + warm_start_from=warm_start_from) class LinearRegressor(estimator.Estimator): @@ -432,8 +424,8 @@ class LinearRegressor(estimator.Estimator): loss_reduction=loss_reduction) def _model_fn(features, labels, mode, config): - """Call the defined shared _linear_model_fn and possibly warm-start.""" - estimator_spec = _linear_model_fn( + """Call the defined shared _linear_model_fn.""" + return _linear_model_fn( features=features, labels=labels, mode=mode, @@ -442,16 +434,9 @@ class LinearRegressor(estimator.Estimator): optimizer=optimizer, partitioner=partitioner, config=config) - # pylint: disable=protected-access - warm_start_settings = warm_starting_util._get_default_warm_start_settings( - warm_start_from) - if warm_start_settings: - warm_starting_util._warm_start(warm_start_settings) - # pylint: enable=protected-access - - return estimator_spec super(LinearRegressor, self).__init__( model_fn=_model_fn, model_dir=model_dir, - config=config) + config=config, + warm_start_from=warm_start_from) diff --git a/tensorflow/python/estimator/estimator.py b/tensorflow/python/estimator/estimator.py index 2e914fa7e0..face20d530 100644 --- a/tensorflow/python/estimator/estimator.py +++ b/tensorflow/python/estimator/estimator.py @@ -35,6 +35,7 @@ from tensorflow.python.eager import context from tensorflow.python.estimator import model_fn as model_fn_lib from tensorflow.python.estimator import run_config from tensorflow.python.estimator import util +from tensorflow.python.estimator import warm_starting_util from tensorflow.python.estimator.export.export import build_all_signature_defs from tensorflow.python.estimator.export.export import get_temp_export_dir from tensorflow.python.estimator.export.export import get_timestamped_export_dir @@ -96,9 +97,22 @@ class Estimator(object): @end_compatibility """ - def __init__(self, model_fn, model_dir=None, config=None, params=None): + def __init__(self, model_fn, model_dir=None, config=None, params=None, + warm_start_from=None): """Constructs an `Estimator` instance. + See @{$estimators} for more information. To warm-start an `Estimator`: + + ```python + estimator = tf.estimator.DNNClassifier( + feature_columns=[categorical_feature_a_emb, categorical_feature_b_emb], + hidden_units=[1024, 512, 256], + warm_start_from="/path/to/checkpoint/dir") + ``` + + For more details on warm-start configuration, see + @{tf.estimator.WarmStartSettings$WarmStartSettings}. + Args: model_fn: Model function. Follows the signature: @@ -135,6 +149,12 @@ class Estimator(object): config: Configuration object. params: `dict` of hyper parameters that will be passed into `model_fn`. Keys are names of parameters, values are basic python types. + warm_start_from: Optional string filepath to a checkpoint to warm-start + from, or a `tf.estimator.WarmStartSettings` object to + fully configure warm-starting. If the string filepath is + provided instead of a `WarmStartSettings`, then all + variables are warm-started, and it is assumed that + vocabularies and Tensor names are unchanged. Raises: RuntimeError: If eager execution is enabled. @@ -192,6 +212,11 @@ class Estimator(object): self._model_fn = model_fn self._params = copy.deepcopy(params or {}) + # pylint: disable=protected-access + self._warm_start_settings = ( + warm_starting_util._get_default_warm_start_settings(warm_start_from)) + # pylint: enable=protected-access + @property def model_dir(self): return self._model_dir @@ -781,6 +806,13 @@ class Estimator(object): worker_hooks.extend(input_hooks) estimator_spec = self._call_model_fn( features, labels, model_fn_lib.ModeKeys.TRAIN, self.config) + + if self._warm_start_settings: + logging.info('Warm-starting with WarmStartSettings: %s' % + (self._warm_start_settings,)) + # pylint: disable=protected-access + warm_starting_util._warm_start(self._warm_start_settings) + # pylint: enable=protected-access # Check if the user created a loss summary, and add one if they didn't. # We assume here that the summary is called 'loss'. If it is not, we will # make another one with the name 'loss' to ensure it shows up in the right diff --git a/tensorflow/python/estimator/estimator_test.py b/tensorflow/python/estimator/estimator_test.py index ed1676a92d..833f3dcac3 100644 --- a/tensorflow/python/estimator/estimator_test.py +++ b/tensorflow/python/estimator/estimator_test.py @@ -52,6 +52,7 @@ from tensorflow.python.ops import metrics as metrics_lib from tensorflow.python.ops import parsing_ops from tensorflow.python.ops import state_ops from tensorflow.python.ops import string_ops +from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables from tensorflow.python.ops.losses import losses from tensorflow.python.platform import gfile @@ -629,6 +630,33 @@ class EstimatorTrainTest(test.TestCase): self.assertEqual( 10, estimator._load_global_step_from_checkpoint_dir(est.model_dir)) + def test_warm_starts(self): + def _make_model_fn(x): + def _variable_creating_model_fn(features, labels, mode): + _, _ = features, labels + variable_scope.get_variable('x', initializer=x) + global_step = training.get_global_step() + return model_fn_lib.EstimatorSpec( + mode, + loss=constant_op.constant(1.), + train_op=state_ops.assign_add(global_step, 1)) + return _variable_creating_model_fn + + est = estimator.Estimator(model_fn=_make_model_fn(42.)) + est.train(dummy_input_fn, steps=10) + + warm_started_est = estimator.Estimator( + model_fn=_make_model_fn(36.), + warm_start_from=est.model_dir) + warm_started_est.train(dummy_input_fn, steps=5) + # warm_start is called after the model_fn, so x should have the value + # from the checkpoint. + self.assertEqual(42., warm_started_est.get_variable_value('x')) + # global_step should not be warm-started. + self.assertEqual( + 5, estimator._load_global_step_from_checkpoint_dir( + warm_started_est.model_dir)) + def test_max_step(self): est = estimator.Estimator(model_fn=model_fn_global_step_incrementer) est.train(dummy_input_fn, max_steps=5) diff --git a/tensorflow/python/estimator/warm_starting_util.py b/tensorflow/python/estimator/warm_starting_util.py index c748b318b7..ad95c71234 100644 --- a/tensorflow/python/estimator/warm_starting_util.py +++ b/tensorflow/python/estimator/warm_starting_util.py @@ -402,10 +402,10 @@ def _warm_start_var_with_vocab(var, def _warm_start(warm_start_settings): - """Warmstarts a model using the given settings. + """Warm-starts a model using the given settings. - Currently, this is intended for use only in canned Estimators. Once made - public, it can be used in any model_fn. + If you are using a tf.estimator.Estimator, this will automatically be called + during training. Args: warm_start_settings: An object of `WarmStartSettings`. diff --git a/tensorflow/tools/api/golden/tensorflow.estimator.-estimator.pbtxt b/tensorflow/tools/api/golden/tensorflow.estimator.-estimator.pbtxt index d0bf043754..76f527f796 100644 --- a/tensorflow/tools/api/golden/tensorflow.estimator.-estimator.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.estimator.-estimator.pbtxt @@ -20,7 +20,7 @@ tf_class { } member_method { name: "__init__" - argspec: "args=[\'self\', \'model_fn\', \'model_dir\', \'config\', \'params\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'self\', \'model_fn\', \'model_dir\', \'config\', \'params\', \'warm_start_from\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } member_method { name: "evaluate" -- GitLab From 15b368d31f38547aa3eb69f2c05dacff8ce8858a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 25 Jan 2018 04:48:59 -0800 Subject: [PATCH 247/258] Fixes FunctionLibraryRuntime to be destroyed before ExecutorImpl when NewLocalExecutor returns an error status. PiperOrigin-RevId: 183220585 --- tensorflow/core/common_runtime/direct_session.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/common_runtime/direct_session.cc b/tensorflow/core/common_runtime/direct_session.cc index e9bdd922ba..20c59ad42b 100644 --- a/tensorflow/core/common_runtime/direct_session.cc +++ b/tensorflow/core/common_runtime/direct_session.cc @@ -1143,8 +1143,8 @@ Status DirectSession::GetOrCreateExecutors( options.debug_options = run_state_args->debug_options; } - std::shared_ptr ek(new ExecutorsAndKeys); std::unique_ptr func_info(new FunctionInfo); + std::shared_ptr ek(new ExecutorsAndKeys); // The executor_lock_ is intentionally released while executor is // being created. -- GitLab From 9acbe517b5fa5d3a88770c7a02450d755691beda Mon Sep 17 00:00:00 2001 From: mktozk Date: Fri, 26 Jan 2018 02:01:37 +0900 Subject: [PATCH 248/258] Fix Conv3DTranspose in tf.keras (#16307) * Update convolutional.py Fix Conv3DTranspose * Update tensorflow.keras.layers.-conv3-d-transpose.pbtxt * Update tensorflow.keras.layers.-convolution3-d-transpose.pbtxt * Update convolutional.py * Fix compute_output_shape() in Conv3DTranspose * Fix compute_output_shape() in Conv3DTranspose * Update convolutional.py --- .../python/keras/_impl/keras/layers/convolutional.py | 2 +- tensorflow/python/layers/convolutional.py | 9 ++++++--- .../tensorflow.keras.layers.-conv3-d-transpose.pbtxt | 1 + ...nsorflow.keras.layers.-convolution3-d-transpose.pbtxt | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/keras/_impl/keras/layers/convolutional.py b/tensorflow/python/keras/_impl/keras/layers/convolutional.py index 22496e8a76..f0f5e1fb46 100644 --- a/tensorflow/python/keras/_impl/keras/layers/convolutional.py +++ b/tensorflow/python/keras/_impl/keras/layers/convolutional.py @@ -563,7 +563,7 @@ class Conv2DTranspose(tf_convolutional_layers.Conv2DTranspose, Layer): return dict(list(base_config.items()) + list(config.items())) -class Conv3DTranspose(tf_convolutional_layers.Conv3D, Layer): +class Conv3DTranspose(tf_convolutional_layers.Conv3DTranspose, Layer): """Transposed convolution layer (sometimes called Deconvolution). The need for transposed convolutions generally arises diff --git a/tensorflow/python/layers/convolutional.py b/tensorflow/python/layers/convolutional.py index d5147b237b..e8dba3cea3 100644 --- a/tensorflow/python/layers/convolutional.py +++ b/tensorflow/python/layers/convolutional.py @@ -1904,6 +1904,7 @@ class Conv3DTranspose(Conv3D): dtype=self.dtype) else: self.bias = None + self.built = True def call(self, inputs): inputs_shape = array_ops.shape(inputs) @@ -1974,6 +1975,8 @@ class Conv3DTranspose(Conv3D): if self.use_bias: outputs_shape = outputs.shape.as_list() + if outputs_shape[0] is None: + outputs_shape[0] = -1 if self.data_format == 'channels_first': outputs_4d = array_ops.reshape(outputs, [ outputs_shape[0], outputs_shape[1], @@ -2007,11 +2010,11 @@ class Conv3DTranspose(Conv3D): output_shape[c_axis] = self.filters output_shape[d_axis] = utils.deconv_output_length( - output_shape[d_axis], stride_d, kernel_d, self.padding) + output_shape[d_axis], kernel_d, self.padding, stride_d) output_shape[h_axis] = utils.deconv_output_length( - output_shape[h_axis], stride_h, kernel_h, self.padding) + output_shape[h_axis], kernel_h, self.padding, stride_h) output_shape[w_axis] = utils.deconv_output_length( - output_shape[w_axis], stride_w, kernel_w, self.padding) + output_shape[w_axis], kernel_w, self.padding, stride_w) return tensor_shape.TensorShape(output_shape) diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-conv3-d-transpose.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-conv3-d-transpose.pbtxt index d898c54627..11e05f884d 100644 --- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-conv3-d-transpose.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-conv3-d-transpose.pbtxt @@ -1,6 +1,7 @@ path: "tensorflow.keras.layers.Conv3DTranspose" tf_class { is_instance: "" + is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-convolution3-d-transpose.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-convolution3-d-transpose.pbtxt index a7001bbe34..58724a1e16 100644 --- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-convolution3-d-transpose.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-convolution3-d-transpose.pbtxt @@ -1,6 +1,7 @@ path: "tensorflow.keras.layers.Convolution3DTranspose" tf_class { is_instance: "" + is_instance: "" is_instance: "" is_instance: "" is_instance: "" -- GitLab From 76d621efecc63a08821c294390115ff5f96d47e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kapica?= Date: Thu, 25 Jan 2018 18:02:17 +0100 Subject: [PATCH 249/258] RGB<->YIQ colorspace conversion (#15555) * image colorspace conversion using tensordot op * fixed bug with assuming input tensor is 4D * fix * fix - push with all changes commited * fix tuple object in np.random.rand * updated goldens --- tensorflow/python/ops/image_ops.py | 4 + tensorflow/python/ops/image_ops_impl.py | 103 ++++++++++++++++++ tensorflow/python/ops/image_ops_test.py | 58 ++++++++++ .../tools/api/golden/tensorflow.image.pbtxt | 16 +++ 4 files changed, 181 insertions(+) diff --git a/tensorflow/python/ops/image_ops.py b/tensorflow/python/ops/image_ops.py index 3b0b5a978c..de12c5f63f 100644 --- a/tensorflow/python/ops/image_ops.py +++ b/tensorflow/python/ops/image_ops.py @@ -49,6 +49,10 @@ See the @{$python/image} guide. @@grayscale_to_rgb @@hsv_to_rgb @@rgb_to_hsv +@@rgb_to_yiq +@@yiq_to_rgb +@@rgb_to_yuv +@@yuv_to_rgb @@convert_image_dtype @@adjust_brightness @@random_brightness diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 9bd452155c..721efcf786 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -1668,3 +1668,106 @@ def non_max_suppression(boxes, return gen_image_ops._non_max_suppression_v2(boxes, scores, max_output_size, iou_threshold) # pylint: enable=protected-access + + +_rgb_to_yiq_kernel = [[0.299, 0.59590059, 0.2115], + [0.587, -0.27455667, -0.52273617], + [0.114, -0.32134392, 0.31119955]] + + +def rgb_to_yiq(images): + """Converts one or more images from RGB to YIQ. + + Outputs a tensor of the same shape as the `images` tensor, containing the YIQ + value of the pixels. + The output is only well defined if the value in images are in [0,1]. + + Args: + images: 2-D or higher rank. Image data to convert. Last dimension must be + size 3. + + Returns: + images: tensor with the same shape as `images`. + """ + images = ops.convert_to_tensor(images, name='images') + kernel = ops.convert_to_tensor(_rgb_to_yiq_kernel, dtype=images.dtype, name='kernel') + ndims = images.get_shape().ndims + return math_ops.tensordot(images, kernel, axes=[[ndims-1], [0]]) + + +_yiq_to_rgb_kernel = [[1, 1, 1], + [0.95598634, -0.27201283, -1.10674021], + [0.6208248, -0.64720424, 1.70423049]] + + +def yiq_to_rgb(images): + """Converts one or more images from YIQ to RGB. + + Outputs a tensor of the same shape as the `images` tensor, containing the RGB + value of the pixels. + The output is only well defined if the Y value in images are in [0,1], + I value are in [-0.5957,0.5957] and Q value are in [-0.5226,0.5226]. + + Args: + images: 2-D or higher rank. Image data to convert. Last dimension must be + size 3. + + Returns: + images: tensor with the same shape as `images`. + """ + images = ops.convert_to_tensor(images, name='images') + kernel = ops.convert_to_tensor(_yiq_to_rgb_kernel, dtype=images.dtype, name='kernel') + ndims = images.get_shape().ndims + return math_ops.tensordot(images, kernel, axes=[[ndims-1], [0]]) + + +_rgb_to_yuv_kernel = [[0.299, -0.14714119, 0.61497538], + [0.587, -0.28886916, -0.51496512], + [0.114, 0.43601035, -0.10001026]] + + +def rgb_to_yuv(images): + """Converts one or more images from RGB to YUV. + + Outputs a tensor of the same shape as the `images` tensor, containing the YUV + value of the pixels. + The output is only well defined if the value in images are in [0,1]. + + Args: + images: 2-D or higher rank. Image data to convert. Last dimension must be + size 3. + + Returns: + images: tensor with the same shape as `images`. + """ + images = ops.convert_to_tensor(images, name='images') + kernel = ops.convert_to_tensor(_rgb_to_yuv_kernel, dtype=images.dtype, name='kernel') + ndims = images.get_shape().ndims + return math_ops.tensordot(images, kernel, axes=[[ndims-1], [0]]) + + +_yuv_to_rgb_kernel = [[1, 1, 1], + [0, -0.394642334, 2.03206185], + [1.13988303, -0.58062185, 0]] + + +def yuv_to_rgb(images): + """Converts one or more images from YUV to RGB. + + Outputs a tensor of the same shape as the `images` tensor, containing the RGB + value of the pixels. + The output is only well defined if the Y value in images are in [0,1], + U and V value are in [-0.5,0.5]. + + Args: + images: 2-D or higher rank. Image data to convert. Last dimension must be + size 3. + + Returns: + images: tensor with the same shape as `images`. + """ + images = ops.convert_to_tensor(images, name='images') + kernel = ops.convert_to_tensor(_yuv_to_rgb_kernel, dtype=images.dtype, name='kernel') + ndims = images.get_shape().ndims + return math_ops.tensordot(images, kernel, axes=[[ndims-1], [0]]) + diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index 0c5ed2150d..9834384634 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -85,6 +85,64 @@ class RGBToHSVTest(test_util.TensorFlowTestCase): self.assertAllClose(rgb_tf, rgb_np) +class RGBToYIQTest(test_util.TensorFlowTestCase): + + def testBatch(self): + # Build an arbitrary RGB image + np.random.seed(7) + batch_size = 5 + shape = (batch_size, 2, 7, 3) + + for nptype in [np.float32, np.float64]: + inp = np.random.rand(*shape).astype(nptype) + + # Convert to YIQ and back, as a batch and individually + with self.test_session(use_gpu=True) as sess: + batch0 = constant_op.constant(inp) + batch1 = image_ops.rgb_to_yiq(batch0) + batch2 = image_ops.yiq_to_rgb(batch1) + split0 = array_ops.unstack(batch0) + split1 = list(map(image_ops.rgb_to_yiq, split0)) + split2 = list(map(image_ops.yiq_to_rgb, split1)) + join1 = array_ops.stack(split1) + join2 = array_ops.stack(split2) + batch1, batch2, join1, join2 = sess.run([batch1, batch2, join1, join2]) + + # Verify that processing batch elements together is the same as separate + self.assertAllClose(batch1, join1, rtol=1e-4, atol=1e-4) + self.assertAllClose(batch2, join2, rtol=1e-4, atol=1e-4) + self.assertAllClose(batch2, inp, rtol=1e-4, atol=1e-4) + + +class RGBToYUVTest(test_util.TensorFlowTestCase): + + def testBatch(self): + # Build an arbitrary RGB image + np.random.seed(7) + batch_size = 5 + shape = (batch_size, 2, 7, 3) + + for nptype in [np.float32, np.float64]: + inp = np.random.rand(*shape).astype(nptype) + + # Convert to YUV and back, as a batch and individually + with self.test_session(use_gpu=True) as sess: + batch0 = constant_op.constant(inp) + batch1 = image_ops.rgb_to_yuv(batch0) + batch2 = image_ops.yuv_to_rgb(batch1) + split0 = array_ops.unstack(batch0) + split1 = list(map(image_ops.rgb_to_yuv, split0)) + split2 = list(map(image_ops.yuv_to_rgb, split1)) + join1 = array_ops.stack(split1) + join2 = array_ops.stack(split2) + batch1, batch2, join1, join2 = sess.run([batch1, batch2, join1, join2]) + + # Verify that processing batch elements together is the same as separate + self.assertAllClose(batch1, join1, rtol=1e-4, atol=1e-4) + self.assertAllClose(batch2, join2, rtol=1e-4, atol=1e-4) + self.assertAllClose(batch2, inp, rtol=1e-4, atol=1e-4) + + class GrayscaleToRGBTest(test_util.TensorFlowTestCase): def _RGBToGrayscale(self, images): diff --git a/tensorflow/tools/api/golden/tensorflow.image.pbtxt b/tensorflow/tools/api/golden/tensorflow.image.pbtxt index 441621a2a0..baedf596e8 100644 --- a/tensorflow/tools/api/golden/tensorflow.image.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.image.pbtxt @@ -168,6 +168,14 @@ tf_module { name: "rgb_to_hsv" argspec: "args=[\'images\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "rgb_to_yiq" + argspec: "args=[\'images\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "rgb_to_yuv" + argspec: "args=[\'images\'], varargs=None, keywords=None, defaults=None" + } member_method { name: "rot90" argspec: "args=[\'image\', \'k\', \'name\'], varargs=None, keywords=None, defaults=[\'1\', \'None\'], " @@ -184,4 +192,12 @@ tf_module { name: "transpose_image" argspec: "args=[\'image\'], varargs=None, keywords=None, defaults=None" } + member_method { + name: "yiq_to_rgb" + argspec: "args=[\'images\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "yuv_to_rgb" + argspec: "args=[\'images\'], varargs=None, keywords=None, defaults=None" + } } -- GitLab From ee8b13791a921964cad1fc699e72ff1f738b704f Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Thu, 25 Jan 2018 09:42:55 -0800 Subject: [PATCH 250/258] Improve SkipNBytes to RandomInputStream (#14557) * Convert SkipNBytes in InputStreamInterface to pure virtual This fix tries to address the issue raised in 14512 where SkipNBytes will takes a long time as it needs to read through the file even though it is possible to random access. This fix convert SkipNBytes in InputStreamInterface to pure virtual so that it is possible to have different implementations based on the underlying file type (seekable vs. no seekable) This fix fixes 14512. Signed-off-by: Yong Tang * Add missing implementation in inputstream_interface_test.cc Signed-off-by: Yong Tang * Update implementation of RandomInputStream So that if random access read of 1 byte to the expected pos is able to complete then return immediately. Otherwise, read through until the pos is reached. Signed-off-by: Yong Tang * Add SkipNBytes to SnappyInputBuffer Signed-off-by: Yong Tang * Remove inputstream_interface.cc from makefile Signed-off-by: Yong Tang * Remove pure virtual and use override for RandomInputStream Signed-off-by: Yong Tang --- tensorflow/core/lib/io/random_inputstream.cc | 37 ++++++++++++++++++++ tensorflow/core/lib/io/random_inputstream.h | 2 ++ 2 files changed, 39 insertions(+) diff --git a/tensorflow/core/lib/io/random_inputstream.cc b/tensorflow/core/lib/io/random_inputstream.cc index 8b8c1392a1..09336e79cd 100644 --- a/tensorflow/core/lib/io/random_inputstream.cc +++ b/tensorflow/core/lib/io/random_inputstream.cc @@ -57,6 +57,43 @@ Status RandomAccessInputStream::ReadNBytes(int64 bytes_to_read, return Status::OK(); } +// To limit memory usage, the default implementation of SkipNBytes() only reads +// 8MB at a time. +static constexpr int64 kMaxSkipSize = 8 * 1024 * 1024; + +Status RandomAccessInputStream::SkipNBytes(int64 bytes_to_skip) { + if (bytes_to_skip < 0) { + return errors::InvalidArgument("Can't skip a negative number of bytes"); + } + std::unique_ptr scratch(new char[kMaxSkipSize]); + // Try to read 1 bytes first, if we could complete the read then EOF is + // not reached yet and we could return. + if (bytes_to_skip > 0) { + StringPiece data; + Status s = file_->Read(pos_ + bytes_to_skip - 1, 1, &data, scratch.get()); + if ((s.ok() || errors::IsOutOfRange(s)) && data.size() == 1) { + pos_ += bytes_to_skip; + return Status::OK(); + } + } + // Read kDefaultSkipSize at a time till bytes_to_skip. + while (bytes_to_skip > 0) { + int64 bytes_to_read = std::min(kMaxSkipSize, bytes_to_skip); + StringPiece data; + Status s = file_->Read(pos_, bytes_to_read, &data, scratch.get()); + if (s.ok() || errors::IsOutOfRange(s)) { + pos_ += data.size(); + } else { + return s; + } + if (data.size() < bytes_to_read) { + return errors::OutOfRange("reached end of file"); + } + bytes_to_skip -= bytes_to_read; + } + return Status::OK(); +} + int64 RandomAccessInputStream::Tell() const { return pos_; } } // namespace io diff --git a/tensorflow/core/lib/io/random_inputstream.h b/tensorflow/core/lib/io/random_inputstream.h index 09ebe9ba49..bdbdbd71ff 100644 --- a/tensorflow/core/lib/io/random_inputstream.h +++ b/tensorflow/core/lib/io/random_inputstream.h @@ -34,6 +34,8 @@ class RandomAccessInputStream : public InputStreamInterface { Status ReadNBytes(int64 bytes_to_read, string* result) override; + Status SkipNBytes(int64 bytes_to_skip) override; + int64 Tell() const override; Status Seek(int64 position) { -- GitLab From f492fac8e31f15b9529d20f9787cafc888669fbc Mon Sep 17 00:00:00 2001 From: Sam Matzek Date: Thu, 25 Jan 2018 12:39:31 -0600 Subject: [PATCH 251/258] Build libjpeg-turbo ALTIVEC SIMD (#16409) The libjpeg-turbo package has ALTIVEC SIMD and this updates the third_party build to build the ALTIVEC SIMD on the appropriate platform. --- third_party/jpeg/jpeg.BUILD | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/third_party/jpeg/jpeg.BUILD b/third_party/jpeg/jpeg.BUILD index 37924125cf..ca2d38d687 100644 --- a/third_party/jpeg/jpeg.BUILD +++ b/third_party/jpeg/jpeg.BUILD @@ -34,6 +34,10 @@ libjpegturbo_copts = select({ "-mfloat-abi=softfp", "-fprefetch-loop-arrays", ], + ":linux_ppc64le": [ + "-mcpu=power8", + "-mtune=power8", + ], "//conditions:default": [], }) @@ -123,10 +127,50 @@ cc_library( ":k8": [":simd_x86_64"], ":armeabi-v7a": [":simd_armv7a"], ":arm64-v8a": [":simd_armv8a"], + ":linux_ppc64le": [":simd_altivec"], "//conditions:default": [":simd_none"], }), ) +cc_library( + name = "simd_altivec", + srcs = [ + "jchuff.h", + "jconfig.h", + "jdct.h", + "jerror.h", + "jinclude.h", + "jmorecfg.h", + "jpegint.h", + "jpeglib.h", + "jsimd.h", + "jsimddct.h", + "simd/jsimd.h", + "simd/jccolor-altivec.c", + "simd/jcgray-altivec.c", + "simd/jcsample-altivec.c", + "simd/jdcolor-altivec.c", + "simd/jdmerge-altivec.c", + "simd/jdsample-altivec.c", + "simd/jfdctfst-altivec.c", + "simd/jfdctint-altivec.c", + "simd/jidctfst-altivec.c", + "simd/jidctint-altivec.c", + "simd/jquanti-altivec.c", + "simd/jsimd_powerpc.c", + "simd/jsimd_altivec.h", + "simd/jcsample.h", + ], + hdrs = [ + "simd/jdmrgext-altivec.c", # should have been named .inc + "simd/jccolext-altivec.c", # should have been named .inc + "simd/jcgryext-altivec.c", # should have been named .inc + "simd/jdcolext-altivec.c", # should have been named .inc + ], + copts = libjpegturbo_copts, + nocopts = libjpegturbo_nocopts, +) + cc_library( name = "simd_x86_64", srcs = [ @@ -381,6 +425,7 @@ genrule( ":k8": "cp $(location jconfig_nowin_simd.h) $@", ":armeabi-v7a": "cp $(location jconfig_nowin_simd.h) $@", ":arm64-v8a": "cp $(location jconfig_nowin_simd.h) $@", + ":linux_ppc64le": "cp $(location jconfig_nowin_simd.h) $@", "//conditions:default": "cp $(location jconfig_nowin_nosimd.h) $@", }), ) @@ -498,3 +543,9 @@ config_setting( name = "windows_msvc", values = {"cpu": "x64_windows_msvc"}, ) + +config_setting( + name = "linux_ppc64le", + values = {"cpu": "ppc"}, + +) -- GitLab From dcb918a8f64790c615d1ec018b7b6e141a6a8653 Mon Sep 17 00:00:00 2001 From: Jerome Date: Fri, 26 Jan 2018 02:41:30 +0800 Subject: [PATCH 252/258] Modified Implementation of ndlstm_base_dynamic. (#16402) * Added ctc_loss_dense_labels. This does the conversion of dense labels into sparse ones to be passed into the core ctc_loss function. * Removed constant_op from the import. * Matched ctc_loss_dense_labels with the other layers ops. * Added ctc_loss_dense_labels to contrib.layers __init__.py file * Added missing comma to list of ops. * Reordred arguments for ctc_loss_dense_labels Labels should be first then inputs for ctc_loss. * Removed ctc_loss_dense_labels. Replaced it with dense_to_sparse instead so that there'll be only one ctc_loss function. * Replaced ctc_loss_dense_labels with dense_to_sparse * Fixed dense_to_sparse. Some of the names of the variables did not match with that of the parameters. * Updated documentation for dense_to_sparse since it can accept a tensor of any shape. * Added test case for dense_to_sparse. * Updated documentation. Dense to sparse accepts int tensors. * Fixed testDenseFromConstantToSparse. The sparse_to_dense order of arguments in the test are wrong and the expected constant should be of int64. * Modified implementation of ndlstm_base_dynamic. It now uses a BasicLSTMCell that has state_is_tuple=True to address deprecation. Right now it is still unknown why it was set to false in the first place. --- tensorflow/contrib/ndlstm/python/lstm1d.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tensorflow/contrib/ndlstm/python/lstm1d.py b/tensorflow/contrib/ndlstm/python/lstm1d.py index d3c3531f40..b24e332e4a 100644 --- a/tensorflow/contrib/ndlstm/python/lstm1d.py +++ b/tensorflow/contrib/ndlstm/python/lstm1d.py @@ -22,7 +22,6 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.contrib.framework.python.ops import variables from tensorflow.python.framework import constant_op from tensorflow.python.ops import array_ops -from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import rnn @@ -85,18 +84,11 @@ def ndlstm_base_dynamic(inputs, noutput, scope=None, reverse=False): Output sequence (length, batch_size, noutput) """ with variable_scope.variable_scope(scope, "SeqLstm", [inputs]): - # TODO(tmb) make batch size, sequence_length dynamic - # example: sequence_length = tf.shape(inputs)[0] - _, batch_size, _ = _shape(inputs) - lstm_cell = rnn_cell.BasicLSTMCell(noutput, state_is_tuple=False) - state = array_ops.zeros([batch_size, lstm_cell.state_size]) - sequence_length = int(inputs.get_shape()[0]) - sequence_lengths = math_ops.to_int64( - array_ops.fill([batch_size], sequence_length)) + lstm_cell = rnn_cell.BasicLSTMCell(noutput) if reverse: inputs = array_ops.reverse_v2(inputs, [0]) outputs, _ = rnn.dynamic_rnn( - lstm_cell, inputs, sequence_lengths, state, time_major=True) + lstm_cell, inputs, time_major=True, dtype=inputs.dtype) if reverse: outputs = array_ops.reverse_v2(outputs, [0]) return outputs -- GitLab From ab9ff0047b10dbca2bf819d4656a59213f98184a Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Fri, 26 Jan 2018 03:52:06 +0900 Subject: [PATCH 253/258] fix typos (#16384) --- tensorflow/compiler/xla/client/computation_builder.h | 2 +- tensorflow/tools/docs/pretty_docs.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/compiler/xla/client/computation_builder.h b/tensorflow/compiler/xla/client/computation_builder.h index d82ba63e8a..ea4cdb7667 100644 --- a/tensorflow/compiler/xla/client/computation_builder.h +++ b/tensorflow/compiler/xla/client/computation_builder.h @@ -67,7 +67,7 @@ class ComputationBuilder { // OpMetadata is often applied to a series of XLA HLO instructions. As a // result, OpMetadata is set on the Computation Builder. All subsequent // instructions generated via this Computation Builder will have the same - // OpMetadata attached until a call to ClearOpMetdata. + // OpMetadata attached until a call to ClearOpMetadata. void SetOpMetadata(const OpMetadata& metadata) { metadata_ = metadata; } // Clears the HloMetadata state. diff --git a/tensorflow/tools/docs/pretty_docs.py b/tensorflow/tools/docs/pretty_docs.py index c033c16ae9..b5df633800 100644 --- a/tensorflow/tools/docs/pretty_docs.py +++ b/tensorflow/tools/docs/pretty_docs.py @@ -323,7 +323,7 @@ class _Metadata(object): """ def __init__(self, name): - """Creata a Metadata builder. + """Create a Metadata builder. Args: name: The name of the page being described by the Metadata block. -- GitLab From 5b8e8ce30c4f424b5a9c2906e2d95bc177181133 Mon Sep 17 00:00:00 2001 From: ted chang Date: Thu, 25 Jan 2018 11:05:08 -0800 Subject: [PATCH 254/258] Add additional argument to freeze_graph (#15906) --- tensorflow/python/tools/freeze_graph.py | 22 ++++++++++++++------ tensorflow/python/tools/freeze_graph_test.py | 3 ++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tensorflow/python/tools/freeze_graph.py b/tensorflow/python/tools/freeze_graph.py index 0ddf09260b..a2e86a1c43 100644 --- a/tensorflow/python/tools/freeze_graph.py +++ b/tensorflow/python/tools/freeze_graph.py @@ -72,7 +72,8 @@ def freeze_graph_with_def_protos(input_graph_def, variable_names_blacklist="", input_meta_graph_def=None, input_saved_model_dir=None, - saved_model_tags=None): + saved_model_tags=None, + checkpoint_version=saver_pb2.SaverDef.V2): """Converts all variables in a graph and checkpoint into constants.""" del restore_op_name, filename_tensor_name # Unused by updated loading code. @@ -100,7 +101,8 @@ def freeze_graph_with_def_protos(input_graph_def, _ = importer.import_graph_def(input_graph_def, name="") with session.Session() as sess: if input_saver_def: - saver = saver_lib.Saver(saver_def=input_saver_def) + saver = saver_lib.Saver(saver_def=input_saver_def, + write_version=checkpoint_version) saver.restore(sess, input_checkpoint) elif input_meta_graph_def: restorer = saver_lib.import_meta_graph( @@ -124,7 +126,8 @@ def freeze_graph_with_def_protos(input_graph_def, # 'global_step' or a similar housekeeping element) so skip it. continue var_list[key] = tensor - saver = saver_lib.Saver(var_list=var_list) + saver = saver_lib.Saver(var_list=var_list, + write_version=checkpoint_version) saver.restore(sess, input_checkpoint) if initializer_nodes: sess.run(initializer_nodes.split(",")) @@ -217,7 +220,8 @@ def freeze_graph(input_graph, variable_names_blacklist="", input_meta_graph=None, input_saved_model_dir=None, - saved_model_tags=tag_constants.SERVING): + saved_model_tags=tag_constants.SERVING, + checkpoint_version=saver_pb2.SaverDef.V2): """Converts all variables in a graph and checkpoint into constants.""" input_graph_def = None if input_saved_model_dir: @@ -236,7 +240,8 @@ def freeze_graph(input_graph, input_graph_def, input_saver_def, input_checkpoint, output_node_names, restore_op_name, filename_tensor_name, output_graph, clear_devices, initializer_nodes, variable_names_whitelist, variable_names_blacklist, - input_meta_graph_def, input_saved_model_dir, saved_model_tags.split(",")) + input_meta_graph_def, input_saved_model_dir, + saved_model_tags.split(","), checkpoint_version=checkpoint_version) def main(unused_args): @@ -246,7 +251,7 @@ def main(unused_args): FLAGS.output_graph, FLAGS.clear_devices, FLAGS.initializer_nodes, FLAGS.variable_names_whitelist, FLAGS.variable_names_blacklist, FLAGS.input_meta_graph, FLAGS.input_saved_model_dir, - FLAGS.saved_model_tags) + FLAGS.saved_model_tags, checkpoint_version=checkpoint_version) if __name__ == "__main__": @@ -267,6 +272,11 @@ if __name__ == "__main__": type=str, default="", help="TensorFlow variables file to load.") + parser.add_argument( + "--checkpoint_version", + type=int, + default=saver_pb2.SaverDef.V2, + help="Tensorflow variable file format") parser.add_argument( "--output_graph", type=str, diff --git a/tensorflow/python/tools/freeze_graph_test.py b/tensorflow/python/tools/freeze_graph_test.py index feeed7102c..342732465d 100644 --- a/tensorflow/python/tools/freeze_graph_test.py +++ b/tensorflow/python/tools/freeze_graph_test.py @@ -86,7 +86,8 @@ class FreezeGraphTest(test_util.TensorFlowTestCase): freeze_graph.freeze_graph( input_graph_path, input_saver_def_path, input_binary, checkpoint_path, output_node_names, restore_op_name, filename_tensor_name, - output_graph_path, clear_devices, "", "", input_meta_graph) + output_graph_path, clear_devices, "", "", input_meta_graph, + checkpoint_version=saver_write_version) # Now we make sure the variable is now a constant, and that the graph still # produces the expected result. -- GitLab From 2a16133061ba3f8fa60c0338cd629f2211f9b17d Mon Sep 17 00:00:00 2001 From: ted chang Date: Thu, 25 Jan 2018 11:16:27 -0800 Subject: [PATCH 255/258] Add checkpoint file prefix check (#14341) Additionally fix Two failed tests caused by the PR Fixes #9465 --- .../contrib/slim/python/slim/evaluation_test.py | 2 +- tensorflow/python/training/saver.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/slim/python/slim/evaluation_test.py b/tensorflow/contrib/slim/python/slim/evaluation_test.py index 870f504d10..f5a9299d26 100644 --- a/tensorflow/contrib/slim/python/slim/evaluation_test.py +++ b/tensorflow/contrib/slim/python/slim/evaluation_test.py @@ -236,7 +236,7 @@ class SingleEvaluationTest(test.TestCase): def _prepareCheckpoint(self, checkpoint_path): init_op = control_flow_ops.group(variables.global_variables_initializer(), variables.local_variables_initializer()) - saver = saver_lib.Saver(write_version=saver_pb2.SaverDef.V1) + saver = saver_lib.Saver() with self.test_session() as sess: sess.run(init_op) saver.save(sess, checkpoint_path) diff --git a/tensorflow/python/training/saver.py b/tensorflow/python/training/saver.py index 2c59b82ebe..4f3773c0fc 100644 --- a/tensorflow/python/training/saver.py +++ b/tensorflow/python/training/saver.py @@ -1592,9 +1592,9 @@ class Saver(object): [Stripping Default-Valued Attributes](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md#stripping-default-valued-attributes). Returns: - A string: path prefix used for the checkpoint files. If the saver is - sharded, this string ends with: '-?????-of-nnnnn' where 'nnnnn' - is the number of shards created. + A string: path prefix used for the checkpoint files. If checkpoint + format is V1 and the saver is sharded, this string ends with: + '-?????-of-nnnnn' where 'nnnnn' is the number of shards created. If the saver is empty, returns None. Raises: @@ -1744,6 +1744,11 @@ class Saver(object): return if save_path is None: raise ValueError("Can't load save_path when it is None.") + if (os.path.isfile(save_path) and + self._write_version != saver_pb2.SaverDef.V1): + raise ValueError("The specified path: %s is a file." + " Please specify only the path prefix" + " to the checkpoint files." % save_path) logging.info("Restoring parameters from %s", save_path) if context.in_graph_mode(): sess.run(self.saver_def.restore_op_name, -- GitLab From 45d47f30243dd4a26705f24b2a82188b0ec9b7d2 Mon Sep 17 00:00:00 2001 From: Andrew Harp Date: Thu, 25 Jan 2018 14:56:22 -0500 Subject: [PATCH 256/258] Don't load libcupti.so from regular path on Android (#16303) * Don't load libcupti.so from regular path on Android * replace NVIDIA_TEGRA with ANDROID_TEGRA to be less redundant and more specific --- tensorflow/contrib/makefile/Makefile | 6 +++--- tensorflow/core/common_runtime/gpu/gpu_device.cc | 2 +- tensorflow/core/framework/register_types.h | 2 +- tensorflow/stream_executor/cuda/cuda_diagnostics.cc | 2 +- tensorflow/stream_executor/dso_loader.cc | 8 ++++++++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/tensorflow/contrib/makefile/Makefile b/tensorflow/contrib/makefile/Makefile index dd5770dc99..c50f8ceec0 100644 --- a/tensorflow/contrib/makefile/Makefile +++ b/tensorflow/contrib/makefile/Makefile @@ -377,10 +377,10 @@ $(MARCH_OPTION) \ ifeq ($(BUILD_FOR_TEGRA),1) NVCC := $(JETPACK)/cuda/bin/nvcc - NVCCFLAGS := -x=cu -D__CUDACC__ -DNVCC -DNVIDIA_TEGRA -ccbin $(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/$(ANDROID_HOST_OS_ARCH)/bin/$(BIN_PREFIX)-g++ --std c++11 --expt-relaxed-constexpr -m64 -gencode arch=compute_53,\"code=sm_53\" -gencode arch=compute_62,\"code=sm_62\" -DEIGEN_AVOID_STL_ARRAY -DTENSORFLOW_USE_EIGEN_THREADPOOL -DLANG_CXX11 -DEIGEN_HAS_C99_MATH -DGOOGLE_CUDA=1 -DTF_EXTRA_CUDA_CAPABILITIES=5.3 + NVCCFLAGS := -x=cu -D__CUDACC__ -DNVCC -DANDROID_TEGRA -ccbin $(NDK_ROOT)/toolchains/$(TOOLCHAIN)/prebuilt/$(ANDROID_HOST_OS_ARCH)/bin/$(BIN_PREFIX)-g++ --std c++11 --expt-relaxed-constexpr -m64 -gencode arch=compute_53,\"code=sm_53\" -gencode arch=compute_62,\"code=sm_62\" -DEIGEN_AVOID_STL_ARRAY -DTENSORFLOW_USE_EIGEN_THREADPOOL -DLANG_CXX11 -DEIGEN_HAS_C99_MATH -DGOOGLE_CUDA=1 -DTF_EXTRA_CUDA_CAPABILITIES=5.3 CXXFLAGS4NVCC =\ -DIS_SLIM_BUILD \ --DNVIDIA_TEGRA \ +-DANDROID_TEGRA \ -fno-exceptions \ -DNDEBUG $(OPTFLAGS) \ -march=armv8-a \ @@ -391,7 +391,7 @@ $(MARCH_OPTION) \ CXXFLAGS +=\ -DGOOGLE_CUDA=1 \ -D__ANDROID_TYPES_FULL__ \ --DNVIDIA_TEGRA \ +-DANDROID_TEGRA \ -DEIGEN_AVOID_STL_ARRAY \ -DEIGEN_HAS_C99_MATH \ -DLANG_CXX11 -DTENSORFLOW_USE_EIGEN_THREADPOOL -DTF_EXTRA_CUDA_CAPABILITIES=5.3 diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.cc b/tensorflow/core/common_runtime/gpu/gpu_device.cc index 0e5b6b7ef8..933d700f60 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device.cc @@ -762,7 +762,7 @@ int64 MinSystemMemory(int64 available_memory) { // is necessary. min_system_memory *= 2; #endif -#if defined(NVIDIA_TEGRA) +#if defined(ANDROID_TEGRA) // 1GB system mem for NVIDIA Tegra devices since they use the same mem for RAM and Video RAM min_system_memory = 1<<30; #endif diff --git a/tensorflow/core/framework/register_types.h b/tensorflow/core/framework/register_types.h index edc93aec7f..e062adffe8 100644 --- a/tensorflow/core/framework/register_types.h +++ b/tensorflow/core/framework/register_types.h @@ -53,7 +53,7 @@ limitations under the License. */ #if !defined(IS_MOBILE_PLATFORM) || defined(SUPPORT_SELECTIVE_REGISTRATION) || \ - defined(NVIDIA_TEGRA) + defined(ANDROID_TEGRA) // All types are supported, so all macros are invoked. // diff --git a/tensorflow/stream_executor/cuda/cuda_diagnostics.cc b/tensorflow/stream_executor/cuda/cuda_diagnostics.cc index f35542e18f..933c103f52 100644 --- a/tensorflow/stream_executor/cuda/cuda_diagnostics.cc +++ b/tensorflow/stream_executor/cuda/cuda_diagnostics.cc @@ -232,7 +232,7 @@ port::StatusOr Diagnostician::FindDsoVersion() { result = StringToDriverVersion(version); } #else -#if !defined(PLATFORM_WINDOWS) && !defined(NVIDIA_TEGRA) +#if !defined(PLATFORM_WINDOWS) && !defined(ANDROID_TEGRA) // Callback used when iterating through DSOs. Looks for the driver-interfacing // DSO and yields its version number into the callback data, when found. auto iterate_phdr = diff --git a/tensorflow/stream_executor/dso_loader.cc b/tensorflow/stream_executor/dso_loader.cc index 5210a81092..d71938634d 100644 --- a/tensorflow/stream_executor/dso_loader.cc +++ b/tensorflow/stream_executor/dso_loader.cc @@ -96,10 +96,18 @@ string GetCudnnVersion() { return TF_CUDNN_VERSION; } } /* static */ port::Status DsoLoader::GetLibcuptiDsoHandle(void** dso_handle) { +#if defined(ANDROID_TEGRA) + // On Android devices the CUDA version number is not added to the library name. + return GetDsoHandle(FindDsoPath(port::Env::Default()->FormatLibraryFileName( + "cupti", ""), + GetCudaCuptiLibraryPath()), + dso_handle); +#else return GetDsoHandle(FindDsoPath(port::Env::Default()->FormatLibraryFileName( "cupti", GetCudaVersion()), GetCudaCuptiLibraryPath()), dso_handle); +#endif } static mutex& GetRpathMutex() { -- GitLab From dce14f5d38a19b3a19c834a877acc0042f1e9fbd Mon Sep 17 00:00:00 2001 From: Viraj Navkal Date: Thu, 25 Jan 2018 13:11:40 -0800 Subject: [PATCH 257/258] Remove calculation of unnecessary matrix columns in SVD gradient (#15801) * remove calculation of unnecessary matrix columns in svd gradient * simplify expression for svd gradient when compute_uv=False * assign Operation attribute to local variable --- tensorflow/python/ops/linalg_grad.py | 59 ++++++++++++---------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/tensorflow/python/ops/linalg_grad.py b/tensorflow/python/ops/linalg_grad.py index 13a32c83d9..3cbbf3412a 100644 --- a/tensorflow/python/ops/linalg_grad.py +++ b/tensorflow/python/ops/linalg_grad.py @@ -277,20 +277,28 @@ def _SvdGrad(op, grad_s, grad_u, grad_v): # https://j-towns.github.io/papers/svd-derivative.pdf a = op.inputs[0] a_shape = a.get_shape().with_rank_at_least(2) + grad_s_mat = array_ops.matrix_diag(grad_s) - if op.get_attr("compute_uv"): - # TODO(rmlarsen): Make this work with complex types. - if a.dtype.is_complex: - raise NotImplementedError( - "SVD gradient is not implemented for complex types and " - "compute_uv=True.") - grad_u_shape = grad_u.get_shape().with_rank_at_least(2) - grad_v_shape = grad_v.get_shape().with_rank_at_least(2) - m = a_shape[-2].merge_with(grad_u_shape[-2]) - n = a_shape[-1].merge_with(grad_v_shape[-2]) - batch_shape = a_shape[:-2].merge_with(grad_u_shape[:-2]).merge_with( - grad_v_shape[:-2]) - a_shape = batch_shape.concatenate([m, n]) + if not op.get_attr("compute_uv"): + s, u, v = linalg_ops.svd(a, compute_uv=True) + grad_a = math_ops.matmul(u, math_ops.matmul(grad_s_mat, v, adjoint_b=True)) + grad_a.set_shape(a_shape) + return grad_a + + full_matrices = op.get_attr("full_matrices") + + # TODO(rmlarsen): Make this work with complex types. + if a.dtype.is_complex: + raise NotImplementedError( + "SVD gradient is not implemented for complex types and " + "compute_uv=True.") + grad_u_shape = grad_u.get_shape().with_rank_at_least(2) + grad_v_shape = grad_v.get_shape().with_rank_at_least(2) + m = a_shape[-2].merge_with(grad_u_shape[-2]) + n = a_shape[-1].merge_with(grad_v_shape[-2]) + batch_shape = a_shape[:-2].merge_with(grad_u_shape[:-2]).merge_with( + grad_v_shape[:-2]) + a_shape = batch_shape.concatenate([m, n]) m = a_shape[-2].value n = a_shape[-1].value @@ -300,12 +308,9 @@ def _SvdGrad(op, grad_s, grad_u, grad_v): "SVD gradient has not been implemented for input with unknown " "inner matrix shape.") - if not op.get_attr("compute_uv"): - s, u, v = linalg_ops.svd(a, compute_uv=True, full_matrices=True) - else: - s = op.outputs[0] - u = op.outputs[1] - v = op.outputs[2] + s = op.outputs[0] + u = op.outputs[1] + v = op.outputs[2] use_adjoint = False if m > n: @@ -317,19 +322,7 @@ def _SvdGrad(op, grad_s, grad_u, grad_v): grad_u, grad_v = grad_v, grad_u with ops.control_dependencies([grad_s, grad_u, grad_v]): - grad_s_mat = array_ops.matrix_diag(grad_s) - if not op.get_attr("compute_uv"): - if use_adjoint: - grad_a = math_ops.matmul( - v[..., :, :m], math_ops.matmul(u, grad_s_mat), adjoint_b=True) - else: - grad_a = math_ops.matmul(u, - math_ops.matmul( - grad_s_mat, v[..., :, :m], adjoint_b=True)) - grad_a.set_shape(a_shape) - return grad_a - - if op.get_attr("full_matrices") and abs(m - n) > 1: + if full_matrices and abs(m - n) > 1: raise NotImplementedError( "svd gradient is not implemented for abs(m - n) > 1 " "when full_matrices is True") @@ -371,7 +364,7 @@ def _SvdGrad(op, grad_s, grad_u, grad_v): gv1t_v1 = math_ops.matmul(gv1t, v1) term2_nous = gv1t - math_ops.matmul(gv1t_v1, v1, adjoint_b=True) - if op.get_attr("full_matrices"): + if full_matrices: v2 = v[..., :, m:n] grad_v2 = grad_v[..., :, m:n] -- GitLab From 119b993e00a2a138d1ef2f4886e39ca528bad1c3 Mon Sep 17 00:00:00 2001 From: "freedom\" Koan-Sin Tan" Date: Fri, 26 Jan 2018 06:24:23 +0800 Subject: [PATCH 258/258] make label_image for tflite build again (#16206) * make label_image for tflite build again 1. add namespace to label_image.h to make label_image for tflite build again 2. add --config monolithic and mention NDK settings in label_image.md 3. fix a typo in display_usage() * relies on tensor type info to switch types use tensor types of input and output tensors instead of command line flag from user * reformatted according to review --- .../lite/examples/label_image/label_image.cc | 55 +++++++++++-------- .../lite/examples/label_image/label_image.h | 7 ++- .../lite/examples/label_image/label_image.md | 12 ++-- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/tensorflow/contrib/lite/examples/label_image/label_image.cc b/tensorflow/contrib/lite/examples/label_image/label_image.cc index 4d2e1ce0bc..d7f49ad875 100644 --- a/tensorflow/contrib/lite/examples/label_image/label_image.cc +++ b/tensorflow/contrib/lite/examples/label_image/label_image.cc @@ -148,14 +148,22 @@ void RunInference(Settings* s) { int wanted_width = dims->data[2]; int wanted_channels = dims->data[3]; - if (s->input_floating) { - downsize(interpreter->typed_tensor(input), in, image_height, - image_width, image_channels, wanted_height, wanted_width, - wanted_channels, s); - } else { - downsize(interpreter->typed_tensor(input), in, - image_height, image_width, image_channels, wanted_height, - wanted_width, wanted_channels, s); + switch (interpreter->tensor(input)->type) { + case kTfLiteFloat32: + s->input_floating = true; + downsize(interpreter->typed_tensor(input), in, + image_height, image_width, image_channels, + wanted_height, wanted_width, wanted_channels, s); + break; + case kTfLiteUInt8: + downsize(interpreter->typed_tensor(input), in, + image_height, image_width, image_channels, + wanted_height, wanted_width, wanted_channels, s); + break; + default: + LOG(FATAL) << "cannot handle input type " + << interpreter->tensor(input)->type << " yet"; + exit(-1); } struct timeval start_time, stop_time; @@ -177,13 +185,22 @@ void RunInference(Settings* s) { std::vector> top_results; - if (s->input_floating) { - get_top_n(interpreter->typed_output_tensor(0), output_size, - num_results, threshold, &top_results, s->input_floating); - } else { - get_top_n(interpreter->typed_output_tensor(0), + int output = interpreter->outputs()[0]; + switch (interpreter->tensor(output)->type) { + case kTfLiteFloat32: + get_top_n(interpreter->typed_output_tensor(0), output_size, num_results, threshold, &top_results, - s->input_floating); + true); + break; + case kTfLiteUInt8: + get_top_n(interpreter->typed_output_tensor(0), + output_size, num_results, threshold, &top_results, + false); + break; + default: + LOG(FATAL) << "cannot handle output type " + << interpreter->tensor(input)->type << " yet"; + exit(-1); } std::vector labels; @@ -203,13 +220,11 @@ void display_usage() { LOG(INFO) << "label_image\n" << "--accelerated, -a: [0|1], use Android NNAPI or note\n" << "--count, -c: loop interpreter->Invoke() for certain times\n" - << "--input_floating, -f: [0|1] type of input layer is floating " - "point numbers\n" << "--input_mean, -b: input mean\n" << "--input_std, -s: input standard deviation\n" << "--image, -i: image_name.bmp\n" << "--labels, -l: labels for the model\n" - << "--tflite_mode, -m: model_name.tflite\n" + << "--tflite_model, -m: model_name.tflite\n" << "--threads, -t: number of threads\n" << "--verbose, -v: [0|1] print more information\n" << "\n"; @@ -223,7 +238,6 @@ int Main(int argc, char** argv) { static struct option long_options[] = { {"accelerated", required_argument, 0, 'a'}, {"count", required_argument, 0, 'c'}, - {"input_floating", required_argument, 0, 'f'}, {"verbose", required_argument, 0, 'v'}, {"image", required_argument, 0, 'i'}, {"labels", required_argument, 0, 'l'}, @@ -254,11 +268,6 @@ int Main(int argc, char** argv) { s.loop_count = strtol( // NOLINT(runtime/deprecated_fn) optarg, (char**)NULL, 10); break; - case 'f': - s.input_floating = strtol( // NOLINT(runtime/deprecated_fn) - optarg, (char**)NULL, 10); - s.input_layer_type = "float"; - break; case 'i': s.input_bmp_name = optarg; break; diff --git a/tensorflow/contrib/lite/examples/label_image/label_image.h b/tensorflow/contrib/lite/examples/label_image/label_image.h index ce98e06fc1..4de32e33fb 100644 --- a/tensorflow/contrib/lite/examples/label_image/label_image.h +++ b/tensorflow/contrib/lite/examples/label_image/label_image.h @@ -16,9 +16,11 @@ limitations under the License. #ifndef TENSORFLOW_CONTRIB_LITE_EXAMPLES_LABEL_IMAGE_LABEL_IMAGE_H #define TENSORFLOW_CONTRIB_LITE_EXAMPLES_LABEL_IMAGE_LABEL_IMAGE_H -#include #include "tensorflow/contrib/lite/string.h" +namespace tflite { +namespace label_image { + struct Settings { bool verbose = false; bool accel = false; @@ -33,4 +35,7 @@ struct Settings { int number_of_threads = 4; }; +} // namespace label_image +} // namespace tflite + #endif // TENSORFLOW_CONTRIB_LITE_EXAMPLES_LABEL_IMAGE_LABEL_IMAGE_H diff --git a/tensorflow/contrib/lite/examples/label_image/label_image.md b/tensorflow/contrib/lite/examples/label_image/label_image.md index d6019d673f..9ce32cf101 100644 --- a/tensorflow/contrib/lite/examples/label_image/label_image.md +++ b/tensorflow/contrib/lite/examples/label_image/label_image.md @@ -1,8 +1,12 @@ label_image for TensorFlow Lite inspired by TensorFlow's label_image. + +To build label_image for Android, run $TENSORFLOW_ROOT/configure +and set Android NDK or configure NDK setting in +$TENSORFLOW_ROOT/WORKSPACE first. To build it for android ARMv8: ``` -> bazel build --cxxopt=-std=c++11 \ +> bazel build --config monolithic --cxxopt=-std=c++11 \ --crosstool_top=//external:android/crosstool \ --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \ --cpu=arm64-v8a \ @@ -10,13 +14,13 @@ To build it for android ARMv8: ``` or ``` -> bazel build --config android_arm64 --cxxopt=-std=c++11 \ +> bazel build --config android_arm64 --config monolithic --cxxopt=-std=c++11 \ //tensorflow/contrib/lite/examples/label_image:label_image ``` To build it for android arm-v7a: ``` -> bazel build --cxxopt=-std=c++11 \ +> bazel build --config monolithic --cxxopt=-std=c++11 \ --crosstool_top=//external:android/crosstool \ --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \ --cpu=armeabi-v7a \ @@ -24,7 +28,7 @@ To build it for android arm-v7a: ``` or ``` -> bazel build --config android_arm --cxxopt=-std=c++11 \ +> bazel build --config android_arm --config monolithic --cxxopt=-std=c++11 \ //tensorflow/contrib/lite/examples/label_image:label_image ``` -- GitLab
Version:CPU/GPU:Python Version:Compiler:Build Tools:cuDNN:CUDA:
tensorflow-1.5.0-rc1CPU3.5-3.6MSVC 2015 update 3Cmake v3.6.3N/AN/A
tensorflow_gpu-1.5.0-rc1GPU3.5-3.6MSVC 2015 update 3Cmake v3.6.379
tensorflow-1.4.0CPU3.5-3.6MSVC 2015 update 3Cmake v3.6.3N/AN/A
tensorflow_gpu-1.4.0GPU3.5-3.6MSVC 2015 update 3Cmake v3.6.368
tensorflow-1.3.0CPU3.5-3.6MSVC 2015 update 3Cmake v3.6.3N/AN/A