Skip to content

Qué es una Neurona

Las redes neuronales artificiales son modelos matemáticos inspirados en el sistema nervioso biológico.

En una red neuronal, las neuronas son los bloques de construcción fundamentales. Estas neuronas artificiales son unidades computacionales que procesan información recibida a través de entradas y, en función de su comportamiento, generan una salida.

Las neuronas artificiales se utilizan en las redes neuronales para modelar la manera en que las neuronas biológicas procesan información.

En las redes neuronales, las neuronas artificiales tienen una entrada, que se multiplica por un peso, y se les aplica una función de activación.

La suma de estas entradas ponderadas y la función de activación dan como resultado una salida.

La estructura básica de una neurona consta de tres componentes principales:

  1. Entrada: los datos se ingresan en la neurona a través de una o más entradas.
  2. Peso: Cada entrada está asociada con un peso que representa la importancia de esa entrada.
  3. Función de activación: esta función define cómo se procesa la entrada y se genera una salida.

La entrada y los pesos se multiplican y luego se suman para producir la suma ponderada.

El resultado de la suma ponderada se pasa a través de la función de activación, que genera la salida de la neurona. La función de activación puede ser una función lineal o no lineal.

En una red neuronal, las neuronas están organizadas en capas. La capa de entrada recibe los datos y las capas ocultas y la capa de salida procesan la información.

En una red neuronal completamente conectada, cada neurona en una capa está conectada a cada neurona en la siguiente capa.

Ejemplos en Delphi de Neuronas Artificiales para cada tipo de Red

Feedforward Neural Networks

Ejemplo de cómo crear una neurona en Delphi para una red neuronal del tipo “Feedforward Neural Networks“:

type
  TNeuron = class
  private
    FWeights: array of Double;
    FInput: array of Double;
    FOutput: Double;
    FActivationFunction: TActivationFunction;
  public
    constructor Create(WeightCount: Integer; ActivationFunction: TActivationFunction);
    procedure RandomizeWeights;
    function CalculateOutput: Double;
    procedure AdjustWeights(Error: Double; LearningRate: Double);
    property Weights: array of Double read FWeights;
    property Input: array of Double read FInput write FInput;
    property Output: Double read FOutput;
  end;

{ TNeuron }

constructor TNeuron.Create(WeightCount: Integer; ActivationFunction: TActivationFunction);
begin
  SetLength(FWeights, WeightCount);
  FActivationFunction := ActivationFunction;
end;

procedure TNeuron.RandomizeWeights;
var
  i: Integer;
begin
  for i := 0 to Length(FWeights) - 1 do
    FWeights[i] := Random - 0.5;
end;

function TNeuron.CalculateOutput: Double;
var
  NetInput: Double;
  i: Integer;
begin
  NetInput := 0;
  for i := 0 to Length(FWeights) - 1 do
    NetInput := NetInput + FWeights[i] * FInput[i];
  FOutput := FActivationFunction(NetInput);
  Result := FOutput;
end;

procedure TNeuron.AdjustWeights(Error, LearningRate: Double);
var
  i: Integer;
begin
  for i := 0 to Length(FWeights) - 1 do
    FWeights[i] := FWeights[i] + LearningRate * Error * FInput[i];
end;

Este código define una clase TNeuron que representa una neurona en una red neuronal de tipo “Feedforward Neural Networks”.

La neurona tiene un número variable de pesos que se inicializan aleatoriamente, un conjunto de entradas, una salida y una función de activación.

Los métodos de la clase se utilizan para calcular la salida de la neurona, ajustar los pesos de la neurona y para inicializar los pesos de la neurona.

Recurrent Neural Networks

Ejemplo de cómo crear una neurona en Delphi para una red neuronal del tipo “Recurrent Neural Networks“:

unit RecurrentNeuron;

interface

type
  TRecurrentNeuron = class
  private
    FWeights: TArray<Double>;
    FPreviousOutput: Double;
    FActivationFunc: TFunc<Double, Double>;
  public
    constructor Create(inputSize: Integer);
    function ComputeOutput(input: TArray<Double>): Double;
  end;

implementation

uses
  Math;

constructor TRecurrentNeuron.Create(inputSize: Integer);
begin
  // Initialize weights randomly
  SetLength(FWeights, inputSize + 1); // +1 for bias weight
  for var i := 0 to Length(FWeights) - 1 do
    FWeights[i] := Random - 0.5; // Random value between -0.5 and 0.5

  // Initialize previous output to 0
  FPreviousOutput := 0;

  // Set activation function to sigmoid
  FActivationFunc := function(x: Double): Double
    begin
      Result := 1 / (1 + Exp(-x));
    end;
end;

function TRecurrentNeuron.ComputeOutput(input: TArray<Double>): Double;
var
  weightedSum: Double;
begin
  // Calculate weighted sum of inputs and previous output
  weightedSum := FWeights[0]; // bias weight
  for var i := 0 to Length(input) - 1 do
    weightedSum := weightedSum + FWeights[i + 1] * input[i];
  weightedSum := weightedSum + FWeights[Length(FWeights) - 1] * FPreviousOutput;

  // Apply activation function to get output
  Result := FActivationFunc(weightedSum);

  // Save output as previous output for next iteration
  FPreviousOutput := Result;
end;

end.

En una red neuronal recurrente, las neuronas tienen conexiones hacia atrás en el tiempo, lo que les permite mantener información a lo largo del tiempo. En este ejemplo, la neurona recurrente tiene una conexión desde su salida anterior a su entrada actual.

La neurona recurrente tiene un constructor que inicializa los pesos aleatoriamente, establece la función de activación y la salida anterior en cero.

El método ComputeOutput calcula la suma ponderada de las entradas y la salida anterior, y aplica la función de activación para obtener la salida actual.

La salida actual se guarda como la salida anterior para la siguiente iteración.

Es importante tener en cuenta que, en una red neuronal recurrente, el cálculo de la salida depende de la salida anterior, lo que puede hacer que la red sea más difícil de entrenar.

Sin embargo, las redes neuronales recurrentes son útiles en aplicaciones que involucran secuencias de datos, como el procesamiento del lenguaje natural y la predicción de series temporales.

Convolutional Neural Networks

Ejemplo de cómo crear una neurona en Delphi para una red neuronal del tipo “Convolutional Neural Networks“:

type
  TConvNeuron = class(TNeuron)
  public
    constructor Create(AInputSize: integer; AOutputSize: integer; AKernelSize: integer);
    procedure SetInput(AInput: TMatrix); override;
    function GetOutput: TMatrix; override;
  private
    FKernel: TMatrix;
    FInput: TMatrix;
    FOutput: TMatrix;
    FKernelSize: integer;
  end;

constructor TConvNeuron.Create(AInputSize, AOutputSize, AKernelSize: integer);
begin
  inherited Create(AInputSize, AOutputSize);
  FKernelSize := AKernelSize;
  RandomizeWeights;
  FKernel := TMatrix.Create(AKernelSize, AKernelSize);
  FInput := TMatrix.Create(AInputSize, AInputSize);
  FOutput := TMatrix.Create(AOutputSize, AOutputSize);
end;

procedure TConvNeuron.SetInput(AInput: TMatrix);
var
  i, j, x, y: integer;
begin
  inherited SetInput(AInput);
  FInput.CopyFrom(AInput);

  for i := 0 to FOutput.Rows - 1 do
  begin
    for j := 0 to FOutput.Cols - 1 do
    begin
      FOutput.SetValue(i, j, 0);
      for x := 0 to FKernelSize - 1 do
      begin
        for y := 0 to FKernelSize - 1 do
        begin
          FOutput.SetValue(i, j, FOutput.GetValue(i, j) + FKernel.GetValue(x, y) * FInput.GetValue(i + x, j + y));
        end;
      end;
    end;
  end;
end;

function TConvNeuron.GetOutput: TMatrix;
begin
  Result := FOutput;
end;

En este caso, la neurona es de tipo convolucional, lo que significa que se aplica una operación de convolución sobre los datos de entrada para producir la salida.

En este ejemplo, la operación de convolución se realiza utilizando una matriz de kernel que se ajusta a los datos de entrada.

La neurona se inicializa con un tamaño de entrada, un tamaño de salida y un tamaño de kernel. El tamaño de entrada se refiere al tamaño de la matriz de entrada, el tamaño de salida se refiere al tamaño de la matriz de salida de la neurona y el tamaño de kernel se refiere al tamaño de la matriz de kernel que se utiliza para la convolución.

En el método SetInput, se realiza la convolución utilizando la matriz de entrada y la matriz de kernel. La matriz de salida se actualiza en consecuencia. En el método GetOutput, se devuelve la matriz de salida.

Feedback Neural Networks

Ejemplo de cómo crear una neurona en Delphi para una red neuronal del tipo “Feedback Neural Networks“:

type
  TRNNNeuron = class(TNeuron)
  private
    FPrevOutput: Double;
  public
    procedure FeedForward; override;
    procedure BackPropagate; override;
  end;

{ TRNNNeuron }

procedure TRNNNeuron.FeedForward;
var
  i: Integer;
begin
  inherited;
  FOutput := FActivationFunction(FInput + FPrevOutput);
  for i := 0 to FOutputConnections.Count - 1 do
    TRNNNeuron(FOutputConnections[i].ToNeuron).FPrevOutput := FOutput;
end;

procedure TRNNNeuron.BackPropagate;
var
  i: Integer;
  error: Double;
begin
  inherited;
  error := 0;
  for i := 0 to FOutputConnections.Count - 1 do
    error := error + FOutputConnections[i].ToNeuron.Delta * FOutputConnections[i].Weight;
  FDelta := FOutput * (1 - FOutput) * error;
end;

En este ejemplo, la neurona TRNNNeuron extiende la clase TNeuron que mostramos anteriormente. La única diferencia es que la neurona RNN tiene una propiedad adicional FPrevOutput que mantiene el valor de la salida de la neurona en la iteración anterior.

En la función FeedForward, la salida de la neurona se calcula como la función de activación aplicada a la suma de la entrada y la salida de la iteración anterior. Luego, se actualiza FPrevOutput de todas las neuronas de salida a las que está conectada.

En la función BackPropagate, el cálculo de error se hace igual que en la neurona de la red de alimentación directa. La única diferencia es que se utiliza FPrevOutput en lugar de FInput en el cálculo de la salida de la neurona.

Long Short-Term Memory Networks

type
  TFeedbackNeuron = class(TNeuron)
  private
    FPrevOutput: Double;
    FPrevError: Double;
    FFeedbackWeight: Double;
  public
    constructor Create(WeightCount: Integer;
      ActivationFunction: TActivationFunction; FeedbackWeight: Double);
    function CalculateOutput: Double; override;
    procedure AdjustWeights(Error, LearningRate: Double); override;
  end;

  { TFeedbackNeuron }

constructor TFeedbackNeuron.Create(WeightCount: Integer;
  ActivationFunction: TActivationFunction; FeedbackWeight: Double);
begin
  inherited Create(WeightCount, ActivationFunction);
  FPrevOutput := 0;
  FPrevError := 0;
  FFeedbackWeight := FeedbackWeight;
  SetLength(FInput, WeightCount + 1); // Add extra input for previous output
end;

function TFeedbackNeuron.CalculateOutput: Double;
var
  NetInput: Double;
  i: Integer;
begin
  NetInput := FWeights[0] * FPrevOutput;
  for i := 0 to Length(FWeights) - 2 do
    NetInput := NetInput + FWeights[i + 1] * FInput[i];
  FOutput := FActivationFunction(NetInput);
  FInput[Length(FInput) - 1] := FPrevOutput;
  FPrevOutput := FOutput;
  Result := FOutput;
end;

procedure TFeedbackNeuron.AdjustWeights(Error, LearningRate: Double);
var
  i: Integer;
  NewWeight: Double;
begin
  inherited AdjustWeights(Error, LearningRate);
  NewWeight := FFeedbackWeight * FPrevError * LearningRate;
  FWeights[0] := FWeights[0] + NewWeight;
  for i := 0 to Length(FWeights) - 2 do
    FWeights[i + 1] := FWeights[i + 1] + NewWeight * FInput[i];
  FPrevError := Error;
end;

En este ejemplo, la clase TFeedbackNeuron hereda de TNeuron y agrega algunas propiedades y métodos específicos para la red neuronal de retroalimentación.

En este caso, agregamos una propiedad FPrevOutput para almacenar la salida anterior de la neurona, una propiedad FPrevError para almacenar el error anterior y una propiedad FFeedbackWeight para almacenar el peso de retroalimentación.

También ajustamos el método CalculateOutput para incluir la salida anterior como entrada, y el método AdjustWeights para actualizar los pesos de retroalimentación junto con los pesos normales.

Es importante tener en cuenta que este es solo un ejemplo básico y que hay muchas variantes y configuraciones posibles para las redes neuronales de retroalimentación, por lo que esta implementación puede requerir modificaciones para adaptarse a diferentes casos de uso.