Skip to main content

High-performance neural network library with Keras-like API

Project description

GRNexus Python - Neural Network Library

GRNexus Python License PyPI

A high-performance neural network library with Keras-like API


📑 Table of Contents


✨ Features

  • 🚀 High Performance: Optimized operations with native C libraries
  • 🎯 Keras-like API: Familiar and easy to use for ML developers
  • 🧩 Modular: Flexible architecture with decoupled layers
  • 💾 Persistence: Save and load models in .nexus format
  • 🎨 50+ Activation Functions: From ReLU to Snake, Mish, GELU, etc.
  • 🔧 Multiple Optimizers: SGD, Momentum, Adam, RMSprop
  • 📊 Regularization: Dropout, Batch Normalization
  • 🤖 ML Algorithms: KNN, K-Means, Linear/Logistic Regression, Naive Bayes
  • 🌍 Cross-Platform: Windows, macOS, Linux

📦 Installation

pip install grnexus

Instalación desde Código Fuente

Para desarrolladores que quieran contribuir o usar la última versión:

# Clonar el repositorio
git clone https://github.com/grcodedigitalsolutions/GRNexus.git
cd GRNexus/python

# Instalar en modo desarrollo
pip install -e .

# O instalar dependencias opcionales para tests
pip install flet numpy

Requisitos

  • Python 3.8 o superior
  • Sin dependencias externas (100% Python puro)
  • Flet (opcional, solo para tests interactivos)
  • NumPy (opcional, para operaciones matriciales avanzadas)

Verificar Instalación

from grnexus import NeuralNetwork

# Crear un modelo simple
model = NeuralNetwork()
print(f"✅ GRNexus v{grnexus.__version__} instalado correctamente!")

🚀 Inicio Rápido

from grnexus import NeuralNetwork, DenseLayer, ReLU, DropoutLayer

# 1. Crear modelo
model = NeuralNetwork()

# 2. Agregar capas
model.add(DenseLayer(128, input_dim=784, activation=ReLU()))
model.add(DropoutLayer(0.2))
model.add(DenseLayer(64, activation=ReLU()))
model.add(DenseLayer(10))  # Capa de salida

# 3. Compilar
model.compile(
    optimizer='adam',
    loss='cross_entropy',
    learning_rate=0.001
)

# 4. Entrenar
history = model.train(
    x_train,  # Datos de entrenamiento
    y_train,  # Etiquetas (one-hot encoded)
    epochs=10,
    batch_size=32
)

# 5. Predecir
predictions = model.predict(x_test)

# 6. Guardar modelo
model.save('mi_modelo.nexus')

# Cargar modelo
model_cargado = NeuralNetwork.load('mi_modelo.nexus')

🏗️ Arquitectura

Estructura del Proyecto

GRNexus/python/
├── grnexus.py              # Clase principal GRNexus
├── lib/
│   ├── grnexus_layers.py   # Implementación de capas
│   ├── grnexus_activations.py  # Funciones de activación
│   └── grnexus_optimizers.py   # Optimizers
├── test/
│   ├── test_digitos.py     # Test de reconocimiento de dígitos
│   ├── test_sentiment.py   # Test de análisis de sentimientos
│   ├── test_iris.py        # Test de clasificación Iris
│   ├── test_housing.py     # Test de predicción de precios
│   └── test_suite.py       # Launcher de todos los tests
└── README.md               # Este archivo

Flujo de Datos

Input → DenseLayer → Activation → Dropout → ... → Softmax → Output
   ↓                                                            ↑
   └──────────── Backpropagation (gradientes) ─────────────────┘

🧠 Cómo Funciona una Red Neuronal

📖 Explicación Básica para Principiantes (Click para expandir)

¿Qué es una Neurona Artificial?

Imagina una neurona como una pequeña calculadora que:

  1. Recibe varios números de entrada
  2. Los multiplica por "pesos" (importancia de cada entrada)
  3. Los suma todos
  4. Aplica una función de activación (decide si "activarse" o no)
  5. Produce un número de salida
Ejemplo simple:
Entradas: [2, 3, 1]
Pesos:    [0.5, 0.3, 0.2]

Cálculo: (2 × 0.5) + (3 × 0.3) + (1 × 0.2) = 1.0 + 0.9 + 0.2 = 2.1
Activación ReLU: max(0, 2.1) = 2.1
Salida: 2.1

¿Qué son los Pesos y Bias?

  • Pesos: Son como "perillas de volumen" que controlan qué tan importante es cada entrada

    • Al inicio son aleatorios
    • Durante el entrenamiento se ajustan automáticamente
    • Pesos grandes = entrada muy importante
    • Pesos pequeños = entrada poco importante
  • Bias: Es como un "ajuste fino" adicional

    • Permite a la neurona activarse incluso sin entradas
    • Ayuda a que la red sea más flexible

¿Cómo Aprende la Red?

El aprendizaje es un proceso de prueba y error automatizado:

1. PREDICCIÓN (Forward Pass):
   Entrada → Capa 1 → Capa 2 → ... → Salida
   
2. COMPARACIÓN:
   ¿Qué predijo la red? vs ¿Cuál era la respuesta correcta?
   Error = |Predicción - Respuesta Correcta|
   
3. AJUSTE (Backward Pass / Backpropagation):
   - La red calcula: "¿Qué pesos causaron este error?"
   - Ajusta los pesos en la dirección que reduce el error
   - Usa el "learning rate" para controlar qué tan grandes son los ajustes
   
4. REPETIR:
   - Hace esto miles de veces con muchos ejemplos
   - Gradualmente los pesos mejoran
   - El error disminuye
   - ¡La red aprende!

¿Qué hace la Función de Activación?

Las funciones de activación añaden no-linealidad (capacidad de aprender patrones complejos):

  • Sin activación: La red solo puede aprender líneas rectas (muy limitado)
  • Con activación: La red puede aprender curvas, formas complejas, patrones

Analogía:

  • Sin activación = Solo puedes dibujar con una regla
  • Con activación = Puedes dibujar cualquier forma libremente

Funciones comunes:

  • ReLU: Si el número es negativo → 0, si es positivo → déjalo igual
  • Sigmoid: Convierte cualquier número a rango 0-1
  • Softmax: Convierte números en probabilidades que suman 1

Ejemplo Completo: Reconocimiento de Dígitos

PASO 1: PREPARAR DATOS
Imagen 28×28 → Aplanar → Vector de 784 números
[pixel1, pixel2, ..., pixel784]

PASO 2: FORWARD PASS (Predicción)
784 números → Capa 1 (128 neuronas con ReLU)
           → Capa 2 (64 neuronas con ReLU)  
           → Capa 3 (10 neuronas, una por dígito)
           → Softmax (convierte a probabilidades)
           → [0.01, 0.02, 0.85, 0.03, ...] ← "85% seguro que es un 2"

PASO 3: CALCULAR ERROR
Predicción: [0.01, 0.02, 0.85, 0.03, 0.01, 0.02, 0.01, 0.03, 0.01, 0.01]
Correcto:   [0,    0,    1,    0,    0,    0,    0,    0,    0,    0   ] (es un 2)
Error: Categorical Cross-Entropy = 0.16 (bastante bajo, buena predicción)

PASO 4: BACKWARD PASS (Aprendizaje)
- Calcular gradientes: "¿Qué pesos causaron el error?"
- Actualizar pesos: peso_nuevo = peso_viejo - (learning_rate × gradiente)
- Los pesos se ajustan para que la próxima vez prediga mejor

PASO 5: REPETIR
- Entrenar con miles de imágenes
- Cada vez los pesos mejoran un poquito
- Después de muchas épocas, ¡la red reconoce dígitos con 95%+ precisión!

Conceptos Clave

Concepto Explicación Simple Analogía
Neurona Calculadora que suma entradas ponderadas Una persona votando (cada voto tiene diferente peso)
Peso Importancia de una conexión Volumen de un canal de audio
Bias Ajuste fino adicional Temperatura base de un termostato
Activación Función que decide si la neurona "se activa" Interruptor que decide si pasa la señal
Forward Pass Calcular la predicción Resolver un problema de matemáticas
Loss Qué tan equivocada está la predicción Distancia entre tu respuesta y la correcta
Backward Pass Ajustar pesos para reducir error Aprender de tus errores
Epoch Una pasada completa por todos los datos Leer un libro completo una vez
Batch Grupo pequeño de ejemplos Estudiar un capítulo del libro
Learning Rate Qué tan grandes son los ajustes Tamaño de los pasos cuando caminas

Flujo Detallado de Entrenamiento

graph TD
    A[Datos de Entrada] --> B[Normalización]
    B --> C[Forward Pass]
    C --> D[Capa Dense 1]
    D --> E[Activación ReLU]
    E --> F[Dropout]
    F --> G[Capa Dense 2]
    G --> H[Activación]
    H --> I[Capa de Salida]
    I --> J[Softmax/Output]
    J --> K[Calcular Loss]
    K --> L[Backward Pass]
    L --> M[Calcular Gradientes]
    M --> N[Actualizar Pesos]
    N --> O{¿Más Epochs?}
    O -->|Sí| C
    O -->|No| P[Modelo Entrenado]

Proceso de Predicción vs Entrenamiento

Fase Forward Pass Backward Pass Actualizar Pesos
Entrenamiento ✅ Sí ✅ Sí ✅ Sí
Predicción ✅ Sí ❌ No ❌ No

Durante Entrenamiento:

  1. Forward: Calcular predicción
  2. Comparar con etiqueta real
  3. Backward: Calcular gradientes
  4. Actualizar pesos con optimizer

Durante Predicción:

  1. Forward: Calcular predicción
  2. Retornar resultado
  3. ¡Listo!

📚 Guía Paso a Paso

1. Crear un Modelo

from grnexus import GRNexus

# Especificar la dimensión de entrada
model = GRNexus(input_dim=784)

Parámetros:

  • input_dim (int): Número de características de entrada

¿Cómo determinar input_dim?

  • Para imágenes 28x28: input_dim = 28 * 28 = 784
  • Para texto vectorizado: input_dim = tamaño_vocabulario
  • Para datos tabulares: input_dim = número_de_columnas

2. Agregar Capas

2.1 Capa Densa (Dense Layer)

model.add_dense(
    units=128,              # Número de neuronas
    activation='ReLU',      # Función de activación
    use_bias=True,          # Usar bias
    weight_init='he'        # Inicialización de pesos
)

Parámetros:

  • units (int): Número de neuronas en la capa
  • activation (str, opcional): Nombre de la función de activación
    • Opciones: 'ReLU', 'Sigmoid', 'Tanh', 'Swish', 'GELU', 'Mish', etc.
  • use_bias (bool): Si usar bias (default: True)
  • weight_init (str): Método de inicialización
    • 'xavier': Para Sigmoid/Tanh
    • 'he': Para ReLU y variantes (recomendado)
    • 'normal': Distribución normal
    • 'uniform': Distribución uniforme

2.2 Capa de Dropout

model.add_dropout(rate=0.2)  # Desactivar 20% de neuronas durante entrenamiento

Parámetros:

  • rate (float): Proporción de neuronas a desactivar (0.0 - 1.0)

¿Cuándo usar Dropout?

  • Para prevenir overfitting
  • Típicamente después de capas densas
  • Valores comunes: 0.2 - 0.5

2.3 Capa de Batch Normalization

model.add_batch_norm(
    momentum=0.99,
    epsilon=1e-5
)

Parámetros:

  • momentum (float): Momentum para actualizar media y varianza móviles
  • epsilon (float): Valor pequeño para estabilidad numérica

2.4 Capa de Activación

model.add_activation('ReLU')

¿Cuándo usar?

  • Cuando necesitas aplicar una activación sin una capa densa
  • Para arquitecturas más complejas

2.5 Capa Softmax

model.add_softmax()  # Para clasificación multiclase

Importante:

  • Solo usar en la capa de salida
  • Para problemas de clasificación
  • Convierte logits en probabilidades que suman 1.0

3. Compilar

model.compile(
    optimizer='adam',        # Optimizer a usar
    loss='categorical_crossentropy',  # Función de pérdida
    learning_rate=0.01,      # Tasa de aprendizaje
    metrics=['accuracy']     # Métricas a monitorear
)

Parámetros:

  • optimizer (str): Algoritmo de optimización
    • 'sgd': Stochastic Gradient Descent
    • 'momentum': SGD con Momentum
    • 'adam': Adaptive Moment Estimation (recomendado)
    • 'rmsprop': RMSprop
  • loss (str): Función de pérdida
    • 'categorical_crossentropy': Para clasificación multiclase
    • 'mse': Mean Squared Error (para regresión)
  • learning_rate (float): Tasa de aprendizaje
    • Valores típicos: 0.001 - 0.1
    • Valores más bajos: aprendizaje más estable pero lento
    • Valores más altos: aprendizaje más rápido pero puede divergir
  • metrics (list, opcional): Métricas a calcular

🎯 Guía de Learning Rate:

Optimizer LR Recomendado
SGD 0.01 - 0.1
Momentum 0.01 - 0.05
Adam 0.001 - 0.01
RMSprop 0.001 - 0.01

4. Entrenar

4.1 Método fit() (Recomendado)

history = model.fit(
    x_train,           # Datos de entrenamiento
    y_train,           # Etiquetas
    epochs=10,         # Número de épocas
    batch_size=32,     # Tamaño del batch
    validation_data=(x_val, y_val),  # Datos de validación (opcional)
    verbose=1          # Nivel de detalle (0, 1, 2)
)

Parámetros:

  • x_train (list): Datos de entrada (lista de listas)
    • Ejemplo: [[0.1, 0.2, ...], [0.3, 0.4, ...], ...]
  • y_train (list): Etiquetas (one-hot encoded para clasificación)
    • Ejemplo: [[1, 0, 0], [0, 1, 0], ...] para 3 clases
  • epochs (int): Número de veces que pasar por todo el dataset
  • batch_size (int): Número de muestras por actualización de pesos
  • validation_data (tuple, opcional): (x_val, y_val) para validación
  • verbose (int): 0=silencioso, 1=barra de progreso, 2=una línea por época

Retorna:

  • history (dict): Historial de entrenamiento con pérdidas por época

4.2 Método train_on_batch() (Para control fino)

for epoch in range(epochs):
    for i in range(0, len(x_train), batch_size):
        x_batch = x_train[i:i+batch_size]
        y_batch = y_train[i:i+batch_size]
        
        loss = model.train_on_batch(x_batch, y_batch)
        print(f"Batch loss: {loss}")

5. Predecir

5.1 Predicción Simple

# Predecir una muestra
prediction = model.predict(x_sample)  # x_sample es una lista de números

# Predecir múltiples muestras
predictions = model.predict(x_test)   # x_test es lista de listas

5.2 Obtener Clase Predicha

# Para clasificación
prediction = model.predict(x_sample)
predicted_class = prediction.index(max(prediction))  # Índice de máxima probabilidad
confidence = max(prediction)  # Confianza de la predicción

print(f"Clase predicha: {predicted_class}")
print(f"Confianza: {confidence:.2%}")

6. Guardar/Cargar

6.1 Guardar Modelo

model.save('mi_modelo.nexus')

Formato .nexus:

  • Guarda arquitectura completa del modelo
  • Guarda todos los pesos y biases
  • Guarda configuración del optimizer
  • Compatible entre plataformas

6.2 Cargar Modelo

from grnexus import GRNexus

modelo_cargado = GRNexus.load('mi_modelo.nexus')

# Usar inmediatamente sin recompilar
predicciones = modelo_cargado.predict(x_test)

📊 Entendiendo los Datos

Preparación de Datos para Entrenamiento

Los datos son el combustible de las redes neuronales. Aquí aprenderás cómo prepararlos correctamente.

1. Formato de Entrada

Las redes neuronales solo entienden números. Debes convertir tus datos a listas de números.

Ejemplos por tipo de dato:

# IMÁGENES (28x28 píxeles)
imagen_2d = [
    [0.0, 0.1, 0.2, ...],  # Fila 1
    [0.3, 0.4, 0.5, ...],  # Fila 2
    ...
]
# Aplanar a 1D
imagen_1d = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, ...]  # 784 números

# TEXTO
texto = "This movie is great"
# Convertir a bag-of-words o embeddings
vector_texto = [0.0, 0.2, 0.0, 0.5, ...]  # Cada posición = una palabra

# DATOS TABULARES
casa = {
    'habitaciones': 3,
    'baños': 2,
    'metros': 120,
    'año': 2010,
    'distancia': 5
}
# Convertir a lista
vector_casa = [3, 2, 120, 2010, 5]

2. Normalización de Datos

¿Por qué normalizar?

  • Las redes aprenden mejor cuando todos los valores están en rangos similares
  • Evita que características con valores grandes dominen el aprendizaje
  • Acelera la convergencia

Métodos de normalización:

# MIN-MAX NORMALIZATION (escala a [0, 1])
def normalizar_min_max(valor, min_val, max_val):
    return (valor - min_val) / (max_val - min_val)

# Ejemplo:
edad = 25  # rango: 18-80
edad_norm = (25 - 18) / (80 - 18) = 0.113

# Z-SCORE NORMALIZATION (media=0, std=1)
def normalizar_z_score(valor, media, std):
    return (valor - media) / std

# PARA IMÁGENES (ya están en [0, 255])
pixel = 128
pixel_norm = pixel / 255.0  # → 0.502

Ejemplo completo:

# Datos sin normalizar
datos_crudos = [
    [3, 2, 120, 2010, 5],    # habitaciones, baños, m², año, km
    [4, 3, 180, 2015, 3],
    [2, 1, 80, 1990, 10]
]

# Encontrar min y max de cada característica
mins = [2, 1, 70, 1985, 1]
maxs = [6, 5, 320, 2024, 15]

# Normalizar
datos_normalizados = []
for muestra in datos_crudos:
    muestra_norm = []
    for i, valor in enumerate(muestra):
        norm = (valor - mins[i]) / (maxs[i] - mins[i])
        muestra_norm.append(norm)
    datos_normalizados.append(muestra_norm)

# Resultado:
# [[0.25, 0.25, 0.2, 0.64, 0.29],
#  [0.5, 0.5, 0.44, 0.77, 0.14],
#  [0.0, 0.0, 0.04, 0.13, 0.64]]

3. One-Hot Encoding

Para clasificación, las etiquetas deben estar en formato one-hot.

¿Qué es One-Hot Encoding?

Convertir una categoría en un vector donde:

  • Todas las posiciones son 0
  • Excepto la posición de la categoría correcta que es 1
# EJEMPLO: Clasificación de dígitos (0-9)
digito = 3

# One-hot encoding:
one_hot = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
#          0  1  2  3  4  5  6  7  8  9
#                 ↑
#            posición 3 = 1

# Función para crear one-hot
def crear_one_hot(etiqueta, num_clases):
    vector = [0.0] * num_clases
    vector[etiqueta] = 1.0
    return vector

# Ejemplos:
crear_one_hot(0, 10)  # → [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
crear_one_hot(5, 10)  # → [0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
crear_one_hot(9, 10)  # → [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

Para múltiples muestras:

# Etiquetas originales
etiquetas = [3, 7, 2, 9, 1]

# Convertir a one-hot
y_train = []
for etiqueta in etiquetas:
    one_hot = [0.0] * 10
    one_hot[etiqueta] = 1.0
    y_train.append(one_hot)

# Resultado:
# [[0,0,0,1,0,0,0,0,0,0],  # 3
#  [0,0,0,0,0,0,0,1,0,0],  # 7
#  [0,0,1,0,0,0,0,0,0,0],  # 2
#  [0,0,0,0,0,0,0,0,0,1],  # 9
#  [0,1,0,0,0,0,0,0,0,0]]  # 1

4. Formato de Entrada/Salida

Para Clasificación:

# ENTRADA: Lista de listas (cada muestra es una lista)
x_train = [
    [0.1, 0.2, 0.3, ...],  # Muestra 1
    [0.4, 0.5, 0.6, ...],  # Muestra 2
    [0.7, 0.8, 0.9, ...]   # Muestra 3
]

# SALIDA: One-hot encoded
y_train = [
    [1, 0, 0],  # Clase 0
    [0, 1, 0],  # Clase 1
    [1, 0, 0]   # Clase 0
]

# ENTRENAR
model.fit(x_train, y_train, epochs=10, batch_size=32)

Para Regresión:

# ENTRADA: Igual que clasificación
x_train = [
    [3, 2, 120, 2010, 5],   # Casa 1
    [4, 3, 180, 2015, 3],   # Casa 2
    [2, 1, 80, 1990, 10]    # Casa 3
]

# SALIDA: Valores continuos (NO one-hot)
y_train = [
    [250],  # Precio casa 1: $250k
    [380],  # Precio casa 2: $380k
    [150]   # Precio casa 3: $150k
]

# ENTRENAR
model.fit(x_train, y_train, epochs=100, batch_size=8)

5. Validación de Datos

Antes de entrenar, verifica que tus datos estén correctos:

# Verificar dimensiones
print(f"Muestras de entrenamiento: {len(x_train)}")
print(f"Dimensión de entrada: {len(x_train[0])}")
print(f"Dimensión de salida: {len(y_train[0])}")

# Verificar que coincidan
assert len(x_train) == len(y_train), "¡x_train y y_train deben tener mismo tamaño!"

# Verificar que input_dim sea correcto
assert len(x_train[0]) == model.input_dim, f"¡input_dim debe ser {len(x_train[0])}!"

# Verificar rangos (después de normalizar)
import statistics
muestra = x_train[0]
print(f"Min: {min(muestra)}, Max: {max(muestra)}")
# Idealmente debe estar en [0, 1] o [-1, 1]

# Verificar one-hot (para clasificación)
for y in y_train:
    assert sum(y) == 1.0, "¡One-hot debe sumar 1!"
    assert max(y) == 1.0, "¡One-hot debe tener un 1!"

6. División Train/Test

Siempre separa tus datos en entrenamiento y prueba:

import random

# Mezclar datos
combined = list(zip(x_data, y_data))
random.shuffle(combined)
x_data, y_data = zip(*combined)

# Dividir 80% train, 20% test
split_idx = int(0.8 * len(x_data))

x_train = list(x_data[:split_idx])
y_train = list(y_data[:split_idx])

x_test = list(x_data[split_idx:])
y_test = list(y_data[split_idx:])

print(f"Train: {len(x_train)} muestras")
print(f"Test: {len(x_test)} muestras")

# Entrenar solo con train
model.fit(x_train, y_train, epochs=50)

# Evaluar con test
for x, y in zip(x_test, y_test):
    pred = model.predict(x)
    # Comparar pred con y

🔧 API Completa

Clase GRNexus

Constructor

GRNexus(input_dim: int)

Métodos de Construcción

Método Descripción
add_dense(units, activation=None, use_bias=True, weight_init='xavier') Agregar capa densa
add_activation(activation) Agregar capa de activación
add_dropout(rate) Agregar dropout
add_batch_norm(momentum=0.99, epsilon=1e-5) Agregar batch normalization
add_softmax() Agregar softmax (salida)

Métodos de Configuración

Método Descripción
compile(optimizer, loss, learning_rate, metrics=None) Compilar modelo

Métodos de Entrenamiento

Método Descripción
fit(x_train, y_train, epochs, batch_size, validation_data=None, verbose=1) Entrenar modelo
train_on_batch(x_batch, y_batch) Entrenar en un batch

Métodos de Predicción

Método Descripción
predict(x, batch_size=32) Hacer predicciones
forward(x, training=False) Forward pass (bajo nivel)

Métodos de Persistencia

Método Descripción
save(filename) Guardar modelo
load(filename) (estático) Cargar modelo

Capas Disponibles

DenseLayer

DenseLayer(units, input_dim, activation=None, use_bias=True, weight_init='xavier')

Capa completamente conectada.

DropoutLayer

DropoutLayer(rate)

Desactiva aleatoriamente neuronas durante entrenamiento.

BatchNormLayer

BatchNormLayer(input_dim, momentum=0.99, epsilon=1e-5)

Normaliza activaciones para acelerar entrenamiento.

ActivationLayer

ActivationLayer(activation)

Aplica función de activación no lineal.

SoftmaxLayer

SoftmaxLayer()

Convierte logits en probabilidades (suma = 1).


Funciones de Activación

Básicas

  • Linear: f(x) = x
  • Step: Función escalón
  • Sigmoid: f(x) = 1 / (1 + e^(-x))
  • Tanh: f(x) = tanh(x)

ReLU y Variantes

  • ReLU: f(x) = max(0, x)
  • LeakyReLU: f(x) = max(αx, x)
  • PReLU: ReLU paramétrico
  • ELU: Exponential Linear Unit
  • SELU: Scaled ELU
  • ReLU6: min(max(0, x), 6)

Modernas

  • Swish: f(x) = x · sigmoid(x)
  • Mish: f(x) = x · tanh(softplus(x))
  • GELU: Gaussian Error Linear Unit
  • LiSHT: Linearly Scaled Hyperbolic Tangent

Especializadas

  • Softplus: f(x) = log(1 + e^x)
  • Softsign: f(x) = x / (1 + |x|)
  • HardSigmoid: Aproximación rápida de sigmoid
  • HardSwish: Aproximación rápida de swish
  • HardTanh: Versión acotada de tanh

Exóticas

  • Snake: Función periódica
  • ISRU: Inverse Square Root Unit
  • FReLU: Funnel ReLU
  • Y más de 40 adicionales...

Ver lista completa en: lib/grnexus_activations.py


Optimizers

SGD (Stochastic Gradient Descent)

model.compile(optimizer='sgd', learning_rate=0.01)

El optimizer más básico. Actualiza pesos en dirección opuesta al gradiente.

Momentum

model.compile(optimizer='momentum', learning_rate=0.01)

SGD con momento. Acelera convergencia y reduce oscilaciones.

Adam (Recomendado)

model.compile(optimizer='adam', learning_rate=0.001)

Adaptive Moment Estimation. Combina momentum con tasas de aprendizaje adaptativas.

RMSprop

model.compile(optimizer='rmsprop', learning_rate=0.001)

Root Mean Square Propagation. Bueno para RNNs.


Funciones de Pérdida

Categorical Cross-Entropy

model.compile(loss='categorical_crossentropy')

Para clasificación multiclase con one-hot encoding.

MSE (Mean Squared Error)

model.compile(loss='mse')

Para problemas de regresión.


💡 Ejemplos Prácticos

Ejemplo 1: Clasificación de Dígitos (MNIST-like)

from grnexus import GRNexus

# ============================================
# PASO 1: CREAR EL MODELO
# ============================================
# input_dim=784 porque las imágenes son 28x28 píxeles
# 28 × 28 = 784 valores de entrada
model = GRNexus(input_dim=784)

# ============================================
# PASO 2: CONSTRUIR LA ARQUITECTURA
# ============================================
# Primera capa oculta: 784 → 128 neuronas
# - ReLU: Función de activación que elimina valores negativos
# - he: Inicialización de pesos óptima para ReLU
model.add_dense(128, activation='ReLU', weight_init='he')

# Dropout: Desactiva aleatoriamente 20% de neuronas durante entrenamiento
# - Previene overfitting (memorización de datos)
# - Solo activo durante entrenamiento, no durante predicción
model.add_dropout(0.2)

# Segunda capa oculta: 128 → 64 neuronas
model.add_dense(64, activation='ReLU')
model.add_dropout(0.2)

# Capa de salida: 64 → 10 neuronas (una por cada dígito 0-9)
model.add_dense(10)

# Softmax: Convierte las 10 salidas en probabilidades que suman 1.0
# Ejemplo: [0.01, 0.02, 0.85, 0.03, ...] → "85% seguro que es un 2"
model.add_softmax()

# ============================================
# PASO 3: COMPILAR EL MODELO
# ============================================
model.compile(
    optimizer='adam',  # Adam: optimizer adaptativo, generalmente el mejor
    loss='categorical_crossentropy',  # Para clasificación multiclase
    learning_rate=0.01  # Qué tan grandes son los ajustes de pesos
)

# ============================================
# PASO 4: PREPARAR DATOS
# ============================================
# Ejemplo de cómo preparar datos (debes tener tus propios datos)
x_train = []  # Lista de imágenes aplanadas (cada una con 784 valores)
y_train = []  # Lista de etiquetas one-hot encoded

# Ejemplo: Agregar una imagen del dígito "3"
imagen_3 = [0.0] * 784  # Imagen de 28x28 aplanada
# ... (aquí irían los valores reales de los píxeles)

etiqueta_3 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]  # One-hot para el dígito 3

x_train.append(imagen_3)
y_train.append(etiqueta_3)

# ... agregar más ejemplos ...

# ============================================
# PASO 5: ENTRENAR
# ============================================
print("Iniciando entrenamiento...")
history = model.fit(
    x_train, y_train,
    epochs=10,      # Número de veces que ver todo el dataset
    batch_size=32,  # Procesar 32 imágenes a la vez
    verbose=1       # Mostrar progreso
)

# ============================================
# PASO 6: HACER PREDICCIONES
# ============================================
# Predecir una imagen de prueba
test_image = [...]  # Imagen de prueba 784D

# Obtener probabilidades para cada dígito
prediction = model.predict(test_image)
# Resultado: [0.01, 0.02, 0.85, 0.03, 0.01, 0.02, 0.01, 0.03, 0.01, 0.01]

# Encontrar el dígito con mayor probabilidad
digit = prediction.index(max(prediction))
confidence = max(prediction)

print(f"Dígito predicho: {digit}")
print(f"Confianza: {confidence:.1%}")
# Salida: "Dígito predicho: 2, Confianza: 85.0%"

# ============================================
# PASO 7: GUARDAR MODELO
# ============================================
model.save('mnist_model.nexus')
print("Modelo guardado exitosamente")

# ============================================
# PASO 8: CARGAR Y USAR MODELO GUARDADO
# ============================================
# En otra sesión, puedes cargar el modelo entrenado
loaded_model = GRNexus.load('mnist_model.nexus')
new_prediction = loaded_model.predict(test_image)

Resultados Esperados:

  • Precisión en entrenamiento: ~90-95% después de 10 épocas
  • Loss final: ~0.2-0.3
  • Tiempo de entrenamiento: Depende del tamaño del dataset

Ejemplo 2: Análisis de Sentimientos

from grnexus import GRNexus

# ============================================
# PREPARAR DATOS DE TEXTO
# ============================================
# Construir vocabulario (palabras únicas)
reviews = [
    "This movie is amazing and wonderful",
    "Terrible film, waste of time",
    "Great acting and beautiful scenes"
]

# Crear diccionario de palabras
vocab = {}
for review in reviews:
    words = review.lower().split()
    for word in words:
        if word not in vocab:
            vocab[word] = len(vocab)

vocab_size = len(vocab)
print(f"Vocabulario: {vocab_size} palabras")

# ============================================
# CONVERTIR TEXTO A VECTORES (BAG-OF-WORDS)
# ============================================
def text_to_vector(text, vocab):
    """
    Convierte texto en vector numérico
    Cada posición representa una palabra del vocabulario
    El valor es la frecuencia de esa palabra
    """
    vector = [0.0] * len(vocab)
    words = text.lower().split()
    
    # Contar ocurrencias
    for word in words:
        if word in vocab:
            vector[vocab[word]] += 1.0
    
    # Normalizar (convertir conteos a frecuencias)
    total = sum(vector)
    if total > 0:
        vector = [v / total for v in vector]
    
    return vector

# ============================================
# CREAR MODELO
# ============================================
model = GRNexus(input_dim=vocab_size)

# Arquitectura para análisis de sentimientos
model.add_dense(64, activation='ReLU')
model.add_dropout(0.3)  # Dropout más alto para texto
model.add_dense(32, activation='Swish')  # Swish: activación moderna
model.add_dense(2)  # 2 clases: Positivo/Negativo
model.add_softmax()

model.compile(
    optimizer='adam',
    loss='categorical_crossentropy',
    learning_rate=0.005  # Learning rate más bajo para mejor convergencia
)

# ============================================
# PREPARAR DATASET
# ============================================
x_train = [
    text_to_vector("This movie is amazing", vocab),
    text_to_vector("Terrible waste of time", vocab),
    # ... más ejemplos ...
]

y_train = [
    [0, 1],  # Positivo
    [1, 0],  # Negativo
    # ... más etiquetas ...
]

# ============================================
# ENTRENAR
# ============================================
model.fit(x_train, y_train, epochs=20, batch_size=16)

# ============================================
# PREDECIR SENTIMIENTO
# ============================================
new_review = "This film is absolutely fantastic"
vector = text_to_vector(new_review, vocab)
prediction = model.predict(vector)

sentiment = "Positivo" if prediction[1] > prediction[0] else "Negativo"
confidence = max(prediction)

print(f"Sentimiento: {sentiment} ({confidence:.1%} confianza)")

Resultados Esperados:

  • Precisión: ~80-90% con dataset pequeño
  • El modelo aprende asociaciones palabra-sentimiento
  • Palabras como "amazing", "great" → Positivo
  • Palabras como "terrible", "waste" → Negativo

Ejemplo 3: Clasificación Multiclase (Iris)

from grnexus import GRNexus

# ============================================
# DATASET IRIS
# ============================================
# 4 características: largo sépalo, ancho sépalo, largo pétalo, ancho pétalo
# 3 especies: Setosa (0), Versicolor (1), Virginica (2)

# Datos de ejemplo (valores reales del dataset Iris)
iris_data = [
    [5.1, 3.5, 1.4, 0.2, 0],  # Setosa
    [7.0, 3.2, 4.7, 1.4, 1],  # Versicolor
    [6.3, 3.3, 6.0, 2.5, 2],  # Virginica
    # ... más muestras ...
]

# ============================================
# NORMALIZAR DATOS
# ============================================
def normalize_iris(data):
    """Normaliza características al rango [0, 1]"""
    # Valores min/max del dataset Iris
    mins = [4.3, 2.0, 1.0, 0.1]
    maxs = [7.9, 4.4, 6.9, 2.5]
    
    normalized = []
    for i, val in enumerate(data[:4]):  # Solo las 4 características
        norm = (val - mins[i]) / (maxs[i] - mins[i])
        normalized.append(norm)
    
    return normalized

# ============================================
# PREPARAR DATOS
# ============================================
x_train = [normalize_iris(sample) for sample in iris_data]

y_train = []
for sample in iris_data:
    species = sample[4]  # Última columna es la especie
    one_hot = [0.0, 0.0, 0.0]
    one_hot[species] = 1.0
    y_train.append(one_hot)

# ============================================
# CREAR MODELO
# ============================================
model = GRNexus(input_dim=4)  # 4 características

# Arquitectura pequeña (dataset pequeño)
model.add_dense(16, activation='ReLU')
model.add_dense(8, activation='Swish')
model.add_dense(3)  # 3 especies
model.add_softmax()

model.compile(
    optimizer='adam',
    loss='categorical_crossentropy',
    learning_rate=0.01
)

# ============================================
# ENTRENAR
# ============================================
model.fit(x_train, y_train, epochs=100, batch_size=16)

# ============================================
# PREDECIR ESPECIE
# ============================================
# Nueva flor con medidas: [6.0, 3.0, 4.5, 1.5]
new_flower = normalize_iris([6.0, 3.0, 4.5, 1.5, 0])
prediction = model.predict(new_flower)

species_names = ["Setosa", "Versicolor", "Virginica"]
predicted_species = prediction.index(max(prediction))

print(f"Especie predicha: {species_names[predicted_species]}")
print(f"Probabilidades:")
for i, name in enumerate(species_names):
    print(f"  {name}: {prediction[i]:.1%}")

Resultados Esperados:

  • Precisión: ~95-98% (dataset Iris es muy separable)
  • El modelo aprende patrones en las medidas de las flores
  • Setosa es fácilmente distinguible (pétalos pequeños)
  • Versicolor y Virginica son más similares

Ejemplo 4: Regresión (Predicción de Precios)

from grnexus import GRNexus

# ============================================
# DATOS DE CASAS
# ============================================
# [habitaciones, baños, m², año, distancia_km, precio_miles]
housing_data = [
    [3, 2, 120, 2010, 5, 250],
    [4, 3, 180, 2015, 3, 380],
    [2, 1, 80, 1990, 10, 150],
    # ... más casas ...
]

# ============================================
# NORMALIZAR ENTRADA Y SALIDA
# ============================================
def normalize_features(features):
    """Normaliza las 5 características"""
    mins = [2, 1, 70, 1985, 1]
    maxs = [6, 5, 320, 2024, 15]
    
    return [(f - mins[i]) / (maxs[i] - mins[i]) 
            for i, f in enumerate(features)]

def normalize_price(price):
    """Normaliza precio a [0, 1]"""
    return (price - 100) / (750 - 100)

def denormalize_price(norm_price):
    """Convierte precio normalizado a valor real"""
    return norm_price * (750 - 100) + 100

# ============================================
# PREPARAR DATOS
# ============================================
x_train = [normalize_features(house[:5]) for house in housing_data]
y_train = [[normalize_price(house[5])] for house in housing_data]

# ============================================
# CREAR MODELO (REGRESIÓN)
# ============================================
model = GRNexus(input_dim=5)

# Arquitectura para regresión
model.add_dense(32, activation='ReLU')
model.add_dropout(0.2)
model.add_dense(16, activation='Swish')
model.add_dense(8, activation='ReLU')
model.add_dense(1)  # UNA sola neurona de salida (precio)
# NO usar Softmax en regresión

model.compile(
    optimizer='adam',
    loss='categorical_crossentropy',  # Usaremos MSE manualmente
    learning_rate=0.001  # Learning rate bajo para regresión
)

# ============================================
# ENTRENAR
# ============================================
print("Entrenando modelo de regresión...")
for epoch in range(150):
    total_loss = 0
    for i in range(0, len(x_train), 4):
        batch_x = x_train[i:i+4]
        batch_y = y_train[i:i+4]
        loss = model.train_on_batch(batch_x, batch_y)
        total_loss += loss
    
    if (epoch + 1) % 30 == 0:
        avg_loss = total_loss / (len(x_train) / 4)
        print(f"Epoch {epoch+1}/150 - loss: {avg_loss:.4f}")

# ============================================
# PREDECIR PRECIO
# ============================================
# Casa nueva: 3 hab, 2 baños, 140m², año 2012, 6km del centro
new_house = normalize_features([3, 2, 140, 2012, 6])
prediction_norm = model.predict(new_house)

# Desnormalizar para obtener precio real
predicted_price = denormalize_price(prediction_norm[0])

print(f"\nCasa: 3 hab, 2 baños, 140m², 2012, 6km centro")
print(f"Precio predicho: ${predicted_price:.0f}k")

# ============================================
# EVALUAR MODELO
# ============================================
errors = []
for house in housing_data:
    features = normalize_features(house[:5])
    real_price = house[5]
    
    pred_norm = model.predict(features)
    pred_price = denormalize_price(pred_norm[0])
    
    error = abs(real_price - pred_price)
    errors.append(error)

avg_error = sum(errors) / len(errors)
print(f"\nError promedio: ${avg_error:.1f}k")

Resultados Esperados:

  • Error promedio: $20-40k (depende del dataset)
  • El modelo aprende relaciones:
    • Más habitaciones → Precio más alto
    • Más metros cuadrados → Precio más alto
    • Más cerca del centro → Precio más alto
    • Más nuevo → Precio más alto

🎮 Tests Interactivos

GRNexus incluye 5 aplicaciones interactivas con Flet para probar las capacidades de la biblioteca:

1. test_digitos.py - Reconocimiento de Dígitos

python3 test/test_digitos.py
  • Dibuja dígitos con el mouse
  • Entrena la red en tiempo real
  • Visualiza probabilidades por clase
  • Guarda/carga modelos

2. test_sentiment.py - Análisis de Sentimientos

python3 test/test_sentiment.py
  • Analiza reseñas de películas
  • 30 reseñas reales de IMDb
  • Clasifica como positivo/negativo
  • Bag-of-words + red neuronal

3. test_iris.py - Clasificación Iris

python3 test/test_iris.py
  • Dataset clásico de ML
  • 90 muestras de 3 especies de flores
  • Sliders para ajustar características
  • Visualización de probabilidades

4. test_housing.py - Predicción de Precios

python3 test/test_housing.py
  • Regresión con datos reales
  • 42 casas con precios
  • Sliders para habitaciones, m², etc.
  • Compara precio real vs predicho

5. test_suite.py - Launcher Maestro

python3 test/test_suite.py
  • Ejecuta todos los tests desde una interfaz
  • Descripción de cada test
  • Ejecutar individual o todos juntos

🔍 Troubleshooting

Problema: "ModuleNotFoundError: No module named 'grnexus'"

Solución:

import sys
import os
sys.path.insert(0, os.path.abspath('path/to/GRNexus/python'))

Problema: "TypeError: layer.backward() takes 2 positional arguments but 3 were given"

Causa: Código desactualizado de GRNexus v1.0

Solución: Actualizar a GRNexus v2.0. El método backward ya no acepta learning_rate.

Problema: Pérdida (loss) no disminuye

Posibles causas:

  1. Learning rate muy alto → Reducir a 0.001 o menos
  2. Learning rate muy bajo → Aumentar a 0.01
  3. Datos no normalizados → Normalizar a rango [0, 1] o [-1, 1]
  4. Arquitectura inadecuada → Agregar más capas/neuronas
  5. Inicialización incorrecta → Usar 'he' para ReLU, 'xavier' para Sigmoid/Tanh

Problema: Overfitting (buena pérdida en entrenamiento, mala en validación)

Soluciones:

  • Agregar Dropout: model.add_dropout(0.2)
  • Reducir tamaño del modelo (menos neuronas/capas)
  • Aumentar tamaño del dataset
  • Agregar regularización

Problema: Predicciones siempre retornan la misma clase

Causas:

  • Clases desbalanceadas en el dataset
  • Learning rate muy alto provocando divergencia
  • Pesos no inicializados correctamente

Soluciones:

  • Balancear clases en el dataset
  • Reducir learning rate
  • Verificar que compile() fue llamado antes de entrenar

Problema: "IndexError: list index out of range" durante entrenamiento

Causa: Dimensiones incorrectas en los datos

Solución:

  • Verificar que x_train tenga dimensión input_dim
  • Verificar que y_train sea one-hot encoded con num_classes elementos
  • Ejemplo: Si 3 clases, usar [[1,0,0], [0,1,0], [0,0,1]]

📊 Mejores Prácticas

1. Preparación de Datos

# Normalizar datos
def normalize(data):
    min_val = min(data)
    max_val = max(data)
    return [(x - min_val) / (max_val - min_val) for x in data]

# One-hot encoding
def one_hot(label, num_classes):
    encoding = [0.0] * num_classes
    encoding[label] = 1.0
    return encoding

2. Arquitectura

  • Clasificación simple: 1-2 capas ocultas
  • Clasificación compleja: 3-5 capas con Dropout
  • Regresión: 2-4 capas sin Softmax final

3. Hiperparámetros

Tamaño Dataset Batch Size Learning Rate Epochs
< 1000 16-32 0.01 50-100
1000-10000 32-64 0.01-0.001 20-50
> 10000 64-128 0.001 10-30

4. Monitoreo

history = model.fit(x_train, y_train, epochs=10, verbose=1)

# Graficar pérdida por época
import matplotlib.pyplot as plt
plt.plot(history['loss'])
plt.xlabel('Época')
plt.ylabel('Pérdida')
plt.title('Curva de Entrenamiento')
plt.show()

Hecho con ❤️ por el equipo de GRNexus

GitHubDocumentaciónExamples

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grnexus-0.1.7.tar.gz (313.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grnexus-0.1.7-py3-none-any.whl (211.9 kB view details)

Uploaded Python 3

File details

Details for the file grnexus-0.1.7.tar.gz.

File metadata

  • Download URL: grnexus-0.1.7.tar.gz
  • Upload date:
  • Size: 313.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for grnexus-0.1.7.tar.gz
Algorithm Hash digest
SHA256 96c53017db3296f6d70754b0ca3351649ff32475d3f1f582e22edfc897d47ce8
MD5 fe7461100fee1c82eededd1935b27459
BLAKE2b-256 f0f5d6c86df07f46cf1634ccfbf94b92549c524a34ab854d78b46e96ba5809d0

See more details on using hashes here.

File details

Details for the file grnexus-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: grnexus-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 211.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for grnexus-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 1e9bf457ef014cdb9e51d71bb667a5c2a72ad1eda01723b484da055db3774ef0
MD5 35028193702b9f1f0ec81fe53d96e2ae
BLAKE2b-256 77789cd8022f1b35fb1193111dbcfbecdb64904562875385367da23e6ddf5d92

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page