chore: import upstream snapshot with attribution
Docker Image CI / build-ubuntu2004 (push) Has been cancelled
Docker Image CI / build-ubuntu2004 (push) Has been cancelled
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,350 @@
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Copyright 2018 & 2016 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.
|
||||
|
||||
"""
|
||||
Changes made by NVIDIA (2022):
|
||||
- Added: load_data_tfrecord_tf() and load_data() functions
|
||||
- Modified preprocess_image_record(): preprocess_image() + tfrecord data deserialization + decode jpeg
|
||||
- Updated global constants with supported models: _DEFAULT_IMAGE_SIZE and _RESIZE_MIN
|
||||
|
||||
About this file: Standalone script for ImageNet TFRecord data loading and input image pre-processing for supported
|
||||
models. Follows TensorFlow's codebase data_loading + pre-processing workflow.
|
||||
|
||||
Important links:
|
||||
- TF's codebase:
|
||||
https://github.com/tensorflow/models/blob/master/official/legacy/image_classification/resnet/imagenet_preprocessing.py
|
||||
- Deserialize tfrecord:
|
||||
https://github.com/tensorflow/models/blob/master/official/vision/dataloaders/tf_example_decoder.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import tensorflow as tf
|
||||
import PIL.Image
|
||||
import numpy as np
|
||||
from typing import Dict, Union
|
||||
|
||||
_SUPPORTED_MODEL_NAMES = [
|
||||
"resnet_v1",
|
||||
"resnet_v2",
|
||||
"efficientnet_b0",
|
||||
"efficientnet_b3",
|
||||
"mobilenet_v1",
|
||||
"mobilenet_v2",
|
||||
"inception_v3",
|
||||
]
|
||||
|
||||
_NUM_CLASSES = 1000
|
||||
_NUM_IMAGES = {
|
||||
"train": 1281167,
|
||||
"validation": 50000,
|
||||
}
|
||||
|
||||
_DEFAULT_IMAGE_SIZE = {
|
||||
"resnet_v1": 224,
|
||||
"resnet_v2": 299,
|
||||
"efficientnet_b0": 224,
|
||||
"efficientnet_b3": 300,
|
||||
"mobilenet_v1": 224,
|
||||
"mobilenet_v2": 224,
|
||||
"inception_v3": 299,
|
||||
}
|
||||
_NUM_CHANNELS = 3
|
||||
_RESIZE_MIN = {
|
||||
"resnet_v1": 256,
|
||||
"resnet_v2": 342,
|
||||
"efficientnet_b0": 256,
|
||||
"efficientnet_b3": 342,
|
||||
"mobilenet_v1": 256,
|
||||
"mobilenet_v2": 256,
|
||||
"inception_v3": 342,
|
||||
}
|
||||
|
||||
|
||||
def load_image_np(test_image, model_name: str = "resnet_v1"):
|
||||
# Image is loaded in NHWC format
|
||||
image_np = np.asarray(PIL.Image.open(test_image).convert('RGB'))
|
||||
image = tf.constant(image_np)
|
||||
image = _aspect_preserving_resize(image, _RESIZE_MIN[model_name])
|
||||
image = _central_crop(image, _DEFAULT_IMAGE_SIZE[model_name], _DEFAULT_IMAGE_SIZE[model_name])
|
||||
image = preprocess_model_func(image, model_name)
|
||||
return image
|
||||
|
||||
|
||||
def get_filenames(
|
||||
data_dir: str,
|
||||
is_training: bool = False,
|
||||
num_train_files: int = 1024,
|
||||
num_val_files: int = 128,
|
||||
):
|
||||
"""
|
||||
Returns filenames for dataset.
|
||||
|
||||
Args:
|
||||
data_dir (str): directory where data is stored.
|
||||
is_training (bool): indicates whether to return the 'train' (True) or 'validation' (False) data filenames.
|
||||
num_train_files (int): number of tfrecord shards available for training.
|
||||
num_val_files (int): number of tfrecord shards available for validation.
|
||||
|
||||
Returns:
|
||||
List: list of shards filenames to compose the dataset.
|
||||
"""
|
||||
if is_training:
|
||||
return [
|
||||
# Example: train-00000-of-01024
|
||||
os.path.join(data_dir, "train-{:05d}-of-{:05d}".format(i, num_train_files))
|
||||
for i in range(num_train_files)
|
||||
]
|
||||
else:
|
||||
return [
|
||||
os.path.join(
|
||||
data_dir, "validation-{:05d}-of-{:05d}".format(i, num_val_files)
|
||||
)
|
||||
for i in range(num_val_files)
|
||||
]
|
||||
|
||||
|
||||
def _deserialize_image_record(record):
|
||||
feature_map = {
|
||||
"image/encoded": tf.io.FixedLenFeature([], tf.string, ""),
|
||||
"image/class/label": tf.io.FixedLenFeature([], tf.int64, -1),
|
||||
"image/class/text": tf.io.FixedLenFeature([], tf.string, ""),
|
||||
"image/object/bbox/xmin": tf.io.VarLenFeature(dtype=tf.float32),
|
||||
"image/object/bbox/ymin": tf.io.VarLenFeature(dtype=tf.float32),
|
||||
"image/object/bbox/xmax": tf.io.VarLenFeature(dtype=tf.float32),
|
||||
"image/object/bbox/ymax": tf.io.VarLenFeature(dtype=tf.float32),
|
||||
}
|
||||
with tf.name_scope("deserialize_image_record"):
|
||||
obj = tf.io.parse_single_example(record, feature_map)
|
||||
imgdata = obj["image/encoded"]
|
||||
label = tf.cast(obj["image/class/label"], tf.int32)
|
||||
bbox = tf.stack(
|
||||
[
|
||||
obj["image/object/bbox/%s" % x].values
|
||||
for x in ["ymin", "xmin", "ymax", "xmax"]
|
||||
]
|
||||
)
|
||||
bbox = tf.transpose(tf.expand_dims(bbox, 0), [0, 2, 1])
|
||||
text = obj["image/class/text"]
|
||||
|
||||
return imgdata, label, bbox, text
|
||||
|
||||
|
||||
def _aspect_preserving_resize(image: tf.Tensor, resize_min: Union[int, tf.Tensor]):
|
||||
"""Resize images preserving the original aspect ratio.
|
||||
|
||||
Args:
|
||||
image (tf.Tensor): A 3-D image `Tensor`.
|
||||
resize_min (int): A python integer or scalar `Tensor` indicating the size of the smallest side after resize.
|
||||
|
||||
Returns:
|
||||
resized_image (tf.Tensor): A 3-D `Tensor` containing the resized image.
|
||||
"""
|
||||
shape = tf.shape(image)
|
||||
height, width = shape[0], shape[1]
|
||||
|
||||
new_height, new_width = _smallest_size_at_least(height, width, resize_min)
|
||||
|
||||
resized_image = tf.image.resize(
|
||||
image, [new_height, new_width], method=tf.image.ResizeMethod.BILINEAR
|
||||
)
|
||||
|
||||
return resized_image
|
||||
|
||||
|
||||
def _smallest_size_at_least(height, width, resize_min):
|
||||
resize_min = tf.cast(resize_min, tf.float32)
|
||||
|
||||
# Convert to floats to make subsequent calculations go smoothly.
|
||||
height, width = tf.cast(height, tf.float32), tf.cast(width, tf.float32)
|
||||
|
||||
smaller_dim = tf.minimum(height, width)
|
||||
scale_ratio = resize_min / smaller_dim
|
||||
|
||||
# Convert back to ints to make heights and widths that TF ops will accept.
|
||||
new_height = tf.cast(height * scale_ratio, tf.int32)
|
||||
new_width = tf.cast(width * scale_ratio, tf.int32)
|
||||
|
||||
return new_height, new_width
|
||||
|
||||
|
||||
def _central_crop(image, crop_height, crop_width):
|
||||
shape = tf.shape(image)
|
||||
height, width = shape[0], shape[1]
|
||||
|
||||
amount_to_be_cropped_h = height - crop_height
|
||||
crop_top = amount_to_be_cropped_h // 2
|
||||
amount_to_be_cropped_w = width - crop_width
|
||||
crop_left = amount_to_be_cropped_w // 2
|
||||
return tf.slice(image, [crop_top, crop_left, 0], [crop_height, crop_width, -1])
|
||||
|
||||
|
||||
def preprocess_image_record(record, min_size=256, image_height=224, image_width=224):
|
||||
"""
|
||||
This function performs image cropping so all images in the dataset have the same height and width dimensions.
|
||||
No value pre-processing is done here.
|
||||
"""
|
||||
|
||||
imgdata, label, _, _ = _deserialize_image_record(record)
|
||||
# Subtract one so that ImageNet labels are in [0, 1000). This assumes your dataset contains 'background' as 0.
|
||||
label -= 1
|
||||
|
||||
try:
|
||||
image = tf.image.decode_jpeg(
|
||||
imgdata,
|
||||
channels=_NUM_CHANNELS,
|
||||
fancy_upscaling=False,
|
||||
dct_method="INTEGER_FAST",
|
||||
)
|
||||
except:
|
||||
image = tf.image.decode_image(imgdata, channels=_NUM_CHANNELS)
|
||||
|
||||
image = tf.cast(image, tf.float32)
|
||||
image = _aspect_preserving_resize(image, min_size)
|
||||
image = _central_crop(image, image_height, image_width)
|
||||
|
||||
return image, label
|
||||
|
||||
|
||||
def preprocess_model_func(image: tf.Tensor, model_name: str = "resnet_v1"):
|
||||
|
||||
if model_name == "resnet_v1":
|
||||
return tf.keras.applications.resnet.preprocess_input(image)
|
||||
elif model_name == "resnet_v2":
|
||||
return tf.keras.applications.resnet_v2.preprocess_input(image)
|
||||
elif model_name == "mobilenet_v1":
|
||||
return tf.keras.applications.mobilenet.preprocess_input(image)
|
||||
elif model_name == "mobilenet_v2":
|
||||
return tf.keras.applications.mobilenet_v2.preprocess_input(image)
|
||||
elif model_name == "inception_v3":
|
||||
return tf.keras.applications.inception_v3.preprocess_input(image)
|
||||
else:
|
||||
# efficientnet doesn't need specific pre-processing (included in the model itself).
|
||||
print("No further pre-processing found for {}".format(model_name))
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def load_data_tfrecord_tf(
|
||||
data_dir: str = "./data/imagenet",
|
||||
batch_size: int = 8,
|
||||
num_train_files: int = 1024,
|
||||
num_val_files: int = 128,
|
||||
model_name: str = "resnet_v1",
|
||||
) -> Dict[str, tf.data.Dataset]:
|
||||
"""
|
||||
Load ImageNet with TensorFlow Datasets (TFDS).
|
||||
|
||||
Args:
|
||||
data_dir (str): directory where data is stored.
|
||||
batch_size (int): batch_size for dataloader.
|
||||
num_train_files (int): number of tfrecord shards available for training.
|
||||
num_val_files (int): number of tfrecord shards available for validation.
|
||||
model_name (str): Model name, used to decide which input pre-processing is needed.
|
||||
Options={supported_model_names}.
|
||||
|
||||
Returns:
|
||||
dataset_dict (Dict[str, tf.data.Dataset]): dictionary with 'train' and 'validation' datasets.
|
||||
|
||||
Raises:
|
||||
ValueError: raised if 'model_name' is not supported.
|
||||
""".format(
|
||||
supported_model_names=_SUPPORTED_MODEL_NAMES
|
||||
)
|
||||
|
||||
# 1. Load ImageNet2012 train dataset - needs to manually download the full ImageNet2012 dataset first.
|
||||
assert os.path.exists(data_dir)
|
||||
if model_name not in _SUPPORTED_MODEL_NAMES:
|
||||
raise ValueError(
|
||||
"Invalid model name ",
|
||||
model_name,
|
||||
" provided. Please select among {}".format(_SUPPORTED_MODEL_NAMES),
|
||||
)
|
||||
|
||||
# 2. Make train/validation datasets
|
||||
dataset_dict = {}
|
||||
for key, is_training in zip(["train", "validation"], [True, False]):
|
||||
filenames = get_filenames(
|
||||
data_dir,
|
||||
is_training=is_training,
|
||||
num_train_files=num_train_files,
|
||||
num_val_files=num_val_files,
|
||||
)
|
||||
dataset = tf.data.TFRecordDataset(filenames)
|
||||
|
||||
# Image cropping and resizing
|
||||
if model_name in _DEFAULT_IMAGE_SIZE and model_name in _RESIZE_MIN:
|
||||
dataset = dataset.map(
|
||||
lambda record: preprocess_image_record(
|
||||
record,
|
||||
min_size=_RESIZE_MIN[model_name],
|
||||
image_height=_DEFAULT_IMAGE_SIZE[model_name],
|
||||
image_width=_DEFAULT_IMAGE_SIZE[model_name],
|
||||
)
|
||||
)
|
||||
else:
|
||||
dataset = dataset.map(preprocess_image_record)
|
||||
|
||||
dataset = dataset.map(lambda image, label: (preprocess_model_func(image, model_name), label))
|
||||
# Divide dataset into batches
|
||||
dataset = dataset.batch(batch_size, drop_remainder=True)
|
||||
dataset_dict[key] = dataset
|
||||
|
||||
return dataset_dict
|
||||
|
||||
|
||||
def load_data(
|
||||
hyperparams: Dict, model_name: str = "resnet_v1"
|
||||
) -> [tf.data.Dataset, tf.data.Dataset]:
|
||||
""" Loads ImageNet data in `tfrecord` format (requires manual data download).
|
||||
|
||||
Args:
|
||||
hyperparams (Dict): dictionary with necessary hyper-parameters for data loading.
|
||||
model_name (str): Model name, used to decide which input pre-processing is needed.
|
||||
Options={supported_model_names}.
|
||||
|
||||
Returns:
|
||||
train_batches (tf.data.Dataset): 'train' dataset.
|
||||
val_batches (tf.data.Dataset): 'validation' dataset.
|
||||
""".format(
|
||||
supported_model_names=_SUPPORTED_MODEL_NAMES
|
||||
)
|
||||
|
||||
data_batches = load_data_tfrecord_tf(
|
||||
data_dir=hyperparams["tfrecord_data_dir"],
|
||||
batch_size=hyperparams["batch_size"],
|
||||
model_name=model_name,
|
||||
)
|
||||
train_batches, val_batches = (data_batches["train"], data_batches["validation"])
|
||||
if hyperparams["train_data_size"] is not None:
|
||||
train_batches = train_batches.take(hyperparams["train_data_size"])
|
||||
if hyperparams["val_data_size"] is not None:
|
||||
val_batches = val_batches.take(hyperparams["val_data_size"])
|
||||
|
||||
return train_batches, val_batches
|
||||
@@ -0,0 +1,44 @@
|
||||
export IMAGENET_HOME=/media/Data/imagenet_data
|
||||
# Setup folders
|
||||
mkdir -p $IMAGENET_HOME/validation
|
||||
mkdir -p $IMAGENET_HOME/train
|
||||
|
||||
# ###### Modification 1: set .tar files path to $IMAGENET_HOME #############
|
||||
# Extract validation and training
|
||||
tar xf $IMAGENET_HOME/ILSVRC2012_img_val.tar -C $IMAGENET_HOME/validation
|
||||
tar xf $IMAGENET_HOME/ILSVRC2012_img_train.tar -C $IMAGENET_HOME/train
|
||||
# ##########################################################################
|
||||
|
||||
# Extract and then delete individual training tar files This can be pasted
|
||||
# directly into a bash command-line or create a file and execute.
|
||||
cd $IMAGENET_HOME/train
|
||||
|
||||
for f in *.tar; do
|
||||
d=`basename $f .tar`
|
||||
mkdir $d
|
||||
tar xf $f -C $d
|
||||
done
|
||||
|
||||
cd $IMAGENET_HOME # Move back to the base folder
|
||||
|
||||
# [Optional] Delete tar files if desired as they are not needed
|
||||
rm $IMAGENET_HOME/train/*.tar
|
||||
|
||||
# ###### Modification 2: Updated deprecated link #############
|
||||
# Download labels file.
|
||||
wget -O $IMAGENET_HOME/synset_labels.txt \
|
||||
https://raw.githubusercontent.com/tensorflow/models/master/research/slim/datasets/imagenet_2012_validation_synset_labels.txt
|
||||
# ############################################################
|
||||
|
||||
# Process the files. Remember to get the script from github first. The TFRecords
|
||||
# will end up in the --local_scratch_dir. To upload to gcs with this method
|
||||
# leave off `nogcs_upload` and provide gcs flags for project and output_path.
|
||||
python imagenet_to_gcs.py \
|
||||
--raw_data_dir=$IMAGENET_HOME \
|
||||
--local_scratch_dir=$IMAGENET_HOME/tf_records \
|
||||
--nogcs_upload
|
||||
|
||||
# ######## Modification 3: move train and validation files to root dir #######################
|
||||
mv $IMAGENET_HOME/tf_records/train* $IMAGENET_HOME/tf_records
|
||||
mv $IMAGENET_HOME/tf_records/validation* $IMAGENET_HOME/tf_records
|
||||
# ############################################################################################
|
||||
@@ -0,0 +1,168 @@
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 1993-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
|
||||
"""
|
||||
This module contains test cases for our data loader, which contains data loading and pre-processing functions
|
||||
for the ImageNet2012 dataset in 'tfrecord' format.
|
||||
NOTE: the user needs to manually download the full ImageNet2012 dataset first.
|
||||
"""
|
||||
|
||||
import tensorflow as tf
|
||||
from examples.data.data_loader import load_data
|
||||
import numpy as np
|
||||
from collections import defaultdict
|
||||
from typing import Dict
|
||||
import pytest
|
||||
|
||||
DATA_HYPERPARAMS = {
|
||||
"tfrecord_data_dir": "/media/Data/ImageNet/train-val-tfrecord",
|
||||
"batch_size": 64,
|
||||
"train_data_size": 100, # If 'None', consider all data, otherwise, consider subset.
|
||||
"val_data_size": 100, # If 'None', consider all data, otherwise, consider subset.
|
||||
}
|
||||
|
||||
|
||||
def load_tfrecord_mean_min_max(model_name: str) -> [Dict, Dict, Dict]:
|
||||
"""
|
||||
Loads `tfrecord` dataset and calculates the data's mean, min, and max values.
|
||||
|
||||
Args:
|
||||
model_name (str): model name for data pre-processing.
|
||||
|
||||
Returns:
|
||||
total_mean_dict: dictionary with MEAN values in 'R', 'G', 'B'.
|
||||
total_min_dict: dictionary with MIN values in 'R', 'G', 'B'.
|
||||
total_max_dict: dictionary with MAX values in 'R', 'G', 'B'.
|
||||
"""
|
||||
# 1. Data loading
|
||||
train_batches, val_batches = load_data(
|
||||
hyperparams=DATA_HYPERPARAMS, model_name=model_name
|
||||
)
|
||||
assert isinstance(train_batches, tf.data.Dataset) and isinstance(
|
||||
val_batches, tf.data.Dataset
|
||||
)
|
||||
|
||||
# 2. Test input preprocessing
|
||||
mean = defaultdict(list)
|
||||
min = defaultdict(list)
|
||||
max = defaultdict(list)
|
||||
for batch in [train_batches]:
|
||||
for examples in batch:
|
||||
image, label = examples
|
||||
image_dict = defaultdict()
|
||||
for i, c in zip([0, 1, 2], ["R", "G", "B"]):
|
||||
image_dict[c] = image[:, :, :, i]
|
||||
mean[c].append(tf.math.reduce_mean(image_dict[c]))
|
||||
min[c].append(tf.math.reduce_min(image_dict[c]))
|
||||
max[c].append(tf.math.reduce_max(image_dict[c]))
|
||||
|
||||
total_mean_dict = defaultdict(list)
|
||||
total_min_dict = defaultdict(list)
|
||||
total_max_dict = defaultdict(list)
|
||||
for c in ["R", "G", "B"]:
|
||||
total_mean_dict[c] = tf.math.reduce_mean(mean[c])
|
||||
total_min_dict[c] = tf.math.reduce_min(min[c])
|
||||
total_max_dict[c] = tf.math.reduce_max(max[c])
|
||||
return total_mean_dict, total_min_dict, total_max_dict
|
||||
|
||||
|
||||
def test_imagenet_tfrecord_efficientnetb0():
|
||||
"""
|
||||
Tests data loading and pre-processing for EfficientNet-B0.
|
||||
Note that EfficientNet doesn't have any input pre-processing methods besides image resizing and cropping.
|
||||
See `data_loader.preprocess_image_record()`.
|
||||
"""
|
||||
print("------------ EfficientNet-B0 pre-processing test -------------")
|
||||
|
||||
# 1. Data loading and get mean, max, min of data without input preprocessing
|
||||
total_mean_dict, total_min_dict, total_max_dict = load_tfrecord_mean_min_max(
|
||||
model_name="efficientnet_b0"
|
||||
)
|
||||
|
||||
# 2. Check if mean is as expected and max/min values
|
||||
mean_RGB = [123.68, 116.779, 103.939]
|
||||
mean_RGB_obtained = list(
|
||||
total_mean_dict.values()
|
||||
) # [total_mean_dict['R'], total_mean_dict['G'], total_mean_dict['B']]
|
||||
mean_diff = abs(np.array(mean_RGB_obtained) - np.array(mean_RGB))
|
||||
print(" Expected mean (RGB): {}".format(mean_RGB))
|
||||
print(" Calculated mean (RGB): {}".format(np.array(mean_RGB_obtained)))
|
||||
print(" Difference: {}".format(np.array(mean_diff)))
|
||||
assert (mean_diff <= 3.0).all()
|
||||
|
||||
# 3. Values expected to be between 0 and 255
|
||||
total_min = min(total_min_dict["R"], min(total_min_dict["G"], total_min_dict["B"]))
|
||||
total_max = max(total_max_dict["R"], max(total_max_dict["G"], total_max_dict["B"]))
|
||||
assert total_min >= 0.0 and total_max <= 255.0
|
||||
|
||||
|
||||
def test_imagenet_tfrecord_resnetv1():
|
||||
"""Tests data loading and pre-processing for ResNetv1.
|
||||
|
||||
ResNetv1 input pre-processing:
|
||||
- Resizing + cropping
|
||||
- "The images are converted from RGB to BGR, then each color channel is zero-centered with respect to the
|
||||
ImageNet dataset, without scaling."
|
||||
- Zero-center: (data - mean(data) / std(data)) -> In this case, std(data) = None.
|
||||
"""
|
||||
print("------------ ResNetv1 pre-processing test -------------")
|
||||
|
||||
# 1. Data loading and get mean, max, min of data without input preprocessing
|
||||
total_mean_dict, total_min_dict, total_max_dict = load_tfrecord_mean_min_max(
|
||||
model_name="resnet_v1"
|
||||
)
|
||||
|
||||
# 2.1 Data should be zero-centered (mean=0)
|
||||
mean_RGB_obtained = list(total_mean_dict.values())
|
||||
print(" Expected mean (RGB): [0, 0, 0]")
|
||||
print(" Calculated mean (RGB): {}".format(np.array(mean_RGB_obtained)))
|
||||
print(" Min values: {}".format(np.array(list(total_min_dict.values()))))
|
||||
print(" Max values: {}".format(np.array(list(total_max_dict.values()))))
|
||||
assert (abs(np.array(mean_RGB_obtained)) <= 3.0).all()
|
||||
|
||||
# 2.2 No scaling, meaning values are between -255 and 255 (after zero-centering)
|
||||
assert (np.array(list(total_min_dict.values())) >= -255.0).all()
|
||||
assert (np.array(list(total_max_dict.values())) <= 255.0).all()
|
||||
|
||||
|
||||
def test_imagenet_tfrecord_resnetv2():
|
||||
"""Tests data loading and pre-processing for ResNetv2.
|
||||
|
||||
ResNetv2 input pre-processing:
|
||||
- Resizing + cropping
|
||||
- "The inputs pixel values are scaled between -1 and 1, sample-wise."
|
||||
- Sample-wise normalization: https://stackoverflow.com/questions/37625272/keras-batchnormalization-what-exactly-is-sample-wise-normalization
|
||||
|
||||
MobileNet-v1/v2 input pre-processing:
|
||||
- "The inputs pixel values are scaled between -1 and 1, sample-wise."
|
||||
- This is the same as ResNet-v2, with the difference that the MobileNet model takes input shape 224x224x3
|
||||
(same as ResNet-v1).
|
||||
"""
|
||||
print("------------ ResNetv2 pre-processing test -------------")
|
||||
|
||||
# 1. Data loading and get mean, max, min of data without input preprocessing
|
||||
total_mean_dict, total_min_dict, total_max_dict = load_tfrecord_mean_min_max(
|
||||
model_name="resnet_v2"
|
||||
)
|
||||
|
||||
# 2. Check that values are between -1 and 1
|
||||
print(" Min values: {}".format(np.array(list(total_min_dict.values()))))
|
||||
print(" Max values: {}".format(np.array(list(total_max_dict.values()))))
|
||||
print(" Mean values: {}".format(np.array(list(total_mean_dict.values()))))
|
||||
assert (np.array(list(total_min_dict.values())) >= -1.0).all()
|
||||
assert (np.array(list(total_max_dict.values())) <= 1.0).all()
|
||||
Reference in New Issue
Block a user