NeuralNetworkCPP — Red neuronal en C++ (from scratch)
NeuralNetworkCPP
Este proyecto es una pequeña librería de redes neuronales escrita en C++ “from scratch”, hecha principalmente para aprender.
En ese momento estaba estudiando los fundamentos de deep learning y también quería un proyecto práctico en C++ que me obligara a implementar por mi cuenta la parte matemática y el bucle de entrenamiento completo.
Por qué lo construí
Muchas veces se puede entrenar una red neuronal sin pensar demasiado en lo que pasa “por debajo”.
Aquí el objetivo era justo el contrario: implementar todo el pipeline (forward pass → loss → backprop → actualización de parámetros) y ver cómo decisiones pequeñas (funciones de activación, learning rate, batch size, etc.) influyen en el entrenamiento.
Esto es intencionalmente una “learning library”, no un framework listo para producción. Está enfocada en claridad y experimentación.
Cómo funciona (tech + algo)
La librería implementa una red feedforward básica con varias capas fully-connected, donde pesos y sesgos se inicializan de forma aleatoria.
Soporta funciones de activación comunes como ReLU, Sigmoid y TanH, configurables por capa.
El entrenamiento es un descenso de gradiente clásico:
- La propagación hacia delante guarda en caché tensores intermedios (Z / A) para reutilizarlos durante la backprop.
- La backprop calcula gradientes capa por capa y aplica la actualización: y , donde es el learning rate.
- La loss usada en el bucle de entrenamiento es una log loss calculada a partir de outputs/targets (con un epsilon pequeño para estabilidad numérica).
También hay un modo opcional de dropout (con keep probability) durante el entrenamiento para reducir overfitting.
Y, por el lado de rendimiento / experimentación, el proyecto incluye una ruta CUDA opcional para acelerar operaciones matriciales en GPUs NVIDIA.
Demo de reconocimiento de dígitos (MNIST)
Para validar que la librería realmente aprende, construí un ejemplo de reconocimiento de dígitos usando imágenes de MNIST.
La demo carga 55 000 imágenes de entrenamiento y 5 000 de test, las normaliza y construye targets one-hot para los dígitos del 0 al 9.
En esta ejecución, la arquitectura es un MLP simple: 784 → 128 → 128 → 128 → 10, entrenado con learning rate 0.1 durante 10 epochs y batch size 512.
Las capas ocultas usan ReLU, y la capa de salida usa Sigmoid en esta implementación.
Durante el entrenamiento activé dropout con keepProb = 0.7.
UI de entrenamiento (terminal)
También dediqué tiempo a la UX en terminal porque hace el proyecto más “vivo”:
- Una barra de progreso personalizada se usa para cargar el dataset y para cada epoch.
- Los valores de loss se muestran de forma regular durante el entrenamiento.

Gráficos de accuracy (terminal)
Al final del entrenamiento, la demo imprime:
- Accuracy global en test set y en training set.
- Un gráfico por dígito: barra verde para aciertos y barra roja para errores, con los contadores al lado.


Resultados (10 epochs)
En este experimento obtuve 94.32% de accuracy en el test set y 95.65% en el training set.
Una diferencia pequeña entre train y test suele indicar un overfitting leve, pero nada exagerado (el modelo aprende características útiles y generaliza bastante bien).
Además, teniendo en cuenta que es una red fully-connected simple (sin convoluciones) y con un bucle de entrenamiento implementado desde cero, fue un resultado muy satisfactorio para solo 10 epochs.
Qué aprendí
Este proyecto me obligó a entender la backprop de manera muy concreta (dimensiones, errores de broadcasting, flujo de gradientes y lo fácil que es “romper” el entrenamiento sin darse cuenta).
También hizo muy real la parte de rendimiento en ML: layout de memoria, coste de multiplicación matricial, batching y por qué las librerías invierten tanto en kernels optimizados (y por qué CUDA es prácticamente un mundo aparte).
A nivel de tooling, construir una CLI con feedback visual (barras de progreso + gráficos) me recordó lo importante que es la usabilidad, incluso para “solo un programa de terminal”.
Qué mejoraría después
Si volviera a este proyecto hoy, algunas mejoras estarían arriba de la lista:
- Cambiar la salida a un enfoque más estándar Softmax + cross-entropy para clasificación multiclase.
- Añadir optimizadores mejores (Adam / RMSProp) y quizá un schedule de learning rate.
- Añadir más regularización y mejor tracking de experimentos (export de métricas, matriz de confusión, etc.).
- Ir más allá de capas densas (manteniéndolo simple) o compararlo con un CNN pequeño para mostrar claramente la diferencia.
Si quieres explorar el código, el repo está aquí: NeuralNetworkCPP on GitHub.
