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,158 @@
|
|
|
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
|
+
"""Classes and functions for handling the DownloadData API call."""
|
|
16
|
+
|
|
17
|
+
import csv
|
|
18
|
+
import io
|
|
19
|
+
import math
|
|
20
|
+
|
|
21
|
+
from tensorbored.plugins.hparams import error
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class OutputFormat:
|
|
25
|
+
"""An enum used to list the valid output formats for API calls."""
|
|
26
|
+
|
|
27
|
+
JSON = "json"
|
|
28
|
+
CSV = "csv"
|
|
29
|
+
LATEX = "latex"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Handler:
|
|
33
|
+
"""Handles a DownloadData request."""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
context,
|
|
38
|
+
experiment,
|
|
39
|
+
session_groups,
|
|
40
|
+
response_format,
|
|
41
|
+
columns_visibility,
|
|
42
|
+
):
|
|
43
|
+
"""Constructor.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
context: A backend_context.Context instance.
|
|
47
|
+
experiment: Experiment proto.
|
|
48
|
+
session_groups: ListSessionGroupsResponse proto.
|
|
49
|
+
response_format: A string in the OutputFormat enum.
|
|
50
|
+
columns_visibility: A list of boolean values to filter columns.
|
|
51
|
+
"""
|
|
52
|
+
self._context = context
|
|
53
|
+
self._experiment = experiment
|
|
54
|
+
self._session_groups = session_groups
|
|
55
|
+
self._response_format = response_format
|
|
56
|
+
self._columns_visibility = columns_visibility
|
|
57
|
+
|
|
58
|
+
def run(self):
|
|
59
|
+
"""Handles the request specified on construction.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
A response body.
|
|
63
|
+
A mime type (string) for the response.
|
|
64
|
+
"""
|
|
65
|
+
experiment = self._experiment
|
|
66
|
+
session_groups = self._session_groups
|
|
67
|
+
response_format = self._response_format
|
|
68
|
+
visibility = self._columns_visibility
|
|
69
|
+
|
|
70
|
+
header = []
|
|
71
|
+
for hparam_info in experiment.hparam_infos:
|
|
72
|
+
header.append(hparam_info.display_name or hparam_info.name)
|
|
73
|
+
|
|
74
|
+
for metric_info in experiment.metric_infos:
|
|
75
|
+
header.append(metric_info.display_name or metric_info.name.tag)
|
|
76
|
+
|
|
77
|
+
def _filter_columns(row):
|
|
78
|
+
return [value for value, visible in zip(row, visibility) if visible]
|
|
79
|
+
|
|
80
|
+
header = _filter_columns(header)
|
|
81
|
+
|
|
82
|
+
rows = []
|
|
83
|
+
|
|
84
|
+
def _get_value(value):
|
|
85
|
+
if value.HasField("number_value"):
|
|
86
|
+
return value.number_value
|
|
87
|
+
if value.HasField("string_value"):
|
|
88
|
+
return value.string_value
|
|
89
|
+
if value.HasField("bool_value"):
|
|
90
|
+
return value.bool_value
|
|
91
|
+
# hyperparameter values can be optional in a session group
|
|
92
|
+
return ""
|
|
93
|
+
|
|
94
|
+
def _get_metric_id(metric):
|
|
95
|
+
return metric.group + "." + metric.tag
|
|
96
|
+
|
|
97
|
+
for group in session_groups.session_groups:
|
|
98
|
+
row = []
|
|
99
|
+
for hparam_info in experiment.hparam_infos:
|
|
100
|
+
row.append(_get_value(group.hparams[hparam_info.name]))
|
|
101
|
+
metric_values = {}
|
|
102
|
+
for metric_value in group.metric_values:
|
|
103
|
+
metric_id = _get_metric_id(metric_value.name)
|
|
104
|
+
metric_values[metric_id] = metric_value.value
|
|
105
|
+
for metric_info in experiment.metric_infos:
|
|
106
|
+
metric_id = _get_metric_id(metric_info.name)
|
|
107
|
+
row.append(metric_values.get(metric_id))
|
|
108
|
+
rows.append(_filter_columns(row))
|
|
109
|
+
|
|
110
|
+
if response_format == OutputFormat.JSON:
|
|
111
|
+
mime_type = "application/json"
|
|
112
|
+
body = dict(header=header, rows=rows)
|
|
113
|
+
elif response_format == OutputFormat.LATEX:
|
|
114
|
+
|
|
115
|
+
def latex_format(value):
|
|
116
|
+
if value is None:
|
|
117
|
+
return "-"
|
|
118
|
+
elif isinstance(value, int):
|
|
119
|
+
return "$%d$" % value
|
|
120
|
+
elif isinstance(value, float):
|
|
121
|
+
if math.isnan(value):
|
|
122
|
+
return r"$\mathrm{NaN}$"
|
|
123
|
+
if value in (float("inf"), float("-inf")):
|
|
124
|
+
return r"$%s\infty$" % ("-" if value < 0 else "+")
|
|
125
|
+
scientific = "%.3g" % value
|
|
126
|
+
if "e" in scientific:
|
|
127
|
+
coefficient, exponent = scientific.split("e")
|
|
128
|
+
return "$%s\\cdot 10^{%d}$" % (
|
|
129
|
+
coefficient,
|
|
130
|
+
int(exponent),
|
|
131
|
+
)
|
|
132
|
+
return "$%s$" % scientific
|
|
133
|
+
return value.replace("_", "\\_").replace("%", "\\%")
|
|
134
|
+
|
|
135
|
+
mime_type = "application/x-latex"
|
|
136
|
+
top_part = "\\begin{table}[tbp]\n\\begin{tabular}{%s}\n" % (
|
|
137
|
+
"l" * len(header)
|
|
138
|
+
)
|
|
139
|
+
header_part = (
|
|
140
|
+
" & ".join(map(latex_format, header)) + " \\\\ \\hline\n"
|
|
141
|
+
)
|
|
142
|
+
middle_part = "".join(
|
|
143
|
+
" & ".join(map(latex_format, row)) + " \\\\\n" for row in rows
|
|
144
|
+
)
|
|
145
|
+
bottom_part = "\\hline\n\\end{tabular}\n\\end{table}\n"
|
|
146
|
+
body = top_part + header_part + middle_part + bottom_part
|
|
147
|
+
elif response_format == OutputFormat.CSV:
|
|
148
|
+
string_io = io.StringIO()
|
|
149
|
+
writer = csv.writer(string_io)
|
|
150
|
+
writer.writerow(header)
|
|
151
|
+
writer.writerows(rows)
|
|
152
|
+
body = string_io.getvalue()
|
|
153
|
+
mime_type = "text/csv"
|
|
154
|
+
else:
|
|
155
|
+
raise error.HParamsError(
|
|
156
|
+
"Invalid reponses format: %s" % response_format
|
|
157
|
+
)
|
|
158
|
+
return body, mime_type
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
"""Defines an error (exception) class for the HParams plugin."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class HParamsError(Exception):
|
|
19
|
+
"""Represents an error that is meaningful to the end-user.
|
|
20
|
+
|
|
21
|
+
Such an error should have a meaningful error message. Other errors,
|
|
22
|
+
(such as resulting from some internal invariants being violated)
|
|
23
|
+
should be represented by other exceptions.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
pass
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
"""Classes and functions for handling the GetExperiment API call."""
|
|
16
|
+
|
|
17
|
+
from tensorbored.plugins.hparams import api_pb2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Handler:
|
|
21
|
+
"""Handles a GetExperiment request."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self, request_context, backend_context, experiment_id, request
|
|
25
|
+
):
|
|
26
|
+
"""Constructor.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
request_context: A tensorboard.context.RequestContext.
|
|
30
|
+
backend_context: A backend_context.Context instance.
|
|
31
|
+
experiment_id: A string, as from `plugin_util.experiment_id`.
|
|
32
|
+
request: A request proto.
|
|
33
|
+
"""
|
|
34
|
+
self._request_context = request_context
|
|
35
|
+
self._backend_context = backend_context
|
|
36
|
+
self._experiment_id = experiment_id
|
|
37
|
+
self._include_metrics = (
|
|
38
|
+
# Metrics are included by default if include_metrics is not
|
|
39
|
+
# specified in the request.
|
|
40
|
+
not request.HasField("include_metrics")
|
|
41
|
+
or request.include_metrics
|
|
42
|
+
)
|
|
43
|
+
self._hparams_limit = (
|
|
44
|
+
request.hparams_limit
|
|
45
|
+
if isinstance(request, api_pb2.GetExperimentRequest)
|
|
46
|
+
else None
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def run(self):
|
|
50
|
+
"""Handles the request specified on construction.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
An Experiment object.
|
|
54
|
+
"""
|
|
55
|
+
data_provider_hparams = (
|
|
56
|
+
self._backend_context.hparams_from_data_provider(
|
|
57
|
+
self._request_context,
|
|
58
|
+
self._experiment_id,
|
|
59
|
+
limit=self._hparams_limit,
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
return self._backend_context.experiment_from_metadata(
|
|
63
|
+
self._request_context,
|
|
64
|
+
self._experiment_id,
|
|
65
|
+
self._include_metrics,
|
|
66
|
+
self._backend_context.hparams_metadata(
|
|
67
|
+
self._request_context, self._experiment_id
|
|
68
|
+
),
|
|
69
|
+
data_provider_hparams,
|
|
70
|
+
self._hparams_limit,
|
|
71
|
+
)
|
|
@@ -0,0 +1,206 @@
|
|
|
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
|
+
"""The TensorBoard HParams plugin.
|
|
16
|
+
|
|
17
|
+
See `http_api.md` in this directory for specifications of the routes for
|
|
18
|
+
this plugin.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
|
|
23
|
+
import werkzeug
|
|
24
|
+
from werkzeug import wrappers
|
|
25
|
+
|
|
26
|
+
from tensorbored import plugin_util
|
|
27
|
+
from tensorbored.plugins.hparams import api_pb2
|
|
28
|
+
from tensorbored.plugins.hparams import backend_context
|
|
29
|
+
from tensorbored.plugins.hparams import download_data
|
|
30
|
+
from tensorbored.plugins.hparams import error
|
|
31
|
+
from tensorbored.plugins.hparams import get_experiment
|
|
32
|
+
from tensorbored.plugins.hparams import list_metric_evals
|
|
33
|
+
from tensorbored.plugins.hparams import list_session_groups
|
|
34
|
+
from tensorbored.plugins.hparams import metadata
|
|
35
|
+
from google.protobuf import json_format
|
|
36
|
+
from tensorbored.backend import http_util
|
|
37
|
+
from tensorbored.plugins import base_plugin
|
|
38
|
+
from tensorbored.plugins.scalar import metadata as scalars_metadata
|
|
39
|
+
from tensorbored.util import tb_logging
|
|
40
|
+
|
|
41
|
+
logger = tb_logging.get_logger()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class HParamsPlugin(base_plugin.TBPlugin):
|
|
45
|
+
"""HParams Plugin for TensorBoard.
|
|
46
|
+
|
|
47
|
+
It supports both GETs and POSTs. See 'http_api.md' for more details.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
plugin_name = metadata.PLUGIN_NAME
|
|
51
|
+
|
|
52
|
+
def __init__(self, context):
|
|
53
|
+
"""Instantiates HParams plugin via TensorBoard core.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
context: A base_plugin.TBContext instance.
|
|
57
|
+
"""
|
|
58
|
+
self._context = backend_context.Context(context)
|
|
59
|
+
|
|
60
|
+
def get_plugin_apps(self):
|
|
61
|
+
"""See base class."""
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
"/download_data": self.download_data_route,
|
|
65
|
+
"/experiment": self.get_experiment_route,
|
|
66
|
+
"/session_groups": self.list_session_groups_route,
|
|
67
|
+
"/metric_evals": self.list_metric_evals_route,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
def is_active(self):
|
|
71
|
+
return False # `list_plugins` as called by TB core suffices
|
|
72
|
+
|
|
73
|
+
def frontend_metadata(self):
|
|
74
|
+
return base_plugin.FrontendMetadata(element_name="tf-hparams-dashboard")
|
|
75
|
+
|
|
76
|
+
# ---- /download_data- -------------------------------------------------------
|
|
77
|
+
@wrappers.Request.application
|
|
78
|
+
def download_data_route(self, request):
|
|
79
|
+
ctx = plugin_util.context(request.environ)
|
|
80
|
+
experiment_id = plugin_util.experiment_id(request.environ)
|
|
81
|
+
try:
|
|
82
|
+
response_format = request.args.get("format")
|
|
83
|
+
columns_visibility = json.loads(
|
|
84
|
+
request.args.get("columnsVisibility")
|
|
85
|
+
)
|
|
86
|
+
request_proto = _parse_request_argument(
|
|
87
|
+
request, api_pb2.ListSessionGroupsRequest
|
|
88
|
+
)
|
|
89
|
+
session_groups = list_session_groups.Handler(
|
|
90
|
+
ctx, self._context, experiment_id, request_proto
|
|
91
|
+
).run()
|
|
92
|
+
experiment = get_experiment.Handler(
|
|
93
|
+
ctx, self._context, experiment_id, request_proto
|
|
94
|
+
).run()
|
|
95
|
+
body, mime_type = download_data.Handler(
|
|
96
|
+
self._context,
|
|
97
|
+
experiment,
|
|
98
|
+
session_groups,
|
|
99
|
+
response_format,
|
|
100
|
+
columns_visibility,
|
|
101
|
+
).run()
|
|
102
|
+
return http_util.Respond(request, body, mime_type)
|
|
103
|
+
except error.HParamsError as e:
|
|
104
|
+
logger.error("HParams error: %s" % e)
|
|
105
|
+
raise werkzeug.exceptions.BadRequest(description=str(e))
|
|
106
|
+
|
|
107
|
+
# ---- /experiment -----------------------------------------------------------
|
|
108
|
+
@wrappers.Request.application
|
|
109
|
+
def get_experiment_route(self, request):
|
|
110
|
+
ctx = plugin_util.context(request.environ)
|
|
111
|
+
experiment_id = plugin_util.experiment_id(request.environ)
|
|
112
|
+
try:
|
|
113
|
+
request_proto = _parse_request_argument(
|
|
114
|
+
request, api_pb2.GetExperimentRequest
|
|
115
|
+
)
|
|
116
|
+
response_proto = get_experiment.Handler(
|
|
117
|
+
ctx,
|
|
118
|
+
self._context,
|
|
119
|
+
experiment_id,
|
|
120
|
+
request_proto,
|
|
121
|
+
).run()
|
|
122
|
+
response = plugin_util.proto_to_json(response_proto)
|
|
123
|
+
return http_util.Respond(
|
|
124
|
+
request,
|
|
125
|
+
response,
|
|
126
|
+
"application/json",
|
|
127
|
+
)
|
|
128
|
+
except error.HParamsError as e:
|
|
129
|
+
logger.error("HParams error: %s" % e)
|
|
130
|
+
raise werkzeug.exceptions.BadRequest(description=str(e))
|
|
131
|
+
|
|
132
|
+
# ---- /session_groups -------------------------------------------------------
|
|
133
|
+
@wrappers.Request.application
|
|
134
|
+
def list_session_groups_route(self, request):
|
|
135
|
+
ctx = plugin_util.context(request.environ)
|
|
136
|
+
experiment_id = plugin_util.experiment_id(request.environ)
|
|
137
|
+
try:
|
|
138
|
+
request_proto = _parse_request_argument(
|
|
139
|
+
request, api_pb2.ListSessionGroupsRequest
|
|
140
|
+
)
|
|
141
|
+
response_proto = list_session_groups.Handler(
|
|
142
|
+
ctx,
|
|
143
|
+
self._context,
|
|
144
|
+
experiment_id,
|
|
145
|
+
request_proto,
|
|
146
|
+
).run()
|
|
147
|
+
response = plugin_util.proto_to_json(response_proto)
|
|
148
|
+
return http_util.Respond(
|
|
149
|
+
request,
|
|
150
|
+
response,
|
|
151
|
+
"application/json",
|
|
152
|
+
)
|
|
153
|
+
except error.HParamsError as e:
|
|
154
|
+
logger.error("HParams error: %s" % e)
|
|
155
|
+
raise werkzeug.exceptions.BadRequest(description=str(e))
|
|
156
|
+
|
|
157
|
+
# ---- /metric_evals ---------------------------------------------------------
|
|
158
|
+
@wrappers.Request.application
|
|
159
|
+
def list_metric_evals_route(self, request):
|
|
160
|
+
ctx = plugin_util.context(request.environ)
|
|
161
|
+
experiment_id = plugin_util.experiment_id(request.environ)
|
|
162
|
+
try:
|
|
163
|
+
request_proto = _parse_request_argument(
|
|
164
|
+
request, api_pb2.ListMetricEvalsRequest
|
|
165
|
+
)
|
|
166
|
+
scalars_plugin = self._get_scalars_plugin()
|
|
167
|
+
if not scalars_plugin:
|
|
168
|
+
raise werkzeug.exceptions.NotFound("Scalars plugin not loaded")
|
|
169
|
+
return http_util.Respond(
|
|
170
|
+
request,
|
|
171
|
+
list_metric_evals.Handler(
|
|
172
|
+
ctx, request_proto, scalars_plugin, experiment_id
|
|
173
|
+
).run(),
|
|
174
|
+
"application/json",
|
|
175
|
+
)
|
|
176
|
+
except error.HParamsError as e:
|
|
177
|
+
logger.error("HParams error: %s" % e)
|
|
178
|
+
raise werkzeug.exceptions.BadRequest(description=str(e))
|
|
179
|
+
|
|
180
|
+
def _get_scalars_plugin(self):
|
|
181
|
+
"""Tries to get the scalars plugin.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
The scalars plugin or None if it is not yet registered.
|
|
185
|
+
"""
|
|
186
|
+
return self._context.tb_context.plugin_name_to_instance.get(
|
|
187
|
+
scalars_metadata.PLUGIN_NAME
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _parse_request_argument(request, proto_class):
|
|
192
|
+
request_json = (
|
|
193
|
+
request.data
|
|
194
|
+
if request.method == "POST"
|
|
195
|
+
else request.args.get("request")
|
|
196
|
+
)
|
|
197
|
+
try:
|
|
198
|
+
return json_format.Parse(request_json, proto_class())
|
|
199
|
+
# if request_json is None, json_format.Parse will throw an AttributeError:
|
|
200
|
+
# 'NoneType' object has no attribute 'decode'.
|
|
201
|
+
except (AttributeError, json_format.ParseError) as e:
|
|
202
|
+
raise error.HParamsError(
|
|
203
|
+
"Expected a JSON-formatted request data of type: {}, but got {} ".format(
|
|
204
|
+
proto_class, request_json
|
|
205
|
+
)
|
|
206
|
+
) from e
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# source: tensorbored/plugins/hparams/hparams_util.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
|
+
from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
|
|
16
|
+
from tensorbored.plugins.hparams import api_pb2 as tensorbored_dot_plugins_dot_hparams_dot_api__pb2
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n.tensorbored/plugins/hparams/hparams_util.proto\x12\x13tensorbored.hparams\x1a\x1cgoogle/protobuf/struct.proto\x1a%tensorbored/plugins/hparams/api.proto\"H\n\x0fHParamInfosList\x12\x35\n\x0chparam_infos\x18\x01 \x03(\x0b\x32\x1f.tensorbored.hparams.HParamInfo\"H\n\x0fMetricInfosList\x12\x35\n\x0cmetric_infos\x18\x01 \x03(\x0b\x32\x1f.tensorbored.hparams.MetricInfo\"\x8d\x01\n\x07HParams\x12:\n\x07hparams\x18\x01 \x03(\x0b\x32).tensorbored.hparams.HParams.HparamsEntry\x1a\x46\n\x0cHparamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12%\n\x05value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.Value:\x02\x38\x01\x62\x06proto3')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_HPARAMINFOSLIST = DESCRIPTOR.message_types_by_name['HParamInfosList']
|
|
24
|
+
_METRICINFOSLIST = DESCRIPTOR.message_types_by_name['MetricInfosList']
|
|
25
|
+
_HPARAMS = DESCRIPTOR.message_types_by_name['HParams']
|
|
26
|
+
_HPARAMS_HPARAMSENTRY = _HPARAMS.nested_types_by_name['HparamsEntry']
|
|
27
|
+
HParamInfosList = _reflection.GeneratedProtocolMessageType('HParamInfosList', (_message.Message,), {
|
|
28
|
+
'DESCRIPTOR' : _HPARAMINFOSLIST,
|
|
29
|
+
'__module__' : 'tensorbored.plugins.hparams.hparams_util_pb2'
|
|
30
|
+
# @@protoc_insertion_point(class_scope:tensorbored.hparams.HParamInfosList)
|
|
31
|
+
})
|
|
32
|
+
_sym_db.RegisterMessage(HParamInfosList)
|
|
33
|
+
|
|
34
|
+
MetricInfosList = _reflection.GeneratedProtocolMessageType('MetricInfosList', (_message.Message,), {
|
|
35
|
+
'DESCRIPTOR' : _METRICINFOSLIST,
|
|
36
|
+
'__module__' : 'tensorbored.plugins.hparams.hparams_util_pb2'
|
|
37
|
+
# @@protoc_insertion_point(class_scope:tensorbored.hparams.MetricInfosList)
|
|
38
|
+
})
|
|
39
|
+
_sym_db.RegisterMessage(MetricInfosList)
|
|
40
|
+
|
|
41
|
+
HParams = _reflection.GeneratedProtocolMessageType('HParams', (_message.Message,), {
|
|
42
|
+
|
|
43
|
+
'HparamsEntry' : _reflection.GeneratedProtocolMessageType('HparamsEntry', (_message.Message,), {
|
|
44
|
+
'DESCRIPTOR' : _HPARAMS_HPARAMSENTRY,
|
|
45
|
+
'__module__' : 'tensorbored.plugins.hparams.hparams_util_pb2'
|
|
46
|
+
# @@protoc_insertion_point(class_scope:tensorbored.hparams.HParams.HparamsEntry)
|
|
47
|
+
})
|
|
48
|
+
,
|
|
49
|
+
'DESCRIPTOR' : _HPARAMS,
|
|
50
|
+
'__module__' : 'tensorbored.plugins.hparams.hparams_util_pb2'
|
|
51
|
+
# @@protoc_insertion_point(class_scope:tensorbored.hparams.HParams)
|
|
52
|
+
})
|
|
53
|
+
_sym_db.RegisterMessage(HParams)
|
|
54
|
+
_sym_db.RegisterMessage(HParams.HparamsEntry)
|
|
55
|
+
|
|
56
|
+
if _descriptor._USE_C_DESCRIPTORS == False:
|
|
57
|
+
|
|
58
|
+
DESCRIPTOR._options = None
|
|
59
|
+
_HPARAMS_HPARAMSENTRY._options = None
|
|
60
|
+
_HPARAMS_HPARAMSENTRY._serialized_options = b'8\001'
|
|
61
|
+
_HPARAMINFOSLIST._serialized_start=140
|
|
62
|
+
_HPARAMINFOSLIST._serialized_end=212
|
|
63
|
+
_METRICINFOSLIST._serialized_start=214
|
|
64
|
+
_METRICINFOSLIST._serialized_end=286
|
|
65
|
+
_HPARAMS._serialized_start=289
|
|
66
|
+
_HPARAMS._serialized_end=430
|
|
67
|
+
_HPARAMS_HPARAMSENTRY._serialized_start=360
|
|
68
|
+
_HPARAMS_HPARAMSENTRY._serialized_end=430
|
|
69
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Copyright 2023 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
|
+
|
|
16
|
+
import math
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def is_serializable_value(value):
|
|
20
|
+
"""Returns whether a protobuf Value will be serializable by MessageToJson.
|
|
21
|
+
|
|
22
|
+
The json_format documentation states that "attempting to serialize NaN or
|
|
23
|
+
Infinity results in error."
|
|
24
|
+
|
|
25
|
+
https://protobuf.dev/reference/protobuf/google.protobuf/#value
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
value: A value of type protobuf.Value.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
True if the Value should be serializable without error by MessageToJson.
|
|
32
|
+
False, otherwise.
|
|
33
|
+
"""
|
|
34
|
+
if not value.HasField("number_value"):
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
number_value = value.number_value
|
|
38
|
+
return not math.isnan(number_value) and not math.isinf(number_value)
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
"""Classes and functions for handling the ListMetricEvals API call."""
|
|
16
|
+
|
|
17
|
+
from tensorbored.plugins.hparams import metrics
|
|
18
|
+
from tensorbored.plugins.scalar import scalars_plugin
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Handler:
|
|
22
|
+
"""Handles a ListMetricEvals request."""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self, request_context, request, scalars_plugin_instance, experiment
|
|
26
|
+
):
|
|
27
|
+
"""Constructor.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
request_context: A tensorboard.context.RequestContext.
|
|
31
|
+
request: A ListSessionGroupsRequest protobuf.
|
|
32
|
+
scalars_plugin_instance: A scalars_plugin.ScalarsPlugin.
|
|
33
|
+
experiment: A experiment ID, as a possibly-empty `str`.
|
|
34
|
+
"""
|
|
35
|
+
self._request_context = request_context
|
|
36
|
+
self._request = request
|
|
37
|
+
self._scalars_plugin_instance = scalars_plugin_instance
|
|
38
|
+
self._experiment = experiment
|
|
39
|
+
|
|
40
|
+
def run(self):
|
|
41
|
+
"""Executes the request.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
An array of tuples representing the metric evaluations--each of the
|
|
45
|
+
form (<wall time in secs>, <training step>, <metric value>).
|
|
46
|
+
"""
|
|
47
|
+
run, tag = metrics.run_tag_from_session_and_metric(
|
|
48
|
+
self._request.session_name, self._request.metric_name
|
|
49
|
+
)
|
|
50
|
+
body, _ = self._scalars_plugin_instance.scalars_impl(
|
|
51
|
+
self._request_context,
|
|
52
|
+
tag,
|
|
53
|
+
run,
|
|
54
|
+
self._experiment,
|
|
55
|
+
scalars_plugin.OutputFormat.JSON,
|
|
56
|
+
)
|
|
57
|
+
return body
|