Solución:
Hay diferentes formas de “normalizar datos”. Dependiendo de cuál tenga en mente, puede que sea o no fácil de implementar en su caso.
1. Normalización fija
Si conoce el rango (s) fijo (s) de sus valores (por ejemplo, la característica # 1 tiene valores en [-5, 5]
, la característica n. ° 2 tiene valores en [0, 100]
, etc.), podría preprocesar fácilmente su feature
tensor en parse_example()
, p.ej:
def normalize_fixed(x, current_range, normed_range):
current_min, current_max = tf.expand_dims(current_range[:, 0], 1), tf.expand_dims(current_range[:, 1], 1)
normed_min, normed_max = tf.expand_dims(normed_range[:, 0], 1), tf.expand_dims(normed_range[:, 1], 1)
x_normed = (x - current_min) / (current_max - current_min)
x_normed = x_normed * (normed_max - normed_min) + normed_min
return x_normed
def parse_example(line_batch,
fixed_range=[[-5, 5], [0, 100], ...],
normed_range=[[0, 1]]):
# ...
features = tf.transpose(features)
features = normalize_fixed(features, fixed_range, normed_range)
# ...
2. Normalización por muestra
Si se supone que sus características tienen aproximadamente el mismo rango de valores, también se podría considerar la normalización por muestra, es decir, aplicar la normalización considerando los momentos de las características (media, varianza) para cada muestra:
def normalize_with_moments(x, axes=[0, 1], epsilon=1e-8):
mean, variance = tf.nn.moments(x, axes=axes)
x_normed = (x - mean) / tf.sqrt(variance + epsilon) # epsilon to avoid dividing by zero
return x_normed
def parse_example(line_batch):
# ...
features = tf.transpose(features)
features = normalize_with_moments(features)
# ...
3. Normalización por lotes
Puede aplicar el mismo procedimiento en un lote completo en lugar de por muestra, lo que puede hacer que el proceso sea más estable:
data_batch = normalize_with_moments(data_batch, axis=[1, 2])
Del mismo modo, podría utilizar tf.nn.batch_normalization
4. Normalización del conjunto de datos
Normalizar utilizando la media / varianza calculada sobre todo el conjunto de datos sería lo más complicado, ya que, como mencionaste, es grande y dividido.
tf.data.Dataset
no está realmente diseñado para tal cálculo global. Una solución sería usar cualquier herramienta que tenga para precalcular los momentos del conjunto de datos y luego usar esta información para su preprocesamiento de TF.
Como lo mencionó @MiniQuark, Tensorflow tiene una biblioteca de transformación que puede usar para preprocesar sus datos. Eche un vistazo a Get Started o, por ejemplo, a tft.scale_to_z_score()
método para la normalización de la muestra.
Ampliando la respuesta de benjaminplanche para la “normalización del conjunto de datos n. ° 4”, en realidad hay una manera bastante fácil de lograr esto.
Keras de Tensorflow proporciona una capa de normalización de preprocesamiento. Ahora bien, como se trata de una capa, su intención es usarse dentro del modelo. Sin embargo, no es necesario (más sobre eso más adelante).
El uso del modelo es simple:
input = tf.keras.Input(shape=dataset.element_spec.shape)
norm = tf.keras.layers.preprocessing.Normalization()
norm.adapt(dataset) # you can use dataset.take(N) if N samples is enough for it to figure out the mean & variance.
layer1 = norm(input)
...
La ventaja de usarlo en el modelo es que la media de normalización y la varianza se guardan como parte de los pesos del modelo. Entonces, cuando cargue el modelo guardado, usará los mismos valores con los que fue entrenado.
Como se mencionó anteriormente, si no desea usar modelos de keras, no es necesario que use la capa como parte de una. Si prefiere usarlo en la canalización de su conjunto de datos, también puede hacerlo.
norm = tf.keras.layers.experimental.preprocessing.Normalization()
norm.adapt(dataset)
dataset = dataset.map(lambda t: norm
La desventaja es que debe guardar y restaurar esos pesos manualmente ahora (norm.get_weights()
y norm.set_weights()
). Numpy tiene conveniente save()
y load()
funciones que puede utilizar aquí.
np.save("norm_weights.npy", norm.get_weights())
norm.set_weights(np.load("norm_weights.npy", allow_pickle=True))