Guardar Modelo y Datos de Entrenamiento de una Red Neuronal Manualmente

Cómo Guardar un Modelo de IA Entrenado y los Datos del Entrenamiento (Red Neuronal Manual)

Cuando construyes una red neuronal desde cero, sin librerías de alto nivel como TensorFlow o PyTorch, guardar el modelo y los datos de entrenamiento requiere un enfoque más manual. Esto implica almacenar los **parámetros** de tu modelo (pesos y sesgos) y los **conjuntos de datos** que utilizaste.

---

Guardando el Modelo Entrenado (Pesos y Sesgos)

Los parámetros de tu modelo de red neuronal creada manualmente son los arreglos de NumPy (o estructuras de datos similares) que representan los **pesos** y **sesgos** que la red ha ajustado durante el entrenamiento.

1. Guardar con NumPy (.npy o .npz)

La forma más eficiente y recomendada de guardar arreglos de NumPy es utilizando las funciones de la propia librería NumPy:

  • Guardar un solo arreglo (.npy):

    Puedes guardar cada arreglo de pesos o sesgos individualmente.

    import numpy as np
    
    # Suponiendo que tu modelo 'nn' ya ha sido entrenado y contiene sus parámetros
    # como self.weights_input_hidden, self.bias_hidden, etc.
    
    np.save('model_weights_input_hidden.npy', nn.weights_input_hidden)
    np.save('model_bias_hidden.npy', nn.bias_hidden)
    np.save('model_weights_hidden_output.npy', nn.weights_hidden_output)
    np.save('model_bias_output.npy', nn.bias_output)
    
    print("Pesos y sesgos guardados como archivos .npy")
    
  • Guardar múltiples arreglos en un solo archivo comprimido (.npz):

    Esta opción es más cómoda si tienes muchos arreglos que almacenar, ya que los agrupa en un único archivo.

    import numpy as np
    
    # Después de entrenar tu modelo 'nn':
    np.savez('trained_model_params.npz',
             weights_input_hidden=nn.weights_input_hidden,
             bias_hidden=nn.bias_hidden,
             weights_hidden_output=nn.weights_hidden_output,
             bias_output=nn.bias_output)
    
    print("Todos los parámetros del modelo guardados en trained_model_params.npz")
    

2. Cargar el Modelo (Pesos y Sesgos)

Para cargar los parámetros y "restaurar" tu modelo, usarás np.load():

  • Cargar archivos .npy individuales:

    import numpy as np
    from your_module import NeuralNetwork # Reemplaza 'your_module' con el nombre de tu archivo .py donde está tu clase
    
    # Cargar los parámetros
    loaded_weights_input_hidden = np.load('model_weights_input_hidden.npy')
    loaded_bias_hidden = np.load('model_bias_hidden.npy')
    loaded_weights_hidden_output = np.load('model_weights_hidden_output.npy')
    loaded_bias_output = np.load('model_bias_output.npy')
    
    # Crear una nueva instancia de la red neuronal y asignar los pesos cargados.
    # ¡Es crucial que la arquitectura de la red (número de capas, neuronas) sea la misma!
    input_size = loaded_weights_input_hidden.shape[0]
    hidden_size = loaded_weights_input_hidden.shape[1]
    output_size = loaded_weights_hidden_output.shape[1]
    
    loaded_nn = NeuralNetwork(input_size, hidden_size, output_size)
    loaded_nn.weights_input_hidden = loaded_weights_input_hidden
    loaded_nn.bias_hidden = loaded_bias_hidden
    loaded_nn.weights_hidden_output = loaded_weights_hidden_output
    loaded_nn.bias_output = loaded_bias_output
    
    print("Modelo cargado exitosamente desde archivos .npy.")
    
  • Cargar un archivo .npz:

    import numpy as np
    from your_module import NeuralNetwork # Reemplaza 'your_module' con el nombre de tu archivo .py
    
    loaded_params = np.load('trained_model_params.npz')
    
    # Crear una nueva instancia de la red y asignar los pesos cargados
    input_size = loaded_params['weights_input_hidden'].shape[0]
    hidden_size = loaded_params['weights_input_hidden'].shape[1]
    output_size = loaded_params['weights_hidden_output'].shape[1]
    
    loaded_nn = NeuralNetwork(input_size, hidden_size, output_size)
    loaded_nn.weights_input_hidden = loaded_params['weights_input_hidden']
    loaded_nn.bias_hidden = loaded_params['bias_hidden']
    loaded_nn.weights_hidden_output = loaded_params['weights_hidden_output']
    loaded_nn.bias_output = loaded_params['bias_output']
    
    print("Modelo cargado exitosamente desde .npz.")
    

Consideraciones Importantes:

  • Arquitectura del modelo: Al cargar los pesos, **debes tener la misma arquitectura de red neuronal** (número de capas, número de neuronas por capa, funciones de activación) que la que usaste para entrenar. Los archivos .npy o .npz solo guardan los valores de los pesos y sesgos, no la lógica de la red.
  • Clase NeuralNetwork: La clase NeuralNetwork debe estar definida y ser accesible (normalmente importada desde un archivo Python) cuando cargues el modelo, ya que esta clase es la que define cómo funcionan esos pesos.
---

Guardando los Datos del Entrenamiento

Los datos de entrenamiento son, por lo general, los arreglos de entrada ($X$) y las etiquetas de salida ($y$) que utilizaste para enseñar a tu modelo. La forma de guardarlos dependerá del formato original de tus datos.

1. Guardar Datos Tabulares (Arreglos de NumPy)

Si tus datos de entrenamiento son arreglos de NumPy (por ejemplo, después de haberlos preprocesado y convertido a este formato), puedes guardarlos de manera similar a los pesos del modelo:

  • Guardar X_train y y_train como .npy:

    import numpy as np
    
    # Suponiendo que tienes X_train y y_train como arreglos de NumPy
    np.save('X_train_data.npy', X_train)
    np.save('y_train_data.npy', y_train)
    
    print("Datos de entrenamiento guardados como archivos .npy")
    
  • Guardar en un .npz:

    import numpy as np
    
    np.savez('training_data.npz', X_train=X_train, y_train=y_train)
    print("Datos de entrenamiento guardados en training_data.npz")
    

2. Cargar Datos Tabulares

import numpy as np

# Cargar X_train y y_train desde .npy
loaded_X_train = np.load('X_train_data.npy')
loaded_y_train = np.load('y_train_data.npy')
print("Datos de entrenamiento cargados desde .npy")

# O cargar desde .npz
loaded_data = np.load('training_data.npz')
loaded_X_train_npz = loaded_data['X_train']
loaded_y_train_npz = loaded_data['y_train']
print("Datos de entrenamiento cargados desde .npz")

3. Guardar Datos Estructurados (CSV, JSON, etc.)

Si tus datos originales provienen de formatos como CSV o JSON, es mejor guardarlos en su formato original o en un formato de datos estructurado que sea fácil de leer y manipular con librerías como Pandas.

  • Usando Pandas para CSV:

    import pandas as pd
    
    # Suponiendo que 'processed_data' es un DataFrame de Pandas listo para el entrenamiento
    processed_data.to_csv('data/processed/final_training_data.csv', index=False)
    print("Datos de entrenamiento procesados guardados como CSV.")
    
  • Cargar CSV con Pandas:

    import pandas as pd
    
    loaded_df = pd.read_csv('data/processed/final_training_data.csv')
    # Luego puedes convertir a NumPy si tu red lo necesita
    X_loaded = loaded_df[['feature1', 'feature2']].values
    y_loaded = loaded_df['target'].values
    print("Datos de entrenamiento cargados desde CSV.")
    
---

Estructura de Archivos Recomendada

Para mantener tu proyecto organizado, te recomiendo la siguiente estructura de directorios:

mi_proyecto_ia_manual/
├── data/
│   ├── raw/
│   │   ├── original_data.csv
│   ├── processed/
│   │   ├── X_train_processed.npy  # O final_training_data.csv
│   │   ├── y_train_processed.npy
├── src/
│   ├── neural_network.py          # Aquí va tu clase NeuralNetwork
│   ├── train_model.py             # Script para entrenar y guardar
│   └── predict.py                 # Script para cargar y hacer predicciones
├── models/
│   ├── trained_model_params.npz   # O los archivos .npy individuales
├── README.md

Ejemplo de train_model.py (actualizado)

import numpy as np
from src.neural_network import NeuralNetwork # Importa tu clase NeuralNetwork desde 'src/neural_network.py'

# Datos de ejemplo (AND gate)
X_train = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=np.float32)
y_train = np.array([[0], [0], [0], [1]], dtype=np.float32) # Asegúrate de que el tipo de dato sea consistente

# Parámetros del modelo
input_size = 2
hidden_size = 3
output_size = 1
learning_rate = 0.1
epochs = 10000

# Crear la red neuronal
nn = NeuralNetwork(input_size, hidden_size, output_size)

print("Iniciando entrenamiento...")
for i in range(epochs):
    predictions = nn.forward(X_train)
    nn.backward(X_train, y_train, learning_rate)

    if (i + 1) % 1000 == 0:
        loss = np.mean(np.square(y_train - predictions)) # MSE
        print(f"Epoch {i+1}, Loss: {loss:.4f}")

print("\nEntrenamiento completado.")

# --- Guardar el modelo entrenado ---
np.savez('models/trained_model_params.npz',
         weights_input_hidden=nn.weights_input_hidden,
         bias_hidden=nn.bias_hidden,
         weights_hidden_output=nn.weights_hidden_output,
         bias_output=nn.bias_output)
print("Parámetros del modelo guardados en 'models/trained_model_params.npz'")

# --- Guardar los datos de entrenamiento (si aún no están en disco) ---
# Puedes guardar los X_train y y_train si son generados o procesados aquí.
# Si ya los cargaste de un archivo, no es necesario guardarlos de nuevo a menos que quieras una copia de los preprocesados.
np.save('data/processed/X_train_processed.npy', X_train)
np.save('data/processed/y_train_processed.npy', y_train)
print("Datos de entrenamiento guardados en 'data/processed/'")

Ejemplo de predict.py (para cargar y usar el modelo)

import numpy as np
from src.neural_network import NeuralNetwork # Importa tu clase NeuralNetwork

# Cargar los parámetros del modelo
loaded_params = np.load('models/trained_model_params.npz')

# Reconstruir la red neuronal con los parámetros cargados
# Asegúrate de que estos tamaños coincidan con los usados durante el entrenamiento
input_size = loaded_params['weights_input_hidden'].shape[0]
hidden_size = loaded_params['weights_input_hidden'].shape[1]
output_size = loaded_params['weights_hidden_output'].shape[1]

loaded_nn = NeuralNetwork(input_size, hidden_size, output_size)
loaded_nn.weights_input_hidden = loaded_params['weights_input_hidden']
loaded_nn.bias_hidden = loaded_params['bias_hidden']
loaded_nn.weights_hidden_output = loaded_params['weights_hidden_output']
loaded_nn.bias_output = loaded_params['bias_output']

print("Modelo cargado exitosamente.")

# Realizar una predicción con el modelo cargado
test_input = np.array([[0, 1]], dtype=np.float32) # Ejemplo: [0, 1] para la compuerta AND
prediction = loaded_nn.forward(test_input)
print(f"\nPredicción para input {test_input}: {prediction}")

test_input_2 = np.array([[1, 1]], dtype=np.float32)
prediction_2 = loaded_nn.forward(test_input_2)
print(f"Predicción para input {test_input_2}: {prediction_2}")

Al seguir estos pasos, podrás persistir el estado de tu red neuronal entrenada manualmente y los datos asociados. Esto te permitirá reutilizar el modelo para hacer predicciones sin la necesidad de volver a entrenarlo cada vez que lo uses.

Comentarios

Entradas populares de este blog

UTF-8 con y sin BOM

Edición y Estructura de Archivos ELF

Análisis de Archivos ELF y Llamadas al Sistema