# (C) Copyright IBM Corp. 2019, 2020, 2021, 2022.
# 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.
import numpy as np
import h5py
import copy
from typing import Union
from simulai.batching import batchdomain_constructor
from simulai.abstract import Normalization
from simulai.metrics import MemorySizeEval
# It rescales to the interval [0, 1]
[docs]class UnitaryNormalization(Normalization):
name = "unitary"
def __init__(self, value_max:float=None, value_min:float=None) -> None:
super().__init__()
self.purpose = "normalization"
if value_max and value_min:
self.value_max = np.array(value_max)
self.value_min = np.array(value_min)
else:
self.value_max = value_max
self.value_min = value_min
self.data_info_dict = dict()
self.data_info_dict['input'] = {'max': self.value_max,
'min': self.value_min}
self.max_values = None
self.min_values = None
def _rescale(self, data_array:np.ndarray, tag:Union[str, int]) -> np.ndarray:
if not self.value_max and not self.value_min:
if len(data_array.shape) <= 2:
data_array_max = data_array.max(0)
data_array_min = data_array.min(0)
else:
indices = np.arange(len(data_array.shape)).tolist()
ind = len(indices)-1
indices.remove(ind)
data_array_max = data_array.max(axis=tuple(indices))
data_array_min = data_array.min(axis=tuple(indices))
self.data_info_dict[tag] = {'max': data_array_max, 'min': data_array_min}
else:
data_array_max = self.value_max
data_array_min = self.value_min
data_array_transformed = (data_array - data_array_min)/(data_array_max - data_array_min)
return data_array_transformed
def _rescale_structured(self, data_array:np.recarray) -> np.recarray:
arrays_list = list()
for name in data_array.dtype.names:
if not name in self.data_info_dict.keys():
data_array_max = data_array[name].max()
data_array_min = data_array[name].min()
self.data_info_dict[name] = {'max': data_array_max, 'min': data_array_min}
else:
data_array_max = self.data_info_dict[name]['max']
data_array_min = self.data_info_dict[name]['min']
data_array_transformed = (data_array[name] - data_array_min)/(data_array_max - data_array_min)
arrays_list.append(data_array_transformed)
output_vars_names = ', '.join(data_array.dtype.names)
data_array_transformed = np.core.records.fromarrays(arrays_list,
names=output_vars_names,
formats=','.join(len(data_array.dtype.names) * ['f8']))
return data_array_transformed
[docs] def rescale(self, map_dict:dict=None) -> dict:
data_array_info_dict = dict()
for key, data_array in map_dict.items():
if data_array.dtype.names:
data_array_transformed = self._rescale_structured(data_array)
else:
data_array_transformed = self._rescale(data_array, key)
data_array_info_dict[key] = data_array_transformed
return data_array_info_dict
[docs] def apply_rescaling(self, map_dict:dict=None, eval:bool=False, axis:int=4) -> dict:
data_rescaled_dict = dict()
for key, data_array in map_dict.items():
rescale_parameters = self.data_info_dict[key]
if not eval:
max_value = rescale_parameters['max']
min_value = rescale_parameters['min']
else:
axis_list = np.arange(len(data_array.shape)).tolist()
max_value = np.max(data_array, axis=axis_list.remove(axis))
min_value = np.max(data_array, axis=axis_list.remove(axis))
data_array_ = (data_array - min_value)/(max_value - min_value)
data_rescaled_dict[key] = data_array_
return data_rescaled_dict
[docs] def apply_descaling(self, map_dict:dict=None) -> dict:
data_rescaled_dict = dict()
for key, data_array in map_dict.items():
rescale_parameters = self.data_info_dict[key]
max_value = rescale_parameters['max']
min_value = rescale_parameters['min']
data_array_ = data_array*(max_value - min_value) + min_value
data_rescaled_dict[key] = data_array_
return data_rescaled_dict
[docs] def update_global_parameters(self, data:np.ndarray=None) -> None:
indices = np.arange(len(data.shape)).tolist().remove(1)
max_values = data.max(axis=indices)
min_values = data.min(axis=indices)
if not isinstance(self.max_values, np.ndarray):
self.max_values = max_values
elif max_values > self.max_values:
self.max_values = max_values
else:
pass
if not isinstance(self.min_values, np.ndarray):
self.min_values = min_values
elif min_values < self.min_values:
self.min_values = min_values
else:
pass
# It rescales to the interval [-1, 1]
[docs]class UnitarySymmetricalNormalization(UnitaryNormalization):
name = "unitary_symmetrical"
def __init__(self, value_max:float=None, value_min:float=None) -> None:
super().__init__(value_max=value_max, value_min=value_min)
[docs] def rescale(self, map_dict:dict=None) -> dict:
data_array_info_dict = dict()
for key, data_array in map_dict.items():
if data_array.dtype.names:
data_array_transformed = self._rescale_structured(data_array)
else:
data_array_transformed = self._rescale(data_array, key)
data_array_info_dict[key] = 2*data_array_transformed -1
return data_array_info_dict
[docs]class StandardNormalization(Normalization):
name = "standard"
def __init__(self):
self.purpose = "normalization"
self.data_info_dict = dict()
def _rescale(self, data_array, tag):
data_array_mean = data_array.mean(0)
data_array_std = data_array.std(0)
self.data_info_dict[tag] = {'mean': data_array_mean, 'std': data_array_std}
data_array_transformed = (data_array - data_array_mean) / data_array_std
return data_array_transformed
def _rescale_structured(self, data_array):
arrays_list = list()
for name in data_array.dtype.names:
if not name in self.data_info_dict.keys():
data_array_mean = data_array[name].mean(0)
data_array_std = data_array[name].std(0)
self.data_info_dict[name] = {'mean': data_array_mean, 'std': data_array_std}
else:
data_array_mean = self.data_info_dict[name]['mean']
data_array_std = self.data_info_dict[name]['std']
data_array_transformed = (data_array[name] - data_array_mean) / data_array_std
arrays_list.append(data_array_transformed)
output_vars_names = ', '.join(data_array.dtype.names)
data_array_transformed = np.core.records.fromarrays(arrays_list,
names=output_vars_names,
formats=','.join(len(data_array.dtype.names) * ['f8']))
return data_array_transformed
[docs] def rescale(self, map_dict=None):
data_array_info_dict = dict()
for key, data_array in map_dict.items():
if data_array.dtype.names:
data_array_transformed = self._rescale_structured(data_array)
else:
data_array_transformed = self._rescale(data_array, key)
data_array_info_dict[key] = data_array_transformed
return data_array_info_dict
[docs] def apply_rescaling(self, map_dict=None):
data_rescaled_dict = dict()
for key, data_array in map_dict.items():
rescale_parameters = self.data_info_dict[key]
mean_value = rescale_parameters['mean']
std_value = rescale_parameters['std']
data_array_ = (data_array - mean_value) / std_value
data_rescaled_dict[key] = data_array_
return data_rescaled_dict
[docs] def apply_descaling(self, map_dict=None):
data_rescaled_dict = dict()
for key, data_array in map_dict.items():
rescale_parameters = self.data_info_dict[key]
mean_value = rescale_parameters['mean']
std_value = rescale_parameters['std']
data_array_ = data_array * std_value + mean_value
data_rescaled_dict[key] = data_array_
return data_rescaled_dict
[docs]class BatchNormalization:
def __init__(self, norm=None, channels_last=False):
assert isinstance(norm, Normalization), "The norm must be a " \
"simulai.normalization.Normalization object"
self.norm = norm
self.channels_last = channels_last