tensorbored 2.21.0rc1769983804__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tensorbored/__init__.py +112 -0
- tensorbored/_vendor/__init__.py +0 -0
- tensorbored/_vendor/bleach/__init__.py +125 -0
- tensorbored/_vendor/bleach/_vendor/__init__.py +0 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/__init__.py +35 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_ihatexml.py +289 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_inputstream.py +918 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_tokenizer.py +1735 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_trie/__init__.py +5 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_trie/_base.py +40 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_trie/py.py +67 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_utils.py +159 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/constants.py +2946 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/__init__.py +0 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/alphabeticalattributes.py +29 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/base.py +12 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/inject_meta_charset.py +73 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/lint.py +93 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/optionaltags.py +207 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/sanitizer.py +916 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/whitespace.py +38 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/html5parser.py +2795 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/serializer.py +409 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/__init__.py +30 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/genshi.py +54 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/sax.py +50 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/__init__.py +88 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/base.py +417 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/dom.py +239 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/etree.py +343 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/etree_lxml.py +392 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/__init__.py +154 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/base.py +252 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/dom.py +43 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/etree.py +131 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/etree_lxml.py +215 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/genshi.py +69 -0
- tensorbored/_vendor/bleach/_vendor/parse.py +1078 -0
- tensorbored/_vendor/bleach/callbacks.py +32 -0
- tensorbored/_vendor/bleach/html5lib_shim.py +757 -0
- tensorbored/_vendor/bleach/linkifier.py +633 -0
- tensorbored/_vendor/bleach/parse_shim.py +1 -0
- tensorbored/_vendor/bleach/sanitizer.py +638 -0
- tensorbored/_vendor/bleach/six_shim.py +19 -0
- tensorbored/_vendor/webencodings/__init__.py +342 -0
- tensorbored/_vendor/webencodings/labels.py +231 -0
- tensorbored/_vendor/webencodings/mklabels.py +59 -0
- tensorbored/_vendor/webencodings/x_user_defined.py +325 -0
- tensorbored/assets.py +36 -0
- tensorbored/auth.py +102 -0
- tensorbored/backend/__init__.py +0 -0
- tensorbored/backend/application.py +604 -0
- tensorbored/backend/auth_context_middleware.py +38 -0
- tensorbored/backend/client_feature_flags.py +113 -0
- tensorbored/backend/empty_path_redirect.py +46 -0
- tensorbored/backend/event_processing/__init__.py +0 -0
- tensorbored/backend/event_processing/data_ingester.py +276 -0
- tensorbored/backend/event_processing/data_provider.py +535 -0
- tensorbored/backend/event_processing/directory_loader.py +142 -0
- tensorbored/backend/event_processing/directory_watcher.py +272 -0
- tensorbored/backend/event_processing/event_accumulator.py +950 -0
- tensorbored/backend/event_processing/event_file_inspector.py +463 -0
- tensorbored/backend/event_processing/event_file_loader.py +292 -0
- tensorbored/backend/event_processing/event_multiplexer.py +521 -0
- tensorbored/backend/event_processing/event_util.py +68 -0
- tensorbored/backend/event_processing/io_wrapper.py +223 -0
- tensorbored/backend/event_processing/plugin_asset_util.py +104 -0
- tensorbored/backend/event_processing/plugin_event_accumulator.py +721 -0
- tensorbored/backend/event_processing/plugin_event_multiplexer.py +522 -0
- tensorbored/backend/event_processing/reservoir.py +266 -0
- tensorbored/backend/event_processing/tag_types.py +29 -0
- tensorbored/backend/experiment_id.py +71 -0
- tensorbored/backend/experimental_plugin.py +51 -0
- tensorbored/backend/http_util.py +263 -0
- tensorbored/backend/json_util.py +70 -0
- tensorbored/backend/path_prefix.py +67 -0
- tensorbored/backend/process_graph.py +74 -0
- tensorbored/backend/security_validator.py +202 -0
- tensorbored/compat/__init__.py +69 -0
- tensorbored/compat/proto/__init__.py +0 -0
- tensorbored/compat/proto/allocation_description_pb2.py +35 -0
- tensorbored/compat/proto/api_def_pb2.py +82 -0
- tensorbored/compat/proto/attr_value_pb2.py +80 -0
- tensorbored/compat/proto/cluster_pb2.py +58 -0
- tensorbored/compat/proto/config_pb2.py +271 -0
- tensorbored/compat/proto/coordination_config_pb2.py +45 -0
- tensorbored/compat/proto/cost_graph_pb2.py +87 -0
- tensorbored/compat/proto/cpp_shape_inference_pb2.py +70 -0
- tensorbored/compat/proto/debug_pb2.py +65 -0
- tensorbored/compat/proto/event_pb2.py +149 -0
- tensorbored/compat/proto/full_type_pb2.py +74 -0
- tensorbored/compat/proto/function_pb2.py +157 -0
- tensorbored/compat/proto/graph_debug_info_pb2.py +111 -0
- tensorbored/compat/proto/graph_pb2.py +41 -0
- tensorbored/compat/proto/histogram_pb2.py +39 -0
- tensorbored/compat/proto/meta_graph_pb2.py +254 -0
- tensorbored/compat/proto/node_def_pb2.py +61 -0
- tensorbored/compat/proto/op_def_pb2.py +81 -0
- tensorbored/compat/proto/resource_handle_pb2.py +48 -0
- tensorbored/compat/proto/rewriter_config_pb2.py +93 -0
- tensorbored/compat/proto/rpc_options_pb2.py +35 -0
- tensorbored/compat/proto/saved_object_graph_pb2.py +193 -0
- tensorbored/compat/proto/saver_pb2.py +38 -0
- tensorbored/compat/proto/step_stats_pb2.py +116 -0
- tensorbored/compat/proto/struct_pb2.py +144 -0
- tensorbored/compat/proto/summary_pb2.py +111 -0
- tensorbored/compat/proto/tensor_description_pb2.py +38 -0
- tensorbored/compat/proto/tensor_pb2.py +68 -0
- tensorbored/compat/proto/tensor_shape_pb2.py +46 -0
- tensorbored/compat/proto/tfprof_log_pb2.py +307 -0
- tensorbored/compat/proto/trackable_object_graph_pb2.py +90 -0
- tensorbored/compat/proto/types_pb2.py +105 -0
- tensorbored/compat/proto/variable_pb2.py +62 -0
- tensorbored/compat/proto/verifier_config_pb2.py +38 -0
- tensorbored/compat/proto/versions_pb2.py +35 -0
- tensorbored/compat/tensorflow_stub/__init__.py +38 -0
- tensorbored/compat/tensorflow_stub/app.py +124 -0
- tensorbored/compat/tensorflow_stub/compat/__init__.py +131 -0
- tensorbored/compat/tensorflow_stub/compat/v1/__init__.py +20 -0
- tensorbored/compat/tensorflow_stub/dtypes.py +692 -0
- tensorbored/compat/tensorflow_stub/error_codes.py +169 -0
- tensorbored/compat/tensorflow_stub/errors.py +507 -0
- tensorbored/compat/tensorflow_stub/flags.py +124 -0
- tensorbored/compat/tensorflow_stub/io/__init__.py +17 -0
- tensorbored/compat/tensorflow_stub/io/gfile.py +1011 -0
- tensorbored/compat/tensorflow_stub/pywrap_tensorflow.py +285 -0
- tensorbored/compat/tensorflow_stub/tensor_shape.py +1035 -0
- tensorbored/context.py +129 -0
- tensorbored/data/__init__.py +0 -0
- tensorbored/data/grpc_provider.py +365 -0
- tensorbored/data/ingester.py +46 -0
- tensorbored/data/proto/__init__.py +0 -0
- tensorbored/data/proto/data_provider_pb2.py +517 -0
- tensorbored/data/proto/data_provider_pb2_grpc.py +374 -0
- tensorbored/data/provider.py +1365 -0
- tensorbored/data/server_ingester.py +301 -0
- tensorbored/data_compat.py +159 -0
- tensorbored/dataclass_compat.py +224 -0
- tensorbored/default.py +124 -0
- tensorbored/errors.py +130 -0
- tensorbored/lazy.py +99 -0
- tensorbored/main.py +48 -0
- tensorbored/main_lib.py +62 -0
- tensorbored/manager.py +487 -0
- tensorbored/notebook.py +441 -0
- tensorbored/plugin_util.py +266 -0
- tensorbored/plugins/__init__.py +0 -0
- tensorbored/plugins/audio/__init__.py +0 -0
- tensorbored/plugins/audio/audio_plugin.py +229 -0
- tensorbored/plugins/audio/metadata.py +69 -0
- tensorbored/plugins/audio/plugin_data_pb2.py +37 -0
- tensorbored/plugins/audio/summary.py +230 -0
- tensorbored/plugins/audio/summary_v2.py +124 -0
- tensorbored/plugins/base_plugin.py +367 -0
- tensorbored/plugins/core/__init__.py +0 -0
- tensorbored/plugins/core/core_plugin.py +981 -0
- tensorbored/plugins/custom_scalar/__init__.py +0 -0
- tensorbored/plugins/custom_scalar/custom_scalars_plugin.py +320 -0
- tensorbored/plugins/custom_scalar/layout_pb2.py +85 -0
- tensorbored/plugins/custom_scalar/metadata.py +35 -0
- tensorbored/plugins/custom_scalar/summary.py +79 -0
- tensorbored/plugins/debugger_v2/__init__.py +0 -0
- tensorbored/plugins/debugger_v2/debug_data_multiplexer.py +631 -0
- tensorbored/plugins/debugger_v2/debug_data_provider.py +634 -0
- tensorbored/plugins/debugger_v2/debugger_v2_plugin.py +504 -0
- tensorbored/plugins/distribution/__init__.py +0 -0
- tensorbored/plugins/distribution/compressor.py +158 -0
- tensorbored/plugins/distribution/distributions_plugin.py +116 -0
- tensorbored/plugins/distribution/metadata.py +19 -0
- tensorbored/plugins/graph/__init__.py +0 -0
- tensorbored/plugins/graph/graph_util.py +129 -0
- tensorbored/plugins/graph/graphs_plugin.py +336 -0
- tensorbored/plugins/graph/keras_util.py +328 -0
- tensorbored/plugins/graph/metadata.py +42 -0
- tensorbored/plugins/histogram/__init__.py +0 -0
- tensorbored/plugins/histogram/histograms_plugin.py +144 -0
- tensorbored/plugins/histogram/metadata.py +63 -0
- tensorbored/plugins/histogram/plugin_data_pb2.py +34 -0
- tensorbored/plugins/histogram/summary.py +234 -0
- tensorbored/plugins/histogram/summary_v2.py +292 -0
- tensorbored/plugins/hparams/__init__.py +14 -0
- tensorbored/plugins/hparams/_keras.py +93 -0
- tensorbored/plugins/hparams/api.py +130 -0
- tensorbored/plugins/hparams/api_pb2.py +208 -0
- tensorbored/plugins/hparams/backend_context.py +606 -0
- tensorbored/plugins/hparams/download_data.py +158 -0
- tensorbored/plugins/hparams/error.py +26 -0
- tensorbored/plugins/hparams/get_experiment.py +71 -0
- tensorbored/plugins/hparams/hparams_plugin.py +206 -0
- tensorbored/plugins/hparams/hparams_util_pb2.py +69 -0
- tensorbored/plugins/hparams/json_format_compat.py +38 -0
- tensorbored/plugins/hparams/list_metric_evals.py +57 -0
- tensorbored/plugins/hparams/list_session_groups.py +1040 -0
- tensorbored/plugins/hparams/metadata.py +125 -0
- tensorbored/plugins/hparams/metrics.py +41 -0
- tensorbored/plugins/hparams/plugin_data_pb2.py +69 -0
- tensorbored/plugins/hparams/summary.py +205 -0
- tensorbored/plugins/hparams/summary_v2.py +597 -0
- tensorbored/plugins/image/__init__.py +0 -0
- tensorbored/plugins/image/images_plugin.py +232 -0
- tensorbored/plugins/image/metadata.py +65 -0
- tensorbored/plugins/image/plugin_data_pb2.py +34 -0
- tensorbored/plugins/image/summary.py +159 -0
- tensorbored/plugins/image/summary_v2.py +130 -0
- tensorbored/plugins/mesh/__init__.py +14 -0
- tensorbored/plugins/mesh/mesh_plugin.py +292 -0
- tensorbored/plugins/mesh/metadata.py +152 -0
- tensorbored/plugins/mesh/plugin_data_pb2.py +37 -0
- tensorbored/plugins/mesh/summary.py +251 -0
- tensorbored/plugins/mesh/summary_v2.py +214 -0
- tensorbored/plugins/metrics/__init__.py +0 -0
- tensorbored/plugins/metrics/metadata.py +17 -0
- tensorbored/plugins/metrics/metrics_plugin.py +623 -0
- tensorbored/plugins/pr_curve/__init__.py +0 -0
- tensorbored/plugins/pr_curve/metadata.py +75 -0
- tensorbored/plugins/pr_curve/plugin_data_pb2.py +34 -0
- tensorbored/plugins/pr_curve/pr_curves_plugin.py +241 -0
- tensorbored/plugins/pr_curve/summary.py +574 -0
- tensorbored/plugins/profile_redirect/__init__.py +0 -0
- tensorbored/plugins/profile_redirect/profile_redirect_plugin.py +49 -0
- tensorbored/plugins/projector/__init__.py +67 -0
- tensorbored/plugins/projector/metadata.py +26 -0
- tensorbored/plugins/projector/projector_config_pb2.py +54 -0
- tensorbored/plugins/projector/projector_plugin.py +795 -0
- tensorbored/plugins/projector/tf_projector_plugin/index.js +32 -0
- tensorbored/plugins/projector/tf_projector_plugin/projector_binary.html +524 -0
- tensorbored/plugins/projector/tf_projector_plugin/projector_binary.js +15536 -0
- tensorbored/plugins/scalar/__init__.py +0 -0
- tensorbored/plugins/scalar/metadata.py +60 -0
- tensorbored/plugins/scalar/plugin_data_pb2.py +34 -0
- tensorbored/plugins/scalar/scalars_plugin.py +181 -0
- tensorbored/plugins/scalar/summary.py +109 -0
- tensorbored/plugins/scalar/summary_v2.py +124 -0
- tensorbored/plugins/text/__init__.py +0 -0
- tensorbored/plugins/text/metadata.py +62 -0
- tensorbored/plugins/text/plugin_data_pb2.py +34 -0
- tensorbored/plugins/text/summary.py +114 -0
- tensorbored/plugins/text/summary_v2.py +124 -0
- tensorbored/plugins/text/text_plugin.py +288 -0
- tensorbored/plugins/wit_redirect/__init__.py +0 -0
- tensorbored/plugins/wit_redirect/wit_redirect_plugin.py +49 -0
- tensorbored/program.py +910 -0
- tensorbored/summary/__init__.py +35 -0
- tensorbored/summary/_output.py +124 -0
- tensorbored/summary/_tf/__init__.py +14 -0
- tensorbored/summary/_tf/summary/__init__.py +178 -0
- tensorbored/summary/_writer.py +105 -0
- tensorbored/summary/v1.py +51 -0
- tensorbored/summary/v2.py +25 -0
- tensorbored/summary/writer/__init__.py +13 -0
- tensorbored/summary/writer/event_file_writer.py +291 -0
- tensorbored/summary/writer/record_writer.py +50 -0
- tensorbored/util/__init__.py +0 -0
- tensorbored/util/encoder.py +116 -0
- tensorbored/util/grpc_util.py +311 -0
- tensorbored/util/img_mime_type_detector.py +40 -0
- tensorbored/util/io_util.py +20 -0
- tensorbored/util/lazy_tensor_creator.py +110 -0
- tensorbored/util/op_evaluator.py +104 -0
- tensorbored/util/platform_util.py +20 -0
- tensorbored/util/tb_logging.py +24 -0
- tensorbored/util/tensor_util.py +617 -0
- tensorbored/util/timing.py +122 -0
- tensorbored/version.py +21 -0
- tensorbored/webfiles.zip +0 -0
- tensorbored-2.21.0rc1769983804.dist-info/METADATA +49 -0
- tensorbored-2.21.0rc1769983804.dist-info/RECORD +271 -0
- tensorbored-2.21.0rc1769983804.dist-info/WHEEL +5 -0
- tensorbored-2.21.0rc1769983804.dist-info/entry_points.txt +6 -0
- tensorbored-2.21.0rc1769983804.dist-info/licenses/LICENSE +739 -0
- tensorbored-2.21.0rc1769983804.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
# ==============================================================================
|
|
16
|
+
"""Utilities for handling Keras model in graph plugin.
|
|
17
|
+
|
|
18
|
+
Two canonical types of Keras model are Functional and Sequential.
|
|
19
|
+
A model can be serialized as JSON and deserialized to reconstruct a model.
|
|
20
|
+
This utility helps with dealing with the serialized Keras model.
|
|
21
|
+
|
|
22
|
+
They have distinct structures to the configurations in shapes below:
|
|
23
|
+
Functional:
|
|
24
|
+
config
|
|
25
|
+
name: Name of the model. If not specified, it is 'model' with
|
|
26
|
+
an optional suffix if there are more than one instance.
|
|
27
|
+
input_layers: Keras.layers.Inputs in the model.
|
|
28
|
+
output_layers: Layer names that are outputs of the model.
|
|
29
|
+
layers: list of layer configurations.
|
|
30
|
+
layer: [*]
|
|
31
|
+
inbound_nodes: inputs to this layer.
|
|
32
|
+
|
|
33
|
+
Sequential:
|
|
34
|
+
config
|
|
35
|
+
name: Name of the model. If not specified, it is 'sequential' with
|
|
36
|
+
an optional suffix if there are more than one instance.
|
|
37
|
+
layers: list of layer configurations.
|
|
38
|
+
layer: [*]
|
|
39
|
+
|
|
40
|
+
[*]: Note that a model can be a layer.
|
|
41
|
+
Please refer to https://github.com/tensorflow/tfjs-layers/blob/master/src/keras_format/model_serialization.ts
|
|
42
|
+
for more complete definition.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
from tensorbored.compat.proto.graph_pb2 import GraphDef
|
|
46
|
+
from tensorbored.compat.tensorflow_stub import dtypes
|
|
47
|
+
from tensorbored.util import tb_logging
|
|
48
|
+
|
|
49
|
+
logger = tb_logging.get_logger()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _walk_layers(keras_layer):
|
|
53
|
+
"""Walks the nested keras layer configuration in preorder.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
keras_layer: Keras configuration from model.to_json.
|
|
57
|
+
|
|
58
|
+
Yields:
|
|
59
|
+
A tuple of (name_scope, layer_config).
|
|
60
|
+
name_scope: a string representing a scope name, similar to that of tf.name_scope.
|
|
61
|
+
layer_config: a dict representing a Keras layer configuration.
|
|
62
|
+
"""
|
|
63
|
+
yield ("", keras_layer)
|
|
64
|
+
if keras_layer.get("config").get("layers"):
|
|
65
|
+
name_scope = keras_layer.get("config").get("name")
|
|
66
|
+
for layer in keras_layer.get("config").get("layers"):
|
|
67
|
+
for sub_name_scope, sublayer in _walk_layers(layer):
|
|
68
|
+
sub_name_scope = (
|
|
69
|
+
"%s/%s" % (name_scope, sub_name_scope)
|
|
70
|
+
if sub_name_scope
|
|
71
|
+
else name_scope
|
|
72
|
+
)
|
|
73
|
+
yield (sub_name_scope, sublayer)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _scoped_name(name_scope, node_name):
|
|
77
|
+
"""Returns scoped name for a node as a string in the form '<scope>/<node
|
|
78
|
+
name>'.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
name_scope: a string representing a scope name, similar to that of tf.name_scope.
|
|
82
|
+
node_name: a string representing the current node name.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
A string representing a scoped name.
|
|
86
|
+
"""
|
|
87
|
+
if name_scope:
|
|
88
|
+
return "%s/%s" % (name_scope, node_name)
|
|
89
|
+
return node_name
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _is_model(layer):
|
|
93
|
+
"""Returns True if layer is a model.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
layer: a dict representing a Keras model configuration.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
bool: True if layer is a model.
|
|
100
|
+
"""
|
|
101
|
+
return layer.get("config").get("layers") is not None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _norm_to_list_of_layers(maybe_layers):
|
|
105
|
+
"""Normalizes to a list of layers.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
maybe_layers: A list of data[1] or a list of list of data.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
List of list of data.
|
|
112
|
+
|
|
113
|
+
[1]: A Functional model has fields 'inbound_nodes' and 'output_layers' which can
|
|
114
|
+
look like below:
|
|
115
|
+
- ['in_layer_name', 0, 0]
|
|
116
|
+
- [['in_layer_is_model', 1, 0], ['in_layer_is_model', 1, 1]]
|
|
117
|
+
The data inside the list seems to describe [name, size, index].
|
|
118
|
+
"""
|
|
119
|
+
return (
|
|
120
|
+
maybe_layers if isinstance(maybe_layers[0], (list,)) else [maybe_layers]
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _get_inbound_nodes(layer):
|
|
125
|
+
"""Returns a list of [name, size, index] for all inbound nodes of the given layer."""
|
|
126
|
+
inbound_nodes = []
|
|
127
|
+
if layer.get("inbound_nodes") is not None:
|
|
128
|
+
for maybe_inbound_node in layer.get("inbound_nodes", []):
|
|
129
|
+
if not isinstance(maybe_inbound_node, dict):
|
|
130
|
+
# Note that the inbound node parsing is not backward compatible with
|
|
131
|
+
# Keras 2. If given a Keras 2 model, the input nodes will be missing
|
|
132
|
+
# in the final graph.
|
|
133
|
+
continue
|
|
134
|
+
for inbound_node_args in maybe_inbound_node.get("args", []):
|
|
135
|
+
# Sometimes this field is a list when there are multiple inbound nodes
|
|
136
|
+
# for the given layer.
|
|
137
|
+
if not isinstance(inbound_node_args, list):
|
|
138
|
+
inbound_node_args = [inbound_node_args]
|
|
139
|
+
for arg in inbound_node_args:
|
|
140
|
+
history = arg.get("config", {}).get("keras_history", [])
|
|
141
|
+
if len(history) < 3:
|
|
142
|
+
continue
|
|
143
|
+
inbound_nodes.append(history[:3])
|
|
144
|
+
return inbound_nodes
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _update_dicts(
|
|
148
|
+
name_scope,
|
|
149
|
+
model_layer,
|
|
150
|
+
input_to_in_layer,
|
|
151
|
+
model_name_to_output,
|
|
152
|
+
prev_node_name,
|
|
153
|
+
):
|
|
154
|
+
"""Updates input_to_in_layer, model_name_to_output, and prev_node_name
|
|
155
|
+
based on the model_layer.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
name_scope: a string representing a scope name, similar to that of tf.name_scope.
|
|
159
|
+
model_layer: a dict representing a Keras model configuration.
|
|
160
|
+
input_to_in_layer: a dict mapping Keras.layers.Input to inbound layer.
|
|
161
|
+
model_name_to_output: a dict mapping Keras Model name to output layer of the model.
|
|
162
|
+
prev_node_name: a string representing a previous, in sequential model layout,
|
|
163
|
+
node name.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
A tuple of (input_to_in_layer, model_name_to_output, prev_node_name).
|
|
167
|
+
input_to_in_layer: a dict mapping Keras.layers.Input to inbound layer.
|
|
168
|
+
model_name_to_output: a dict mapping Keras Model name to output layer of the model.
|
|
169
|
+
prev_node_name: a string representing a previous, in sequential model layout,
|
|
170
|
+
node name.
|
|
171
|
+
"""
|
|
172
|
+
layer_config = model_layer.get("config")
|
|
173
|
+
if not layer_config.get("layers"):
|
|
174
|
+
raise ValueError("layer is not a model.")
|
|
175
|
+
|
|
176
|
+
node_name = _scoped_name(name_scope, layer_config.get("name"))
|
|
177
|
+
input_layers = layer_config.get("input_layers")
|
|
178
|
+
output_layers = layer_config.get("output_layers")
|
|
179
|
+
inbound_nodes = _get_inbound_nodes(model_layer)
|
|
180
|
+
|
|
181
|
+
is_functional_model = bool(input_layers and output_layers)
|
|
182
|
+
# In case of [1] and the parent model is functional, current layer
|
|
183
|
+
# will have the 'inbound_nodes' property.
|
|
184
|
+
is_parent_functional_model = bool(inbound_nodes)
|
|
185
|
+
|
|
186
|
+
if is_parent_functional_model and is_functional_model:
|
|
187
|
+
for input_layer, inbound_node in zip(input_layers, inbound_nodes):
|
|
188
|
+
input_layer_name = _scoped_name(node_name, input_layer)
|
|
189
|
+
inbound_node_name = _scoped_name(name_scope, inbound_node[0])
|
|
190
|
+
input_to_in_layer[input_layer_name] = inbound_node_name
|
|
191
|
+
elif is_parent_functional_model and not is_functional_model:
|
|
192
|
+
# Sequential model can take only one input. Make sure inbound to the
|
|
193
|
+
# model is linked to the first layer in the Sequential model.
|
|
194
|
+
prev_node_name = _scoped_name(name_scope, inbound_nodes[0][0])
|
|
195
|
+
elif (
|
|
196
|
+
not is_parent_functional_model
|
|
197
|
+
and prev_node_name
|
|
198
|
+
and is_functional_model
|
|
199
|
+
):
|
|
200
|
+
assert len(input_layers) == 1, (
|
|
201
|
+
"Cannot have multi-input Functional model when parent model "
|
|
202
|
+
"is not Functional. Number of input layers: %d" % len(input_layer)
|
|
203
|
+
)
|
|
204
|
+
input_layer = input_layers[0]
|
|
205
|
+
input_layer_name = _scoped_name(node_name, input_layer)
|
|
206
|
+
input_to_in_layer[input_layer_name] = prev_node_name
|
|
207
|
+
|
|
208
|
+
if is_functional_model and output_layers:
|
|
209
|
+
layers = _norm_to_list_of_layers(output_layers)
|
|
210
|
+
layer_names = [_scoped_name(node_name, layer[0]) for layer in layers]
|
|
211
|
+
model_name_to_output[node_name] = layer_names
|
|
212
|
+
else:
|
|
213
|
+
last_layer = layer_config.get("layers")[-1]
|
|
214
|
+
last_layer_name = last_layer.get("config").get("name")
|
|
215
|
+
output_node = _scoped_name(node_name, last_layer_name)
|
|
216
|
+
model_name_to_output[node_name] = [output_node]
|
|
217
|
+
return (input_to_in_layer, model_name_to_output, prev_node_name)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def keras_model_to_graph_def(keras_layer):
|
|
221
|
+
"""Returns a GraphDef representation of the Keras model in a dict form.
|
|
222
|
+
|
|
223
|
+
Note that it only supports models that implemented to_json().
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
keras_layer: A dict from Keras model.to_json().
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
A GraphDef representation of the layers in the model.
|
|
230
|
+
"""
|
|
231
|
+
input_to_layer = {}
|
|
232
|
+
model_name_to_output = {}
|
|
233
|
+
g = GraphDef()
|
|
234
|
+
|
|
235
|
+
# Sequential model layers do not have a field "inbound_nodes" but
|
|
236
|
+
# instead are defined implicitly via order of layers.
|
|
237
|
+
prev_node_name = None
|
|
238
|
+
|
|
239
|
+
for name_scope, layer in _walk_layers(keras_layer):
|
|
240
|
+
if _is_model(layer):
|
|
241
|
+
(
|
|
242
|
+
input_to_layer,
|
|
243
|
+
model_name_to_output,
|
|
244
|
+
prev_node_name,
|
|
245
|
+
) = _update_dicts(
|
|
246
|
+
name_scope,
|
|
247
|
+
layer,
|
|
248
|
+
input_to_layer,
|
|
249
|
+
model_name_to_output,
|
|
250
|
+
prev_node_name,
|
|
251
|
+
)
|
|
252
|
+
continue
|
|
253
|
+
|
|
254
|
+
layer_config = layer.get("config")
|
|
255
|
+
node_name = _scoped_name(name_scope, layer_config.get("name"))
|
|
256
|
+
|
|
257
|
+
node_def = g.node.add()
|
|
258
|
+
node_def.name = node_name
|
|
259
|
+
|
|
260
|
+
if layer.get("class_name") is not None:
|
|
261
|
+
keras_cls_name = layer.get("class_name").encode("ascii")
|
|
262
|
+
node_def.attr["keras_class"].s = keras_cls_name
|
|
263
|
+
|
|
264
|
+
dtype_or_policy = layer_config.get("dtype")
|
|
265
|
+
dtype = None
|
|
266
|
+
has_unsupported_value = False
|
|
267
|
+
# If this is a dict, try and extract the dtype string from
|
|
268
|
+
# `config.name`. Keras will export like this for non-input layers and
|
|
269
|
+
# some other cases (e.g. tf/keras/mixed_precision/Policy, as described
|
|
270
|
+
# in issue #5548).
|
|
271
|
+
if isinstance(dtype_or_policy, dict) and "config" in dtype_or_policy:
|
|
272
|
+
dtype = dtype_or_policy.get("config").get("name")
|
|
273
|
+
elif dtype_or_policy is not None:
|
|
274
|
+
dtype = dtype_or_policy
|
|
275
|
+
|
|
276
|
+
if dtype is not None:
|
|
277
|
+
try:
|
|
278
|
+
tf_dtype = dtypes.as_dtype(dtype)
|
|
279
|
+
node_def.attr["dtype"].type = tf_dtype.as_datatype_enum
|
|
280
|
+
except TypeError:
|
|
281
|
+
has_unsupported_value = True
|
|
282
|
+
elif dtype_or_policy is not None:
|
|
283
|
+
has_unsupported_value = True
|
|
284
|
+
|
|
285
|
+
if has_unsupported_value:
|
|
286
|
+
# There's at least one known case when this happens, which is when
|
|
287
|
+
# mixed precision dtype policies are used, as described in issue
|
|
288
|
+
# #5548. (See https://keras.io/api/mixed_precision/).
|
|
289
|
+
# There might be a better way to handle this, but here we are.
|
|
290
|
+
logger.warning(
|
|
291
|
+
"Unsupported dtype value in graph model config (json):\n%s",
|
|
292
|
+
dtype_or_policy,
|
|
293
|
+
)
|
|
294
|
+
if layer.get("inbound_nodes") is not None:
|
|
295
|
+
for name, size, index in _get_inbound_nodes(layer):
|
|
296
|
+
inbound_name = _scoped_name(name_scope, name)
|
|
297
|
+
# An input to a layer can be output from a model. In that case, the name
|
|
298
|
+
# of inbound_nodes to a layer is a name of a model. Remap the name of the
|
|
299
|
+
# model to output layer of the model. Also, since there can be multiple
|
|
300
|
+
# outputs in a model, make sure we pick the right output_layer from the model.
|
|
301
|
+
inbound_node_names = model_name_to_output.get(
|
|
302
|
+
inbound_name, [inbound_name]
|
|
303
|
+
)
|
|
304
|
+
# There can be multiple inbound_nodes that reference the
|
|
305
|
+
# same upstream layer. This causes issues when looking for
|
|
306
|
+
# a particular index in that layer, since the indices
|
|
307
|
+
# captured in `inbound_nodes` doesn't necessarily match the
|
|
308
|
+
# number of entries in the `inbound_node_names` list. To
|
|
309
|
+
# avoid IndexErrors, we just use the last element in the
|
|
310
|
+
# `inbound_node_names` in this situation.
|
|
311
|
+
# Note that this is a quick hack to avoid IndexErrors in
|
|
312
|
+
# this situation, and might not be an appropriate solution
|
|
313
|
+
# to this problem in general.
|
|
314
|
+
input_name = (
|
|
315
|
+
inbound_node_names[index]
|
|
316
|
+
if index < len(inbound_node_names)
|
|
317
|
+
else inbound_node_names[-1]
|
|
318
|
+
)
|
|
319
|
+
node_def.input.append(input_name)
|
|
320
|
+
elif prev_node_name is not None:
|
|
321
|
+
node_def.input.append(prev_node_name)
|
|
322
|
+
|
|
323
|
+
if node_name in input_to_layer:
|
|
324
|
+
node_def.input.append(input_to_layer.get(node_name))
|
|
325
|
+
|
|
326
|
+
prev_node_name = node_def.name
|
|
327
|
+
|
|
328
|
+
return g
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Information on the graph plugin."""
|
|
16
|
+
|
|
17
|
+
# This name is used as the plugin prefix route and to identify this plugin
|
|
18
|
+
# generally, and is also the `plugin_name` for run graphs after data-compat
|
|
19
|
+
# transformations.
|
|
20
|
+
PLUGIN_NAME = "graphs"
|
|
21
|
+
# The Summary API is implemented in TensorFlow because it uses TensorFlow internal APIs.
|
|
22
|
+
# As a result, this SummaryMetadata is a bit unconventional and uses non-public
|
|
23
|
+
# hardcoded name as the plugin name. Please refer to link below for the summary ops.
|
|
24
|
+
# https://github.com/tensorflow/tensorflow/blob/11f4ecb54708865ec757ca64e4805957b05d7570/tensorflow/python/ops/summary_ops_v2.py#L757
|
|
25
|
+
PLUGIN_NAME_RUN_METADATA = "graph_run_metadata"
|
|
26
|
+
# https://github.com/tensorflow/tensorflow/blob/11f4ecb54708865ec757ca64e4805957b05d7570/tensorflow/python/ops/summary_ops_v2.py#L788
|
|
27
|
+
PLUGIN_NAME_RUN_METADATA_WITH_GRAPH = "graph_run_metadata_graph"
|
|
28
|
+
# https://github.com/tensorflow/tensorflow/blob/565952cc2f17fdfd995e25171cf07be0f6f06180/tensorflow/python/ops/summary_ops_v2.py#L825
|
|
29
|
+
PLUGIN_NAME_KERAS_MODEL = "graph_keras_model"
|
|
30
|
+
# Plugin name used for `Event.tagged_run_metadata`. This doesn't fall into one
|
|
31
|
+
# of the above cases because (despite the name) `PLUGIN_NAME_RUN_METADATA` is
|
|
32
|
+
# _required_ to have both profile and op graphs, whereas tagged run metadata
|
|
33
|
+
# need only have profile data.
|
|
34
|
+
PLUGIN_NAME_TAGGED_RUN_METADATA = "graph_tagged_run_metadata"
|
|
35
|
+
|
|
36
|
+
# In the context of the data provider interface, tag name given to a
|
|
37
|
+
# graph read from the `graph_def` field of an `Event` proto, which is
|
|
38
|
+
# not attached to a summary and thus does not have a proper tag name of
|
|
39
|
+
# its own. Run level graphs always represent `GraphDef`s (graphs of
|
|
40
|
+
# TensorFlow ops), never conceptual graphs, profile graphs, etc. This is
|
|
41
|
+
# the only tag name used by the `"graphs"` plugin.
|
|
42
|
+
RUN_GRAPH_NAME = "__run_graph__"
|
|
File without changes
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""The TensorBoard Histograms plugin.
|
|
16
|
+
|
|
17
|
+
See `http_api.md` in this directory for specifications of the routes for
|
|
18
|
+
this plugin.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from werkzeug import wrappers
|
|
22
|
+
|
|
23
|
+
from tensorbored import errors
|
|
24
|
+
from tensorbored import plugin_util
|
|
25
|
+
from tensorbored.backend import http_util
|
|
26
|
+
from tensorbored.data import provider
|
|
27
|
+
from tensorbored.plugins import base_plugin
|
|
28
|
+
from tensorbored.plugins.histogram import metadata
|
|
29
|
+
|
|
30
|
+
_DEFAULT_DOWNSAMPLING = 500 # histograms per time series
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class HistogramsPlugin(base_plugin.TBPlugin):
|
|
34
|
+
"""Histograms Plugin for TensorBoard.
|
|
35
|
+
|
|
36
|
+
This supports both old-style summaries (created with TensorFlow ops
|
|
37
|
+
that output directly to the `histo` field of the proto) and new-
|
|
38
|
+
style summaries (as created by the
|
|
39
|
+
`tensorboard.plugins.histogram.summary` module).
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
plugin_name = metadata.PLUGIN_NAME
|
|
43
|
+
|
|
44
|
+
# Use a round number + 1 since sampling includes both start and end steps,
|
|
45
|
+
# so N+1 samples corresponds to dividing the step sequence into N intervals.
|
|
46
|
+
SAMPLE_SIZE = 51
|
|
47
|
+
|
|
48
|
+
def __init__(self, context):
|
|
49
|
+
"""Instantiates HistogramsPlugin via TensorBoard core.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
context: A base_plugin.TBContext instance.
|
|
53
|
+
"""
|
|
54
|
+
self._downsample_to = (context.sampling_hints or {}).get(
|
|
55
|
+
self.plugin_name, _DEFAULT_DOWNSAMPLING
|
|
56
|
+
)
|
|
57
|
+
self._data_provider = context.data_provider
|
|
58
|
+
self._version_checker = plugin_util._MetadataVersionChecker(
|
|
59
|
+
data_kind="histogram",
|
|
60
|
+
latest_known_version=0,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def get_plugin_apps(self):
|
|
64
|
+
return {
|
|
65
|
+
"/histograms": self.histograms_route,
|
|
66
|
+
"/tags": self.tags_route,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
def is_active(self):
|
|
70
|
+
return False # `list_plugins` as called by TB core suffices
|
|
71
|
+
|
|
72
|
+
def index_impl(self, ctx, experiment):
|
|
73
|
+
"""Return {runName: {tagName: {displayName: ..., description:
|
|
74
|
+
...}}}."""
|
|
75
|
+
mapping = self._data_provider.list_tensors(
|
|
76
|
+
ctx,
|
|
77
|
+
experiment_id=experiment,
|
|
78
|
+
plugin_name=metadata.PLUGIN_NAME,
|
|
79
|
+
)
|
|
80
|
+
result = {run: {} for run in mapping}
|
|
81
|
+
for run, tag_to_content in mapping.items():
|
|
82
|
+
for tag, metadatum in tag_to_content.items():
|
|
83
|
+
description = plugin_util.markdown_to_safe_html(
|
|
84
|
+
metadatum.description
|
|
85
|
+
)
|
|
86
|
+
md = metadata.parse_plugin_metadata(metadatum.plugin_content)
|
|
87
|
+
if not self._version_checker.ok(md.version, run, tag):
|
|
88
|
+
continue
|
|
89
|
+
result[run][tag] = {
|
|
90
|
+
"displayName": metadatum.display_name,
|
|
91
|
+
"description": description,
|
|
92
|
+
}
|
|
93
|
+
return result
|
|
94
|
+
|
|
95
|
+
def frontend_metadata(self):
|
|
96
|
+
return base_plugin.FrontendMetadata(
|
|
97
|
+
element_name="tf-histogram-dashboard"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def histograms_impl(self, ctx, tag, run, experiment, downsample_to=None):
|
|
101
|
+
"""Result of the form `(body, mime_type)`.
|
|
102
|
+
|
|
103
|
+
At most `downsample_to` events will be returned. If this value is
|
|
104
|
+
`None`, then default downsampling will be performed.
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
tensorboard.errors.PublicError: On invalid request.
|
|
108
|
+
"""
|
|
109
|
+
sample_count = (
|
|
110
|
+
downsample_to if downsample_to is not None else self._downsample_to
|
|
111
|
+
)
|
|
112
|
+
all_histograms = self._data_provider.read_tensors(
|
|
113
|
+
ctx,
|
|
114
|
+
experiment_id=experiment,
|
|
115
|
+
plugin_name=metadata.PLUGIN_NAME,
|
|
116
|
+
downsample=sample_count,
|
|
117
|
+
run_tag_filter=provider.RunTagFilter(runs=[run], tags=[tag]),
|
|
118
|
+
)
|
|
119
|
+
histograms = all_histograms.get(run, {}).get(tag, None)
|
|
120
|
+
if histograms is None:
|
|
121
|
+
raise errors.NotFoundError(
|
|
122
|
+
"No histogram tag %r for run %r" % (tag, run)
|
|
123
|
+
)
|
|
124
|
+
events = [(e.wall_time, e.step, e.numpy.tolist()) for e in histograms]
|
|
125
|
+
return (events, "application/json")
|
|
126
|
+
|
|
127
|
+
@wrappers.Request.application
|
|
128
|
+
def tags_route(self, request):
|
|
129
|
+
ctx = plugin_util.context(request.environ)
|
|
130
|
+
experiment = plugin_util.experiment_id(request.environ)
|
|
131
|
+
index = self.index_impl(ctx, experiment=experiment)
|
|
132
|
+
return http_util.Respond(request, index, "application/json")
|
|
133
|
+
|
|
134
|
+
@wrappers.Request.application
|
|
135
|
+
def histograms_route(self, request):
|
|
136
|
+
"""Given a tag and single run, return array of histogram values."""
|
|
137
|
+
ctx = plugin_util.context(request.environ)
|
|
138
|
+
experiment = plugin_util.experiment_id(request.environ)
|
|
139
|
+
tag = request.args.get("tag")
|
|
140
|
+
run = request.args.get("run")
|
|
141
|
+
body, mime_type = self.histograms_impl(
|
|
142
|
+
ctx, tag, run, experiment=experiment, downsample_to=self.SAMPLE_SIZE
|
|
143
|
+
)
|
|
144
|
+
return http_util.Respond(request, body, mime_type)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Information about histogram summaries."""
|
|
16
|
+
|
|
17
|
+
from tensorbored.compat.proto import summary_pb2
|
|
18
|
+
from tensorbored.plugins.histogram import plugin_data_pb2
|
|
19
|
+
|
|
20
|
+
PLUGIN_NAME = "histograms"
|
|
21
|
+
|
|
22
|
+
# The most recent value for the `version` field of the
|
|
23
|
+
# `HistogramPluginData` proto.
|
|
24
|
+
PROTO_VERSION = 0
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_summary_metadata(display_name, description):
|
|
28
|
+
"""Create a `summary_pb2.SummaryMetadata` proto for histogram plugin data.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
A `summary_pb2.SummaryMetadata` protobuf object.
|
|
32
|
+
"""
|
|
33
|
+
content = plugin_data_pb2.HistogramPluginData(version=PROTO_VERSION)
|
|
34
|
+
return summary_pb2.SummaryMetadata(
|
|
35
|
+
display_name=display_name,
|
|
36
|
+
summary_description=description,
|
|
37
|
+
plugin_data=summary_pb2.SummaryMetadata.PluginData(
|
|
38
|
+
plugin_name=PLUGIN_NAME, content=content.SerializeToString()
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def parse_plugin_metadata(content):
|
|
44
|
+
"""Parse summary metadata to a Python object.
|
|
45
|
+
|
|
46
|
+
Arguments:
|
|
47
|
+
content: The `content` field of a `SummaryMetadata` proto
|
|
48
|
+
corresponding to the histogram plugin.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
A `HistogramPluginData` protobuf object.
|
|
52
|
+
"""
|
|
53
|
+
if not isinstance(content, bytes):
|
|
54
|
+
raise TypeError("Content type must be bytes")
|
|
55
|
+
if content == b"{}":
|
|
56
|
+
# Old-style JSON format. Equivalent to an all-default proto.
|
|
57
|
+
return plugin_data_pb2.HistogramPluginData()
|
|
58
|
+
else:
|
|
59
|
+
result = plugin_data_pb2.HistogramPluginData.FromString(content)
|
|
60
|
+
if result.version == 0:
|
|
61
|
+
return result
|
|
62
|
+
# No other versions known at this time, so no migrations to do.
|
|
63
|
+
return result
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# source: tensorbored/plugins/histogram/plugin_data.proto
|
|
4
|
+
"""Generated protocol buffer code."""
|
|
5
|
+
from google.protobuf import descriptor as _descriptor
|
|
6
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
7
|
+
from google.protobuf import message as _message
|
|
8
|
+
from google.protobuf import reflection as _reflection
|
|
9
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
10
|
+
# @@protoc_insertion_point(imports)
|
|
11
|
+
|
|
12
|
+
_sym_db = _symbol_database.Default()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n/tensorbored/plugins/histogram/plugin_data.proto\x12\x0btensorbored\"&\n\x13HistogramPluginData\x12\x0f\n\x07version\x18\x01 \x01(\x05\x62\x06proto3')
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_HISTOGRAMPLUGINDATA = DESCRIPTOR.message_types_by_name['HistogramPluginData']
|
|
22
|
+
HistogramPluginData = _reflection.GeneratedProtocolMessageType('HistogramPluginData', (_message.Message,), {
|
|
23
|
+
'DESCRIPTOR' : _HISTOGRAMPLUGINDATA,
|
|
24
|
+
'__module__' : 'tensorbored.plugins.histogram.plugin_data_pb2'
|
|
25
|
+
# @@protoc_insertion_point(class_scope:tensorbored.HistogramPluginData)
|
|
26
|
+
})
|
|
27
|
+
_sym_db.RegisterMessage(HistogramPluginData)
|
|
28
|
+
|
|
29
|
+
if _descriptor._USE_C_DESCRIPTORS == False:
|
|
30
|
+
|
|
31
|
+
DESCRIPTOR._options = None
|
|
32
|
+
_HISTOGRAMPLUGINDATA._serialized_start=64
|
|
33
|
+
_HISTOGRAMPLUGINDATA._serialized_end=102
|
|
34
|
+
# @@protoc_insertion_point(module_scope)
|