Discusión sobre el artículo "Redes neuronales de propagación inversa del error en matrices MQL5" - página 2

 
Lorentzos Roussos #:

Sí, pero los valores de activación se pasan a la función de derivación mientras que ésta espera los valores de preactivación. Eso es lo que estoy diciendo .

Creo que se equivoca. La derivación se calcula de acuerdo a la fórmula que di anteriormente: y'(x) = y(x)*(1-y(x)), donde x es el estado de la neurona antes de la activación y y(x) es el resultado de aplicar la función de activación. No se utiliza el valor previo a la activación para calcular la derivada, en su lugar se utiliza el resultado de la activación (y). He aquí una prueba simplificada:

double derivative(double output)
{
  return output * (1 - output);
}

void OnStart()
{
  vector x = {{0.68}};
  vector y;
  x.Activation(y, AF_SIGMOID);                            // obtuvo el resultado de la activación/sigmoide como "y(x)" en y[0]
  vector d;
  x.Derivative(d, AF_SIGMOID);                            // se obtiene la derivada de la sigmoidea en x
  Print(derivative(x[0]), " ", derivative(y[0]), " ", d); // 0.2176 0.2231896389723258 [0.2231896389723258]
}
 
Stanislav Korotky #:

Creo que te equivocas. La derivación se calcula según la fórmula que he dado más arriba: y'(x) = y(x)*(1-y(x)), donde x es el estado de la neurona antes de la activación e y(x) es el resultado de aplicar la función de activación. No se utiliza el valor previo a la activación para calcular la derivada, en su lugar se utiliza el resultado de la activación (y). He aquí una prueba simplificada:

Si , eso es lo que estoy diciendo , la derivada correcta coincide con la derivada llamada desde los valores x.

En la función back prop estas llamando al equivalente y.Derivative(d,AF_SIGMOID)

La matriz de salida es y en el backprop del articulo no creo que estes almacenando el equivalente de x en una matriz para llamar a la derivada desde esa.

(de nuevo , de acuerdo con la función mq)

--

incluso en tu ejemplo estas llamando a la derivada desde x , apuesto a que escribiste y al principio y luego "whoopsed"

Solo díselo en el foro ruso . Se ahorrara mucho tiempo a mucha gente si lo añaden en los documentos.

Gracias

 
Stanislav Korotky #:

Creo que te equivocas. La derivación se calcula según la fórmula que he dado más arriba: y'(x) = y(x)*(1-y(x)), donde x es el estado de la neurona antes de la activación e y(x) es el resultado de aplicar la función de activación. No se utiliza el valor previo a la activación para calcular la derivada, en su lugar se utiliza el resultado de la activación (y). He aquí una prueba simplificada:

Permítanme simplificar esto .

Este es tu ejemplo

double derivative(double output)
{
  return output * (1 - output);
}

void OnStart()
{
  vector x = {{0.68}};
  vector y;
  x.Activation(y, AF_SIGMOID);                            // obtuvo el resultado de la activación/sigmoide como "y(x)" en y[0]
  vector d;
  x.Derivative(d, AF_SIGMOID);                            // se obtiene la derivada de la sigmoidea en x
  Print(derivative(x[0]), " ", derivative(y[0]), " ", d); // 0.2176 0.2231896389723258 [0.2231896389723258]
}

En tu ejemplo estás llamando a x.Der ivative para llenar el vector de derivadas d.

Usted no está llamando y.Derivative para llenar los derivados, ¿por qué? Porque devuelve valores erróneos. (y probablemente lo viste, por eso usaste x.Derivative).

¿ Que es y? los valores de activación de x.

Entonces cuando haces esto :

x.Activation(y, AF_SIGMOID);  

llenas y con los valores de activación de x, pero llamas a la derivada en x no en y. (lo cual es correcto de acuerdo a la función mql5)

En tu articulo , en el feed forward temp es x

matrix temp = outputs[i].MatMul(weights[i]);

Y y serían los valores de activación de x. ¿ Que matriz es esa ?

temp.Activation(outputs[i + 1], i < n - 1 ? af : of)

Lassalidas. En el artículo la y ( de la que no llamas a la derivada en el ejemplo) es la matriz de salidas .

(lo que estamos viendo en el código de arriba es el equivalente x.Activation(y,AF) del ejemplo que rellena y con los valores de activación)

En tu código back prop no estás llamando a x.Derivative porque x(matriz temp = salidas[i].MatMul(pesos[i]);)

no se almacena en ninguna parte y no se puede llamar. Usted está llamando el equivalente de y. Derivative que devuelve los valores erróneos

outputs[n].Derivative(temp, of)
outputs[i].Derivative(temp, af)

porque y tiene los valores de activación.

De nuevo, de acuerdo con la función mql5.

Así que en tu ejemplo estás usando la llamada correcta y en tu artículo estás usando la llamada incorrecta .

Saludos

 

Así que quieres esto:

   bool backProp(const matrix &target)
   {
      if(!ready) return false;
   
      if(target.Rows() != outputs[n].Rows() ||
         target.Cols() != outputs[n].Cols())
         return false;
      
      // capa de salida
      matrix temp;
      //*if(!outputs[n].Derivative(temp, of))
      //* return false;
      if(!outputs[n - 1].MatMul(weights[n - 1]).Derivative(temp, of))
         return false;
      matrix loss = (outputs[n] - target) * temp; // registro de datos por fila
     
      for(int i = n - 1; i >= 0; --i) // para cada capa excepto salida
      {
         //*// remove unusable pseudo-errors for neurons, added as constant bias source
         //*// (in all layers except for the last (where it wasn't added))
         //*if(i < n - 1) loss.Resize(loss.Rows(), loss.Cols() - 1);
         #ifdef  BATCH_PROP
         matrix delta = speed[i] * outputs[i].Transpose().MatMul(loss);
         adjustSpeed(speed[i], delta * deltas[i]);
         deltas[i] = delta;
         #else
         matrix delta = speed * outputs[i].Transpose().MatMul(loss);
         #endif
         
         //*if(!salidas[i].Derivada(temp, af))
         //* return false;
         //*pérdida = pérdida.MatMul(pesos[i].Transponer()) * temp;
         if(i > 0) // retropropagación de pérdidas a capas anteriores
         {
            if(!outputs[i - 1].MatMul(weights[i - 1]).Derivative(temp, af))
               return false;
            matrix mul = loss.MatMul(weights[i].Transpose());
            // eliminar pseudo-errores inutilizables para las neuronas, añadidos como fuente de sesgo constante
            mul.Resize(mul.Rows(), mul.Cols() - 1);
            loss = mul * temp;
         }
         
         weights[i] -= delta;
      }
      return true;
   }

Lo pensaré.

 
Stanislav Korotky #:

Así que quieres esto:

Lo pensaré.

A primera vista parece bien, sí. El cálculo en el acto es más rápido que el almacenamiento supongo .

👍

 
Lorentzos Roussos #:

A primera vista parece bien, sí. El cálculo sobre el terreno es más rápido que el almacenamiento, supongo.

Creo que sé la razón por la que se codifica originalmente a través de la salida de la función de activación. En todas mis librerías NN anteriores y en algunas librerías de otras personas que he utilizado, las derivadas se calculan a través de las salidas, porque es más simple y eficaz (durante la adaptación a la API de matrices, no presté atención a la diferencia). Por ejemplo:

sigmoid' = sigmoid * (1 - sigmoid)
tanh' = 1 - tanh^2
softsign' = (1 - |softsign|)^2

De esta forma no necesitamos mantener argumentos de pre-activación (matrices) o recalcularlos de nuevo durante la fase de backpropagation (como se hace en el fix). No me gustan ambos enfoques. El cálculo de la "autoderivada", por así decirlo, parece más elegante. De ahí que prefiera encontrar algunas referencias con fórmulas para autoderivadas de todas (o muchas) las funciones de activación soportadas, y volver a mi enfoque original.

Es interesante que no se requiera que la fórmula de la autoderivada se derive estrictamente de la función de activación - cualquier función con efecto equivalente es suficiente.
 
Stanislav Korotky #:

Creo que sé la razón por la que originalmente se codifica a través de la salida de la función de activación. En todas mis librerías NN anteriores y en algunas librerías de otras personas que he utilizado, las derivadas se calculan a través de las salidas, porque es más simple y eficaz (durante la adaptación a la API de matrices, no presté atención a la diferencia). Por ejemplo:

De esta forma no necesitamos mantener argumentos de pre-activación (matrices) o recalcularlos de nuevo durante la fase de backpropagation (como se hace en el fix). No me gustan ambos enfoques. El cálculo de la "autoderivada", por así decirlo, parece más elegante. Por lo tanto, preferiría encontrar algunas referencias con fórmulas para las autoderivadas de todas (o muchas) las funciones de activación soportadas, y volver a mi enfoque original.

Sí, pero mq ha decidido hacerlo de esta manera, por lo que se aplica a todas las funciones de activación.

En palabras simples , en lugar de la función .Derivative "adaptarse" a la función de activación (como los 3 que usted ha mencionado podría recibir las salidas) que han decidido tener las funciones de recibir los valores de pre-activación en todos los ámbitos de todos modos. Eso está bien, el problema es que no está en la documentación.

La suposición por defecto por cualquier persona es que se adapta a la AF.

Esto es malo para alguien nuevo (como yo por ejemplo) ya que los "abordan" incluso antes de empezar. Lo que me salvó fue que primero construí una red basada en objetos.

(la comparacion de redes basadas en objetos y matrices seria tambien un articulo muy interesante y ayudaria a muchos codificadores que no son expertos en matematicas)

De todas formas lo puse en el hilo que un moderador tiene para reportar problemas de documentación .

(off topic : puedes usar este TanH , es mas rapido y correcto , creo)

double customTanH(double of){
  double ex=MathExp(2*of);
  return((ex-1.0)/(ex+1.0));
}
Es interesante que no se requiere que la fórmula auto-derivativa se deriva estrictamente de la función de activación - cualquier función con efecto equivalente es suficiente.

¿Te refieres a un "sustituto"?

Por ejemplo, un nodo recibe un error en su salida, y usted conoce la "fluctuación" de la salida, así que si la "cambia" a una activación más simple y la deriva, ¿funcionará?

Así que en teoría sería como "regularizar" la salida pero sin hacerlo y simplemente multiplicando por la derivada de la regularización antes de la derivada de la activación?

Por ejemplo :

tanh output -1 -> +1 
sigmoid output 0 -> +1 
tanh to sigmoid output = (tanh_out+1)/2.0
and you just multiply by the derivative of that which is 0.5 ? (without touching the tanh outputs at all)
mql5 documentation errors, defaults or inconsistencies.
mql5 documentation errors, defaults or inconsistencies.
  • 2023.04.07
  • www.mql5.com
Page : https://www.mql5.com/en/docs/globals/globalvariabletime This is inexact, GlobalVariableCheck() does NOT modify the last access time. 2023.04...
 
Archivos adjuntos:
MatrixNet.mqh  23 kb
 

Un administrador respondió a los moderadores hilo sobre esto . Tal vez le interese

 
Stanislav Korotky # : Corrección de errores.

@Stanislav Korotky

Sus esfuerzos para poner el concepto de red neuronal con MQL es bien apreciada. Esto es realmente una gran pieza de trabajo para empezar con los principiantes como yo. Kudos :)

Gracias por actualizar el archivo con error corregido. Sin embargo, yo sugeriría para reemplazar el archivo en el área de descarga.

Por suerte me fui a través de la discusión sobre el tema y se encontró que hay un error en el archivo. Y que ahora estaba tratando de buscar la solución, me encontré con este enlace de archivo aquí.

Espero que haya sólo estos lugares para la corrección de errores en los números de línea 490-493, 500, 515-527, podría con // * marcado. Si en cualquier otro lugar por favor mencione los números de línea o marque //*BugFix ...

Saludos