TechLead
Intermedio
35 min
Guía completa

Redes Neuronales

Comprende redes neuronales, neuronas, capas y cómo procesan información

¿Qué son las redes neuronales?

Las redes neuronales son sistemas de cómputo inspirados en las redes neuronales biológicas del cerebro. Están formadas por nodos interconectados (neuronas) organizados en capas que pueden aprender a realizar tareas a partir de ejemplos, sin reglas específicas programadas.

🧠 Inspiración biológica:

Así como las neuronas del cerebro reciben señales, las procesan y las transmiten, las neuronas artificiales reciben entradas, aplican transformaciones y producen salidas.

Arquitectura de una red neuronal

📥 Capa de entrada

Recibe los datos crudos (features). Cada neurona representa una característica.

Neurona 1
Neurona 2
Neurona 3

🔄 Capas ocultas

Procesan y transforman los datos. Pueden tener múltiples capas (deep learning).

Neurona 1
Neurona 2
Neurona 3
Neurona 4

📤 Capa de salida

Produce la predicción o clasificación final.

Salida 1
Salida 2

Cómo funciona una neurona

Componentes de una neurona:

  1. 1. Entradas (x): Datos de la capa anterior o características crudas
  2. 2. Pesos (w): Parámetros aprendibles que determinan la importancia de las entradas
  3. 3. Sesgo (b): Parámetro de desplazamiento aprendible
  4. 4. Suma ponderada: z = (w₁×x₁ + w₂×x₂ + ... + wₙ×xₙ) + b
  5. 5. Función de activación: Introduce no linealidad, a = f(z)
  6. 6. Salida: Pasa a la siguiente capa
// Single Neuron Implementation
class Neuron {
  constructor(inputSize) {
    // Initialize weights randomly
    this.weights = Array(inputSize).fill(0).map(() => Math.random() * 2 - 1);
    this.bias = Math.random() * 2 - 1;
  }

  // Activation functions
  sigmoid(x) {
    return 1 / (1 + Math.exp(-x));
  }

  relu(x) {
    return Math.max(0, x);
  }

  tanh(x) {
    return Math.tanh(x);
  }

  // Forward pass
  forward(inputs, activationFunc = 'sigmoid') {
    // Calculate weighted sum
    const z = inputs.reduce((sum, input, i) => {
      return sum + input * this.weights[i];
    }, this.bias);

    // Apply activation function
    let activation;
    switch(activationFunc) {
      case 'relu':
        activation = this.relu(z);
        break;
      case 'tanh':
        activation = this.tanh(z);
        break;
      default:
        activation = this.sigmoid(z);
    }

    return { output: activation, weightedSum: z };
  }
}

// Example usage
const neuron = new Neuron(3);
console.log("Neuron weights:", neuron.weights);
console.log("Neuron bias:", neuron.bias);

const inputs = [0.5, 0.8, 0.2];
const result = neuron.forward(inputs, 'sigmoid');
console.log("Input:", inputs);
console.log("Weighted sum:", result.weightedSum.toFixed(4));
console.log("Output:", result.output.toFixed(4));

Funciones de activación visualizadas

Sigmoid

σ(x) = 1/(1+e⁻ˣ)

Rango: (0, 1)

Uso: Clasificación binaria

Salida: Similar a probabilidad

ReLU

f(x) = max(0, x)

Rango: [0, ∞)

Uso: Capas ocultas

Salida: Rápida de calcular

Tanh

f(x) = (eˣ-e⁻ˣ)/(eˣ+e⁻ˣ)

Rango: (-1, 1)

Uso: Capas ocultas

Salida: Centrada en cero

Implementación completa de una red neuronal

Construyamos una red neuronal multicapa desde cero:

// Full Neural Network Implementation
class NeuralNetwork {
  constructor(inputSize, hiddenSize, outputSize, learningRate = 0.1) {
    this.learningRate = learningRate;
    
    // Initialize weights for hidden layer
    this.weightsInputHidden = this.initializeWeights(inputSize, hiddenSize);
    this.biasHidden = Array(hiddenSize).fill(0);
    
    // Initialize weights for output layer
    this.weightsHiddenOutput = this.initializeWeights(hiddenSize, outputSize);
    this.biasOutput = Array(outputSize).fill(0);
  }

  initializeWeights(rows, cols) {
    return Array(rows).fill(0).map(() =>
      Array(cols).fill(0).map(() => Math.random() * 2 - 1)
    );
  }

  sigmoid(x) {
    return 1 / (1 + Math.exp(-x));
  }

  sigmoidDerivative(x) {
    return x * (1 - x);
  }

  // Forward propagation
  forward(inputs) {
    // Input to hidden layer
    this.hidden = [];
    for (let i = 0; i < this.weightsInputHidden[0].length; i++) {
      let sum = this.biasHidden[i];
      for (let j = 0; j < inputs.length; j++) {
        sum += inputs[j] * this.weightsInputHidden[j][i];
      }
      this.hidden.push(this.sigmoid(sum));
    }

    // Hidden to output layer
    this.output = [];
    for (let i = 0; i < this.weightsHiddenOutput[0].length; i++) {
      let sum = this.biasOutput[i];
      for (let j = 0; j < this.hidden.length; j++) {
        sum += this.hidden[j] * this.weightsHiddenOutput[j][i];
      }
      this.output.push(this.sigmoid(sum));
    }

    return this.output;
  }

  // Backward propagation (training)
  backward(inputs, target) {
    // Calculate output layer error
    const outputErrors = this.output.map((out, i) => target[i] - out);
    const outputDeltas = outputErrors.map((error, i) =>
      error * this.sigmoidDerivative(this.output[i])
    );

    // Calculate hidden layer error
    const hiddenErrors = this.hidden.map((_, i) => {
      let error = 0;
      for (let j = 0; j < this.output.length; j++) {
        error += outputDeltas[j] * this.weightsHiddenOutput[i][j];
      }
      return error;
    });
    const hiddenDeltas = hiddenErrors.map((error, i) =>
      error * this.sigmoidDerivative(this.hidden[i])
    );

    // Update weights and biases (hidden to output)
    for (let i = 0; i < this.weightsHiddenOutput.length; i++) {
      for (let j = 0; j < this.weightsHiddenOutput[i].length; j++) {
        this.weightsHiddenOutput[i][j] +=
          this.learningRate * outputDeltas[j] * this.hidden[i];
      }
    }
    for (let i = 0; i < this.biasOutput.length; i++) {
      this.biasOutput[i] += this.learningRate * outputDeltas[i];
    }

    // Update weights and biases (input to hidden)
    for (let i = 0; i < this.weightsInputHidden.length; i++) {
      for (let j = 0; j < this.weightsInputHidden[i].length; j++) {
        this.weightsInputHidden[i][j] +=
          this.learningRate * hiddenDeltas[j] * inputs[i];
      }
    }
    for (let i = 0; i < this.biasHidden.length; i++) {
      this.biasHidden[i] += this.learningRate * hiddenDeltas[i];
    }
  }

  // Train the network
  train(trainingData, epochs) {
    for (let epoch = 0; epoch < epochs; epoch++) {
      let totalLoss = 0;
      
      for (const data of trainingData) {
        const output = this.forward(data.input);
        this.backward(data.input, data.target);
        
        // Calculate loss (MSE)
        const loss = output.reduce((sum, out, i) =>
          sum + Math.pow(data.target[i] - out, 2), 0) / output.length;
        totalLoss += loss;
      }
      
      if (epoch % 1000 === 0) {
        console.log(`Epoch ${epoch}: Loss = ${(totalLoss / trainingData.length).toFixed(6)}`);
      }
    }
  }

  predict(inputs) {
    const output = this.forward(inputs);
    return output.map(o => Math.round(o));
  }
}

// Example: XOR Problem (not linearly separable)
const trainingData = [
  { input: [0, 0], target: [0] },
  { input: [0, 1], target: [1] },
  { input: [1, 0], target: [1] },
  { input: [1, 1], target: [0] }
];

console.log("Training Neural Network on XOR problem...");
const nn = new NeuralNetwork(2, 4, 1, 0.5);
nn.train(trainingData, 10000);

console.log("\nTesting:");
trainingData.forEach(data => {
  const prediction = nn.forward(data.input);
  console.log(`Input: [${data.input}] → Prediction: ${prediction[0].toFixed(4)} (Target: ${data.target[0]})`);
});

🎯 Por qué XOR es importante:

XOR no se puede resolver con una sola neurona (clasificador lineal). Requiere al menos una capa oculta, mostrando el poder de las redes neuronales para aprender patrones no lineales.

Proceso de entrenamiento: backpropagation

Cómo aprenden las redes neuronales:

1

Paso hacia adelante

La entrada fluye por la red y produce una salida

2

Calcular pérdida

Compara la predicción con el objetivo real

3

Paso hacia atrás

El error se propaga hacia atrás por las capas

4

Actualizar pesos

Ajusta los pesos con descenso de gradiente

5

Repetir

Iterar hasta que la red converja

Arquitecturas comunes de redes neuronales

Red neuronal feedforward (FNN)

La información fluye en una sola dirección de entrada a salida.

Casos de uso: Clasificación, regresión, reconocimiento de patrones

Red neuronal convolucional (CNN)

Especializada en datos tipo grid (imágenes).

Casos de uso: Reconocimiento de imágenes, detección de objetos, visión por computadora

Red neuronal recurrente (RNN)

Tiene memoria de entradas previas (bucles de retroalimentación).

Casos de uso: Generación de texto, series temporales, reconocimiento de voz

Transformer

Usa mecanismo de atención para procesar datos secuenciales.

Casos de uso: Modelos de lenguaje (GPT), traducción, PLN

💡 Conclusiones clave

  • Las redes neuronales se inspiran en neuronas biológicas
  • Capas: Entrada, ocultas (procesamiento) y salida
  • Las neuronas aplican pesos, sesgo y funciones de activación
  • Backpropagation es cómo las redes aprenden de errores
  • Las funciones de activación introducen no linealidad (Sigmoid, ReLU, Tanh)
  • Múltiples capas permiten aprender patrones complejos no lineales

📚 Siguientes pasos

Continúa tu recorrido en redes neuronales:

  • Deep Learning: Redes con muchas capas ocultas
  • Redes convolucionales: Especializadas en procesamiento de imágenes
  • Múltiples capas permiten aprender patrones complejos no lineales

📚 Siguientes pasos

Continúa tu recorrido en redes neuronales:

  • Deep Learning: Redes con muchas capas ocultas
  • Redes convolucionales: Especializadas en procesamiento de imágenes
  • Técnicas de optimización: Adam, RMSprop, scheduling de learning rate