Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/guide/keras/preprocessing_layers.ipynb
25118 views
Kernel: Python 3
#@title 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.

Cómo trabajar con capas de preprocesamiento

El preprocesamiento en Keras

La API con capas para preprocesamiento de Keras permite a los desarrolladores crear canalizaciones de procesamiento para las entradas nativas de Keras. Estas canalizaciones para el procesamiento de las entradas se pueden utilizar como un código de preprocesamiento independiente en flujos de trabajo que no sean parte de Keras, combinarse directamente con modelos de Keras y exportarse como parte de un SavedModel de Keras.

Con las capas para preprocesamiento de Keras, puede crear y exportar modelos que sean realmente integrales: modelos que acepten como entrada imágenes o datos estructurados sin procesar, modelos que controlen la normalización de características o la indexación de los valores de dichas características por su cuenta.

Preprocesamiento disponible

Preprocesamiento de texto

  • tf.keras.layers.TextVectorization: convierte las cadenas sin procesar en una representación codificada que puede leerse por una capa Embedding o una capa de tipo Dense.

Preprocesamiento de funciones numéricas

  • tf.keras.layers.Normalization: realiza la normalización de las funciones de entrada.

  • tf.keras.layers.Discretization: convierte a las funciones numéricas continuas en funciones categóricas enteras.

Preprocesamiento de funciones categóricas

  • tf.keras.layers.CategoryEncoding: convierte a las funciones categóricas enteras en representaciones densas de one-hot, multi-hot o un número de ellas.

  • tf.keras.layers.Hashing: realiza el hashing de las funciones categóricas, también conocido como el "truco del hashing".

  • tf.keras.layers.StringLookup: convierte a los valores categóricos de la cadena en una representación cifrada que puede leerse por una capa Embedding o una capa Dense.

  • tf.keras.layers.IntegerLookup: convierte a los valores categóricos enteros en una representación cifrada que puede leerse por una capa Embedding o una capa Dense.

Preprocesamiento de imágenes

Estas capas sirven para estandarizar las entradas en un modelo de imagen.

  • tf.keras.layers.Resizing: redimensiona un lote de imágenes a un tamaño objetivo.

  • tf.keras.layers.Rescaling: redimensiona y compensa los valores de un lote de imágenes (por ejemplo, pasar las entradas de un rango [0, 255] a las entradas en el rango [0, 1].

  • tf.keras.layers.CenterCrop: devuelve el recorte central de un lote de imágenes.

Aumentar los datos de la imagen

Estas capas aplican aumento en las transformaciones de forma aleatoria a un lote de imágenes. Solo estarán activas durante el entrenamiento.

  • tf.keras.layers.RandomCrop

  • tf.keras.layers.RandomFlip

  • tf.keras.layers.RandomTranslation

  • tf.keras.layers.RandomRotation

  • tf.keras.layers.RandomZoom

  • tf.keras.layers.RandomHeight

  • tf.keras.layers.RandomWidth

  • tf.keras.layers.RandomContrast

El método adapt()

Algunas capas de preprocesamiento tienen un estado interno que puede calcularse a partir de una muestra de los datos de entrenamiento. La lista de capas de preprocesamiento con estado es:

  • TextVectorization: contiene un mapeo entre tokens de cadena e índices enteros

  • StringLookup y IntegerLookup: contienen una correspondencia entre valores de entrada e índices enteros.

  • Normalization: contiene el promedio y la desviación estándar de las características.

  • Discretization: contiene información sobre los límites de los cubos de valores.

Estas capas no son entrenables. Su estado no se establece durante el entrenamiento; debe establecerse antes del entrenamiento, ya sea inicializándolas a partir de una constante precalculada o "adaptándolas" a los datos.

Se establece el estado de una capa de preprocesamiento exponiéndola a los datos de entrenamiento, mediante el método adapt():

import numpy as np import tensorflow as tf from tensorflow.keras import layers data = np.array([[0.1, 0.2, 0.3], [0.8, 0.9, 1.0], [1.5, 1.6, 1.7],]) layer = layers.Normalization() layer.adapt(data) normalized_data = layer(data) print("Features mean: %.2f" % (normalized_data.numpy().mean())) print("Features std: %.2f" % (normalized_data.numpy().std()))

El método adapt() toma un array Numpy o un objeto tf.data.Dataset. En el caso de StringLookup y TextVectorization, también se puede pasar una lista de cadenas:

data = [ "ξεῖν᾽, ἦ τοι μὲν ὄνειροι ἀμήχανοι ἀκριτόμυθοι", "γίγνοντ᾽, οὐδέ τι πάντα τελείεται ἀνθρώποισι.", "δοιαὶ γάρ τε πύλαι ἀμενηνῶν εἰσὶν ὀνείρων:", "αἱ μὲν γὰρ κεράεσσι τετεύχαται, αἱ δ᾽ ἐλέφαντι:", "τῶν οἳ μέν κ᾽ ἔλθωσι διὰ πριστοῦ ἐλέφαντος,", "οἵ ῥ᾽ ἐλεφαίρονται, ἔπε᾽ ἀκράαντα φέροντες:", "οἱ δὲ διὰ ξεστῶν κεράων ἔλθωσι θύραζε,", "οἵ ῥ᾽ ἔτυμα κραίνουσι, βροτῶν ὅτε κέν τις ἴδηται.", ] layer = layers.TextVectorization() layer.adapt(data) vectorized_text = layer(data) print(vectorized_text)

Además, las capas adaptables siempre exponen una opción para establecer directamente el estado mediante argumentos del constructor o asignación de pesos. Si los valores de estado deseados se conocen en el momento de la construcción de la capa, o se calculan fuera de la llamada adapt(), pueden establecerse sin depender del cálculo interno de la capa. Por ejemplo, si ya existen archivos de vocabulario externos para las capas TextVectorization, StringLookup, o IntegerLookup, pueden cargarse directamente en las tablas de búsqueda pasando una ruta al archivo de vocabulario en los argumentos del constructor de la capa.

A continuación se muestra un ejemplo en el que creamos una capa StringLookup con vocabulario precalculado:

vocab = ["a", "b", "c", "d"] data = tf.constant([["a", "c", "d"], ["d", "z", "b"]]) layer = layers.StringLookup(vocabulary=vocab) vectorized_data = layer(data) print(vectorized_data)

Preprocesamiento de datos antes del modelo o dentro del modelo

Hay dos formas de utilizar las capas de preprocesamiento:

Opción 1: Haga que sean parte del modelo, de la siguiente manera:

inputs = keras.Input(shape=input_shape) x = preprocessing_layer(inputs) outputs = rest_of_the_model(x) model = keras.Model(inputs, outputs)

Con esta opción, el preprocesamiento se realizará en el dispositivo, de forma sincronizada con el resto de la ejecución del modelo, lo que significa que se beneficiará de la aceleración de la GPU. Si está entrenando en la GPU, esta es la mejor opción para la capa Normalization, y para todas las capas de preprocesamiento de imágenes y aumento de datos.

Opción 2: aplíquelo a su tf.data.Dataset, para obtener un conjunto de datos que produzca lotes de datos preprocesados, como este:

dataset = dataset.map(lambda x, y: (preprocessing_layer(x), y))

Con esta opción, el preprocesamiento se realizará en la CPU, de forma asíncrona, y se almacenará en el búfer antes de pasar al modelo. Además, si llama dataset.prefetch(tf.data.AUTOTUNE) a su conjunto de datos, el preprocesamiento se realizará eficientemente en paralelo con el entrenamiento:

dataset = dataset.map(lambda x, y: (preprocessing_layer(x), y)) dataset = dataset.prefetch(tf.data.AUTOTUNE) model.fit(dataset, ...)

Esta es la mejor opción para TextVectorization, y todas las capas de preprocesamiento de datos estructurados. También puede ser una buena opción si entrena con CPU y utiliza capas de preprocesamiento de imágenes.

Cuando se ejecuta en TPU, siempre debe colocar las capas de preprocesamiento en el pipeline tf.data (con la excepción de Normalization y Rescaling, que se ejecutan bien en TPU y se utilizan comúnmente ya que la primera capa es un modelo de imagen).

Ventajas de preprocesar el modelo durante la inferencia

Incluso si opta por la opción 2, es posible que más adelante desee exportar un modelo de extremo a extremo basado solo en la inferencia que incluya las capas de preprocesamiento. La principal ventaja de hacer esto es que hace que el modelo sea portátil y ayuda a reducir la distorsión del entrenamiento/servicio.

Cuando todo el preprocesamiento de datos forma parte del modelo, otras personas pueden cargar y utilizar su modelo sin tener que saber cómo se espera que se codifique y normalice cada característica. Su modelo de inferencia podrá procesar imágenes en bruto o datos estructurados en bruto, y no requerirá que los usuarios del modelo conozcan los detalles de, por ejemplo, el esquema de tokenización utilizado para el texto, el esquema de indexación utilizado para las características categóricas, si los valores de los pixeles de la imagen se normalizan a [-1, +1] o a [0, 1], etc. Esto es especialmente poderoso si exporta su modelo a otro tiempo de ejecución, como TensorFlow.js: no tendrá que volver a implementar su canal de preprocesamiento en JavaScript.

Si inicialmente coloca sus capas de preprocesamiento en su canalización tf.data, puede exportar un modelo de inferencia que empaquete el preprocesamiento. Simplemente instancie un nuevo modelo que encadene sus capas de preprocesamiento y su modelo de entrenamiento:

inputs = keras.Input(shape=input_shape) x = preprocessing_layer(inputs) outputs = training_model(x) inference_model = keras.Model(inputs, outputs)

Recursos rápidos

Aumentar los datos de la imagen

Tenga en cuenta que las capas de aumento de datos de la imagen solo están activas durante el entrenamiento (de forma similar a la capa Dropout).

from tensorflow import keras from tensorflow.keras import layers # Create a data augmentation stage with horizontal flipping, rotations, zooms data_augmentation = keras.Sequential( [ layers.RandomFlip("horizontal"), layers.RandomRotation(0.1), layers.RandomZoom(0.1), ] ) # Load some data (x_train, y_train), _ = keras.datasets.cifar10.load_data() input_shape = x_train.shape[1:] classes = 10 # Create a tf.data pipeline of augmented images (and their labels) train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)) train_dataset = train_dataset.batch(16).map(lambda x, y: (data_augmentation(x), y)) # Create a model and train it on the augmented image data inputs = keras.Input(shape=input_shape) x = layers.Rescaling(1.0 / 255)(inputs) # Rescale inputs outputs = keras.applications.ResNet50( # Add the rest of the model weights=None, input_shape=input_shape, classes=classes )(x) model = keras.Model(inputs, outputs) model.compile(optimizer="rmsprop", loss="sparse_categorical_crossentropy") model.fit(train_dataset, steps_per_epoch=5)

Puede ver una configuración similar en acción en el ejemplo clasificación de imágenes desde cero.

Normalización de las características numéricas

# Load some data (x_train, y_train), _ = keras.datasets.cifar10.load_data() x_train = x_train.reshape((len(x_train), -1)) input_shape = x_train.shape[1:] classes = 10 # Create a Normalization layer and set its internal state using the training data normalizer = layers.Normalization() normalizer.adapt(x_train) # Create a model that include the normalization layer inputs = keras.Input(shape=input_shape) x = normalizer(inputs) outputs = layers.Dense(classes, activation="softmax")(x) model = keras.Model(inputs, outputs) # Train the model model.compile(optimizer="adam", loss="sparse_categorical_crossentropy") model.fit(x_train, y_train)

Codificación de funciones categóricas de las cadenas mediante la codificación en un solo paso

# Define some toy data data = tf.constant([["a"], ["b"], ["c"], ["b"], ["c"], ["a"]]) # Use StringLookup to build an index of the feature values and encode output. lookup = layers.StringLookup(output_mode="one_hot") lookup.adapt(data) # Convert new test data (which includes unknown feature values) test_data = tf.constant([["a"], ["b"], ["c"], ["d"], ["e"], [""]]) encoded_data = lookup(test_data) print(encoded_data)

Observe que, aquí, el índice 0 se reserva para valores que están fuera del vocabulario (valores que no se vieron durante adapt()).

Puede ver el StringLookup en acción en el ejemplo Clasificación de datos estructurados desde cero.

Codificación de funciones categóricas de números enteros mediante la codificación en un solo paso

# Define some toy data data = tf.constant([[10], [20], [20], [10], [30], [0]]) # Use IntegerLookup to build an index of the feature values and encode output. lookup = layers.IntegerLookup(output_mode="one_hot") lookup.adapt(data) # Convert new test data (which includes unknown feature values) test_data = tf.constant([[10], [10], [20], [50], [60], [0]]) encoded_data = lookup(test_data) print(encoded_data)

Tenga en cuenta que el índice 0 está reservado para aquellos valores que faltan (que debería especificar como el valor 0), y el índice 1 está reservado para valores fuera del vocabulario (valores que no se vieron durante adapt()). Puede configurar esto utilizando los argumentos del constructor mask_token y oov_token de IntegerLookup.

Puede ver IntegerLookup en acción en el ejemplo clasificación de datos estructurados desde cero.

Cómo aplicar el truco hashing a una característica categórica entera

Si tiene una característica categórica que puede tomar muchos valores diferentes (del orden de 10e3 o más), en la que cada valor solo aparece unas pocas veces en los datos, resulta poco práctico e ineficaz indexar y codificar con un solo paso los valores de la característica. En cambio, puede ser una buena idea aplicar el "truco del hash": codificar los valores en un vector de tamaño fijo. De este modo, el tamaño del espacio de características se mantiene administrable y se elimina la necesidad de una indexación explícita.

# Sample data: 10,000 random integers with values between 0 and 100,000 data = np.random.randint(0, 100000, size=(10000, 1)) # Use the Hashing layer to hash the values to the range [0, 64] hasher = layers.Hashing(num_bins=64, salt=1337) # Use the CategoryEncoding layer to multi-hot encode the hashed values encoder = layers.CategoryEncoding(num_tokens=64, output_mode="multi_hot") encoded_data = encoder(hasher(data)) print(encoded_data.shape)

Codificación de texto como secuencia de índices de tokens

Así es como debe preprocesar el texto que va a pasar a una capa Embedding.

# Define some text data to adapt the layer adapt_data = tf.constant( [ "The Brain is wider than the Sky", "For put them side by side", "The one the other will contain", "With ease and You beside", ] ) # Create a TextVectorization layer text_vectorizer = layers.TextVectorization(output_mode="int") # Index the vocabulary via `adapt()` text_vectorizer.adapt(adapt_data) # Try out the layer print( "Encoded text:\n", text_vectorizer(["The Brain is deeper than the sea"]).numpy(), ) # Create a simple model inputs = keras.Input(shape=(None,), dtype="int64") x = layers.Embedding(input_dim=text_vectorizer.vocabulary_size(), output_dim=16)(inputs) x = layers.GRU(8)(x) outputs = layers.Dense(1)(x) model = keras.Model(inputs, outputs) # Create a labeled dataset (which includes unknown tokens) train_dataset = tf.data.Dataset.from_tensor_slices( (["The Brain is deeper than the sea", "for if they are held Blue to Blue"], [1, 0]) ) # Preprocess the string inputs, turning them into int sequences train_dataset = train_dataset.batch(2).map(lambda x, y: (text_vectorizer(x), y)) # Train the model on the int sequences print("\nTraining model...") model.compile(optimizer="rmsprop", loss="mse") model.fit(train_dataset) # For inference, you can export a model that accepts strings as input inputs = keras.Input(shape=(1,), dtype="string") x = text_vectorizer(inputs) outputs = model(x) end_to_end_model = keras.Model(inputs, outputs) # Call the end-to-end model on test data (which includes unknown tokens) print("\nCalling end-to-end model on test string...") test_data = tf.constant(["The one the other will absorb"]) test_output = end_to_end_model(test_data) print("Model output:", test_output)

Puede ver la capa TextVectorization en acción, combinada con un modo Embedding, en el ejemplo clasificación de texto desde cero.

Tenga en cuenta que al entrenar un modelo de este tipo, para obtener el mejor rendimiento, siempre debe utilizar la capa TextVectorization como parte del canal de entrada.

Codificación de textos como matrices densas de ngramas con codificación multi-hot

Esta es la forma en que debe preprocesar el texto que va a pasar a una capa Dense.

# Define some text data to adapt the layer adapt_data = tf.constant( [ "The Brain is wider than the Sky", "For put them side by side", "The one the other will contain", "With ease and You beside", ] ) # Instantiate TextVectorization with "multi_hot" output_mode # and ngrams=2 (index all bigrams) text_vectorizer = layers.TextVectorization(output_mode="multi_hot", ngrams=2) # Index the bigrams via `adapt()` text_vectorizer.adapt(adapt_data) # Try out the layer print( "Encoded text:\n", text_vectorizer(["The Brain is deeper than the sea"]).numpy(), ) # Create a simple model inputs = keras.Input(shape=(text_vectorizer.vocabulary_size(),)) outputs = layers.Dense(1)(inputs) model = keras.Model(inputs, outputs) # Create a labeled dataset (which includes unknown tokens) train_dataset = tf.data.Dataset.from_tensor_slices( (["The Brain is deeper than the sea", "for if they are held Blue to Blue"], [1, 0]) ) # Preprocess the string inputs, turning them into int sequences train_dataset = train_dataset.batch(2).map(lambda x, y: (text_vectorizer(x), y)) # Train the model on the int sequences print("\nTraining model...") model.compile(optimizer="rmsprop", loss="mse") model.fit(train_dataset) # For inference, you can export a model that accepts strings as input inputs = keras.Input(shape=(1,), dtype="string") x = text_vectorizer(inputs) outputs = model(x) end_to_end_model = keras.Model(inputs, outputs) # Call the end-to-end model on test data (which includes unknown tokens) print("\nCalling end-to-end model on test string...") test_data = tf.constant(["The one the other will absorb"]) test_output = end_to_end_model(test_data) print("Model output:", test_output)

Codificación de texto como matriz densa de ngramas con ponderación TF-IDF

Se trata de una forma alternativa de preprocesar el texto antes de pasarlo a una capa Dense.

# Define some text data to adapt the layer adapt_data = tf.constant( [ "The Brain is wider than the Sky", "For put them side by side", "The one the other will contain", "With ease and You beside", ] ) # Instantiate TextVectorization with "tf-idf" output_mode # (multi-hot with TF-IDF weighting) and ngrams=2 (index all bigrams) text_vectorizer = layers.TextVectorization(output_mode="tf-idf", ngrams=2) # Index the bigrams and learn the TF-IDF weights via `adapt()` with tf.device("CPU"): # A bug that prevents this from running on GPU for now. text_vectorizer.adapt(adapt_data) # Try out the layer print( "Encoded text:\n", text_vectorizer(["The Brain is deeper than the sea"]).numpy(), ) # Create a simple model inputs = keras.Input(shape=(text_vectorizer.vocabulary_size(),)) outputs = layers.Dense(1)(inputs) model = keras.Model(inputs, outputs) # Create a labeled dataset (which includes unknown tokens) train_dataset = tf.data.Dataset.from_tensor_slices( (["The Brain is deeper than the sea", "for if they are held Blue to Blue"], [1, 0]) ) # Preprocess the string inputs, turning them into int sequences train_dataset = train_dataset.batch(2).map(lambda x, y: (text_vectorizer(x), y)) # Train the model on the int sequences print("\nTraining model...") model.compile(optimizer="rmsprop", loss="mse") model.fit(train_dataset) # For inference, you can export a model that accepts strings as input inputs = keras.Input(shape=(1,), dtype="string") x = text_vectorizer(inputs) outputs = model(x) end_to_end_model = keras.Model(inputs, outputs) # Call the end-to-end model on test data (which includes unknown tokens) print("\nCalling end-to-end model on test string...") test_data = tf.constant(["The one the other will absorb"]) test_output = end_to_end_model(test_data) print("Model output:", test_output)

Trucos importantes

Trabajar con capas de búsqueda y vocabularios muy extensos

Puede que se encuentre trabajando con un vocabulario muy grande en una capa TextVectorization, una capa StringLookup o una capa IntegerLookup. Normalmente, un vocabulario de más de 500 MB se consideraría "muy grande".

En tal caso, para obtener el mejor rendimiento, debe evitar el uso de adapt(). En cambio, precalcule su vocabulario con antelación (puede utilizar Apache Beam o TF Transform para ello) y guárdelo en un archivo. A continuación, cargue el vocabulario en la capa en el momento de la construcción pasando la ruta del archivo como argumento vocabulary.

Cómo utilizar capas de búsqueda en un pod TPU o con ParameterServerStrategy.

Hay un problema pendiente que hace que el rendimiento se reduzca cuando se utiliza una capa TextVectorization, StringLookup, o IntegerLookup mientras se entrena en un pod TPU o en múltiples máquinas mediante ParameterServerStrategy. Esto está programado para ser corregido en TensorFlow 2.7.