TensorFlow: Preprocesados y preparación
Aprende las técnicas fundamentales de preprocesamiento de datos para TensorFlow. Desde normalización y limpieza hasta augmentación y transformación de datos, domina las estrategias que garantizan que tus modelos de redes neuronales reciban información ópt
Aprende TensorFlow GRATIS y certifícateEl preprocesado de datos constituye una fase crítica en cualquier proyecto de aprendizaje automático. Antes de que un modelo pueda aprender patrones útiles, los datos deben ser transformados a un formato adecuado, limpiados de inconsistencias y preparados para maximizar la eficacia del entrenamiento. TensorFlow proporciona un conjunto completo de herramientas que facilitan estas tareas, permitiendo construir pipelines de datos eficientes y optimizados.
API tf.data: la base del preprocesado en TensorFlow
La API tf.data
es el núcleo del ecosistema de preprocesado en TensorFlow, diseñada para construir pipelines de datos eficientes, flexibles y con alto rendimiento. Esta API permite cargar datos desde diferentes fuentes, transformarlos y entregarlos al modelo en lotes, todo dentro del grafo de computación de TensorFlow, lo que optimiza el rendimiento y evita cuellos de botella.
import tensorflow as tf
import numpy as np
# Crear un dataset simple desde un tensor
datos = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
dataset = tf.data.Dataset.from_tensor_slices(datos)
# Aplicar transformaciones
dataset = dataset.map(lambda x: x * 2) # Multiplicar cada elemento por 2
dataset = dataset.batch(3) # Agrupar en lotes de 3 elementos
# Iterar sobre el dataset
for lote in dataset:
print(lote.numpy())
La creación de un dataset puede realizarse desde diversas fuentes como tensores, archivos TFRecord, archivos de texto o generadores de Python. Una vez creado, podemos aplicar una serie de transformaciones encadenadas para preparar los datos según nuestras necesidades.
Carga de diferentes tipos de datos
Datos tabulares y numéricos
Los datos tabulares pueden cargarse desde diferentes formatos como CSV, Excel o bases de datos. TensorFlow facilita la carga directa de archivos CSV:
csv_dataset = tf.data.experimental.make_csv_dataset(
file_pattern="datos.csv",
batch_size=32,
column_names=["caracteristica1", "caracteristica2", "etiqueta"],
label_name="etiqueta",
num_epochs=1
)
for features_batch, labels_batch in csv_dataset:
print(f"Características: {features_batch}")
print(f"Etiquetas: {labels_batch}")
break # Solo mostramos el primer lote
Para conjuntos de datos más complejos o que requieren un preprocesado específico, podemos utilizar bibliotecas como pandas para la carga inicial y luego convertirlos a objetos tf.data.Dataset
:
import pandas as pd
# Cargar datos con pandas
df = pd.read_csv("datos.csv")
# Separar características y etiquetas
features = df.drop("etiqueta", axis=1).values
labels = df["etiqueta"].values
# Crear dataset de TensorFlow
dataset = tf.data.Dataset.from_tensor_slices((features, labels))
Imágenes
El preprocesado de imágenes es crucial en tareas de visión por computador. TensorFlow proporciona funciones específicas para cargar y transformar imágenes:
def cargar_imagen(ruta_archivo):
# Leer el archivo
img_raw = tf.io.read_file(ruta_archivo)
# Decodificar la imagen
img = tf.io.decode_image(img_raw, channels=3, expand_animations=False)
# Redimensionar
img = tf.image.resize(img, [224, 224])
# Normalizar valores a [0, 1]
img = tf.cast(img, tf.float32) / 255.0
return img
# Crear una lista de rutas de archivos
rutas_imagenes = tf.data.Dataset.list_files("imagenes/*.jpg")
# Aplicar la función de carga a cada ruta
dataset_imagenes = rutas_imagenes.map(cargar_imagen, num_parallel_calls=tf.data.AUTOTUNE)
La API tf.image
ofrece numerosas funciones para transformar imágenes, incluyendo operaciones de redimensionado, recorte, rotación, ajuste de brillo y contraste, y muchas más. Estas operaciones pueden integrarse perfectamente en el pipeline de datos.
Datos de texto
El procesamiento de texto requiere transformar palabras o caracteres en representaciones numéricas que los modelos puedan entender. TensorFlow proporciona herramientas específicas para esta tarea:
# Lista de frases de ejemplo
frases = ["Hola mundo", "Aprendizaje automático", "TensorFlow es genial"]
dataset_texto = tf.data.Dataset.from_tensor_slices(frases)
# Crear un tokenizador y ajustarlo a los datos
tokenizador = tf.keras.preprocessing.text.Tokenizer()
tokenizador.fit_on_texts(frases)
# Convertir texto a secuencias de índices
def tokenizar(texto):
secuencias = tokenizador.texts_to_sequences([texto.numpy().decode('utf-8')])
return tf.constant(secuencias[0])
# Aplicar la tokenización a cada elemento
dataset_texto = dataset_texto.map(
lambda texto: tf.py_function(func=tokenizar, inp=[texto], Tout=tf.int32)
)
Para manejar secuencias de diferentes longitudes, necesitamos aplicar padding para que todas tengan la misma dimensión:
def aplicar_padding(secuencia):
return tf.pad(
secuencia,
[[0, 50 - tf.shape(secuencia)[0]]],
"CONSTANT",
constant_values=0
)[:50] # Truncar si es más larga que 50
dataset_texto = dataset_texto.map(aplicar_padding)
Limpieza y transformación de datos
Manejo de valores faltantes
Los valores faltantes son un problema común en conjuntos de datos reales. Para manejarlos, podemos utilizar diversas técnicas como:
def manejar_valores_faltantes(features):
# Reemplazar NaN con un valor predeterminado
features = {k: tf.where(tf.math.is_nan(v), tf.zeros_like(v), v)
for k, v in features.items()}
# O imputar con la media (calculada previamente)
medias = {"caracteristica1": 3.5, "caracteristica2": 2.7}
features = {k: tf.where(tf.math.is_nan(v), tf.constant(medias[k], dtype=v.dtype), v)
for k, v in features.items()}
return features
dataset = dataset.map(lambda x, y: (manejar_valores_faltantes(x), y))
Normalización y estandarización
La normalización de datos es esencial para muchos algoritmos de aprendizaje automático, ya que ayuda a que el proceso de entrenamiento sea más estable y eficiente:
def normalizar_min_max(x):
# Normalización a [0, 1]
min_val = tf.reduce_min(x)
max_val = tf.reduce_max(x)
return (x - min_val) / (max_val - min_val)
def estandarizar(x):
# Estandarización (media 0, desviación estándar 1)
media = tf.reduce_mean(x)
desv_std = tf.math.reduce_std(x)
return (x - media) / desv_std
# Aplicar normalización a cada característica
dataset = dataset.map(
lambda x: {k: normalizar_min_max(v) for k, v in x.items()}
)
En la práctica, es recomendable calcular las estadísticas (mínimo, máximo, media, desviación estándar) sobre el conjunto de entrenamiento y aplicar las mismas transformaciones al conjunto de validación y prueba:
# Calcular estadísticas sobre el conjunto de entrenamiento
estadisticas = {}
for batch in dataset_entrenamiento:
for key, tensor in batch.items():
if key not in estadisticas:
estadisticas[key] = {"min": float('inf'), "max": float('-inf'),
"sum": 0, "count": 0, "sum_squared": 0}
estadisticas[key]["min"] = min(estadisticas[key]["min"], tf.reduce_min(tensor))
estadisticas[key]["max"] = max(estadisticas[key]["max"], tf.reduce_max(tensor))
estadisticas[key]["sum"] += tf.reduce_sum(tensor)
estadisticas[key]["count"] += tf.size(tensor)
estadisticas[key]["sum_squared"] += tf.reduce_sum(tf.square(tensor))
# Calcular media y desviación estándar
for key in estadisticas:
estadisticas[key]["mean"] = estadisticas[key]["sum"] / estadisticas[key]["count"]
varianza = (estadisticas[key]["sum_squared"] / estadisticas[key]["count"]) - tf.square(estadisticas[key]["mean"])
estadisticas[key]["std"] = tf.sqrt(varianza)
# Función de normalización usando las estadísticas calculadas
def normalizar_con_estadisticas(features):
return {k: (v - estadisticas[k]["mean"]) / estadisticas[k]["std"]
for k, v in features.items()}
# Aplicar a los conjuntos de datos
dataset_entrenamiento = dataset_entrenamiento.map(normalizar_con_estadisticas)
dataset_validacion = dataset_validacion.map(normalizar_con_estadisticas)
Codificación de variables categóricas
Las variables categóricas deben transformarse en representaciones numéricas. TensorFlow ofrece diversas opciones para esta codificación:
# One-hot encoding
def one_hot_encoding(valor, num_categorias):
return tf.one_hot(valor, depth=num_categorias)
# Ejemplo para una variable categórica con 5 posibles valores
dataset = dataset.map(
lambda x, y: ({**x, "categoria_one_hot": one_hot_encoding(x["categoria"], 5)}, y)
)
# Embedding para categorías con alta cardinalidad
embedding_layer = tf.keras.layers.Embedding(input_dim=1000, output_dim=16)
def aplicar_embedding(x):
categoria_embedding = embedding_layer(x["categoria"])
return {**x, "categoria_embedding": categoria_embedding}
dataset = dataset.map(aplicar_embedding)
Partición de datos
La división adecuada del conjunto de datos en entrenamiento, validación y prueba es fundamental para evaluar correctamente el rendimiento del modelo:
def particionar_dataset(dataset, proporciones):
"""
Particiona un dataset en múltiples subconjuntos según las proporciones dadas.
Args:
dataset: Dataset a particionar
proporciones: Lista de proporciones para cada partición (debe sumar 1)
Returns:
Lista de datasets particionados
"""
assert sum(proporciones) == 1.0, "Las proporciones deben sumar 1"
# Obtener el tamaño total del dataset
dataset = dataset.cache()
tamanio = 0
for _ in dataset:
tamanio += 1
# Crear índices aleatorios
indices = tf.range(tamanio)
indices = tf.random.shuffle(indices)
# Calcular los puntos de corte
puntos_corte = [0]
for i in range(len(proporciones) - 1):
puntos_cort
Lecciones de este módulo de TensorFlow
Lecciones de programación del módulo Preprocesados y preparación del curso de TensorFlow.