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.
Files changed (271) hide show
  1. tensorbored/__init__.py +112 -0
  2. tensorbored/_vendor/__init__.py +0 -0
  3. tensorbored/_vendor/bleach/__init__.py +125 -0
  4. tensorbored/_vendor/bleach/_vendor/__init__.py +0 -0
  5. tensorbored/_vendor/bleach/_vendor/html5lib/__init__.py +35 -0
  6. tensorbored/_vendor/bleach/_vendor/html5lib/_ihatexml.py +289 -0
  7. tensorbored/_vendor/bleach/_vendor/html5lib/_inputstream.py +918 -0
  8. tensorbored/_vendor/bleach/_vendor/html5lib/_tokenizer.py +1735 -0
  9. tensorbored/_vendor/bleach/_vendor/html5lib/_trie/__init__.py +5 -0
  10. tensorbored/_vendor/bleach/_vendor/html5lib/_trie/_base.py +40 -0
  11. tensorbored/_vendor/bleach/_vendor/html5lib/_trie/py.py +67 -0
  12. tensorbored/_vendor/bleach/_vendor/html5lib/_utils.py +159 -0
  13. tensorbored/_vendor/bleach/_vendor/html5lib/constants.py +2946 -0
  14. tensorbored/_vendor/bleach/_vendor/html5lib/filters/__init__.py +0 -0
  15. tensorbored/_vendor/bleach/_vendor/html5lib/filters/alphabeticalattributes.py +29 -0
  16. tensorbored/_vendor/bleach/_vendor/html5lib/filters/base.py +12 -0
  17. tensorbored/_vendor/bleach/_vendor/html5lib/filters/inject_meta_charset.py +73 -0
  18. tensorbored/_vendor/bleach/_vendor/html5lib/filters/lint.py +93 -0
  19. tensorbored/_vendor/bleach/_vendor/html5lib/filters/optionaltags.py +207 -0
  20. tensorbored/_vendor/bleach/_vendor/html5lib/filters/sanitizer.py +916 -0
  21. tensorbored/_vendor/bleach/_vendor/html5lib/filters/whitespace.py +38 -0
  22. tensorbored/_vendor/bleach/_vendor/html5lib/html5parser.py +2795 -0
  23. tensorbored/_vendor/bleach/_vendor/html5lib/serializer.py +409 -0
  24. tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/__init__.py +30 -0
  25. tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/genshi.py +54 -0
  26. tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/sax.py +50 -0
  27. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/__init__.py +88 -0
  28. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/base.py +417 -0
  29. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/dom.py +239 -0
  30. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/etree.py +343 -0
  31. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/etree_lxml.py +392 -0
  32. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/__init__.py +154 -0
  33. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/base.py +252 -0
  34. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/dom.py +43 -0
  35. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/etree.py +131 -0
  36. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/etree_lxml.py +215 -0
  37. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/genshi.py +69 -0
  38. tensorbored/_vendor/bleach/_vendor/parse.py +1078 -0
  39. tensorbored/_vendor/bleach/callbacks.py +32 -0
  40. tensorbored/_vendor/bleach/html5lib_shim.py +757 -0
  41. tensorbored/_vendor/bleach/linkifier.py +633 -0
  42. tensorbored/_vendor/bleach/parse_shim.py +1 -0
  43. tensorbored/_vendor/bleach/sanitizer.py +638 -0
  44. tensorbored/_vendor/bleach/six_shim.py +19 -0
  45. tensorbored/_vendor/webencodings/__init__.py +342 -0
  46. tensorbored/_vendor/webencodings/labels.py +231 -0
  47. tensorbored/_vendor/webencodings/mklabels.py +59 -0
  48. tensorbored/_vendor/webencodings/x_user_defined.py +325 -0
  49. tensorbored/assets.py +36 -0
  50. tensorbored/auth.py +102 -0
  51. tensorbored/backend/__init__.py +0 -0
  52. tensorbored/backend/application.py +604 -0
  53. tensorbored/backend/auth_context_middleware.py +38 -0
  54. tensorbored/backend/client_feature_flags.py +113 -0
  55. tensorbored/backend/empty_path_redirect.py +46 -0
  56. tensorbored/backend/event_processing/__init__.py +0 -0
  57. tensorbored/backend/event_processing/data_ingester.py +276 -0
  58. tensorbored/backend/event_processing/data_provider.py +535 -0
  59. tensorbored/backend/event_processing/directory_loader.py +142 -0
  60. tensorbored/backend/event_processing/directory_watcher.py +272 -0
  61. tensorbored/backend/event_processing/event_accumulator.py +950 -0
  62. tensorbored/backend/event_processing/event_file_inspector.py +463 -0
  63. tensorbored/backend/event_processing/event_file_loader.py +292 -0
  64. tensorbored/backend/event_processing/event_multiplexer.py +521 -0
  65. tensorbored/backend/event_processing/event_util.py +68 -0
  66. tensorbored/backend/event_processing/io_wrapper.py +223 -0
  67. tensorbored/backend/event_processing/plugin_asset_util.py +104 -0
  68. tensorbored/backend/event_processing/plugin_event_accumulator.py +721 -0
  69. tensorbored/backend/event_processing/plugin_event_multiplexer.py +522 -0
  70. tensorbored/backend/event_processing/reservoir.py +266 -0
  71. tensorbored/backend/event_processing/tag_types.py +29 -0
  72. tensorbored/backend/experiment_id.py +71 -0
  73. tensorbored/backend/experimental_plugin.py +51 -0
  74. tensorbored/backend/http_util.py +263 -0
  75. tensorbored/backend/json_util.py +70 -0
  76. tensorbored/backend/path_prefix.py +67 -0
  77. tensorbored/backend/process_graph.py +74 -0
  78. tensorbored/backend/security_validator.py +202 -0
  79. tensorbored/compat/__init__.py +69 -0
  80. tensorbored/compat/proto/__init__.py +0 -0
  81. tensorbored/compat/proto/allocation_description_pb2.py +35 -0
  82. tensorbored/compat/proto/api_def_pb2.py +82 -0
  83. tensorbored/compat/proto/attr_value_pb2.py +80 -0
  84. tensorbored/compat/proto/cluster_pb2.py +58 -0
  85. tensorbored/compat/proto/config_pb2.py +271 -0
  86. tensorbored/compat/proto/coordination_config_pb2.py +45 -0
  87. tensorbored/compat/proto/cost_graph_pb2.py +87 -0
  88. tensorbored/compat/proto/cpp_shape_inference_pb2.py +70 -0
  89. tensorbored/compat/proto/debug_pb2.py +65 -0
  90. tensorbored/compat/proto/event_pb2.py +149 -0
  91. tensorbored/compat/proto/full_type_pb2.py +74 -0
  92. tensorbored/compat/proto/function_pb2.py +157 -0
  93. tensorbored/compat/proto/graph_debug_info_pb2.py +111 -0
  94. tensorbored/compat/proto/graph_pb2.py +41 -0
  95. tensorbored/compat/proto/histogram_pb2.py +39 -0
  96. tensorbored/compat/proto/meta_graph_pb2.py +254 -0
  97. tensorbored/compat/proto/node_def_pb2.py +61 -0
  98. tensorbored/compat/proto/op_def_pb2.py +81 -0
  99. tensorbored/compat/proto/resource_handle_pb2.py +48 -0
  100. tensorbored/compat/proto/rewriter_config_pb2.py +93 -0
  101. tensorbored/compat/proto/rpc_options_pb2.py +35 -0
  102. tensorbored/compat/proto/saved_object_graph_pb2.py +193 -0
  103. tensorbored/compat/proto/saver_pb2.py +38 -0
  104. tensorbored/compat/proto/step_stats_pb2.py +116 -0
  105. tensorbored/compat/proto/struct_pb2.py +144 -0
  106. tensorbored/compat/proto/summary_pb2.py +111 -0
  107. tensorbored/compat/proto/tensor_description_pb2.py +38 -0
  108. tensorbored/compat/proto/tensor_pb2.py +68 -0
  109. tensorbored/compat/proto/tensor_shape_pb2.py +46 -0
  110. tensorbored/compat/proto/tfprof_log_pb2.py +307 -0
  111. tensorbored/compat/proto/trackable_object_graph_pb2.py +90 -0
  112. tensorbored/compat/proto/types_pb2.py +105 -0
  113. tensorbored/compat/proto/variable_pb2.py +62 -0
  114. tensorbored/compat/proto/verifier_config_pb2.py +38 -0
  115. tensorbored/compat/proto/versions_pb2.py +35 -0
  116. tensorbored/compat/tensorflow_stub/__init__.py +38 -0
  117. tensorbored/compat/tensorflow_stub/app.py +124 -0
  118. tensorbored/compat/tensorflow_stub/compat/__init__.py +131 -0
  119. tensorbored/compat/tensorflow_stub/compat/v1/__init__.py +20 -0
  120. tensorbored/compat/tensorflow_stub/dtypes.py +692 -0
  121. tensorbored/compat/tensorflow_stub/error_codes.py +169 -0
  122. tensorbored/compat/tensorflow_stub/errors.py +507 -0
  123. tensorbored/compat/tensorflow_stub/flags.py +124 -0
  124. tensorbored/compat/tensorflow_stub/io/__init__.py +17 -0
  125. tensorbored/compat/tensorflow_stub/io/gfile.py +1011 -0
  126. tensorbored/compat/tensorflow_stub/pywrap_tensorflow.py +285 -0
  127. tensorbored/compat/tensorflow_stub/tensor_shape.py +1035 -0
  128. tensorbored/context.py +129 -0
  129. tensorbored/data/__init__.py +0 -0
  130. tensorbored/data/grpc_provider.py +365 -0
  131. tensorbored/data/ingester.py +46 -0
  132. tensorbored/data/proto/__init__.py +0 -0
  133. tensorbored/data/proto/data_provider_pb2.py +517 -0
  134. tensorbored/data/proto/data_provider_pb2_grpc.py +374 -0
  135. tensorbored/data/provider.py +1365 -0
  136. tensorbored/data/server_ingester.py +301 -0
  137. tensorbored/data_compat.py +159 -0
  138. tensorbored/dataclass_compat.py +224 -0
  139. tensorbored/default.py +124 -0
  140. tensorbored/errors.py +130 -0
  141. tensorbored/lazy.py +99 -0
  142. tensorbored/main.py +48 -0
  143. tensorbored/main_lib.py +62 -0
  144. tensorbored/manager.py +487 -0
  145. tensorbored/notebook.py +441 -0
  146. tensorbored/plugin_util.py +266 -0
  147. tensorbored/plugins/__init__.py +0 -0
  148. tensorbored/plugins/audio/__init__.py +0 -0
  149. tensorbored/plugins/audio/audio_plugin.py +229 -0
  150. tensorbored/plugins/audio/metadata.py +69 -0
  151. tensorbored/plugins/audio/plugin_data_pb2.py +37 -0
  152. tensorbored/plugins/audio/summary.py +230 -0
  153. tensorbored/plugins/audio/summary_v2.py +124 -0
  154. tensorbored/plugins/base_plugin.py +367 -0
  155. tensorbored/plugins/core/__init__.py +0 -0
  156. tensorbored/plugins/core/core_plugin.py +981 -0
  157. tensorbored/plugins/custom_scalar/__init__.py +0 -0
  158. tensorbored/plugins/custom_scalar/custom_scalars_plugin.py +320 -0
  159. tensorbored/plugins/custom_scalar/layout_pb2.py +85 -0
  160. tensorbored/plugins/custom_scalar/metadata.py +35 -0
  161. tensorbored/plugins/custom_scalar/summary.py +79 -0
  162. tensorbored/plugins/debugger_v2/__init__.py +0 -0
  163. tensorbored/plugins/debugger_v2/debug_data_multiplexer.py +631 -0
  164. tensorbored/plugins/debugger_v2/debug_data_provider.py +634 -0
  165. tensorbored/plugins/debugger_v2/debugger_v2_plugin.py +504 -0
  166. tensorbored/plugins/distribution/__init__.py +0 -0
  167. tensorbored/plugins/distribution/compressor.py +158 -0
  168. tensorbored/plugins/distribution/distributions_plugin.py +116 -0
  169. tensorbored/plugins/distribution/metadata.py +19 -0
  170. tensorbored/plugins/graph/__init__.py +0 -0
  171. tensorbored/plugins/graph/graph_util.py +129 -0
  172. tensorbored/plugins/graph/graphs_plugin.py +336 -0
  173. tensorbored/plugins/graph/keras_util.py +328 -0
  174. tensorbored/plugins/graph/metadata.py +42 -0
  175. tensorbored/plugins/histogram/__init__.py +0 -0
  176. tensorbored/plugins/histogram/histograms_plugin.py +144 -0
  177. tensorbored/plugins/histogram/metadata.py +63 -0
  178. tensorbored/plugins/histogram/plugin_data_pb2.py +34 -0
  179. tensorbored/plugins/histogram/summary.py +234 -0
  180. tensorbored/plugins/histogram/summary_v2.py +292 -0
  181. tensorbored/plugins/hparams/__init__.py +14 -0
  182. tensorbored/plugins/hparams/_keras.py +93 -0
  183. tensorbored/plugins/hparams/api.py +130 -0
  184. tensorbored/plugins/hparams/api_pb2.py +208 -0
  185. tensorbored/plugins/hparams/backend_context.py +606 -0
  186. tensorbored/plugins/hparams/download_data.py +158 -0
  187. tensorbored/plugins/hparams/error.py +26 -0
  188. tensorbored/plugins/hparams/get_experiment.py +71 -0
  189. tensorbored/plugins/hparams/hparams_plugin.py +206 -0
  190. tensorbored/plugins/hparams/hparams_util_pb2.py +69 -0
  191. tensorbored/plugins/hparams/json_format_compat.py +38 -0
  192. tensorbored/plugins/hparams/list_metric_evals.py +57 -0
  193. tensorbored/plugins/hparams/list_session_groups.py +1040 -0
  194. tensorbored/plugins/hparams/metadata.py +125 -0
  195. tensorbored/plugins/hparams/metrics.py +41 -0
  196. tensorbored/plugins/hparams/plugin_data_pb2.py +69 -0
  197. tensorbored/plugins/hparams/summary.py +205 -0
  198. tensorbored/plugins/hparams/summary_v2.py +597 -0
  199. tensorbored/plugins/image/__init__.py +0 -0
  200. tensorbored/plugins/image/images_plugin.py +232 -0
  201. tensorbored/plugins/image/metadata.py +65 -0
  202. tensorbored/plugins/image/plugin_data_pb2.py +34 -0
  203. tensorbored/plugins/image/summary.py +159 -0
  204. tensorbored/plugins/image/summary_v2.py +130 -0
  205. tensorbored/plugins/mesh/__init__.py +14 -0
  206. tensorbored/plugins/mesh/mesh_plugin.py +292 -0
  207. tensorbored/plugins/mesh/metadata.py +152 -0
  208. tensorbored/plugins/mesh/plugin_data_pb2.py +37 -0
  209. tensorbored/plugins/mesh/summary.py +251 -0
  210. tensorbored/plugins/mesh/summary_v2.py +214 -0
  211. tensorbored/plugins/metrics/__init__.py +0 -0
  212. tensorbored/plugins/metrics/metadata.py +17 -0
  213. tensorbored/plugins/metrics/metrics_plugin.py +623 -0
  214. tensorbored/plugins/pr_curve/__init__.py +0 -0
  215. tensorbored/plugins/pr_curve/metadata.py +75 -0
  216. tensorbored/plugins/pr_curve/plugin_data_pb2.py +34 -0
  217. tensorbored/plugins/pr_curve/pr_curves_plugin.py +241 -0
  218. tensorbored/plugins/pr_curve/summary.py +574 -0
  219. tensorbored/plugins/profile_redirect/__init__.py +0 -0
  220. tensorbored/plugins/profile_redirect/profile_redirect_plugin.py +49 -0
  221. tensorbored/plugins/projector/__init__.py +67 -0
  222. tensorbored/plugins/projector/metadata.py +26 -0
  223. tensorbored/plugins/projector/projector_config_pb2.py +54 -0
  224. tensorbored/plugins/projector/projector_plugin.py +795 -0
  225. tensorbored/plugins/projector/tf_projector_plugin/index.js +32 -0
  226. tensorbored/plugins/projector/tf_projector_plugin/projector_binary.html +524 -0
  227. tensorbored/plugins/projector/tf_projector_plugin/projector_binary.js +15536 -0
  228. tensorbored/plugins/scalar/__init__.py +0 -0
  229. tensorbored/plugins/scalar/metadata.py +60 -0
  230. tensorbored/plugins/scalar/plugin_data_pb2.py +34 -0
  231. tensorbored/plugins/scalar/scalars_plugin.py +181 -0
  232. tensorbored/plugins/scalar/summary.py +109 -0
  233. tensorbored/plugins/scalar/summary_v2.py +124 -0
  234. tensorbored/plugins/text/__init__.py +0 -0
  235. tensorbored/plugins/text/metadata.py +62 -0
  236. tensorbored/plugins/text/plugin_data_pb2.py +34 -0
  237. tensorbored/plugins/text/summary.py +114 -0
  238. tensorbored/plugins/text/summary_v2.py +124 -0
  239. tensorbored/plugins/text/text_plugin.py +288 -0
  240. tensorbored/plugins/wit_redirect/__init__.py +0 -0
  241. tensorbored/plugins/wit_redirect/wit_redirect_plugin.py +49 -0
  242. tensorbored/program.py +910 -0
  243. tensorbored/summary/__init__.py +35 -0
  244. tensorbored/summary/_output.py +124 -0
  245. tensorbored/summary/_tf/__init__.py +14 -0
  246. tensorbored/summary/_tf/summary/__init__.py +178 -0
  247. tensorbored/summary/_writer.py +105 -0
  248. tensorbored/summary/v1.py +51 -0
  249. tensorbored/summary/v2.py +25 -0
  250. tensorbored/summary/writer/__init__.py +13 -0
  251. tensorbored/summary/writer/event_file_writer.py +291 -0
  252. tensorbored/summary/writer/record_writer.py +50 -0
  253. tensorbored/util/__init__.py +0 -0
  254. tensorbored/util/encoder.py +116 -0
  255. tensorbored/util/grpc_util.py +311 -0
  256. tensorbored/util/img_mime_type_detector.py +40 -0
  257. tensorbored/util/io_util.py +20 -0
  258. tensorbored/util/lazy_tensor_creator.py +110 -0
  259. tensorbored/util/op_evaluator.py +104 -0
  260. tensorbored/util/platform_util.py +20 -0
  261. tensorbored/util/tb_logging.py +24 -0
  262. tensorbored/util/tensor_util.py +617 -0
  263. tensorbored/util/timing.py +122 -0
  264. tensorbored/version.py +21 -0
  265. tensorbored/webfiles.zip +0 -0
  266. tensorbored-2.21.0rc1769983804.dist-info/METADATA +49 -0
  267. tensorbored-2.21.0rc1769983804.dist-info/RECORD +271 -0
  268. tensorbored-2.21.0rc1769983804.dist-info/WHEEL +5 -0
  269. tensorbored-2.21.0rc1769983804.dist-info/entry_points.txt +6 -0
  270. tensorbored-2.21.0rc1769983804.dist-info/licenses/LICENSE +739 -0
  271. tensorbored-2.21.0rc1769983804.dist-info/top_level.txt +1 -0
@@ -0,0 +1,623 @@
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
+ """The TensorBoard metrics plugin."""
16
+
17
+ import collections
18
+ import json
19
+
20
+ from werkzeug import wrappers
21
+
22
+ from tensorbored import errors
23
+ from tensorbored import plugin_util
24
+ from tensorbored.backend import http_util
25
+ from tensorbored.data import provider
26
+ from tensorbored.plugins import base_plugin
27
+ from tensorbored.plugins.histogram import metadata as histogram_metadata
28
+ from tensorbored.plugins.image import metadata as image_metadata
29
+ from tensorbored.plugins.metrics import metadata
30
+ from tensorbored.plugins.scalar import metadata as scalar_metadata
31
+ from tensorbored.util import img_mime_type_detector
32
+
33
+ _SINGLE_RUN_PLUGINS = frozenset(
34
+ [histogram_metadata.PLUGIN_NAME, image_metadata.PLUGIN_NAME]
35
+ )
36
+
37
+ _SAMPLED_PLUGINS = frozenset([image_metadata.PLUGIN_NAME])
38
+
39
+
40
+ def _get_tag_description_info(mapping):
41
+ """Gets maps from tags to descriptions, and descriptions to runs.
42
+
43
+ Args:
44
+ mapping: a nested map `d` such that `d[run][tag]` is a time series
45
+ produced by DataProvider's `list_*` methods.
46
+
47
+ Returns:
48
+ A tuple containing
49
+ tag_to_descriptions: A map from tag strings to a set of description
50
+ strings.
51
+ description_to_runs: A map from description strings to a set of run
52
+ strings.
53
+ """
54
+ tag_to_descriptions = collections.defaultdict(set)
55
+ description_to_runs = collections.defaultdict(set)
56
+ for run, tag_to_content in mapping.items():
57
+ for tag, metadatum in tag_to_content.items():
58
+ description = metadatum.description
59
+ if len(description):
60
+ tag_to_descriptions[tag].add(description)
61
+ description_to_runs[description].add(run)
62
+
63
+ return tag_to_descriptions, description_to_runs
64
+
65
+
66
+ def _build_combined_description(descriptions, description_to_runs):
67
+ """Creates a single description from a set of descriptions.
68
+
69
+ Descriptions may be composites when a single tag has different descriptions
70
+ across multiple runs.
71
+
72
+ Args:
73
+ descriptions: A list of description strings.
74
+ description_to_runs: A map from description strings to a set of run
75
+ strings.
76
+
77
+ Returns:
78
+ The combined description string.
79
+ """
80
+ prefixed_descriptions = []
81
+ for description in descriptions:
82
+ runs = sorted(description_to_runs[description])
83
+ run_or_runs = "runs" if len(runs) > 1 else "run"
84
+ run_header = "## For " + run_or_runs + ": " + ", ".join(runs)
85
+ description_html = run_header + "\n" + description
86
+ prefixed_descriptions.append(description_html)
87
+
88
+ header = "# Multiple descriptions\n"
89
+ return header + "\n".join(prefixed_descriptions)
90
+
91
+
92
+ def _get_tag_to_description(mapping):
93
+ """Returns a map of tags to descriptions.
94
+
95
+ Args:
96
+ mapping: a nested map `d` such that `d[run][tag]` is a time series
97
+ produced by DataProvider's `list_*` methods.
98
+
99
+ Returns:
100
+ A map from tag strings to description HTML strings. E.g.
101
+ {
102
+ "loss": "<h1>Multiple descriptions</h1><h2>For runs: test, train
103
+ </h2><p>...</p>",
104
+ "loss2": "<p>The lossy details</p>",
105
+ }
106
+ """
107
+ tag_to_descriptions, description_to_runs = _get_tag_description_info(
108
+ mapping
109
+ )
110
+
111
+ result = {}
112
+ for tag in tag_to_descriptions:
113
+ descriptions = sorted(tag_to_descriptions[tag])
114
+ if len(descriptions) == 1:
115
+ description = descriptions[0]
116
+ else:
117
+ description = _build_combined_description(
118
+ descriptions, description_to_runs
119
+ )
120
+ result[tag] = plugin_util.markdown_to_safe_html(description)
121
+
122
+ return result
123
+
124
+
125
+ def _get_run_tag_info(mapping):
126
+ """Returns a map of run names to a list of tag names.
127
+
128
+ Args:
129
+ mapping: a nested map `d` such that `d[run][tag]` is a time series
130
+ produced by DataProvider's `list_*` methods.
131
+
132
+ Returns:
133
+ A map from run strings to a list of tag strings. E.g.
134
+ {"loss001a": ["actor/loss", "critic/loss"], ...}
135
+ """
136
+ return {run: sorted(mapping[run]) for run in mapping}
137
+
138
+
139
+ def _format_basic_mapping(mapping):
140
+ """Prepares a scalar or histogram mapping for client consumption.
141
+
142
+ Args:
143
+ mapping: a nested map `d` such that `d[run][tag]` is a time series
144
+ produced by DataProvider's `list_*` methods.
145
+
146
+ Returns:
147
+ A dict with the following fields:
148
+ runTagInfo: the return type of `_get_run_tag_info`
149
+ tagDescriptions: the return type of `_get_tag_to_description`
150
+ """
151
+ return {
152
+ "runTagInfo": _get_run_tag_info(mapping),
153
+ "tagDescriptions": _get_tag_to_description(mapping),
154
+ }
155
+
156
+
157
+ def _format_image_blob_sequence_datum(sorted_datum_list, sample):
158
+ """Formats image metadata from a list of BlobSequenceDatum's for clients.
159
+
160
+ This expects that frontend clients need to access images based on the
161
+ run+tag+sample.
162
+
163
+ Args:
164
+ sorted_datum_list: a list of DataProvider's `BlobSequenceDatum`, sorted by
165
+ step. This can be produced via DataProvider's `read_blob_sequences`.
166
+ sample: zero-indexed integer for the requested sample.
167
+
168
+ Returns:
169
+ A list of `ImageStepDatum` (see http_api.md).
170
+ """
171
+ # For images, ignore the first 2 items of a BlobSequenceDatum's values, which
172
+ # correspond to width, height.
173
+ index = sample + 2
174
+ step_data = []
175
+ for datum in sorted_datum_list:
176
+ if len(datum.values) <= index:
177
+ continue
178
+
179
+ step_data.append(
180
+ {
181
+ "step": datum.step,
182
+ "wallTime": datum.wall_time,
183
+ "imageId": datum.values[index].blob_key,
184
+ }
185
+ )
186
+ return step_data
187
+
188
+
189
+ def _get_tag_run_image_info(mapping):
190
+ """Returns a map of tag names to run information.
191
+
192
+ Args:
193
+ mapping: the result of DataProvider's `list_blob_sequences`.
194
+
195
+ Returns:
196
+ A nested map from run strings to tag string to image info, where image
197
+ info is an object of form {"maxSamplesPerStep": num}. For example,
198
+ {
199
+ "reshaped": {
200
+ "test": {"maxSamplesPerStep": 1},
201
+ "train": {"maxSamplesPerStep": 1}
202
+ },
203
+ "convolved": {"test": {"maxSamplesPerStep": 50}},
204
+ }
205
+ """
206
+ tag_run_image_info = collections.defaultdict(dict)
207
+ for run, tag_to_content in mapping.items():
208
+ for tag, metadatum in tag_to_content.items():
209
+ tag_run_image_info[tag][run] = {
210
+ "maxSamplesPerStep": metadatum.max_length - 2 # width, height
211
+ }
212
+ return dict(tag_run_image_info)
213
+
214
+
215
+ def _format_image_mapping(mapping):
216
+ """Prepares an image mapping for client consumption.
217
+
218
+ Args:
219
+ mapping: the result of DataProvider's `list_blob_sequences`.
220
+
221
+ Returns:
222
+ A dict with the following fields:
223
+ tagRunSampledInfo: the return type of `_get_tag_run_image_info`
224
+ tagDescriptions: the return type of `_get_tag_description_info`
225
+ """
226
+ return {
227
+ "tagDescriptions": _get_tag_to_description(mapping),
228
+ "tagRunSampledInfo": _get_tag_run_image_info(mapping),
229
+ }
230
+
231
+
232
+ class MetricsPlugin(base_plugin.TBPlugin):
233
+ """Metrics Plugin for TensorBoard."""
234
+
235
+ plugin_name = metadata.PLUGIN_NAME
236
+
237
+ def __init__(self, context):
238
+ """Instantiates MetricsPlugin.
239
+
240
+ Args:
241
+ context: A base_plugin.TBContext instance. MetricsLoader checks that
242
+ it contains a valid `data_provider`.
243
+ """
244
+ self._data_provider = context.data_provider
245
+
246
+ # For histograms, use a round number + 1 since sampling includes both start
247
+ # and end steps, so N+1 samples corresponds to dividing the step sequence
248
+ # into N intervals.
249
+ sampling_hints = context.sampling_hints or {}
250
+ self._plugin_downsampling = {
251
+ "scalars": sampling_hints.get(scalar_metadata.PLUGIN_NAME, 1000),
252
+ "histograms": sampling_hints.get(
253
+ histogram_metadata.PLUGIN_NAME, 51
254
+ ),
255
+ "images": sampling_hints.get(image_metadata.PLUGIN_NAME, 10),
256
+ }
257
+ self._scalar_version_checker = plugin_util._MetadataVersionChecker(
258
+ data_kind="scalar time series",
259
+ latest_known_version=0,
260
+ )
261
+ self._histogram_version_checker = plugin_util._MetadataVersionChecker(
262
+ data_kind="histogram time series",
263
+ latest_known_version=0,
264
+ )
265
+ self._image_version_checker = plugin_util._MetadataVersionChecker(
266
+ data_kind="image time series",
267
+ latest_known_version=0,
268
+ )
269
+
270
+ def frontend_metadata(self):
271
+ return base_plugin.FrontendMetadata(
272
+ is_ng_component=True, tab_name="Time Series"
273
+ )
274
+
275
+ def get_plugin_apps(self):
276
+ return {
277
+ "/tags": self._serve_tags,
278
+ "/timeSeries": self._serve_time_series,
279
+ "/imageData": self._serve_image_data,
280
+ }
281
+
282
+ def data_plugin_names(self):
283
+ return (
284
+ scalar_metadata.PLUGIN_NAME,
285
+ histogram_metadata.PLUGIN_NAME,
286
+ image_metadata.PLUGIN_NAME,
287
+ )
288
+
289
+ def is_active(self):
290
+ return False # 'data_plugin_names' suffices.
291
+
292
+ @wrappers.Request.application
293
+ def _serve_tags(self, request):
294
+ ctx = plugin_util.context(request.environ)
295
+ experiment = plugin_util.experiment_id(request.environ)
296
+ index = self._tags_impl(ctx, experiment=experiment)
297
+ return http_util.Respond(request, index, "application/json")
298
+
299
+ def _tags_impl(self, ctx, experiment=None):
300
+ """Returns tag metadata for a given experiment's logged metrics.
301
+
302
+ Args:
303
+ ctx: A `tensorboard.context.RequestContext` value.
304
+ experiment: optional string ID of the request's experiment.
305
+
306
+ Returns:
307
+ A nested dict 'd' with keys in ("scalars", "histograms", "images")
308
+ and values being the return type of _format_*mapping.
309
+ """
310
+ scalar_mapping = self._data_provider.list_scalars(
311
+ ctx,
312
+ experiment_id=experiment,
313
+ plugin_name=scalar_metadata.PLUGIN_NAME,
314
+ )
315
+ scalar_mapping = self._filter_by_version(
316
+ scalar_mapping,
317
+ scalar_metadata.parse_plugin_metadata,
318
+ self._scalar_version_checker,
319
+ )
320
+
321
+ histogram_mapping = self._data_provider.list_tensors(
322
+ ctx,
323
+ experiment_id=experiment,
324
+ plugin_name=histogram_metadata.PLUGIN_NAME,
325
+ )
326
+ if histogram_mapping is None:
327
+ histogram_mapping = {}
328
+ histogram_mapping = self._filter_by_version(
329
+ histogram_mapping,
330
+ histogram_metadata.parse_plugin_metadata,
331
+ self._histogram_version_checker,
332
+ )
333
+
334
+ image_mapping = self._data_provider.list_blob_sequences(
335
+ ctx,
336
+ experiment_id=experiment,
337
+ plugin_name=image_metadata.PLUGIN_NAME,
338
+ )
339
+ if image_mapping is None:
340
+ image_mapping = {}
341
+ image_mapping = self._filter_by_version(
342
+ image_mapping,
343
+ image_metadata.parse_plugin_metadata,
344
+ self._image_version_checker,
345
+ )
346
+
347
+ result = {}
348
+ result["scalars"] = _format_basic_mapping(scalar_mapping)
349
+ result["histograms"] = _format_basic_mapping(histogram_mapping)
350
+ result["images"] = _format_image_mapping(image_mapping)
351
+ return result
352
+
353
+ def _filter_by_version(self, mapping, parse_metadata, version_checker):
354
+ """Filter `DataProvider.list_*` output by summary metadata version."""
355
+ result = {run: {} for run in mapping}
356
+ for run, tag_to_content in mapping.items():
357
+ for tag, metadatum in tag_to_content.items():
358
+ md = parse_metadata(metadatum.plugin_content)
359
+ if not version_checker.ok(md.version, run, tag):
360
+ continue
361
+ result[run][tag] = metadatum
362
+ return result
363
+
364
+ @wrappers.Request.application
365
+ def _serve_time_series(self, request):
366
+ ctx = plugin_util.context(request.environ)
367
+ experiment = plugin_util.experiment_id(request.environ)
368
+ if request.method == "POST":
369
+ series_requests_string = request.form.get("requests")
370
+ else:
371
+ series_requests_string = request.args.get("requests")
372
+ if not series_requests_string:
373
+ raise errors.InvalidArgumentError("Missing 'requests' field")
374
+ try:
375
+ series_requests = json.loads(series_requests_string)
376
+ except ValueError:
377
+ raise errors.InvalidArgumentError(
378
+ "Unable to parse 'requests' as JSON"
379
+ )
380
+
381
+ response = self._time_series_impl(ctx, experiment, series_requests)
382
+ return http_util.Respond(request, response, "application/json")
383
+
384
+ def _time_series_impl(self, ctx, experiment, series_requests):
385
+ """Constructs a list of responses from a list of series requests.
386
+
387
+ Args:
388
+ ctx: A `tensorboard.context.RequestContext` value.
389
+ experiment: string ID of the request's experiment.
390
+ series_requests: a list of `TimeSeriesRequest` dicts (see http_api.md).
391
+
392
+ Returns:
393
+ A list of `TimeSeriesResponse` dicts (see http_api.md).
394
+ """
395
+ responses = [
396
+ self._get_time_series(ctx, experiment, request)
397
+ for request in series_requests
398
+ ]
399
+ return responses
400
+
401
+ def _create_base_response(self, series_request):
402
+ tag = series_request.get("tag")
403
+ run = series_request.get("run")
404
+ plugin = series_request.get("plugin")
405
+ sample = series_request.get("sample")
406
+ response = {"plugin": plugin, "tag": tag}
407
+ if isinstance(run, str):
408
+ response["run"] = run
409
+ if isinstance(sample, int):
410
+ response["sample"] = sample
411
+
412
+ return response
413
+
414
+ def _get_invalid_request_error(self, series_request):
415
+ tag = series_request.get("tag")
416
+ plugin = series_request.get("plugin")
417
+ run = series_request.get("run")
418
+ sample = series_request.get("sample")
419
+
420
+ if not isinstance(tag, str):
421
+ return "Missing tag"
422
+
423
+ if (
424
+ plugin != scalar_metadata.PLUGIN_NAME
425
+ and plugin != histogram_metadata.PLUGIN_NAME
426
+ and plugin != image_metadata.PLUGIN_NAME
427
+ ):
428
+ return "Invalid plugin"
429
+
430
+ if plugin in _SINGLE_RUN_PLUGINS and not isinstance(run, str):
431
+ return "Missing run"
432
+
433
+ if plugin in _SAMPLED_PLUGINS and not isinstance(sample, int):
434
+ return "Missing sample"
435
+
436
+ return None
437
+
438
+ def _get_time_series(self, ctx, experiment, series_request):
439
+ """Returns time series data for a given tag, plugin.
440
+
441
+ Args:
442
+ ctx: A `tensorboard.context.RequestContext` value.
443
+ experiment: string ID of the request's experiment.
444
+ series_request: a `TimeSeriesRequest` (see http_api.md).
445
+
446
+ Returns:
447
+ A `TimeSeriesResponse` dict (see http_api.md).
448
+ """
449
+ tag = series_request.get("tag")
450
+ run = series_request.get("run")
451
+ plugin = series_request.get("plugin")
452
+ sample = series_request.get("sample")
453
+ response = self._create_base_response(series_request)
454
+ request_error = self._get_invalid_request_error(series_request)
455
+ if request_error:
456
+ response["error"] = request_error
457
+ return response
458
+
459
+ runs = [run] if run else None
460
+ run_to_series = None
461
+ if plugin == scalar_metadata.PLUGIN_NAME:
462
+ run_to_series = self._get_run_to_scalar_series(
463
+ ctx, experiment, tag, runs
464
+ )
465
+
466
+ if plugin == histogram_metadata.PLUGIN_NAME:
467
+ run_to_series = self._get_run_to_histogram_series(
468
+ ctx, experiment, tag, runs
469
+ )
470
+
471
+ if plugin == image_metadata.PLUGIN_NAME:
472
+ run_to_series = self._get_run_to_image_series(
473
+ ctx, experiment, tag, sample, runs
474
+ )
475
+
476
+ response["runToSeries"] = run_to_series
477
+ return response
478
+
479
+ def _get_run_to_scalar_series(self, ctx, experiment, tag, runs):
480
+ """Builds a run-to-scalar-series dict for client consumption.
481
+
482
+ Args:
483
+ ctx: A `tensorboard.context.RequestContext` value.
484
+ experiment: a string experiment id.
485
+ tag: string of the requested tag.
486
+ runs: optional list of run names as strings.
487
+
488
+ Returns:
489
+ A map from string run names to `ScalarStepDatum` (see http_api.md).
490
+ """
491
+ mapping = self._data_provider.read_scalars(
492
+ ctx,
493
+ experiment_id=experiment,
494
+ plugin_name=scalar_metadata.PLUGIN_NAME,
495
+ downsample=self._plugin_downsampling["scalars"],
496
+ run_tag_filter=provider.RunTagFilter(runs=runs, tags=[tag]),
497
+ )
498
+
499
+ run_to_series = {}
500
+ for result_run, tag_data in mapping.items():
501
+ if tag not in tag_data:
502
+ continue
503
+ values = [
504
+ {
505
+ "wallTime": datum.wall_time,
506
+ "step": datum.step,
507
+ "value": datum.value,
508
+ }
509
+ for datum in tag_data[tag]
510
+ ]
511
+ run_to_series[result_run] = values
512
+
513
+ return run_to_series
514
+
515
+ def _format_histogram_datum_bins(self, datum):
516
+ """Formats a histogram datum's bins for client consumption.
517
+
518
+ Args:
519
+ datum: a DataProvider's TensorDatum.
520
+
521
+ Returns:
522
+ A list of `HistogramBin`s (see http_api.md).
523
+ """
524
+ numpy_list = datum.numpy.tolist()
525
+ bins = [{"min": x[0], "max": x[1], "count": x[2]} for x in numpy_list]
526
+ return bins
527
+
528
+ def _get_run_to_histogram_series(self, ctx, experiment, tag, runs):
529
+ """Builds a run-to-histogram-series dict for client consumption.
530
+
531
+ Args:
532
+ ctx: A `tensorboard.context.RequestContext` value.
533
+ experiment: a string experiment id.
534
+ tag: string of the requested tag.
535
+ runs: optional list of run names as strings.
536
+
537
+ Returns:
538
+ A map from string run names to `HistogramStepDatum` (see http_api.md).
539
+ """
540
+ mapping = self._data_provider.read_tensors(
541
+ ctx,
542
+ experiment_id=experiment,
543
+ plugin_name=histogram_metadata.PLUGIN_NAME,
544
+ downsample=self._plugin_downsampling["histograms"],
545
+ run_tag_filter=provider.RunTagFilter(runs=runs, tags=[tag]),
546
+ )
547
+
548
+ run_to_series = {}
549
+ for result_run, tag_data in mapping.items():
550
+ if tag not in tag_data:
551
+ continue
552
+ values = [
553
+ {
554
+ "wallTime": datum.wall_time,
555
+ "step": datum.step,
556
+ "bins": self._format_histogram_datum_bins(datum),
557
+ }
558
+ for datum in tag_data[tag]
559
+ ]
560
+ run_to_series[result_run] = values
561
+
562
+ return run_to_series
563
+
564
+ def _get_run_to_image_series(self, ctx, experiment, tag, sample, runs):
565
+ """Builds a run-to-image-series dict for client consumption.
566
+
567
+ Args:
568
+ ctx: A `tensorboard.context.RequestContext` value.
569
+ experiment: a string experiment id.
570
+ tag: string of the requested tag.
571
+ sample: zero-indexed integer for the requested sample.
572
+ runs: optional list of run names as strings.
573
+
574
+ Returns:
575
+ A `RunToSeries` dict (see http_api.md).
576
+ """
577
+ mapping = self._data_provider.read_blob_sequences(
578
+ ctx,
579
+ experiment_id=experiment,
580
+ plugin_name=image_metadata.PLUGIN_NAME,
581
+ downsample=self._plugin_downsampling["images"],
582
+ run_tag_filter=provider.RunTagFilter(runs, tags=[tag]),
583
+ )
584
+
585
+ run_to_series = {}
586
+ for result_run, tag_data in mapping.items():
587
+ if tag not in tag_data:
588
+ continue
589
+ blob_sequence_datum_list = tag_data[tag]
590
+ series = _format_image_blob_sequence_datum(
591
+ blob_sequence_datum_list, sample
592
+ )
593
+ if series:
594
+ run_to_series[result_run] = series
595
+
596
+ return run_to_series
597
+
598
+ @wrappers.Request.application
599
+ def _serve_image_data(self, request):
600
+ """Serves an individual image."""
601
+ ctx = plugin_util.context(request.environ)
602
+ blob_key = request.args["imageId"]
603
+ if not blob_key:
604
+ raise errors.InvalidArgumentError("Missing 'imageId' field")
605
+
606
+ data, mime_type = self._image_data_impl(ctx, blob_key)
607
+ return http_util.Respond(request, data, mime_type)
608
+
609
+ def _image_data_impl(self, ctx, blob_key):
610
+ """Gets the image data for a blob key.
611
+
612
+ Args:
613
+ ctx: A `tensorboard.context.RequestContext` value.
614
+ blob_key: a string identifier for a DataProvider blob.
615
+
616
+ Returns:
617
+ A tuple containing:
618
+ data: a raw bytestring of the requested image's contents.
619
+ content_type: a string HTTP content type.
620
+ """
621
+ data = self._data_provider.read_blob(ctx, blob_key=blob_key)
622
+ mime_type = img_mime_type_detector.from_bytes(data)
623
+ return (data, mime_type)
File without changes
@@ -0,0 +1,75 @@
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
+ """Internal information about the pr_curves plugin."""
16
+
17
+ from tensorbored.compat.proto import summary_pb2
18
+ from tensorbored.plugins.pr_curve import plugin_data_pb2
19
+
20
+ PLUGIN_NAME = "pr_curves"
21
+
22
+ # Indices for obtaining various values from the tensor stored in a summary.
23
+ TRUE_POSITIVES_INDEX = 0
24
+ FALSE_POSITIVES_INDEX = 1
25
+ TRUE_NEGATIVES_INDEX = 2
26
+ FALSE_NEGATIVES_INDEX = 3
27
+ PRECISION_INDEX = 4
28
+ RECALL_INDEX = 5
29
+
30
+ # The most recent value for the `version` field of the
31
+ # `PrCurvePluginData` proto.
32
+ PROTO_VERSION = 0
33
+
34
+
35
+ def create_summary_metadata(display_name, description, num_thresholds):
36
+ """Create a `summary_pb2.SummaryMetadata` proto for pr_curves plugin data.
37
+
38
+ Arguments:
39
+ display_name: The display name used in TensorBoard.
40
+ description: The description to show in TensorBoard.
41
+ num_thresholds: The number of thresholds to use for PR curves.
42
+
43
+ Returns:
44
+ A `summary_pb2.SummaryMetadata` protobuf object.
45
+ """
46
+ pr_curve_plugin_data = plugin_data_pb2.PrCurvePluginData(
47
+ version=PROTO_VERSION, num_thresholds=num_thresholds
48
+ )
49
+ content = pr_curve_plugin_data.SerializeToString()
50
+ return summary_pb2.SummaryMetadata(
51
+ display_name=display_name,
52
+ summary_description=description,
53
+ plugin_data=summary_pb2.SummaryMetadata.PluginData(
54
+ plugin_name=PLUGIN_NAME, content=content
55
+ ),
56
+ )
57
+
58
+
59
+ def parse_plugin_metadata(content):
60
+ """Parse summary metadata to a Python object.
61
+
62
+ Arguments:
63
+ content: The `content` field of a `SummaryMetadata` proto
64
+ corresponding to the pr_curves plugin.
65
+
66
+ Returns:
67
+ A `PrCurvesPlugin` protobuf object.
68
+ """
69
+ if not isinstance(content, bytes):
70
+ raise TypeError("Content type must be bytes")
71
+ result = plugin_data_pb2.PrCurvePluginData.FromString(content)
72
+ if result.version == 0:
73
+ return result
74
+ # No other versions known at this time, so no migrations to do.
75
+ return result