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:
- Entrada: los datos se ingresan en la neurona a través de una o más entradas.
- Peso: Cada entrada está asociada con un peso que representa la importancia de esa entrada.
- 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.