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,116 @@
|
|
|
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 Distributions (a.k.a. compressed 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 plugin_util
|
|
24
|
+
from tensorbored.backend import http_util
|
|
25
|
+
from tensorbored.plugins import base_plugin
|
|
26
|
+
from tensorbored.plugins.distribution import compressor
|
|
27
|
+
from tensorbored.plugins.distribution import metadata
|
|
28
|
+
from tensorbored.plugins.histogram import histograms_plugin
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DistributionsPlugin(base_plugin.TBPlugin):
|
|
32
|
+
"""Distributions Plugin for TensorBoard.
|
|
33
|
+
|
|
34
|
+
This supports both old-style summaries (created with TensorFlow ops
|
|
35
|
+
that output directly to the `histo` field of the proto) and new-
|
|
36
|
+
style summaries (as created by the
|
|
37
|
+
`tensorboard.plugins.histogram.summary` module).
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
plugin_name = metadata.PLUGIN_NAME
|
|
41
|
+
|
|
42
|
+
# Use a round number + 1 since sampling includes both start and end steps,
|
|
43
|
+
# so N+1 samples corresponds to dividing the step sequence into N intervals.
|
|
44
|
+
SAMPLE_SIZE = 501
|
|
45
|
+
|
|
46
|
+
def __init__(self, context):
|
|
47
|
+
"""Instantiates DistributionsPlugin via TensorBoard core.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
context: A base_plugin.TBContext instance.
|
|
51
|
+
"""
|
|
52
|
+
self._histograms_plugin = histograms_plugin.HistogramsPlugin(context)
|
|
53
|
+
|
|
54
|
+
def get_plugin_apps(self):
|
|
55
|
+
return {
|
|
56
|
+
"/distributions": self.distributions_route,
|
|
57
|
+
"/tags": self.tags_route,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
def is_active(self):
|
|
61
|
+
"""This plugin is active iff any run has at least one histogram tag.
|
|
62
|
+
|
|
63
|
+
(The distributions plugin uses the same data source as the
|
|
64
|
+
histogram plugin.)
|
|
65
|
+
"""
|
|
66
|
+
return self._histograms_plugin.is_active()
|
|
67
|
+
|
|
68
|
+
def data_plugin_names(self):
|
|
69
|
+
return (self._histograms_plugin.plugin_name,)
|
|
70
|
+
|
|
71
|
+
def frontend_metadata(self):
|
|
72
|
+
return base_plugin.FrontendMetadata(
|
|
73
|
+
element_name="tf-distribution-dashboard",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def distributions_impl(self, ctx, tag, run, experiment):
|
|
77
|
+
"""Result of the form `(body, mime_type)`.
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
tensorboard.errors.PublicError: On invalid request.
|
|
81
|
+
"""
|
|
82
|
+
histograms, mime_type = self._histograms_plugin.histograms_impl(
|
|
83
|
+
ctx, tag, run, experiment=experiment, downsample_to=self.SAMPLE_SIZE
|
|
84
|
+
)
|
|
85
|
+
return (
|
|
86
|
+
[self._compress(histogram) for histogram in histograms],
|
|
87
|
+
mime_type,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def _compress(self, histogram):
|
|
91
|
+
wall_time, step, buckets = histogram
|
|
92
|
+
converted_buckets = compressor.compress_histogram(buckets)
|
|
93
|
+
return [wall_time, step, converted_buckets]
|
|
94
|
+
|
|
95
|
+
def index_impl(self, ctx, experiment):
|
|
96
|
+
return self._histograms_plugin.index_impl(ctx, experiment=experiment)
|
|
97
|
+
|
|
98
|
+
@wrappers.Request.application
|
|
99
|
+
def tags_route(self, request):
|
|
100
|
+
ctx = plugin_util.context(request.environ)
|
|
101
|
+
experiment = plugin_util.experiment_id(request.environ)
|
|
102
|
+
index = self.index_impl(ctx, experiment=experiment)
|
|
103
|
+
return http_util.Respond(request, index, "application/json")
|
|
104
|
+
|
|
105
|
+
@wrappers.Request.application
|
|
106
|
+
def distributions_route(self, request):
|
|
107
|
+
"""Given a tag and single run, return an array of compressed
|
|
108
|
+
histograms."""
|
|
109
|
+
ctx = plugin_util.context(request.environ)
|
|
110
|
+
experiment = plugin_util.experiment_id(request.environ)
|
|
111
|
+
tag = request.args.get("tag")
|
|
112
|
+
run = request.args.get("run")
|
|
113
|
+
body, mime_type = self.distributions_impl(
|
|
114
|
+
ctx, tag, run, experiment=experiment
|
|
115
|
+
)
|
|
116
|
+
return http_util.Respond(request, body, mime_type)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Copyright 2020 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 distributions plugin."""
|
|
16
|
+
|
|
17
|
+
# This name is used as the plugin prefix route and to identify this plugin
|
|
18
|
+
# generally.
|
|
19
|
+
PLUGIN_NAME = "distributions"
|
|
File without changes
|
|
@@ -0,0 +1,129 @@
|
|
|
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
|
+
"""Utilities for graph plugin."""
|
|
16
|
+
|
|
17
|
+
from tensorbored.compat.proto import graph_pb2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _prefixed_op_name(prefix, op_name):
|
|
21
|
+
return "%s/%s" % (prefix, op_name)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _prefixed_func_name(prefix, func_name):
|
|
25
|
+
"""Returns function name prefixed with `prefix`.
|
|
26
|
+
|
|
27
|
+
For function libraries, which are often created out of autographed Python
|
|
28
|
+
function, are factored out in the graph vis. They are grouped under a
|
|
29
|
+
function name which often has a shape of
|
|
30
|
+
`__inference_[py_func_name]_[numeric_suffix]`.
|
|
31
|
+
|
|
32
|
+
While it does not have some unique information about which graph it is from,
|
|
33
|
+
creating another wrapping structure with graph prefix and "/" is less than
|
|
34
|
+
ideal so we join the prefix and func_name using underscore.
|
|
35
|
+
|
|
36
|
+
TODO(stephanwlee): add business logic to strip "__inference_" for more user
|
|
37
|
+
friendlier name
|
|
38
|
+
"""
|
|
39
|
+
return "%s_%s" % (prefix, func_name)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _add_with_prepended_names(prefix, graph_to_add, destination_graph):
|
|
43
|
+
for node in graph_to_add.node:
|
|
44
|
+
new_node = destination_graph.node.add()
|
|
45
|
+
new_node.CopyFrom(node)
|
|
46
|
+
new_node.name = _prefixed_op_name(prefix, node.name)
|
|
47
|
+
new_node.input[:] = [
|
|
48
|
+
_prefixed_op_name(prefix, input_name) for input_name in node.input
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
# Remap tf.function method name in the PartitionedCall. 'f' is short for
|
|
52
|
+
# function.
|
|
53
|
+
if new_node.op == "PartitionedCall" and new_node.attr["f"]:
|
|
54
|
+
|
|
55
|
+
new_node.attr["f"].func.name = _prefixed_func_name(
|
|
56
|
+
prefix,
|
|
57
|
+
new_node.attr["f"].func.name,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
for func in graph_to_add.library.function:
|
|
61
|
+
new_func = destination_graph.library.function.add()
|
|
62
|
+
new_func.CopyFrom(func)
|
|
63
|
+
new_func.signature.name = _prefixed_func_name(
|
|
64
|
+
prefix, new_func.signature.name
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
for gradient in graph_to_add.library.gradient:
|
|
68
|
+
new_gradient = destination_graph.library.gradient.add()
|
|
69
|
+
new_gradient.CopyFrom(gradient)
|
|
70
|
+
new_gradient.function_name = _prefixed_func_name(
|
|
71
|
+
prefix,
|
|
72
|
+
new_gradient.function_name,
|
|
73
|
+
)
|
|
74
|
+
new_gradient.gradient_func = _prefixed_func_name(
|
|
75
|
+
prefix,
|
|
76
|
+
new_gradient.gradient_func,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def merge_graph_defs(graph_defs):
|
|
81
|
+
"""Merges GraphDefs by adding unique prefix, `graph_{ind}`, to names.
|
|
82
|
+
|
|
83
|
+
All GraphDefs are expected to be of TensorBoard's.
|
|
84
|
+
|
|
85
|
+
When collecting graphs using the `tf.summary.trace` API, node names are not
|
|
86
|
+
guranteed to be unique. When non-unique names are not considered, it can
|
|
87
|
+
lead to graph visualization showing them as one which creates inaccurate
|
|
88
|
+
depiction of the flow of the graph (e.g., if there are A -> B -> C and D ->
|
|
89
|
+
B -> E, you may see {A, D} -> B -> E). To prevent such graph, we checked
|
|
90
|
+
for uniquenss while merging but it resulted in
|
|
91
|
+
https://github.com/tensorflow/tensorboard/issues/1929.
|
|
92
|
+
|
|
93
|
+
To remedy these issues, we simply "apply name scope" on each graph by
|
|
94
|
+
prefixing it with unique name (with a chance of collision) to create
|
|
95
|
+
unconnected group of graphs.
|
|
96
|
+
|
|
97
|
+
In case there is only one graph def passed, it returns the original
|
|
98
|
+
graph_def. In case no graph defs are passed, it returns an empty GraphDef.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
graph_defs: TensorBoard GraphDefs to merge.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
TensorBoard GraphDef that merges all graph_defs with unique prefixes.
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
ValueError in case GraphDef versions mismatch.
|
|
108
|
+
"""
|
|
109
|
+
if len(graph_defs) == 1:
|
|
110
|
+
return graph_defs[0]
|
|
111
|
+
elif len(graph_defs) == 0:
|
|
112
|
+
return graph_pb2.GraphDef()
|
|
113
|
+
|
|
114
|
+
dst_graph_def = graph_pb2.GraphDef()
|
|
115
|
+
|
|
116
|
+
if graph_defs[0].versions.producer:
|
|
117
|
+
dst_graph_def.versions.CopyFrom(graph_defs[0].versions)
|
|
118
|
+
|
|
119
|
+
for index, graph_def in enumerate(graph_defs):
|
|
120
|
+
if dst_graph_def.versions.producer != graph_def.versions.producer:
|
|
121
|
+
raise ValueError("Cannot combine GraphDefs of different versions.")
|
|
122
|
+
|
|
123
|
+
_add_with_prepended_names(
|
|
124
|
+
"graph_%d" % (index + 1),
|
|
125
|
+
graph_def,
|
|
126
|
+
dst_graph_def,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
return dst_graph_def
|
|
@@ -0,0 +1,336 @@
|
|
|
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 Graphs plugin."""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from werkzeug import wrappers
|
|
19
|
+
|
|
20
|
+
from tensorbored import errors
|
|
21
|
+
from tensorbored import plugin_util
|
|
22
|
+
from tensorbored.backend import http_util
|
|
23
|
+
from tensorbored.backend import process_graph
|
|
24
|
+
from tensorbored.compat.proto import config_pb2
|
|
25
|
+
from tensorbored.compat.proto import graph_pb2
|
|
26
|
+
from tensorbored.data import provider
|
|
27
|
+
from tensorbored.plugins import base_plugin
|
|
28
|
+
from tensorbored.plugins.graph import graph_util
|
|
29
|
+
from tensorbored.plugins.graph import keras_util
|
|
30
|
+
from tensorbored.plugins.graph import metadata
|
|
31
|
+
from tensorbored.util import tb_logging
|
|
32
|
+
|
|
33
|
+
logger = tb_logging.get_logger()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class GraphsPlugin(base_plugin.TBPlugin):
|
|
37
|
+
"""Graphs Plugin for TensorBoard."""
|
|
38
|
+
|
|
39
|
+
plugin_name = metadata.PLUGIN_NAME
|
|
40
|
+
|
|
41
|
+
def __init__(self, context):
|
|
42
|
+
"""Instantiates GraphsPlugin via TensorBoard core.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
context: A base_plugin.TBContext instance.
|
|
46
|
+
"""
|
|
47
|
+
self._data_provider = context.data_provider
|
|
48
|
+
|
|
49
|
+
def get_plugin_apps(self):
|
|
50
|
+
return {
|
|
51
|
+
"/graph": self.graph_route,
|
|
52
|
+
"/info": self.info_route,
|
|
53
|
+
"/run_metadata": self.run_metadata_route,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
def is_active(self):
|
|
57
|
+
"""The graphs plugin is active iff any run has a graph or metadata."""
|
|
58
|
+
return False # `list_plugins` as called by TB core suffices
|
|
59
|
+
|
|
60
|
+
def data_plugin_names(self):
|
|
61
|
+
return (
|
|
62
|
+
metadata.PLUGIN_NAME,
|
|
63
|
+
metadata.PLUGIN_NAME_RUN_METADATA,
|
|
64
|
+
metadata.PLUGIN_NAME_RUN_METADATA_WITH_GRAPH,
|
|
65
|
+
metadata.PLUGIN_NAME_KERAS_MODEL,
|
|
66
|
+
metadata.PLUGIN_NAME_TAGGED_RUN_METADATA,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def frontend_metadata(self):
|
|
70
|
+
return base_plugin.FrontendMetadata(
|
|
71
|
+
element_name="tf-graph-dashboard",
|
|
72
|
+
# TODO(@chihuahua): Reconcile this setting with Health Pills.
|
|
73
|
+
disable_reload=True,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def info_impl(self, ctx, experiment=None):
|
|
77
|
+
"""Returns a dict of all runs and their data availabilities."""
|
|
78
|
+
result = {}
|
|
79
|
+
|
|
80
|
+
def add_row_item(run, tag=None):
|
|
81
|
+
run_item = result.setdefault(
|
|
82
|
+
run,
|
|
83
|
+
{
|
|
84
|
+
"run": run,
|
|
85
|
+
"tags": {},
|
|
86
|
+
# A run-wide GraphDef of ops.
|
|
87
|
+
"run_graph": False,
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
tag_item = None
|
|
92
|
+
if tag:
|
|
93
|
+
tag_item = run_item.get("tags").setdefault(
|
|
94
|
+
tag,
|
|
95
|
+
{
|
|
96
|
+
"tag": tag,
|
|
97
|
+
"conceptual_graph": False,
|
|
98
|
+
# A tagged GraphDef of ops.
|
|
99
|
+
"op_graph": False,
|
|
100
|
+
"profile": False,
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
return (run_item, tag_item)
|
|
104
|
+
|
|
105
|
+
mapping = self._data_provider.list_blob_sequences(
|
|
106
|
+
ctx,
|
|
107
|
+
experiment_id=experiment,
|
|
108
|
+
plugin_name=metadata.PLUGIN_NAME_RUN_METADATA_WITH_GRAPH,
|
|
109
|
+
)
|
|
110
|
+
for run_name, tags in mapping.items():
|
|
111
|
+
for tag, tag_data in tags.items():
|
|
112
|
+
# The Summary op is defined in TensorFlow and does not use a stringified proto
|
|
113
|
+
# as a content of plugin data. It contains single string that denotes a version.
|
|
114
|
+
# https://github.com/tensorflow/tensorflow/blob/11f4ecb54708865ec757ca64e4805957b05d7570/tensorflow/python/ops/summary_ops_v2.py#L789-L790
|
|
115
|
+
if tag_data.plugin_content != b"1":
|
|
116
|
+
logger.warning(
|
|
117
|
+
"Ignoring unrecognizable version of RunMetadata."
|
|
118
|
+
)
|
|
119
|
+
continue
|
|
120
|
+
_, tag_item = add_row_item(run_name, tag)
|
|
121
|
+
tag_item["op_graph"] = True
|
|
122
|
+
|
|
123
|
+
# Tensors associated with plugin name metadata.PLUGIN_NAME_RUN_METADATA
|
|
124
|
+
# contain both op graph and profile information.
|
|
125
|
+
mapping = self._data_provider.list_blob_sequences(
|
|
126
|
+
ctx,
|
|
127
|
+
experiment_id=experiment,
|
|
128
|
+
plugin_name=metadata.PLUGIN_NAME_RUN_METADATA,
|
|
129
|
+
)
|
|
130
|
+
for run_name, tags in mapping.items():
|
|
131
|
+
for tag, tag_data in tags.items():
|
|
132
|
+
if tag_data.plugin_content != b"1":
|
|
133
|
+
logger.warning(
|
|
134
|
+
"Ignoring unrecognizable version of RunMetadata."
|
|
135
|
+
)
|
|
136
|
+
continue
|
|
137
|
+
_, tag_item = add_row_item(run_name, tag)
|
|
138
|
+
tag_item["profile"] = True
|
|
139
|
+
tag_item["op_graph"] = True
|
|
140
|
+
|
|
141
|
+
# Tensors associated with plugin name metadata.PLUGIN_NAME_KERAS_MODEL
|
|
142
|
+
# contain serialized Keras model in JSON format.
|
|
143
|
+
mapping = self._data_provider.list_blob_sequences(
|
|
144
|
+
ctx,
|
|
145
|
+
experiment_id=experiment,
|
|
146
|
+
plugin_name=metadata.PLUGIN_NAME_KERAS_MODEL,
|
|
147
|
+
)
|
|
148
|
+
for run_name, tags in mapping.items():
|
|
149
|
+
for tag, tag_data in tags.items():
|
|
150
|
+
if tag_data.plugin_content != b"1":
|
|
151
|
+
logger.warning(
|
|
152
|
+
"Ignoring unrecognizable version of RunMetadata."
|
|
153
|
+
)
|
|
154
|
+
continue
|
|
155
|
+
_, tag_item = add_row_item(run_name, tag)
|
|
156
|
+
tag_item["conceptual_graph"] = True
|
|
157
|
+
|
|
158
|
+
mapping = self._data_provider.list_blob_sequences(
|
|
159
|
+
ctx,
|
|
160
|
+
experiment_id=experiment,
|
|
161
|
+
plugin_name=metadata.PLUGIN_NAME,
|
|
162
|
+
)
|
|
163
|
+
for run_name, tags in mapping.items():
|
|
164
|
+
if metadata.RUN_GRAPH_NAME in tags:
|
|
165
|
+
run_item, _ = add_row_item(run_name, None)
|
|
166
|
+
run_item["run_graph"] = True
|
|
167
|
+
|
|
168
|
+
# Top level `Event.tagged_run_metadata` represents profile data only.
|
|
169
|
+
mapping = self._data_provider.list_blob_sequences(
|
|
170
|
+
ctx,
|
|
171
|
+
experiment_id=experiment,
|
|
172
|
+
plugin_name=metadata.PLUGIN_NAME_TAGGED_RUN_METADATA,
|
|
173
|
+
)
|
|
174
|
+
for run_name, tags in mapping.items():
|
|
175
|
+
for tag in tags:
|
|
176
|
+
_, tag_item = add_row_item(run_name, tag)
|
|
177
|
+
tag_item["profile"] = True
|
|
178
|
+
|
|
179
|
+
return result
|
|
180
|
+
|
|
181
|
+
def _read_blob(self, ctx, experiment, plugin_names, run, tag):
|
|
182
|
+
for plugin_name in plugin_names:
|
|
183
|
+
blob_sequences = self._data_provider.read_blob_sequences(
|
|
184
|
+
ctx,
|
|
185
|
+
experiment_id=experiment,
|
|
186
|
+
plugin_name=plugin_name,
|
|
187
|
+
run_tag_filter=provider.RunTagFilter(runs=[run], tags=[tag]),
|
|
188
|
+
downsample=1,
|
|
189
|
+
)
|
|
190
|
+
blob_sequence_data = blob_sequences.get(run, {}).get(tag, ())
|
|
191
|
+
try:
|
|
192
|
+
blob_ref = blob_sequence_data[0].values[0]
|
|
193
|
+
except IndexError:
|
|
194
|
+
continue
|
|
195
|
+
return self._data_provider.read_blob(
|
|
196
|
+
ctx, blob_key=blob_ref.blob_key
|
|
197
|
+
)
|
|
198
|
+
raise errors.NotFoundError()
|
|
199
|
+
|
|
200
|
+
def graph_impl(
|
|
201
|
+
self,
|
|
202
|
+
ctx,
|
|
203
|
+
run,
|
|
204
|
+
tag,
|
|
205
|
+
is_conceptual,
|
|
206
|
+
experiment=None,
|
|
207
|
+
limit_attr_size=None,
|
|
208
|
+
large_attrs_key=None,
|
|
209
|
+
):
|
|
210
|
+
"""Result of the form `(body, mime_type)`; may raise `NotFound`."""
|
|
211
|
+
if is_conceptual:
|
|
212
|
+
keras_model_config = json.loads(
|
|
213
|
+
self._read_blob(
|
|
214
|
+
ctx,
|
|
215
|
+
experiment,
|
|
216
|
+
[metadata.PLUGIN_NAME_KERAS_MODEL],
|
|
217
|
+
run,
|
|
218
|
+
tag,
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
graph = keras_util.keras_model_to_graph_def(keras_model_config)
|
|
222
|
+
|
|
223
|
+
elif tag is None:
|
|
224
|
+
graph_raw = self._read_blob(
|
|
225
|
+
ctx,
|
|
226
|
+
experiment,
|
|
227
|
+
[metadata.PLUGIN_NAME],
|
|
228
|
+
run,
|
|
229
|
+
metadata.RUN_GRAPH_NAME,
|
|
230
|
+
)
|
|
231
|
+
graph = graph_pb2.GraphDef.FromString(graph_raw)
|
|
232
|
+
|
|
233
|
+
else:
|
|
234
|
+
# Op graph: could be either of two plugins. (Cf. `info_impl`.)
|
|
235
|
+
plugins = [
|
|
236
|
+
metadata.PLUGIN_NAME_RUN_METADATA,
|
|
237
|
+
metadata.PLUGIN_NAME_RUN_METADATA_WITH_GRAPH,
|
|
238
|
+
]
|
|
239
|
+
raw_run_metadata = self._read_blob(
|
|
240
|
+
ctx, experiment, plugins, run, tag
|
|
241
|
+
)
|
|
242
|
+
run_metadata = config_pb2.RunMetadata.FromString(raw_run_metadata)
|
|
243
|
+
graph = graph_util.merge_graph_defs(
|
|
244
|
+
[
|
|
245
|
+
func_graph.pre_optimization_graph
|
|
246
|
+
for func_graph in run_metadata.function_graphs
|
|
247
|
+
]
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
# This next line might raise a ValueError if the limit parameters
|
|
251
|
+
# are invalid (size is negative, size present but key absent, etc.).
|
|
252
|
+
process_graph.prepare_graph_for_ui(
|
|
253
|
+
graph, limit_attr_size, large_attrs_key
|
|
254
|
+
)
|
|
255
|
+
return (str(graph), "text/x-protobuf") # pbtxt
|
|
256
|
+
|
|
257
|
+
def run_metadata_impl(self, ctx, experiment, run, tag):
|
|
258
|
+
"""Result of the form `(body, mime_type)`; may raise `NotFound`."""
|
|
259
|
+
# Profile graph: could be either of two plugins. (Cf. `info_impl`.)
|
|
260
|
+
plugins = [
|
|
261
|
+
metadata.PLUGIN_NAME_TAGGED_RUN_METADATA,
|
|
262
|
+
metadata.PLUGIN_NAME_RUN_METADATA,
|
|
263
|
+
]
|
|
264
|
+
raw_run_metadata = self._read_blob(ctx, experiment, plugins, run, tag)
|
|
265
|
+
run_metadata = config_pb2.RunMetadata.FromString(raw_run_metadata)
|
|
266
|
+
return (str(run_metadata), "text/x-protobuf") # pbtxt
|
|
267
|
+
|
|
268
|
+
@wrappers.Request.application
|
|
269
|
+
def info_route(self, request):
|
|
270
|
+
ctx = plugin_util.context(request.environ)
|
|
271
|
+
experiment = plugin_util.experiment_id(request.environ)
|
|
272
|
+
info = self.info_impl(ctx, experiment)
|
|
273
|
+
return http_util.Respond(request, info, "application/json")
|
|
274
|
+
|
|
275
|
+
@wrappers.Request.application
|
|
276
|
+
def graph_route(self, request):
|
|
277
|
+
"""Given a single run, return the graph definition in protobuf
|
|
278
|
+
format."""
|
|
279
|
+
ctx = plugin_util.context(request.environ)
|
|
280
|
+
experiment = plugin_util.experiment_id(request.environ)
|
|
281
|
+
run = request.args.get("run")
|
|
282
|
+
tag = request.args.get("tag")
|
|
283
|
+
conceptual_arg = request.args.get("conceptual", False)
|
|
284
|
+
is_conceptual = True if conceptual_arg == "true" else False
|
|
285
|
+
|
|
286
|
+
if run is None:
|
|
287
|
+
return http_util.Respond(
|
|
288
|
+
request, 'query parameter "run" is required', "text/plain", 400
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
limit_attr_size = request.args.get("limit_attr_size", None)
|
|
292
|
+
if limit_attr_size is not None:
|
|
293
|
+
try:
|
|
294
|
+
limit_attr_size = int(limit_attr_size)
|
|
295
|
+
except ValueError:
|
|
296
|
+
return http_util.Respond(
|
|
297
|
+
request,
|
|
298
|
+
"query parameter `limit_attr_size` must be an integer",
|
|
299
|
+
"text/plain",
|
|
300
|
+
400,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
large_attrs_key = request.args.get("large_attrs_key", None)
|
|
304
|
+
|
|
305
|
+
try:
|
|
306
|
+
result = self.graph_impl(
|
|
307
|
+
ctx,
|
|
308
|
+
run,
|
|
309
|
+
tag,
|
|
310
|
+
is_conceptual,
|
|
311
|
+
experiment,
|
|
312
|
+
limit_attr_size,
|
|
313
|
+
large_attrs_key,
|
|
314
|
+
)
|
|
315
|
+
except ValueError as e:
|
|
316
|
+
return http_util.Respond(request, e.message, "text/plain", code=400)
|
|
317
|
+
body, mime_type = result
|
|
318
|
+
return http_util.Respond(request, body, mime_type)
|
|
319
|
+
|
|
320
|
+
@wrappers.Request.application
|
|
321
|
+
def run_metadata_route(self, request):
|
|
322
|
+
"""Given a tag and a run, return the session.run() metadata."""
|
|
323
|
+
ctx = plugin_util.context(request.environ)
|
|
324
|
+
experiment = plugin_util.experiment_id(request.environ)
|
|
325
|
+
tag = request.args.get("tag")
|
|
326
|
+
run = request.args.get("run")
|
|
327
|
+
if tag is None:
|
|
328
|
+
return http_util.Respond(
|
|
329
|
+
request, 'query parameter "tag" is required', "text/plain", 400
|
|
330
|
+
)
|
|
331
|
+
if run is None:
|
|
332
|
+
return http_util.Respond(
|
|
333
|
+
request, 'query parameter "run" is required', "text/plain", 400
|
|
334
|
+
)
|
|
335
|
+
body, mime_type = self.run_metadata_impl(ctx, experiment, run, tag)
|
|
336
|
+
return http_util.Respond(request, body, mime_type)
|