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,234 @@
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
+ """Histogram summaries and TensorFlow operations to create them.
16
+
17
+ A histogram summary stores a list of buckets. Each bucket is encoded as
18
+ a triple `[left_edge, right_edge, count]`. Thus, a full histogram is
19
+ encoded as a tensor of dimension `[k, 3]`.
20
+
21
+ In general, the value of `k` (the number of buckets) will be a constant,
22
+ like 30. There are two edge cases: if there is no data, then there are
23
+ no buckets (the shape is `[0, 3]`); and if there is data but all points
24
+ have the same value, then there is one bucket whose left and right
25
+ endpoints are the same (the shape is `[1, 3]`).
26
+
27
+ NOTE: This module is in beta, and its API is subject to change, but the
28
+ data that it stores to disk will be supported forever.
29
+ """
30
+
31
+ import numpy as np
32
+
33
+ from tensorbored.plugins.histogram import metadata
34
+ from tensorbored.plugins.histogram import summary_v2
35
+
36
+ # Export V3 versions.
37
+ histogram = summary_v2.histogram
38
+ histogram_pb = summary_v2.histogram_pb
39
+
40
+
41
+ def _buckets(data, bucket_count=None):
42
+ """Create a TensorFlow op to group data into histogram buckets.
43
+
44
+ Arguments:
45
+ data: A `Tensor` of any shape. Must be castable to `float64`.
46
+ bucket_count: Optional positive `int` or scalar `int32` `Tensor`.
47
+ Returns:
48
+ A `Tensor` of shape `[k, 3]` and type `float64`. The `i`th row is
49
+ a triple `[left_edge, right_edge, count]` for a single bucket.
50
+ The value of `k` is either `bucket_count` or `1` or `0`.
51
+ """
52
+ # TODO(nickfelt): remove on-demand imports once dep situation is fixed.
53
+ import tensorflow.compat.v1 as tf
54
+
55
+ if bucket_count is None:
56
+ bucket_count = summary_v2.DEFAULT_BUCKET_COUNT
57
+ with tf.name_scope(
58
+ "buckets", values=[data, bucket_count]
59
+ ), tf.control_dependencies(
60
+ [tf.assert_scalar(bucket_count), tf.assert_type(bucket_count, tf.int32)]
61
+ ):
62
+ data = tf.reshape(data, shape=[-1]) # flatten
63
+ data = tf.cast(data, tf.float64)
64
+ is_empty = tf.equal(tf.size(input=data), 0)
65
+
66
+ def when_empty():
67
+ return tf.constant([], shape=(0, 3), dtype=tf.float64)
68
+
69
+ def when_nonempty():
70
+ min_ = tf.reduce_min(input_tensor=data)
71
+ max_ = tf.reduce_max(input_tensor=data)
72
+ range_ = max_ - min_
73
+ is_singular = tf.equal(range_, 0)
74
+
75
+ def when_nonsingular():
76
+ bucket_width = range_ / tf.cast(bucket_count, tf.float64)
77
+ offsets = data - min_
78
+ bucket_indices = tf.cast(
79
+ tf.floor(offsets / bucket_width), dtype=tf.int32
80
+ )
81
+ clamped_indices = tf.minimum(bucket_indices, bucket_count - 1)
82
+ # Use float64 instead of float32 to avoid accumulating floating point error
83
+ # later in tf.reduce_sum when summing more than 2^24 individual `1.0` values.
84
+ # See https://github.com/tensorflow/tensorflow/issues/51419 for details.
85
+ one_hots = tf.one_hot(
86
+ clamped_indices, depth=bucket_count, dtype=tf.float64
87
+ )
88
+ bucket_counts = tf.cast(
89
+ tf.reduce_sum(input_tensor=one_hots, axis=0),
90
+ dtype=tf.float64,
91
+ )
92
+ edges = tf.linspace(min_, max_, bucket_count + 1)
93
+ left_edges = edges[:-1]
94
+ right_edges = edges[1:]
95
+ return tf.transpose(
96
+ a=tf.stack([left_edges, right_edges, bucket_counts])
97
+ )
98
+
99
+ def when_singular():
100
+ center = min_
101
+ bucket_starts = tf.stack([center - 0.5])
102
+ bucket_ends = tf.stack([center + 0.5])
103
+ bucket_counts = tf.stack(
104
+ [tf.cast(tf.size(input=data), tf.float64)]
105
+ )
106
+ return tf.transpose(
107
+ a=tf.stack([bucket_starts, bucket_ends, bucket_counts])
108
+ )
109
+
110
+ return tf.cond(is_singular, when_singular, when_nonsingular)
111
+
112
+ return tf.cond(is_empty, when_empty, when_nonempty)
113
+
114
+
115
+ def op(
116
+ name,
117
+ data,
118
+ bucket_count=None,
119
+ display_name=None,
120
+ description=None,
121
+ collections=None,
122
+ ):
123
+ """Create a legacy histogram summary op.
124
+
125
+ Arguments:
126
+ name: A unique name for the generated summary node.
127
+ data: A `Tensor` of any shape. Must be castable to `float64`.
128
+ bucket_count: Optional positive `int`. The output will have this
129
+ many buckets, except in two edge cases. If there is no data, then
130
+ there are no buckets. If there is data but all points have the
131
+ same value, then there is one bucket whose left and right
132
+ endpoints are the same.
133
+ display_name: Optional name for this summary in TensorBoard, as a
134
+ constant `str`. Defaults to `name`.
135
+ description: Optional long-form description for this summary, as a
136
+ constant `str`. Markdown is supported. Defaults to empty.
137
+ collections: Optional list of graph collections keys. The new
138
+ summary op is added to these collections. Defaults to
139
+ `[Graph Keys.SUMMARIES]`.
140
+
141
+ Returns:
142
+ A TensorFlow summary op.
143
+ """
144
+ # TODO(nickfelt): remove on-demand imports once dep situation is fixed.
145
+ import tensorflow.compat.v1 as tf
146
+
147
+ if display_name is None:
148
+ display_name = name
149
+ summary_metadata = metadata.create_summary_metadata(
150
+ display_name=display_name, description=description
151
+ )
152
+ with tf.name_scope(name):
153
+ tensor = _buckets(data, bucket_count=bucket_count)
154
+ return tf.summary.tensor_summary(
155
+ name="histogram_summary",
156
+ tensor=tensor,
157
+ collections=collections,
158
+ summary_metadata=summary_metadata,
159
+ )
160
+
161
+
162
+ def pb(name, data, bucket_count=None, display_name=None, description=None):
163
+ """Create a legacy histogram summary protobuf.
164
+
165
+ Arguments:
166
+ name: A unique name for the generated summary, including any desired
167
+ name scopes.
168
+ data: A `np.array` or array-like form of any shape. Must have type
169
+ castable to `float`.
170
+ bucket_count: Optional positive `int`. The output will have this
171
+ many buckets, except in two edge cases. If there is no data, then
172
+ there are no buckets. If there is data but all points have the
173
+ same value, then there is one bucket whose left and right
174
+ endpoints are the same.
175
+ display_name: Optional name for this summary in TensorBoard, as a
176
+ `str`. Defaults to `name`.
177
+ description: Optional long-form description for this summary, as a
178
+ `str`. Markdown is supported. Defaults to empty.
179
+
180
+ Returns:
181
+ A `tf.Summary` protobuf object.
182
+ """
183
+ # TODO(nickfelt): remove on-demand imports once dep situation is fixed.
184
+ import tensorflow.compat.v1 as tf
185
+
186
+ if bucket_count is None:
187
+ bucket_count = summary_v2.DEFAULT_BUCKET_COUNT
188
+ data = np.array(data).flatten().astype(float)
189
+ if data.size == 0:
190
+ buckets = np.array([]).reshape((0, 3))
191
+ else:
192
+ min_ = np.min(data)
193
+ max_ = np.max(data)
194
+ range_ = max_ - min_
195
+ if range_ == 0:
196
+ center = min_
197
+ buckets = np.array([[center - 0.5, center + 0.5, float(data.size)]])
198
+ else:
199
+ bucket_width = range_ / bucket_count
200
+ offsets = data - min_
201
+ bucket_indices = np.floor(offsets / bucket_width).astype(int)
202
+ clamped_indices = np.minimum(bucket_indices, bucket_count - 1)
203
+ one_hots = np.array([clamped_indices]).transpose() == np.arange(
204
+ 0, bucket_count
205
+ ) # broadcast
206
+ assert one_hots.shape == (data.size, bucket_count), (
207
+ one_hots.shape,
208
+ (data.size, bucket_count),
209
+ )
210
+ bucket_counts = np.sum(one_hots, axis=0)
211
+ edges = np.linspace(min_, max_, bucket_count + 1)
212
+ left_edges = edges[:-1]
213
+ right_edges = edges[1:]
214
+ buckets = np.array(
215
+ [left_edges, right_edges, bucket_counts]
216
+ ).transpose()
217
+ tensor = tf.make_tensor_proto(buckets, dtype=tf.float64)
218
+
219
+ if display_name is None:
220
+ display_name = name
221
+ summary_metadata = metadata.create_summary_metadata(
222
+ display_name=display_name, description=description
223
+ )
224
+ tf_summary_metadata = tf.SummaryMetadata.FromString(
225
+ summary_metadata.SerializeToString()
226
+ )
227
+
228
+ summary = tf.Summary()
229
+ summary.value.add(
230
+ tag="%s/histogram_summary" % name,
231
+ metadata=tf_summary_metadata,
232
+ tensor=tensor,
233
+ )
234
+ return summary
@@ -0,0 +1,292 @@
1
+ # Copyright 2018 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
+ """Histogram summaries and TensorFlow operations to create them, V2 versions.
16
+
17
+ A histogram summary stores a list of buckets. Each bucket is encoded as a triple
18
+ `[left_edge, right_edge, count]`. Thus, a full histogram is encoded as a tensor
19
+ of dimension `[k, 3]`, where the first `k - 1` buckets are closed-open and the
20
+ last bucket is closed-closed.
21
+
22
+ In general, the shape of the output histogram is always constant (`[k, 3]`).
23
+ In the case of empty data, the output will be an all-zero histogram of shape
24
+ `[k, 3]`, where all edges and counts are zeros. If there is data but all points
25
+ have the same value, then all buckets' left and right edges are the same and only
26
+ the last bucket has nonzero count.
27
+ """
28
+
29
+ import numpy as np
30
+
31
+ from tensorbored.compat import tf2 as tf
32
+ from tensorbored.compat.proto import summary_pb2
33
+ from tensorbored.plugins.histogram import metadata
34
+ from tensorbored.util import lazy_tensor_creator
35
+ from tensorbored.util import tensor_util
36
+
37
+ DEFAULT_BUCKET_COUNT = 30
38
+
39
+
40
+ def histogram_pb(tag, data, buckets=None, description=None):
41
+ """Create a histogram summary protobuf.
42
+
43
+ Arguments:
44
+ tag: String tag for the summary.
45
+ data: A `np.array` or array-like form of any shape. Must have type
46
+ castable to `float`.
47
+ buckets: Optional positive `int`. The output shape will always be
48
+ [buckets, 3]. If there is no data, then an all-zero array of shape
49
+ [buckets, 3] will be returned. If there is data but all points have
50
+ the same value, then all buckets' left and right endpoints are the
51
+ same and only the last bucket has nonzero count. Defaults to 30 if
52
+ not specified.
53
+ description: Optional long-form description for this summary, as a
54
+ `str`. Markdown is supported. Defaults to empty.
55
+
56
+ Returns:
57
+ A `summary_pb2.Summary` protobuf object.
58
+ """
59
+ bucket_count = DEFAULT_BUCKET_COUNT if buckets is None else buckets
60
+ data = np.array(data).flatten().astype(float)
61
+ if bucket_count == 0 or data.size == 0:
62
+ histogram_buckets = np.zeros((bucket_count, 3))
63
+ else:
64
+ min_ = np.min(data)
65
+ max_ = np.max(data)
66
+ range_ = max_ - min_
67
+ if range_ == 0:
68
+ left_edges = right_edges = np.array([min_] * bucket_count)
69
+ bucket_counts = np.array([0] * (bucket_count - 1) + [data.size])
70
+ histogram_buckets = np.array(
71
+ [left_edges, right_edges, bucket_counts]
72
+ ).transpose()
73
+ else:
74
+ bucket_width = range_ / bucket_count
75
+ offsets = data - min_
76
+ bucket_indices = np.floor(offsets / bucket_width).astype(int)
77
+ clamped_indices = np.minimum(bucket_indices, bucket_count - 1)
78
+ one_hots = np.array([clamped_indices]).transpose() == np.arange(
79
+ 0, bucket_count
80
+ ) # broadcast
81
+ assert one_hots.shape == (data.size, bucket_count), (
82
+ one_hots.shape,
83
+ (data.size, bucket_count),
84
+ )
85
+ bucket_counts = np.sum(one_hots, axis=0)
86
+ edges = np.linspace(min_, max_, bucket_count + 1)
87
+ left_edges = edges[:-1]
88
+ right_edges = edges[1:]
89
+ histogram_buckets = np.array(
90
+ [left_edges, right_edges, bucket_counts]
91
+ ).transpose()
92
+ tensor = tensor_util.make_tensor_proto(histogram_buckets, dtype=np.float64)
93
+
94
+ summary_metadata = metadata.create_summary_metadata(
95
+ display_name=None, description=description
96
+ )
97
+ summary = summary_pb2.Summary()
98
+ summary.value.add(tag=tag, metadata=summary_metadata, tensor=tensor)
99
+ return summary
100
+
101
+
102
+ # This is the TPU compatible V3 histogram implementation as of 2021-12-01.
103
+ def histogram(name, data, step=None, buckets=None, description=None):
104
+ """Write a histogram summary.
105
+
106
+ See also `tf.summary.scalar`, `tf.summary.SummaryWriter`.
107
+
108
+ Writes a histogram to the current default summary writer, for later analysis
109
+ in TensorBoard's 'Histograms' and 'Distributions' dashboards (data written
110
+ using this API will appear in both places). Like `tf.summary.scalar` points,
111
+ each histogram is associated with a `step` and a `name`. All the histograms
112
+ with the same `name` constitute a time series of histograms.
113
+
114
+ The histogram is calculated over all the elements of the given `Tensor`
115
+ without regard to its shape or rank.
116
+
117
+ This example writes 2 histograms:
118
+
119
+ ```python
120
+ w = tf.summary.create_file_writer('test/logs')
121
+ with w.as_default():
122
+ tf.summary.histogram("activations", tf.random.uniform([100, 50]), step=0)
123
+ tf.summary.histogram("initial_weights", tf.random.normal([1000]), step=0)
124
+ ```
125
+
126
+ A common use case is to examine the changing activation patterns (or lack
127
+ thereof) at specific layers in a neural network, over time.
128
+
129
+ ```python
130
+ w = tf.summary.create_file_writer('test/logs')
131
+ with w.as_default():
132
+ for step in range(100):
133
+ # Generate fake "activations".
134
+ activations = [
135
+ tf.random.normal([1000], mean=step, stddev=1),
136
+ tf.random.normal([1000], mean=step, stddev=10),
137
+ tf.random.normal([1000], mean=step, stddev=100),
138
+ ]
139
+
140
+ tf.summary.histogram("layer1/activate", activations[0], step=step)
141
+ tf.summary.histogram("layer2/activate", activations[1], step=step)
142
+ tf.summary.histogram("layer3/activate", activations[2], step=step)
143
+ ```
144
+
145
+ Arguments:
146
+ name: A name for this summary. The summary tag used for TensorBoard will
147
+ be this name prefixed by any active name scopes.
148
+ data: A `Tensor` of any shape. The histogram is computed over its elements,
149
+ which must be castable to `float64`.
150
+ step: Explicit `int64`-castable monotonic step value for this summary. If
151
+ omitted, this defaults to `tf.summary.experimental.get_step()`, which must
152
+ not be None.
153
+ buckets: Optional positive `int`. The output will have this
154
+ many buckets, except in two edge cases. If there is no data, then
155
+ there are no buckets. If there is data but all points have the
156
+ same value, then all buckets' left and right endpoints are the same
157
+ and only the last bucket has nonzero count. Defaults to 30 if not
158
+ specified.
159
+ description: Optional long-form description for this summary, as a
160
+ constant `str`. Markdown is supported. Defaults to empty.
161
+
162
+ Returns:
163
+ True on success, or false if no summary was emitted because no default
164
+ summary writer was available.
165
+
166
+ Raises:
167
+ ValueError: if a default writer exists, but no step was provided and
168
+ `tf.summary.experimental.get_step()` is None.
169
+ """
170
+ # Avoid building unused gradient graphs for conds below. This works around
171
+ # an error building second-order gradient graphs when XlaDynamicUpdateSlice
172
+ # is used, and will generally speed up graph building slightly.
173
+ data = tf.stop_gradient(data)
174
+ summary_metadata = metadata.create_summary_metadata(
175
+ display_name=None, description=description
176
+ )
177
+ # TODO(https://github.com/tensorflow/tensorboard/issues/2109): remove fallback
178
+ summary_scope = (
179
+ getattr(tf.summary.experimental, "summary_scope", None)
180
+ or tf.summary.summary_scope
181
+ )
182
+
183
+ # TODO(ytjing): add special case handling.
184
+ with summary_scope(
185
+ name, "histogram_summary", values=[data, buckets, step]
186
+ ) as (tag, _):
187
+ # Defer histogram bucketing logic by passing it as a callable to
188
+ # write(), wrapped in a LazyTensorCreator for backwards
189
+ # compatibility, so that we only do this work when summaries are
190
+ # actually written.
191
+ @lazy_tensor_creator.LazyTensorCreator
192
+ def lazy_tensor():
193
+ return _buckets(data, buckets)
194
+
195
+ return tf.summary.write(
196
+ tag=tag,
197
+ tensor=lazy_tensor,
198
+ step=step,
199
+ metadata=summary_metadata,
200
+ )
201
+
202
+
203
+ def _buckets(data, bucket_count=None):
204
+ """Create a TensorFlow op to group data into histogram buckets.
205
+
206
+ Arguments:
207
+ data: A `Tensor` of any shape. Must be castable to `float64`.
208
+ bucket_count: Optional non-negative `int` or scalar `int32` `Tensor`,
209
+ defaults to 30.
210
+ Returns:
211
+ A `Tensor` of shape `[k, 3]` and type `float64`. The `i`th row is
212
+ a triple `[left_edge, right_edge, count]` for a single bucket.
213
+ The value of `k` is either `bucket_count` or `0` (when input data
214
+ is empty).
215
+ """
216
+ if bucket_count is None:
217
+ bucket_count = DEFAULT_BUCKET_COUNT
218
+ with tf.name_scope("buckets"):
219
+ tf.debugging.assert_scalar(bucket_count)
220
+ tf.debugging.assert_type(bucket_count, tf.int32)
221
+ # Treat a negative bucket count as zero.
222
+ bucket_count = tf.math.maximum(0, bucket_count)
223
+ data = tf.reshape(data, shape=[-1]) # flatten
224
+ data = tf.cast(data, tf.float64)
225
+ data_size = tf.size(input=data)
226
+ is_empty = tf.logical_or(
227
+ tf.equal(data_size, 0), tf.less_equal(bucket_count, 0)
228
+ )
229
+
230
+ def when_empty():
231
+ """When input data is empty or bucket_count is zero.
232
+
233
+ 1. If bucket_count is specified as zero, an empty tensor of shape
234
+ (0, 3) will be returned.
235
+ 2. If the input data is empty, a tensor of shape (bucket_count, 3)
236
+ of all zero values will be returned.
237
+ """
238
+ return tf.zeros((bucket_count, 3), dtype=tf.float64)
239
+
240
+ def when_nonempty():
241
+ min_ = tf.reduce_min(input_tensor=data)
242
+ max_ = tf.reduce_max(input_tensor=data)
243
+ range_ = max_ - min_
244
+ has_single_value = tf.equal(range_, 0)
245
+
246
+ def when_multiple_values():
247
+ """When input data contains multiple values."""
248
+ bucket_width = range_ / tf.cast(bucket_count, tf.float64)
249
+ offsets = data - min_
250
+ bucket_indices = tf.cast(
251
+ tf.floor(offsets / bucket_width), dtype=tf.int32
252
+ )
253
+ clamped_indices = tf.minimum(bucket_indices, bucket_count - 1)
254
+ # Use float64 instead of float32 to avoid accumulating floating point error
255
+ # later in tf.reduce_sum when summing more than 2^24 individual `1.0` values.
256
+ # See https://github.com/tensorflow/tensorflow/issues/51419 for details.
257
+ one_hots = tf.one_hot(
258
+ clamped_indices, depth=bucket_count, dtype=tf.float64
259
+ )
260
+ bucket_counts = tf.cast(
261
+ tf.reduce_sum(input_tensor=one_hots, axis=0),
262
+ dtype=tf.float64,
263
+ )
264
+ edges = tf.linspace(min_, max_, bucket_count + 1)
265
+ # Ensure edges[-1] == max_, which TF's linspace implementation does not
266
+ # do, leaving it subject to the whim of floating point rounding error.
267
+ edges = tf.concat([edges[:-1], [max_]], 0)
268
+ left_edges = edges[:-1]
269
+ right_edges = edges[1:]
270
+ return tf.transpose(
271
+ a=tf.stack([left_edges, right_edges, bucket_counts])
272
+ )
273
+
274
+ def when_single_value():
275
+ """When input data contains a single unique value."""
276
+ # Left and right edges are the same for single value input.
277
+ edges = tf.fill([bucket_count], max_)
278
+ # Bucket counts are 0 except the last bucket (if bucket_count > 0),
279
+ # which is `data_size`. Ensure that the resulting counts vector has
280
+ # length `bucket_count` always, including the bucket_count==0 case.
281
+ zeroes = tf.fill([bucket_count], 0)
282
+ bucket_counts = tf.cast(
283
+ tf.concat([zeroes[:-1], [data_size]], 0)[:bucket_count],
284
+ dtype=tf.float64,
285
+ )
286
+ return tf.transpose(a=tf.stack([edges, edges, bucket_counts]))
287
+
288
+ return tf.cond(
289
+ has_single_value, when_single_value, when_multiple_values
290
+ )
291
+
292
+ return tf.cond(is_empty, when_empty, when_nonempty)
@@ -0,0 +1,14 @@
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
+ # ==============================================================================
@@ -0,0 +1,93 @@
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
+ """Keras integration for TensorBoard hparams.
16
+
17
+ Use `tensorboard.plugins.hparams.api` to access this module's contents.
18
+ """
19
+
20
+ import tensorflow as tf
21
+
22
+ from tensorbored.plugins.hparams import api_pb2
23
+ from tensorbored.plugins.hparams import summary
24
+ from tensorbored.plugins.hparams import summary_v2
25
+
26
+
27
+ class Callback(tf.keras.callbacks.Callback):
28
+ """Callback for logging hyperparameters to TensorBoard.
29
+
30
+ NOTE: This callback only works in TensorFlow eager mode.
31
+ """
32
+
33
+ def __init__(self, writer, hparams, trial_id=None):
34
+ """Create a callback for logging hyperparameters to TensorBoard.
35
+
36
+ As with the standard `tf.keras.callbacks.TensorBoard` class, each
37
+ callback object is valid for only one call to `model.fit`.
38
+
39
+ Args:
40
+ writer: The `SummaryWriter` object to which hparams should be
41
+ written, or a logdir (as a `str`) to be passed to
42
+ `tf.summary.create_file_writer` to create such a writer.
43
+ hparams: A `dict` mapping hyperparameters to the values used in
44
+ this session. Keys should be the names of `HParam` objects used
45
+ in an experiment, or the `HParam` objects themselves. Values
46
+ should be Python `bool`, `int`, `float`, or `string` values,
47
+ depending on the type of the hyperparameter.
48
+ trial_id: An optional `str` ID for the set of hyperparameter
49
+ values used in this trial. Defaults to a hash of the
50
+ hyperparameters.
51
+
52
+ Raises:
53
+ ValueError: If two entries in `hparams` share the same
54
+ hyperparameter name.
55
+ """
56
+ # Defer creating the actual summary until we write it, so that the
57
+ # timestamp is correct. But create a "dry-run" first to fail fast in
58
+ # case the `hparams` are invalid.
59
+ self._hparams = dict(hparams)
60
+ self._trial_id = trial_id
61
+ summary_v2.hparams_pb(self._hparams, trial_id=self._trial_id)
62
+ if writer is None:
63
+ raise TypeError(
64
+ "writer must be a `SummaryWriter` or `str`, not None"
65
+ )
66
+ elif isinstance(writer, str):
67
+ self._writer = tf.compat.v2.summary.create_file_writer(writer)
68
+ else:
69
+ self._writer = writer
70
+
71
+ def _get_writer(self):
72
+ if self._writer is None:
73
+ raise RuntimeError(
74
+ "hparams Keras callback cannot be reused across training sessions"
75
+ )
76
+ if not tf.executing_eagerly():
77
+ raise RuntimeError(
78
+ "hparams Keras callback only supported in TensorFlow eager mode"
79
+ )
80
+ return self._writer
81
+
82
+ def on_train_begin(self, logs=None):
83
+ del logs # unused
84
+ with self._get_writer().as_default():
85
+ summary_v2.hparams(self._hparams, trial_id=self._trial_id)
86
+
87
+ def on_train_end(self, logs=None):
88
+ del logs # unused
89
+ with self._get_writer().as_default():
90
+ pb = summary.session_end_pb(api_pb2.STATUS_SUCCESS)
91
+ raw_pb = pb.SerializeToString()
92
+ tf.compat.v2.summary.experimental.write_raw_pb(raw_pb, step=0)
93
+ self._writer = None