Export the events_writer functions from C++ to Python with pybind11 instead of swig. This is part of a larger effort to deprecate swig and eventually with modularization break pywrap_tensorflow into smaller components. It will also make exporting C++ ops to Python significantly easier. XLA is using the pybind11 macros already. Please refer to https://github.com/tensorflow/community/blob/master/rfcs/20190208-pybind11.md for more information.
We are slightly changing the behavior of EventsWriter. Rather than returning a bad status when writing to a deleted file which is often ignored by the user, we are removing the FileStillExists check. TensorBoard has already been prepared for this change via: https://github.com/tensorflow/tensorboard/pull/2683 PiperOrigin-RevId: 270945727
This commit is contained in:
parent
e9c8a604cf
commit
98f2265343
@ -131,18 +131,6 @@ Status EventsWriter::Flush() {
|
|||||||
TF_RETURN_WITH_CONTEXT_IF_ERROR(recordio_file_->Sync(), "Failed to sync ",
|
TF_RETURN_WITH_CONTEXT_IF_ERROR(recordio_file_->Sync(), "Failed to sync ",
|
||||||
num_outstanding_events_, " events to ",
|
num_outstanding_events_, " events to ",
|
||||||
filename_);
|
filename_);
|
||||||
|
|
||||||
// The FileStillExists() condition is necessary because
|
|
||||||
// recordio_writer_->Sync() can return OK even if the underlying
|
|
||||||
// file has been deleted. EventWriter.FileDeletionBeforeWriting
|
|
||||||
// demonstrates this and will fail if the FileHasDisappeared()
|
|
||||||
// condition is removed.
|
|
||||||
// Also, we deliberately attempt to Sync() before checking for a
|
|
||||||
// disappearing file, in case for some file system File::Exists() is
|
|
||||||
// false after File::Open() but before File::Sync().
|
|
||||||
TF_RETURN_WITH_CONTEXT_IF_ERROR(FileStillExists(), "Failed to flush ",
|
|
||||||
num_outstanding_events_, " events to ",
|
|
||||||
filename_);
|
|
||||||
VLOG(1) << "Wrote " << num_outstanding_events_ << " events to disk.";
|
VLOG(1) << "Wrote " << num_outstanding_events_ << " events to disk.";
|
||||||
num_outstanding_events_ = 0;
|
num_outstanding_events_ = 0;
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
|
@ -142,9 +142,7 @@ TEST(EventWriter, FailFlush) {
|
|||||||
WriteFile(&writer);
|
WriteFile(&writer);
|
||||||
TF_EXPECT_OK(env()->FileExists(filename));
|
TF_EXPECT_OK(env()->FileExists(filename));
|
||||||
TF_ASSERT_OK(env()->DeleteFile(filename));
|
TF_ASSERT_OK(env()->DeleteFile(filename));
|
||||||
EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code());
|
EXPECT_TRUE(writer.Flush().ok());
|
||||||
EXPECT_FALSE(writer.Flush().ok());
|
|
||||||
EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EventWriter, FailClose) {
|
TEST(EventWriter, FailClose) {
|
||||||
@ -154,9 +152,7 @@ TEST(EventWriter, FailClose) {
|
|||||||
WriteFile(&writer);
|
WriteFile(&writer);
|
||||||
TF_EXPECT_OK(env()->FileExists(filename));
|
TF_EXPECT_OK(env()->FileExists(filename));
|
||||||
TF_ASSERT_OK(env()->DeleteFile(filename));
|
TF_ASSERT_OK(env()->DeleteFile(filename));
|
||||||
EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code());
|
EXPECT_TRUE(writer.Close().ok());
|
||||||
EXPECT_FALSE(writer.Close().ok());
|
|
||||||
EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EventWriter, InitWriteClose) {
|
TEST(EventWriter, InitWriteClose) {
|
||||||
|
@ -98,6 +98,7 @@ py_library(
|
|||||||
"//third_party/py/tensorflow_core:__subpackages__",
|
"//third_party/py/tensorflow_core:__subpackages__",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
|
":_pywrap_events_writer",
|
||||||
":_pywrap_stat_summarizer",
|
":_pywrap_stat_summarizer",
|
||||||
":_pywrap_tfprof",
|
":_pywrap_tfprof",
|
||||||
":_pywrap_util_port",
|
":_pywrap_util_port",
|
||||||
@ -463,7 +464,7 @@ tf_python_pybind_extension(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
pybind_extension(
|
tf_python_pybind_extension(
|
||||||
name = "_pywrap_util_port",
|
name = "_pywrap_util_port",
|
||||||
srcs = ["util/port_wrapper.cc"],
|
srcs = ["util/port_wrapper.cc"],
|
||||||
hdrs = ["//tensorflow/core:util_port_hdrs"],
|
hdrs = ["//tensorflow/core:util_port_hdrs"],
|
||||||
@ -475,6 +476,23 @@ pybind_extension(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tf_python_pybind_extension(
|
||||||
|
name = "_pywrap_events_writer",
|
||||||
|
srcs = ["client/events_writer_wrapper.cc"],
|
||||||
|
module_name = "_pywrap_events_writer",
|
||||||
|
deps = [
|
||||||
|
":pybind11_absl",
|
||||||
|
":pybind11_proto",
|
||||||
|
":pybind11_status",
|
||||||
|
"//tensorflow/core:framework",
|
||||||
|
"//tensorflow/core:lib",
|
||||||
|
"//tensorflow/core:protos_all_cc",
|
||||||
|
"//third_party/python_runtime:headers",
|
||||||
|
"@com_google_absl//absl/strings",
|
||||||
|
"@pybind11",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "cpp_python_util",
|
name = "cpp_python_util",
|
||||||
srcs = ["util/util.cc"],
|
srcs = ["util/util.cc"],
|
||||||
@ -784,6 +802,7 @@ py_library(
|
|||||||
],
|
],
|
||||||
srcs_version = "PY2AND3",
|
srcs_version = "PY2AND3",
|
||||||
deps = [
|
deps = [
|
||||||
|
":_pywrap_events_writer",
|
||||||
":_pywrap_stat_summarizer",
|
":_pywrap_stat_summarizer",
|
||||||
":_pywrap_tfprof",
|
":_pywrap_tfprof",
|
||||||
":_pywrap_util_port",
|
":_pywrap_util_port",
|
||||||
@ -4990,7 +5009,6 @@ tf_py_wrap_cc(
|
|||||||
srcs = ["tensorflow.i"],
|
srcs = ["tensorflow.i"],
|
||||||
swig_includes = [
|
swig_includes = [
|
||||||
"client/device_lib.i",
|
"client/device_lib.i",
|
||||||
"client/events_writer.i",
|
|
||||||
"client/tf_session.i",
|
"client/tf_session.i",
|
||||||
"client/tf_sessionrun_wrapper.i",
|
"client/tf_sessionrun_wrapper.i",
|
||||||
"framework/python_op_gen.i",
|
"framework/python_op_gen.i",
|
||||||
|
@ -49,6 +49,7 @@ import numpy as np
|
|||||||
from tensorflow.python import pywrap_tensorflow
|
from tensorflow.python import pywrap_tensorflow
|
||||||
from tensorflow.python import _pywrap_utils
|
from tensorflow.python import _pywrap_utils
|
||||||
from tensorflow.python import _pywrap_tfprof
|
from tensorflow.python import _pywrap_tfprof
|
||||||
|
from tensorflow.python import _pywrap_events_writer
|
||||||
from tensorflow.python import _pywrap_util_port
|
from tensorflow.python import _pywrap_util_port
|
||||||
from tensorflow.python import _pywrap_stat_summarizer
|
from tensorflow.python import _pywrap_stat_summarizer
|
||||||
|
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
/* 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.
|
|
||||||
==============================================================================*/
|
|
||||||
|
|
||||||
%include "tensorflow/python/lib/core/strings.i"
|
|
||||||
%include "tensorflow/python/platform/base.i"
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include "tensorflow/core/util/events_writer.h"
|
|
||||||
#include "tensorflow/core/util/event.pb.h"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%nodefaultctor EventsWriter;
|
|
||||||
|
|
||||||
%ignore tensorflow::Status::operator=;
|
|
||||||
%include "tensorflow/core/lib/core/status.h"
|
|
||||||
|
|
||||||
%ignoreall
|
|
||||||
%unignore tensorflow;
|
|
||||||
%unignore tensorflow::EventsWriter;
|
|
||||||
%unignore tensorflow::EventsWriter::EventsWriter;
|
|
||||||
%unignore tensorflow::EventsWriter::~EventsWriter;
|
|
||||||
%unignore tensorflow::EventsWriter::InitWithSuffix;
|
|
||||||
%unignore tensorflow::EventsWriter::FileName;
|
|
||||||
%rename("_WriteSerializedEvent") tensorflow::EventsWriter::WriteSerializedEvent;
|
|
||||||
%unignore tensorflow::EventsWriter::Flush;
|
|
||||||
%unignore tensorflow::EventsWriter::Close;
|
|
||||||
%include "tensorflow/core/util/events_writer.h"
|
|
||||||
%unignoreall
|
|
||||||
|
|
||||||
%newobject tensorflow::EventsWriter::EventsWriter;
|
|
||||||
|
|
||||||
|
|
||||||
%extend tensorflow::EventsWriter {
|
|
||||||
%insert("python") %{
|
|
||||||
def WriteEvent(self, event):
|
|
||||||
from tensorflow.core.util.event_pb2 import Event
|
|
||||||
if not isinstance(event, Event):
|
|
||||||
raise TypeError("Expected an event_pb2.Event proto, "
|
|
||||||
" but got %s" % type(event))
|
|
||||||
return self._WriteSerializedEvent(event.SerializeToString())
|
|
||||||
%}
|
|
||||||
}
|
|
@ -22,7 +22,7 @@ import os.path
|
|||||||
|
|
||||||
from tensorflow.core.framework import summary_pb2
|
from tensorflow.core.framework import summary_pb2
|
||||||
from tensorflow.core.util import event_pb2
|
from tensorflow.core.util import event_pb2
|
||||||
from tensorflow.python import pywrap_tensorflow
|
from tensorflow.python import _pywrap_events_writer
|
||||||
from tensorflow.python.framework import errors
|
from tensorflow.python.framework import errors
|
||||||
from tensorflow.python.framework import test_util
|
from tensorflow.python.framework import test_util
|
||||||
from tensorflow.python.lib.io import tf_record
|
from tensorflow.python.lib.io import tf_record
|
||||||
@ -34,7 +34,7 @@ class PywrapeventsWriterTest(test_util.TensorFlowTestCase):
|
|||||||
|
|
||||||
def testWriteEvents(self):
|
def testWriteEvents(self):
|
||||||
file_prefix = os.path.join(self.get_temp_dir(), "events")
|
file_prefix = os.path.join(self.get_temp_dir(), "events")
|
||||||
writer = pywrap_tensorflow.EventsWriter(compat.as_bytes(file_prefix))
|
writer = _pywrap_events_writer.EventsWriter(compat.as_bytes(file_prefix))
|
||||||
filename = compat.as_text(writer.FileName())
|
filename = compat.as_text(writer.FileName())
|
||||||
event_written = event_pb2.Event(
|
event_written = event_pb2.Event(
|
||||||
wall_time=123.45,
|
wall_time=123.45,
|
||||||
@ -74,7 +74,7 @@ class PywrapeventsWriterTest(test_util.TensorFlowTestCase):
|
|||||||
return "Invalid"
|
return "Invalid"
|
||||||
|
|
||||||
with self.assertRaisesRegexp(TypeError, "Invalid"):
|
with self.assertRaisesRegexp(TypeError, "Invalid"):
|
||||||
pywrap_tensorflow.EventsWriter(b"foo").WriteEvent(_Invalid())
|
_pywrap_events_writer.EventsWriter(b"foo").WriteEvent(_Invalid())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
49
tensorflow/python/client/events_writer_wrapper.cc
Normal file
49
tensorflow/python/client/events_writer_wrapper.cc
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/* Copyright 2019 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 "absl/strings/string_view.h"
|
||||||
|
#include "include/pybind11/pybind11.h"
|
||||||
|
#include "include/pybind11/pytypes.h"
|
||||||
|
#include "tensorflow/core/util/events_writer.h"
|
||||||
|
#include "tensorflow/python/lib/core/pybind11_absl.h"
|
||||||
|
#include "tensorflow/python/lib/core/pybind11_proto.h"
|
||||||
|
#include "tensorflow/python/lib/core/pybind11_status.h"
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
PYBIND11_MODULE(_pywrap_events_writer, m) {
|
||||||
|
py::class_<tensorflow::EventsWriter> events_writer_class(m, "EventsWriter");
|
||||||
|
events_writer_class.def(py::init<const std::string&>())
|
||||||
|
.def("InitWithSuffix",
|
||||||
|
[](tensorflow::EventsWriter& self, const std::string& suffix) {
|
||||||
|
return self.InitWithSuffix(suffix);
|
||||||
|
})
|
||||||
|
.def("FileName",
|
||||||
|
[](tensorflow::EventsWriter& self) { return self.FileName(); })
|
||||||
|
.def("_WriteSerializedEvent",
|
||||||
|
[](tensorflow::EventsWriter& self,
|
||||||
|
const absl::string_view event_str) {
|
||||||
|
self.WriteSerializedEvent(event_str);
|
||||||
|
})
|
||||||
|
.def("Flush", [](tensorflow::EventsWriter& self) { return self.Flush(); })
|
||||||
|
.def("Close", [](tensorflow::EventsWriter& self) { return self.Close(); })
|
||||||
|
.def("WriteEvent",
|
||||||
|
[](tensorflow::EventsWriter& self, const py::object obj) {
|
||||||
|
// Verify the proto type is an event prior to writing.
|
||||||
|
tensorflow::CheckProtoType(obj, "tensorflow.Event");
|
||||||
|
self.WriteSerializedEvent(
|
||||||
|
obj.attr("SerializeToString")().cast<std::string>());
|
||||||
|
});
|
||||||
|
};
|
@ -38,6 +38,7 @@ import datetime
|
|||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
from tensorflow.python import _pywrap_events_writer
|
||||||
from tensorflow.python import pywrap_tensorflow
|
from tensorflow.python import pywrap_tensorflow
|
||||||
from tensorflow.python.eager import context
|
from tensorflow.python.eager import context
|
||||||
from tensorflow.python.framework import c_api_util
|
from tensorflow.python.framework import c_api_util
|
||||||
@ -122,7 +123,7 @@ def maybe_create_event_file(logdir):
|
|||||||
if file_name.endswith(_EVENT_FILE_SUFFIX):
|
if file_name.endswith(_EVENT_FILE_SUFFIX):
|
||||||
return
|
return
|
||||||
# TODO(b/127330388): Use summary_ops_v2.create_file_writer instead.
|
# TODO(b/127330388): Use summary_ops_v2.create_file_writer instead.
|
||||||
event_writer = pywrap_tensorflow.EventsWriter(
|
event_writer = _pywrap_events_writer.EventsWriter(
|
||||||
compat.as_bytes(os.path.join(logdir, 'events')))
|
compat.as_bytes(os.path.join(logdir, 'events')))
|
||||||
event_writer.InitWithSuffix(compat.as_bytes(_EVENT_FILE_SUFFIX))
|
event_writer.InitWithSuffix(compat.as_bytes(_EVENT_FILE_SUFFIX))
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import time
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from tensorflow.core.util import event_pb2
|
from tensorflow.core.util import event_pb2
|
||||||
from tensorflow.python import pywrap_tensorflow
|
from tensorflow.python import _pywrap_events_writer
|
||||||
from tensorflow.python.platform import gfile
|
from tensorflow.python.platform import gfile
|
||||||
from tensorflow.python.util import compat
|
from tensorflow.python.util import compat
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ class EventFileWriter(object):
|
|||||||
if not gfile.IsDirectory(self._logdir):
|
if not gfile.IsDirectory(self._logdir):
|
||||||
gfile.MakeDirs(self._logdir)
|
gfile.MakeDirs(self._logdir)
|
||||||
self._event_queue = six.moves.queue.Queue(max_queue)
|
self._event_queue = six.moves.queue.Queue(max_queue)
|
||||||
self._ev_writer = pywrap_tensorflow.EventsWriter(
|
self._ev_writer = _pywrap_events_writer.EventsWriter(
|
||||||
compat.as_bytes(os.path.join(self._logdir, "events")))
|
compat.as_bytes(os.path.join(self._logdir, "events")))
|
||||||
self._flush_secs = flush_secs
|
self._flush_secs = flush_secs
|
||||||
self._sentinel_event = self._get_sentinel_event()
|
self._sentinel_event = self._get_sentinel_event()
|
||||||
|
@ -26,7 +26,6 @@ limitations under the License.
|
|||||||
|
|
||||||
%include "tensorflow/python/lib/io/py_record_reader.i"
|
%include "tensorflow/python/lib/io/py_record_reader.i"
|
||||||
%include "tensorflow/python/lib/io/py_record_writer.i"
|
%include "tensorflow/python/lib/io/py_record_writer.i"
|
||||||
%include "tensorflow/python/client/events_writer.i"
|
|
||||||
|
|
||||||
%include "tensorflow/python/client/tf_session.i"
|
%include "tensorflow/python/client/tf_session.i"
|
||||||
%include "tensorflow/python/client/device_lib.i"
|
%include "tensorflow/python/client/device_lib.i"
|
||||||
|
@ -44,3 +44,11 @@ tensorflow::grappler::graph_analyzer::GraphAnalyzerTool
|
|||||||
[bfloat16_lib] # bfloat16
|
[bfloat16_lib] # bfloat16
|
||||||
tensorflow::RegisterNumpyBfloat16
|
tensorflow::RegisterNumpyBfloat16
|
||||||
tensorflow::Bfloat16PyType
|
tensorflow::Bfloat16PyType
|
||||||
|
|
||||||
|
[events_writer] # events_writer
|
||||||
|
tensorflow::EventsWriter::Init
|
||||||
|
tensorflow::EventsWriter::InitWithSuffix
|
||||||
|
tensorflow::EventsWriter::WriteSerializedEvent
|
||||||
|
tensorflow::EventsWriter::Flush
|
||||||
|
tensorflow::EventsWriter::Close
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user