Este proyetco lo relice con el objetrivo de aprender Clojure de forma mas practicca y visual creando una red neuronal basica pero desde el inicio que detecte numeros. Tratandod e no usar las librerias basandome en un poryetco que vi en Redit
El objetivo no es solo ceear la red que funcione, sino quise aprovechar y entender de froma clara que es y que hace que enfocndome en :
- La sintaxis y el estilo funcional de Clojure comparado con Python
- Cómo se implementa una red neuronal feedforward básica y como funciona en clojure
- Cómo conectar todo en un flujo correcto de datos, entrenamiento y visualizaciónde los resulatdos.
La idea central es hacer que el red pueda aprender que tenga cobnsitencia y que se peuda ver
- Usar una red neuronal sencilla para tener un hilo conductor claro.
- Implementar todo a mano (menos visualizacion): generación de datos, operaciones matemáticas, entrenamiento.
- Mantener el código lo suficientemente simple como para poder leerlo casi línea por línea y razonar sobre lo que pasa en cada etapa y por que.
El resultado es un proyecto pequeño, pero con el ciclo completo:
- Datos sintéticos.
- Modelo 2 → 8 → 2.
- Entrenamiento con mini-batches.
- Métricas de evaluación.
- Visualización de la frontera de decisión.
Durante el desarrollo del proyecto se utilizaron dos apoyos principales ya que no hay mucha info como para otros lemguajes tube que crear el rodamap de estudio para Clojure en NotebookLM:
-
Serie de videos de 3Blue1Brown sobre redes neuronales
Se tomó como referencia la forma en que explica:- La interpretación geométrica de los pesos.
- El papel de las funciones de activación.
- La idea de ajustar parámetros mediante gradientes.
-
Cuaderno en NotebookLM: “Clojure Fundamentals, Tools, NN”
En este cuaderno se recopilaron:- Conceptos básicos de Clojure (colecciones, funciones, namespaces).
- Notas sobre herramientas: Clojure CLI, deps.edn, uso de REPL.
- Apuntes sobre cómo organizar el código de la red en módulos.
Espacio para captura del cuaderno:
Estructura principal de archivos:
clj-RedNNTest/
├─ deps.edn
├─ src/
│ └─ nn/
│ ├─ core.clj ; Punto de entrada y ciclo de entrenamiento
│ ├─ data.clj ; Generación y normalización de datos sintéticos
│ ├─ math.clj ; Operaciones matemáticas y funciones de activación
│ ├─ model.clj ; Definición de la red y backpropagation
│ ├─ visualization.clj ; Generación de la frontera de decisión en SVG
│ └─ rng.clj ; Generador de números aleatorios reproducible
└─ images/
└─ decision_boundary.svg ; Fichero generado con la frontera de decisión
Cada archivo:
data.cljdefine cómo se generan y preparan los datos.math.cljconcentra las funciones matemáticas de lo que es bajo nivel.model.cljdescribe la red neuronal y el algoritmo de entrenamiento.core.cljse maneja todo el flujo: datos → modelo → métricas → visualización.visualization.cljcrea una imagen SVG de la frontera de decisión.
- Tipo de red: feedforward para clasificación binaria.
- Arquitectura: 2 → 8 → 2
- 2 entradas.
- 8 neuronas en la capa oculta.
- 2 neuronas de salida (one-hot para las dos clases).
- Función de activación: sigmoide en ambas capas.
- Inicialización de pesos: valores aleatorios en el rango [-0.5, 0.5].
Parámetros por defecto del entrenamiento:
- Épocas: 20
- Learning rate: 0.5
- Batch size: 16
- Puntos por clase: 400
- Método de optimización: mini-batch Stochastic Gradient Descent.
- Backpropagation implementado de forma explícita:
- Cálculo manual de gradientes para cada capa.
- Acumulación de gradientes por mini-batch.
- Función de pérdida: Mean Squared Error (MSE).
- División del dataset:
- 80 % para entrenamiento.
- 20 % para prueba.
- Métricas:
- Exactitud (accuracy) en el conjunto de prueba.
- MSE en el conjunto de prueba.
- Producto punto.
- Suma y resta de vectores.
- Multiplicación escalar.
- Función sigmoide y su derivada.
- Función ReLU y su derivada (preparadas para futuras extensiones).
- Utilidades para aplicar funciones elemento a elemento sobre vectores.
- Generación de dos clusters con distribución aproximadamente normal.
- Uso de un método tipo Box-Muller para obtener puntos gaussianos.
- Normalización de las coordenadas al rango [0, 1] mediante min-max scaling.
- Etiquetas codificadas en one-hot para las dos clases.
- Se construye una cuadrícula de puntos en el plano de entrada.
- Para cada punto del grid se evalúa la red y se colorea en función de la probabilidad.
- Paleta de colores:
- Azul para la clase 0.
- Naranja para la clase 1.
- Se dibujan:
- Los puntos del dataset.
- La frontera de decisión implícita en los cambios de color.
- Semilla fija:
1337. - Funciones auxiliares para:
- Generar números en [0, 1).
- Generar pesos iniciales en [-0.5, 0.5].
- Al mantener la misma semilla es posible repetir los experimentos y obtener los mismos resultados.
El flujo lógico del programa es el siguiente:
-
Generación de datos
Se crean dos grupos de puntos en el plano, cada uno asociado a una clase distinta. -
Normalización y preparación
- Se lleva cada característica al rango [0, 1].
- Se construyen las etiquetas en formato one-hot.
-
División entrenamiento / prueba
- 80 % de los datos para entrenar.
- 20 % para evaluar.
-
Inicialización de la red
Se construye la arquitectura 2 → 8 → 2 con pesos aleatorios. -
Entrenamiento
- Se recorren los datos durante 20 épocas.
- En cada época se procesan mini-batches de tamaño 16.
- Se calculan y aplican los gradientes mediante backpropagation.
-
Evaluación
En cada época se reportan:- Exactitud en el conjunto de prueba.
- MSE en el conjunto de prueba.
-
Visualización
Al finalizar el entrenamiento se genera el archivoimages/decision_boundary.svgcon la frontera de decisión.
- Java instalado (JDK reciente).
- Clojure CLI (
clj) instalado.
Desde la carpeta raíz del proyecto:
clj -M:runEste comando:
- Genera los datos.
- Entrena la red durante 20 épocas.
- Muestra en la terminal las métricas por época.
- Crea el archivo
images/decision_boundary.svg.
Si el alias :run no estuviera disponible en deps.edn, se puede ejecutar también con:
clj -M -m nn.corePara experimentar de forma interactiva:
-
Iniciar un REPL en la raíz del proyecto:
clj
-
Cargar el namespace principal:
(require '[nn.core :as nn])
-
Entrenar el modelo manualmente:
(def model (nn/train 20 0.5 16 400))
No quise complicra mucho el aprendizaje si no entender mas bien comos erealiza el problema es razonablemente separable y se espera:
- Exactitud en el conjunto de prueba por encima de 0.95.
la forma visual de entender el proyecto es la siguiente:
-
rng.clj
Ver cómo se define la semilla y se generan números aleatorios reproducibles. -
data.clj
Revisar cómo se construyen los puntos de cada clase y cómo se normalizan. -
math.clj
Entender las primitivas matemáticas utilizadas por el modelo: operaciones vectoriales, sigmoide, derivadas. -
model.clj
Estudiar cómo se representa la red, cómo se ejecuta el forward pass y cómo se calculan los gradientes para backpropagation. -
core.clj
Ver el ciclo completo de entrenamiento, las llamadas a las métricas y la integración con la visualización. -
visualization.clj
Analizar cómo se convierte la salida del modelo en una imagen SVG de la frontera de decisión.

