I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1,321 @@
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""The TensorBoard Custom Scalars plugin.
This plugin lets the user create scalars plots with custom run-tag combinations
by specifying regular expressions.
See `http_api.md` in this directory for specifications of the routes for
this plugin.
"""
import re
from werkzeug import wrappers
from tensorboard import plugin_util
from tensorboard.backend import http_util
from tensorboard.compat import tf
from tensorboard.data import provider
from tensorboard.plugins import base_plugin
from tensorboard.plugins.custom_scalar import layout_pb2
from tensorboard.plugins.custom_scalar import metadata
from tensorboard.plugins.scalar import metadata as scalars_metadata
from tensorboard.plugins.scalar import scalars_plugin
# The name of the property in the response for whether the regex is valid.
_REGEX_VALID_PROPERTY = "regex_valid"
# The name of the property in the response for the payload (tag to ScalarEvents
# mapping).
_TAG_TO_EVENTS_PROPERTY = "tag_to_events"
# The number of seconds to wait in between checks for the config file specifying
# layout.
_CONFIG_FILE_CHECK_THROTTLE = 60
class CustomScalarsPlugin(base_plugin.TBPlugin):
"""CustomScalars Plugin for TensorBoard."""
plugin_name = metadata.PLUGIN_NAME
def __init__(self, context):
"""Instantiates ScalarsPlugin via TensorBoard core.
Args:
context: A base_plugin.TBContext instance.
"""
self._logdir = context.logdir
self._data_provider = context.data_provider
self._plugin_name_to_instance = context.plugin_name_to_instance
def _get_scalars_plugin(self):
"""Tries to get the scalars plugin.
Returns:
The scalars plugin. Or None if it is not yet registered.
"""
if scalars_metadata.PLUGIN_NAME in self._plugin_name_to_instance:
# The plugin is registered.
return self._plugin_name_to_instance[scalars_metadata.PLUGIN_NAME]
# The plugin is not yet registered.
return None
def get_plugin_apps(self):
return {
"/download_data": self.download_data_route,
"/layout": self.layout_route,
"/scalars": self.scalars_route,
}
def is_active(self):
"""Plugin is active if there is a custom layout for the dashboard."""
return False # `list_plugins` as called by TB core suffices
def frontend_metadata(self):
return base_plugin.FrontendMetadata(
element_name="tf-custom-scalar-dashboard",
tab_name="Custom Scalars",
)
@wrappers.Request.application
def download_data_route(self, request):
ctx = plugin_util.context(request.environ)
run = request.args.get("run")
tag = request.args.get("tag")
experiment = plugin_util.experiment_id(request.environ)
response_format = request.args.get("format")
try:
body, mime_type = self.download_data_impl(
ctx, run, tag, experiment, response_format
)
except ValueError as e:
return http_util.Respond(
request=request,
content=str(e),
content_type="text/plain",
code=400,
)
return http_util.Respond(request, body, mime_type)
def download_data_impl(self, ctx, run, tag, experiment, response_format):
"""Provides a response for downloading scalars data for a data series.
Args:
ctx: A tensorboard.context.RequestContext value.
run: The run.
tag: The specific tag.
experiment: An experiment ID, as a possibly-empty `str`.
response_format: A string. One of the values of the OutputFormat enum
of the scalar plugin.
Raises:
ValueError: If the scalars plugin is not registered.
Returns:
2 entities:
- A JSON object response body.
- A mime type (string) for the response.
"""
scalars_plugin_instance = self._get_scalars_plugin()
if not scalars_plugin_instance:
raise ValueError(
(
"Failed to respond to request for /download_data. "
"The scalars plugin is oddly not registered."
)
)
body, mime_type = scalars_plugin_instance.scalars_impl(
ctx, tag, run, experiment, response_format
)
return body, mime_type
@wrappers.Request.application
def scalars_route(self, request):
"""Given a tag regex and single run, return ScalarEvents.
This route takes 2 GET params:
run: A run string to find tags for.
tag: A string that is a regex used to find matching tags.
The response is a JSON object:
{
// Whether the regular expression is valid. Also false if empty.
regexValid: boolean,
// An object mapping tag name to a list of ScalarEvents.
payload: Object<string, ScalarEvent[]>,
}
"""
ctx = plugin_util.context(request.environ)
tag_regex_string = request.args.get("tag")
run = request.args.get("run")
experiment = plugin_util.experiment_id(request.environ)
mime_type = "application/json"
try:
body = self.scalars_impl(ctx, run, tag_regex_string, experiment)
except ValueError as e:
return http_util.Respond(
request=request,
content=str(e),
content_type="text/plain",
code=400,
)
# Produce the response.
return http_util.Respond(request, body, mime_type)
def scalars_impl(self, ctx, run, tag_regex_string, experiment):
"""Given a tag regex and single run, return ScalarEvents.
Args:
ctx: A tensorboard.context.RequestContext value.
run: A run string.
tag_regex_string: A regular expression that captures portions of tags.
Raises:
ValueError: if the scalars plugin is not registered.
Returns:
A dictionary that is the JSON-able response.
"""
if not tag_regex_string:
# The user provided no regex.
return {
_REGEX_VALID_PROPERTY: False,
_TAG_TO_EVENTS_PROPERTY: {},
}
# Construct the regex.
try:
regex = re.compile(tag_regex_string)
except re.error:
return {
_REGEX_VALID_PROPERTY: False,
_TAG_TO_EVENTS_PROPERTY: {},
}
# Fetch the tags for the run. Filter for tags that match the regex.
run_to_data = self._data_provider.list_scalars(
ctx,
experiment_id=experiment,
plugin_name=scalars_metadata.PLUGIN_NAME,
run_tag_filter=provider.RunTagFilter(runs=[run]),
)
tag_to_data = None
try:
tag_to_data = run_to_data[run]
except KeyError:
# The run could not be found. Perhaps a configuration specified a run that
# TensorBoard has not read from disk yet.
payload = {}
if tag_to_data:
scalars_plugin_instance = self._get_scalars_plugin()
if not scalars_plugin_instance:
raise ValueError(
(
"Failed to respond to request for /scalars. "
"The scalars plugin is oddly not registered."
)
)
form = scalars_plugin.OutputFormat.JSON
payload = {
tag: scalars_plugin_instance.scalars_impl(
ctx, tag, run, experiment, form
)[0]
for tag in tag_to_data.keys()
if regex.match(tag)
}
return {
_REGEX_VALID_PROPERTY: True,
_TAG_TO_EVENTS_PROPERTY: payload,
}
@wrappers.Request.application
def layout_route(self, request):
"""Fetches the custom layout specified by the config file in the logdir.
If more than 1 run contains a layout, this method merges the layouts by
merging charts within individual categories. If 2 categories with the same
name are found, the charts within are merged. The merging is based on the
order of the runs to which the layouts are written.
The response is a JSON object mirroring properties of the Layout proto if a
layout for any run is found.
The response is an empty object if no layout could be found.
"""
ctx = plugin_util.context(request.environ)
experiment = plugin_util.experiment_id(request.environ)
body = self.layout_impl(ctx, experiment)
return http_util.Respond(request, body, "application/json")
def layout_impl(self, ctx, experiment):
# Keep a mapping between and category so we do not create duplicate
# categories.
title_to_category = {}
merged_layout = None
data = self._data_provider.read_tensors(
ctx,
experiment_id=experiment,
plugin_name=metadata.PLUGIN_NAME,
run_tag_filter=provider.RunTagFilter(
tags=[metadata.CONFIG_SUMMARY_TAG]
),
downsample=1,
)
for run in sorted(data):
points = data[run][metadata.CONFIG_SUMMARY_TAG]
content = points[0].numpy.item()
layout_proto = layout_pb2.Layout()
layout_proto.ParseFromString(tf.compat.as_bytes(content))
if merged_layout:
# Append the categories within this layout to the merged layout.
for category in layout_proto.category:
if category.title in title_to_category:
# A category with this name has been seen before. Do not create a
# new one. Merge their charts, skipping any duplicates.
title_to_category[category.title].chart.extend(
[
c
for c in category.chart
if c
not in title_to_category[category.title].chart
]
)
else:
# This category has not been seen before.
merged_layout.category.add().MergeFrom(category)
title_to_category[category.title] = category
else:
# This is the first layout encountered.
merged_layout = layout_proto
for category in layout_proto.category:
title_to_category[category.title] = category
if merged_layout:
return plugin_util.proto_to_json(merged_layout)
else:
# No layout was found.
return {}

View File

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: tensorboard/plugins/custom_scalar/layout.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n.tensorboard/plugins/custom_scalar/layout.proto\x12\x0btensorboard\"\x8d\x01\n\x05\x43hart\x12\r\n\x05title\x18\x01 \x01(\t\x12\x37\n\tmultiline\x18\x02 \x01(\x0b\x32\".tensorboard.MultilineChartContentH\x00\x12\x31\n\x06margin\x18\x03 \x01(\x0b\x32\x1f.tensorboard.MarginChartContentH\x00\x42\t\n\x07\x63ontent\"$\n\x15MultilineChartContent\x12\x0b\n\x03tag\x18\x01 \x03(\t\"\x83\x01\n\x12MarginChartContent\x12\x36\n\x06series\x18\x01 \x03(\x0b\x32&.tensorboard.MarginChartContent.Series\x1a\x35\n\x06Series\x12\r\n\x05value\x18\x01 \x01(\t\x12\r\n\x05lower\x18\x02 \x01(\t\x12\r\n\x05upper\x18\x03 \x01(\t\"L\n\x08\x43\x61tegory\x12\r\n\x05title\x18\x01 \x01(\t\x12!\n\x05\x63hart\x18\x02 \x03(\x0b\x32\x12.tensorboard.Chart\x12\x0e\n\x06\x63losed\x18\x03 \x01(\x08\"B\n\x06Layout\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\'\n\x08\x63\x61tegory\x18\x02 \x03(\x0b\x32\x15.tensorboard.Categoryb\x06proto3')
_CHART = DESCRIPTOR.message_types_by_name['Chart']
_MULTILINECHARTCONTENT = DESCRIPTOR.message_types_by_name['MultilineChartContent']
_MARGINCHARTCONTENT = DESCRIPTOR.message_types_by_name['MarginChartContent']
_MARGINCHARTCONTENT_SERIES = _MARGINCHARTCONTENT.nested_types_by_name['Series']
_CATEGORY = DESCRIPTOR.message_types_by_name['Category']
_LAYOUT = DESCRIPTOR.message_types_by_name['Layout']
Chart = _reflection.GeneratedProtocolMessageType('Chart', (_message.Message,), {
'DESCRIPTOR' : _CHART,
'__module__' : 'tensorboard.plugins.custom_scalar.layout_pb2'
# @@protoc_insertion_point(class_scope:tensorboard.Chart)
})
_sym_db.RegisterMessage(Chart)
MultilineChartContent = _reflection.GeneratedProtocolMessageType('MultilineChartContent', (_message.Message,), {
'DESCRIPTOR' : _MULTILINECHARTCONTENT,
'__module__' : 'tensorboard.plugins.custom_scalar.layout_pb2'
# @@protoc_insertion_point(class_scope:tensorboard.MultilineChartContent)
})
_sym_db.RegisterMessage(MultilineChartContent)
MarginChartContent = _reflection.GeneratedProtocolMessageType('MarginChartContent', (_message.Message,), {
'Series' : _reflection.GeneratedProtocolMessageType('Series', (_message.Message,), {
'DESCRIPTOR' : _MARGINCHARTCONTENT_SERIES,
'__module__' : 'tensorboard.plugins.custom_scalar.layout_pb2'
# @@protoc_insertion_point(class_scope:tensorboard.MarginChartContent.Series)
})
,
'DESCRIPTOR' : _MARGINCHARTCONTENT,
'__module__' : 'tensorboard.plugins.custom_scalar.layout_pb2'
# @@protoc_insertion_point(class_scope:tensorboard.MarginChartContent)
})
_sym_db.RegisterMessage(MarginChartContent)
_sym_db.RegisterMessage(MarginChartContent.Series)
Category = _reflection.GeneratedProtocolMessageType('Category', (_message.Message,), {
'DESCRIPTOR' : _CATEGORY,
'__module__' : 'tensorboard.plugins.custom_scalar.layout_pb2'
# @@protoc_insertion_point(class_scope:tensorboard.Category)
})
_sym_db.RegisterMessage(Category)
Layout = _reflection.GeneratedProtocolMessageType('Layout', (_message.Message,), {
'DESCRIPTOR' : _LAYOUT,
'__module__' : 'tensorboard.plugins.custom_scalar.layout_pb2'
# @@protoc_insertion_point(class_scope:tensorboard.Layout)
})
_sym_db.RegisterMessage(Layout)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_CHART._serialized_start=64
_CHART._serialized_end=205
_MULTILINECHARTCONTENT._serialized_start=207
_MULTILINECHARTCONTENT._serialized_end=243
_MARGINCHARTCONTENT._serialized_start=246
_MARGINCHARTCONTENT._serialized_end=377
_MARGINCHARTCONTENT_SERIES._serialized_start=324
_MARGINCHARTCONTENT_SERIES._serialized_end=377
_CATEGORY._serialized_start=379
_CATEGORY._serialized_end=455
_LAYOUT._serialized_start=457
_LAYOUT._serialized_end=523
# @@protoc_insertion_point(module_scope)

View File

@ -0,0 +1,36 @@
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Information on the custom scalars plugin."""
from tensorboard.compat.proto import summary_pb2
# A special tag named used for the summary that stores the layout.
CONFIG_SUMMARY_TAG = "custom_scalars__config__"
PLUGIN_NAME = "custom_scalars"
def create_summary_metadata():
"""Create a `SummaryMetadata` proto for custom scalar plugin data.
Returns:
A `summary_pb2.SummaryMetadata` protobuf object.
"""
return summary_pb2.SummaryMetadata(
plugin_data=summary_pb2.SummaryMetadata.PluginData(
plugin_name=PLUGIN_NAME
)
)

View File

@ -0,0 +1,80 @@
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains summaries related to laying out the custom scalars dashboard."""
from tensorboard.plugins.custom_scalar import layout_pb2
from tensorboard.plugins.custom_scalar import metadata
def op(scalars_layout, collections=None):
"""Creates a summary that contains a layout.
When users navigate to the custom scalars dashboard, they will see a layout
based on the proto provided to this function.
Args:
scalars_layout: The scalars_layout_pb2.Layout proto that specifies the
layout.
collections: Optional list of graph collections keys. The new
summary op is added to these collections. Defaults to
`[Graph Keys.SUMMARIES]`.
Returns:
A tensor summary op that writes the layout to disk.
"""
# TODO(nickfelt): remove on-demand imports once dep situation is fixed.
import tensorflow.compat.v1 as tf
assert isinstance(scalars_layout, layout_pb2.Layout)
summary_metadata = metadata.create_summary_metadata()
return tf.summary.tensor_summary(
name=metadata.CONFIG_SUMMARY_TAG,
tensor=tf.constant(scalars_layout.SerializeToString(), dtype=tf.string),
collections=collections,
summary_metadata=summary_metadata,
)
def pb(scalars_layout):
"""Creates a summary that contains a layout.
When users navigate to the custom scalars dashboard, they will see a layout
based on the proto provided to this function.
Args:
scalars_layout: The scalars_layout_pb2.Layout proto that specifies the
layout.
Returns:
A summary proto containing the layout.
"""
# TODO(nickfelt): remove on-demand imports once dep situation is fixed.
import tensorflow.compat.v1 as tf
assert isinstance(scalars_layout, layout_pb2.Layout)
tensor = tf.make_tensor_proto(
scalars_layout.SerializeToString(), dtype=tf.string
)
tf_summary_metadata = tf.SummaryMetadata.FromString(
metadata.create_summary_metadata().SerializeToString()
)
summary = tf.Summary()
summary.value.add(
tag=metadata.CONFIG_SUMMARY_TAG,
metadata=tf_summary_metadata,
tensor=tensor,
)
return summary