Commit 1a3c83d6 authored by zhanggzh's avatar zhanggzh
Browse files

增加keras-cv模型及训练代码

parent 9846958a
# Copyright 2022 The KerasCV Authors
#
# 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
#
# https://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.
import tensorflow as tf
from tensorflow.keras import backend
from keras_cv import core
def transform_value_range(images, original_range, target_range, dtype=tf.float32):
"""transforms values in input tensor from original_range to target_range.
This function is intended to be used in preprocessing layers that
rely upon color values. This allows us to assume internally that
the input tensor is always in the range [0, 255].
Args:
images: the set of images to transform to the target range range.
original_range: the value range to transform from.
target_range: the value range to transform to.
dtype: the dtype to compute the conversion with. Defaults to tf.float32.
Returns:
a new Tensor with values in the target range.
Usage:
```python
original_range = [0, 1]
target_range = [0, 255]
images = keras_cv.utils.preprocessing.transform_value_range(
images,
original_range,
target_range
)
images = tf.math.minimum(images + 10, 255)
images = keras_cv.utils.preprocessing.transform_value_range(
images,
target_range,
original_range
)
```
"""
if original_range[0] == target_range[0] and original_range[1] == target_range[1]:
return images
images = tf.cast(images, dtype=dtype)
original_min_value, original_max_value = _unwrap_value_range(
original_range, dtype=dtype
)
target_min_value, target_max_value = _unwrap_value_range(target_range, dtype=dtype)
# images in the [0, 1] scale
images = (images - original_min_value) / (original_max_value - original_min_value)
scale_factor = target_max_value - target_min_value
return (images * scale_factor) + target_min_value
def _unwrap_value_range(value_range, dtype=tf.float32):
min_value, max_value = value_range
min_value = tf.cast(min_value, dtype=dtype)
max_value = tf.cast(max_value, dtype=dtype)
return min_value, max_value
def blend(image1: tf.Tensor, image2: tf.Tensor, factor: float) -> tf.Tensor:
"""Blend image1 and image2 using 'factor'.
FactorSampler should be in the range [0, 1]. A value of 0.0 means only image1
is used. A value of 1.0 means only image2 is used. A value between 0.0
and 1.0 means we linearly interpolate the pixel values between the two
images. A value greater than 1.0 "extrapolates" the difference
between the two pixel values, and we clip the results to values
between 0 and 255.
Args:
image1: An image Tensor of type tf.float32 with value range [0, 255].
image2: An image Tensor of type tf.float32 with value range [0, 255].
factor: A floating point value above 0.0.
Returns:
A blended image Tensor.
"""
difference = image2 - image1
scaled = factor * difference
temp = image1 + scaled
return tf.clip_by_value(temp, 0.0, 255.0)
def parse_factor(param, min_value=0.0, max_value=1.0, param_name="factor", seed=None):
if isinstance(param, core.FactorSampler):
return param
if isinstance(param, float) or isinstance(param, int):
param = (min_value, param)
if param[0] > param[1]:
raise ValueError(
f"`{param_name}[0] > {param_name}[1]`, `{param_name}[0]` must be <= "
f"`{param_name}[1]`. Got `{param_name}={param}`"
)
if (min_value is not None and param[0] < min_value) or (
max_value is not None and param[1] > max_value
):
raise ValueError(
f"`{param_name}` should be inside of range [{min_value}, {max_value}]. "
f"Got {param_name}={param}"
)
if param[0] == param[1]:
return core.ConstantFactorSampler(param[0])
return core.UniformFactorSampler(param[0], param[1], seed=seed)
def random_inversion(random_generator):
"""Randomly returns a -1 or a 1 based on the provided random_generator.
This can be used by KPLs to randomly invert sampled values.
Args:
random_generator: a Keras random number generator. An instance can be passed
from the `self._random_generator` attribute of a `BaseImageAugmentationLayer`.
Returns:
either -1, or -1.
"""
negate = random_generator.random_uniform((), 0, 1, dtype=tf.float32) > 0.5
negate = tf.cond(negate, lambda: -1.0, lambda: 1.0)
return negate
def get_rotation_matrix(angles, image_height, image_width, name=None):
"""Returns projective transform(s) for the given angle(s).
Args:
angles: A scalar angle to rotate all images by, or (for batches of images) a
vector with an angle to rotate each image in the batch. The rank must be
statically known (the shape is not `TensorShape(None)`).
image_height: Height of the image(s) to be transformed.
image_width: Width of the image(s) to be transformed.
name: The name of the op.
Returns:
A tensor of shape (num_images, 8). Projective transforms which can be given
to operation `image_projective_transform_v2`. If one row of transforms is
[a0, a1, a2, b0, b1, b2, c0, c1], then it maps the *output* point
`(x, y)` to a transformed *input* point
`(x', y') = ((a0 x + a1 y + a2) / k, (b0 x + b1 y + b2) / k)`,
where `k = c0 x + c1 y + 1`.
"""
with backend.name_scope(name or "rotation_matrix"):
x_offset = (
(image_width - 1)
- (tf.cos(angles) * (image_width - 1) - tf.sin(angles) * (image_height - 1))
) / 2.0
y_offset = (
(image_height - 1)
- (tf.sin(angles) * (image_width - 1) + tf.cos(angles) * (image_height - 1))
) / 2.0
num_angles = tf.shape(angles)[0]
return tf.concat(
values=[
tf.cos(angles)[:, None],
-tf.sin(angles)[:, None],
x_offset[:, None],
tf.sin(angles)[:, None],
tf.cos(angles)[:, None],
y_offset[:, None],
tf.zeros((num_angles, 2), tf.float32),
],
axis=1,
)
def get_translation_matrix(translations, name=None):
"""Returns projective transform(s) for the given translation(s).
Args:
translations: A matrix of 2-element lists representing `[dx, dy]`
to translate for each image (for a batch of images).
name: The name of the op.
Returns:
A tensor of shape `(num_images, 8)` projective transforms which can be given
to `transform`.
"""
with backend.name_scope(name or "translation_matrix"):
num_translations = tf.shape(translations)[0]
# The translation matrix looks like:
# [[1 0 -dx]
# [0 1 -dy]
# [0 0 1]]
# where the last entry is implicit.
# Translation matrices are always float32.
return tf.concat(
values=[
tf.ones((num_translations, 1), tf.float32),
tf.zeros((num_translations, 1), tf.float32),
-translations[:, 0, None],
tf.zeros((num_translations, 1), tf.float32),
tf.ones((num_translations, 1), tf.float32),
-translations[:, 1, None],
tf.zeros((num_translations, 2), tf.float32),
],
axis=1,
)
def transform(
images,
transforms,
fill_mode="reflect",
fill_value=0.0,
interpolation="bilinear",
output_shape=None,
name=None,
):
"""Applies the given transform(s) to the image(s).
Args:
images: A tensor of shape
`(num_images, num_rows, num_columns, num_channels)` (NHWC). The rank must
be statically known (the shape is not `TensorShape(None)`).
transforms: Projective transform matrix/matrices. A vector of length 8 or
tensor of size N x 8. If one row of transforms is [a0, a1, a2, b0, b1, b2,
c0, c1], then it maps the *output* point `(x, y)` to a transformed *input*
point `(x', y') = ((a0 x + a1 y + a2) / k, (b0 x + b1 y + b2) / k)`, where
`k = c0 x + c1 y + 1`. The transforms are *inverted* compared to the
transform mapping input points to output points. Note that gradients are
not backpropagated into transformation parameters.
fill_mode: Points outside the boundaries of the input are filled according
to the given mode (one of `{"constant", "reflect", "wrap", "nearest"}`).
fill_value: a float represents the value to be filled outside the boundaries
when `fill_mode="constant"`.
interpolation: Interpolation mode. Supported values: `"nearest"`,
`"bilinear"`.
output_shape: Output dimension after the transform, `[height, width]`.
If `None`, output is the same size as input image.
name: The name of the op.
Fill mode behavior for each valid value is as follows:
- reflect (d c b a | a b c d | d c b a)
The input is extended by reflecting about the edge of the last pixel.
- constant (k k k k | a b c d | k k k k)
The input is extended by filling all
values beyond the edge with the same constant value k = 0.
- wrap (a b c d | a b c d | a b c d)
The input is extended by wrapping around to the opposite edge.
- nearest (a a a a | a b c d | d d d d)
The input is extended by the nearest pixel.
Input shape:
4D tensor with shape: `(samples, height, width, channels)`,
in `"channels_last"` format.
Output shape:
4D tensor with shape: `(samples, height, width, channels)`,
in `"channels_last"` format.
Returns:
Image(s) with the same type and shape as `images`, with the given
transform(s) applied. Transformed coordinates outside of the input image
will be filled with zeros.
Raises:
TypeError: If `image` is an invalid type.
ValueError: If output shape is not 1-D int32 Tensor.
"""
with backend.name_scope(name or "transform"):
if output_shape is None:
output_shape = tf.shape(images)[1:3]
if not tf.executing_eagerly():
output_shape_value = tf.get_static_value(output_shape)
if output_shape_value is not None:
output_shape = output_shape_value
output_shape = tf.convert_to_tensor(output_shape, tf.int32, name="output_shape")
if not output_shape.get_shape().is_compatible_with([2]):
raise ValueError(
"output_shape must be a 1-D Tensor of 2 elements: "
"new_height, new_width, instead got "
"{}".format(output_shape)
)
fill_value = tf.convert_to_tensor(fill_value, tf.float32, name="fill_value")
return tf.raw_ops.ImageProjectiveTransformV3(
images=images,
output_shape=output_shape,
fill_value=fill_value,
transforms=transforms,
fill_mode=fill_mode.upper(),
interpolation=interpolation.upper(),
)
def ensure_tensor(inputs, dtype=None):
"""Ensures the input is a Tensor, SparseTensor or RaggedTensor."""
if not isinstance(inputs, (tf.Tensor, tf.RaggedTensor, tf.SparseTensor)):
inputs = tf.convert_to_tensor(inputs, dtype)
if dtype is not None and inputs.dtype != dtype:
inputs = tf.cast(inputs, dtype)
return inputs
def check_fill_mode_and_interpolation(fill_mode, interpolation):
if fill_mode not in {"reflect", "wrap", "constant", "nearest"}:
raise NotImplementedError(
" Want fillmode to be one of `reflect`, `wrap`, "
"`constant` or `nearest`. Got `fill_mode` {}. ".format(fill_mode)
)
if interpolation not in {"nearest", "bilinear"}:
raise NotImplementedError(
"Unknown `interpolation` {}. Only `nearest` and "
"`bilinear` are supported.".format(interpolation)
)
# Copyright 2022 The KerasCV Authors
#
# 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
#
# https://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.
import tensorflow as tf
from keras_cv.utils import preprocessing
class MockRandomGenerator:
def __init__(self, value):
self.value = value
def random_uniform(self, shape, minval, maxval, dtype=None):
del minval, maxval
return tf.constant(self.value, dtype=dtype)
class PreprocessingTestCase(tf.test.TestCase):
def setUp(self):
super().setUp()
def test_transform_to_standard_range_neg_one_range(self):
x = tf.constant([-1, 0, 1])
x = preprocessing.transform_value_range(
x, original_range=[-1, 1], target_range=[0, 255]
)
self.assertAllClose(x, [0.0, 127.5, 255.0])
def test_transform_to_same_range(self):
x = tf.constant([-1, 0, 1])
x = preprocessing.transform_value_range(
x, original_range=[0, 255], target_range=[0, 255]
)
self.assertAllClose(x, [-1, 0, 1])
def test_transform_to_standard_range(self):
x = tf.constant([8 / 255, 9 / 255, 255 / 255])
x = preprocessing.transform_value_range(
x, original_range=[0, 1], target_range=[0, 255]
)
self.assertAllClose(x, [8.0, 9.0, 255.0])
def test_transform_to_value_range(self):
x = tf.constant([128.0, 255.0, 0.0])
x = preprocessing.transform_value_range(
x, original_range=[0, 255], target_range=[0, 1]
)
self.assertAllClose(x, [128 / 255, 1, 0])
def test_random_inversion(self):
generator = MockRandomGenerator(0.75)
self.assertEqual(preprocessing.random_inversion(generator), -1.0)
generator = MockRandomGenerator(0.25)
self.assertEqual(preprocessing.random_inversion(generator), 1.0)
# Copyright 2022 The KerasCV Authors
#
# 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
#
# https://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.
import tensorflow as tf
def scale_loss_for_distribution(loss_value):
"""Scales and returns the given loss value by the number of replicas."""
num_replicas = tf.distribute.get_strategy().num_replicas_in_sync
if num_replicas > 1:
loss_value *= 1.0 / num_replicas
return loss_value
def convert_inputs_to_tf_dataset(x=None, y=None, sample_weight=None, batch_size=None):
if sample_weight is not None:
raise ValueError("Contrastive trainers do not yet support `sample_weight`.")
if isinstance(x, tf.data.Dataset):
if y is not None or batch_size is not None:
raise ValueError(
"When `x` is a `tf.data.Dataset`, please do not provide a value for "
f"`y` or `batch_size`. Got `y={y}`, `batch_size={batch_size}`."
)
return x
# batch_size defaults to 32, as it does in fit().
batch_size = batch_size or 32
# Parse inputs
inputs = x
if y is not None:
inputs = (x, y)
# Construct tf.data.Dataset
dataset = tf.data.Dataset.from_tensor_slices(inputs)
if batch_size is not None:
dataset = dataset.batch(batch_size)
return dataset
# Copyright 2022 The KerasCV Authors
#
# 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
#
# https://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.
"""KerasCV Version check."""
import tensorflow as tf
from packaging.version import parse
MIN_VERSION = "2.9.0"
def check_tf_version():
if parse(tf.__version__) < parse(MIN_VERSION):
raise RuntimeError(
f"The Tensorflow package version needs to be at least {MIN_VERSION} "
"for KerasCV to run. Currently, your TensorFlow version is "
f"{tf.__version__}. Please upgrade with `$ pip install --upgrade tensorflow`. "
"You can use `pip freeze` to check afterwards that everything is ok."
)
# Copyright 2022 The KerasCV Authors
#
# 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
#
# https://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.
import pytest
from keras_cv import version_check
def test_check_tf_version_error():
version_check.tf.__version__ = "2.8.0"
with pytest.raises(
RuntimeError, match="Tensorflow package version needs to be at least 2.9.0"
):
version_check.check_tf_version()
def test_check_tf_version_passes_rc2():
# should pass
version_check.tf.__version__ = "2.9.1rc2"
version_check.check_tf_version()
def test_check_tf_version_passes_nightly():
# should pass
version_check.tf.__version__ = "2.10.0-dev20220419"
version_check.check_tf_version()
[metadata]
license_file = LICENSE
description-file = README.md
version = attr: keras_cv.__version__
[tool:pytest]
filterwarnings =
error
ignore::DeprecationWarning
ignore::ImportWarning
ignore::RuntimeWarning
ignore::PendingDeprecationWarning
ignore::FutureWarning
[flake8]
max-line-length = 88
max-doc-length = 200
per-file-ignores =
./keras_cv/__init__.py:E402, F401
./examples/**/*:E402
**/__init__.py:F401
ignore =
# Conflicts with black
E203
# defaults flake8 ignores
E121,E123,E126,E226,E24,E704,W503,W504
# Function name should be lowercase
N802
# lowercase ... imported as non lowercase
# Useful to ignore for "import keras.backend as K"
N812
# do not use bare 'except'
E722
# Escape characters check.
# Conflict with pytest error message regex.
W605
# Ignore for tf.cond lambda
E731
[isort]
profile = black
force_single_line = True
known_first_party = keras_cv,tests
default_section = THIRDPARTY
line_length = 88
# Copyright 2019 The KerasCV Authors
#
# 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
#
# https://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.
"""Setup script."""
import pathlib
from setuptools import find_packages
from setuptools import setup
from setuptools.dist import Distribution
HERE = pathlib.Path(__file__).parent
README = (HERE / "README.md").read_text()
class BinaryDistribution(Distribution):
"""This class is needed in order to create OS specific wheels."""
def has_ext_modules(self):
return True
def is_pure(self):
return False
setup(
name="keras-cv",
description="Industry-strength computer Vision extensions for Keras.",
long_description=README,
long_description_content_type="text/markdown",
url="https://github.com/keras-team/keras-cv",
author="Keras team",
author_email="keras-cv@google.com",
license="Apache License 2.0",
install_requires=["packaging", "absl-py", "regex"],
python_requires=">=3.7",
extras_require={
"tests": ["flake8", "isort", "black", "pytest", "tensorflow-datasets"],
"examples": ["tensorflow_datasets", "matplotlib"],
},
distclass=BinaryDistribution,
classifiers=[
"Programming Language :: Python",
"Programming Language :: Python :: 3.7",
"Operating System :: Unix",
"Operating System :: Microsoft :: Windows",
"Operating System :: MacOS",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering",
"Topic :: Software Development",
],
packages=find_packages(exclude=("*_test.py",)),
include_package_data=True,
)
#!/bin/bash
rm -rf keras_cv.egg-info/
rm -rf keras_cv/**/__pycache__
rm -rf keras_cv/__pycache__
rm -rf build/
#!/bin/bash
isort --sl --profile=black .
black .
#!/bin/bash
# Usage: # lint.sh can be used without arguments to lint the entire project:
#
# ./lint.sh
#
# or with arguments to lint a subset of files
#
# ./lint.sh examples/*
files="."
if [ $# -ne 0 ]
then
files=$@
fi
isort -c $files
if ! [ $? -eq 0 ]
then
echo "Please run \"sh shell/format.sh\" to format the code."
isort --version
black --version
exit 1
fi
[ $# -eq 0 ] && echo "no issues with isort"
# Allow --max-line-length=200 to support long links in docstrings
flake8 --max-line-length=200 $files
if ! [ $? -eq 0 ]
then
echo "Please fix the code style issue."
exit 1
fi
[ $# -eq 0 ] && echo "no issues with flake8"
black --check $files
if ! [ $? -eq 0 ]
then
echo "Please run \"sh shell/format.sh\" to format the code."
exit 1
fi
[ $# -eq 0 ] && echo "no issues with black"
for i in $(find keras_cv -name '*.py') # or whatever other pattern...
do
if ! grep -q Copyright $i
then
echo "Copyright not found in $i"
exit 1
fi
done
echo "linting success!"
if [ "$#" -ne 4 ]; then
echo USAGE: ./process_weights.sh WEIGHTS_PATH OUTPUT_WEIGHTS_PATH MODEL_NAME GCS_PATH
exit 1
fi
WEIGHTS=$1
OUTPUT_WEIGHTS=$2
MODEL=$3
GCS_PATH=$4
python3 remove_top.py --weights_path=$WEIGHTS --output_weights_path=$OUTPUT_WEIGHTS --model_name=$MODEL
echo With top: $GCS_PATH/$WEIGHTS
echo With top checksum: $(shasum -a 256 $WEIGHTS)
echo Without top: $GCS_PATH/$OUTPUT_WEIGHTS
echo Without top checksum: $(shasum -a 256 $OUTPUT_WEIGHTS)
gsutil cp $WEIGHTS $GCS_PATH/
gsutil cp $OUTPUT_WEIGHTS $GCS_PATH/
gsutil acl ch -u AllUsers:R $GCS_PATH/$WEIGHTS
gsutil acl ch -u AllUsers:R $GCS_PATH/$OUTPUT_WEIGHTS
import sys
import keras
from absl import flags
import keras_cv
flags.DEFINE_string("weights_path", None, "Path of weights to load")
flags.DEFINE_string("output_weights_path", None, "Path of notop weights to store")
flags.DEFINE_string("model_name", None, "Name of the KerasCV.model")
FLAGS = flags.FLAGS
FLAGS(sys.argv)
if not FLAGS.weights_path.endswith(".h5"):
raise ValueError("Weights path must end in .h5")
model = eval(
f"keras_cv.models.{FLAGS.model_name}(include_rescaling=True, include_top=True, classes=1000, weights=FLAGS.weights_path)"
)
without_top = keras.models.Model(model.input, model.layers[-3].output)
without_top.save_weights(FLAGS.output_weights_path)
# Because the usage of keras_cv is in an eval() call, the linter is angry.
# We include this to avoid an unused import warning
keras_cv.models
import json
import os
import sys
import tensorboard as tb
from absl import flags
flags.DEFINE_string(
"model_name", None, "The name of the KerasCV.model that was trained"
)
flags.DEFINE_string("tensorboard_logs_path", None, "Path to tensorboard logs to load")
flags.DEFINE_string("training_script_path", None, "Path to the training script")
flags.DEFINE_string(
"script_version",
None,
"commit hash of the latest commit in KerasCV/master for the training script",
)
flags.DEFINE_string(
"weights_version",
None,
"The version of the training script used to produce the latest weights. For example, v0",
)
flags.DEFINE_string(
"contributor", None, "The GitHub username of the contributor of these results"
)
flags.DEFINE_string(
"accelerators", None, "The number of accelerators used for training."
)
FLAGS = flags.FLAGS
FLAGS(sys.argv)
model_name = FLAGS.model_name or input(
"Input the name of the KerasCV.model that was trained\n"
)
weights_version = FLAGS.weights_version or input(
"Input the weights version for your script\n"
)
training_script_path = FLAGS.training_script_path or input(
"Input the path to your training script\n"
)
full_training_script_path = os.path.abspath(training_script_path)
# Build an experiment name structured as task/training_script_name/model_name-version
training_script_rooted_at_training = full_training_script_path[
full_training_script_path.index("keras-cv/examples/training/") + 27 :
]
training_script_dirs = training_script_rooted_at_training.split("/")
tensorboard_experiment_name = f"{training_script_dirs[0]}/{'/'.join(training_script_dirs[1:])[:-3]}/{model_name}-{weights_version}"
training_script_json_path = full_training_script_path[
: full_training_script_path.index("keras-cv/examples/training/") + 27
] + "/".join(training_script_dirs[:2] + ["training_history.json"])
script_version = FLAGS.script_version or input(
"Input the commit hash of the latest commit in KerasCV/master for the training script used for training."
)
tensorboard_logs_path = FLAGS.tensorboard_logs_path or input(
"Input the path to the TensorBoard logs\n"
)
tensorboard_experiment_id = (
os.popen(
f"python3 -m tensorboard.main dev upload --logdir {tensorboard_logs_path} --name {tensorboard_experiment_name} --one_shot --verbose 0"
)
.read()
.split("/")[-2]
)
tensorboard_experiment = tb.data.experimental.ExperimentFromDev(
tensorboard_experiment_id
)
tensorboard_results = tensorboard_experiment.get_scalars()
training_epochs = max(tensorboard_results[tensorboard_results.run == "train"].step)
max_validation_accuracy = max(
tensorboard_results[
(tensorboard_results.run == "validation")
& (tensorboard_results.tag == "epoch_categorical_accuracy")
].value
)
max_validation_accuracy = f"{max_validation_accuracy:.4f}"
contributor = FLAGS.contributor or input(
"Input your GitHub username (or the username of the contributor, if it's not you)\n"
)
accelerators = FLAGS.accelerators or input(
"Input the number of accelerators used during training.\n"
)
args = input(
"Input any training arguments used for the training script.\n"
"Use comma-separate, colon-split key-value pairs. For example:\n"
"arg1:value, arg2:value\n"
)
args_dict = {}
for arg in args.split(","):
if len(arg.strip()) == 0:
continue
key_value_pair = [s.strip() for s in arg.split(":")]
args_dict[key_value_pair[0]] = key_value_pair[1]
new_results = {
"script": {"name": "/".join(training_script_dirs[2:]), "version": script_version},
"validation_accuracy": max_validation_accuracy,
"epochs_trained": training_epochs,
"tensorboard_logs": f"https://tensorboard.dev/experiment/{tensorboard_experiment_id}/",
"contributor": contributor,
"args": args_dict,
"accelerators": int(accelerators),
}
# Check if the JSON file already exists
results_file = open(training_script_json_path, "r")
results_string = results_file.read()
results = json.loads(results_string) if results_string != "" else {}
results_file.close()
# If we've never run this script on this model, insert a record for it
if model_name not in results:
results[model_name] = {}
# Add this run's results to the model's record
model_results = results[model_name]
model_results[weights_version] = new_results
# Save the updated results
results_file = open(training_script_json_path, "w")
json.dump(results, results_file, indent=4, sort_keys=True)
results_file.close()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment