Hola queridos lectores. Se ha escrito y dicho mucho sobre las redes neuronales, principalmente sobre cómo y por qué se pueden aplicar. Al mismo tiempo, no se presta mucha atención a dos cuestiones importantes: a) cómo simplificar y calcular rápidamente una red neuronal (un cálculo del exponente se realiza mediante funciones de biblioteca de lenguajes de programación, generalmente no menos de 15-20 instrucciones de procesador), b) qué, al menos en parte, la lógica de la red construida; de hecho, las enormes matrices de valores de pesos y desplazamientos obtenidos después de entrenar la red de alguna manera no ayudan realmente a comprender los patrones que ha encontrado esta red (permanecen ocultos y la tarea de determinarlos es tarea de los sauces ción de - a veces muy importante). Hablaré sobre uno de mis enfoques para resolver estos problemas para las redes neuronales de distribución directa ordinaria, mientras trato de salir con un mínimo de matemáticas.
Poco de teoría
La red de distribución directa, desde un punto de vista matemático, es una función muy grande, que incluye los valores de las entradas de la red, los coeficientes de ponderación y los desplazamientos de las neuronas. En cada neurona de la capa, los valores de las entradas de la capa (vector X) se multiplican por el peso de la neurona (vector
), sumar con un desplazamiento
e ingresar funciones de activación
formando las salidas de las neuronas de capa.
Las funciones de activación pueden no ser muy fáciles de calcular, por ejemplo, a menudo contienen exponenciales (sigmoide exponencial, tangente hiperbólica). Si observa el código de ensamblador que implementa exponentes, puede encontrar, en primer lugar, muchas comprobaciones diferentes que no siempre se necesitan, y en segundo lugar, el cálculo del exponente en sí se realiza generalmente en al menos dos operaciones:
Por lo tanto, si queremos acelerar el cálculo de la red, la primera tarea será simplificar el cálculo de la función de activación. Puede intentar sacrificar un poco de calidad debido a una ganancia de velocidad, reemplazando aproximadamente el cálculo de la función de activación clásica con el cálculo de una función más simple, que (en los datos de entrada disponibles) proporciona aproximadamente los mismos resultados. En términos generales, este es un problema de interpolación clásico: tenemos un conjunto de valores calculados por la función original A (s), y seleccionamos una función más simple que proporciona valores muy similares. Tal función simple a (s) puede ser un polinomio ordinario, o un polinomio con poderes negativos, o algo así. Usé cuatro tipos de tales funciones:
;
;
;
;
Supongamos que para cada neurona logramos reemplazar la función de activación con una ligeramente más simple; esto se puede hacer, por ejemplo, aplicando el método de mínimos cuadrados. Tal sustitución en sí misma probablemente no dará una ganancia muy grande. Pero aquí puedes probar otro truco:
- Escriba la función analíticamente enorme NET (X) calculada por la red como un todo;
- Reemplace las funciones originales A (s) en NET (X) con las funciones de reemplazo a (s) obtenidas para ellas;
- Simplifique el NET (X) obtenido algebraicamente (o más bien, use un código listo para la simplificación simbólica de las expresiones). Esto ya es posible (al menos, mucho más fácil de lo que trataríamos de simplificar la red con las funciones originales, por ejemplo, con exponentes).
Como resultado, obtenemos algo más simple y, quizás, un poco más matemáticamente obvio: aquí ya puede intentar comprender qué tipo de función implementa la red.
Esta es la opción de explicar la lógica de la red construida.
La tarea descrita, por supuesto, solo en palabras parece simple. Para usar en mis programas, necesitaba escribir mi propio código para simplificar simbólicamente las expresiones. Además, resolví un problema más complejo, suponiendo que cada neurona con función A (s) puede tener varias opciones para una función de activación alternativa
, por lo tanto, la tarea general también se redujo a enumerar las opciones para tales funciones y la simplificación simbólica de la red para cada una de esas opciones. Aquí solo ayudó la paralelización de los cálculos.
Resultado
El resultado me agradó. Aceleré una red de tres capas (con tres entradas) de ocho neuronas (con pesos y desplazamientos de entrada) con las funciones de activación "sigmoide exponencial". Como se muestra en las mediciones de tiempo, fue posible obtener una ganancia de aproximadamente el 40% en el tiempo sin una pérdida significativa de calidad.
Yo ilustramos Aquí están los datos de la red de origen:


Y en el tercero, capa de salida:

Si las entradas se designan como a, byc, entonces, después de reemplazos y simplificaciones, la función de red NET se considera como sigue:
double a2 = a*a; double b2 = b*b; double c2 = c*c; double a3 = a2*a; double b3 = b2*b; double c3 = c2*c; double z01 = sqrt(-1.6302e-02+7.9324e-01*a+9.65149e-01*b+5.64151e-01*c); double z06 = sqrt(1.583708e+00-8.907654e-01*a-2.844379e-01*a2+1.050942e+00*a3+1.178096e+01*b-1.865618e+00*b*a-3.145465e+00*b*a2-5.777153e+00*b2+3.138123e+00*b2*a-1.043599e+00*b3+1.32778e+00*c+5.849582e-01*c*a-3.440382e+00*c*a2+1.838371e+00*c*b+6.864703e+00*c*b*a-3.42434e+00*c*b2-3.013361e-01*c2+3.754167e+00*c2*a-3.745404e+00*c2*b-1.365524e+00*c3+1.014237e-01*z01); double NET = (-1.477593e+00)/(z06)+1.370237e+00-6.303167e-02*a-1.495051e-03*a2+2.33748e-02*a3+5.558024e-02*b+1.178189e-02*b*a-6.996071e-02*b*a2+1.837937e-02*b2+6.97974e-02*b2*a-2.321149e-02*b3+7.924241e-02*c+3.392287e-03*c*a-7.652018e-02*c*a2-1.214263e-02*c*b+1.526831e-01*c*b*a-7.616337e-02*c*b2-1.915279e-03*c2+8.349931e-02*c2*a-8.33044e-02*c2*b-3.037166e-02*c3+1.949161e-02*z01;
Ganador - Repito, el 40% del tiempo, sin mucho daño a la calidad. Creo que este enfoque se puede aplicar en casos en los que la velocidad de cálculo de una red neuronal es crítica, por ejemplo, si se calcula repetidamente, en un ciclo doble o triple.
Un ejemplo de tal problema : una solución numérica del problema aerodinámico en una cuadrícula, y en cada uno de sus nodos la red neuronal calcula algún pronóstico útil, por ejemplo, para un cálculo más preciso de la viscosidad turbulenta. Luego tenemos un ciclo externo en el tiempo, un ciclo doble o triple en coordenadas está incrustado en él, y ya allí, dentro, hay un cálculo de una red neuronal. En este caso, la simplificación es más que apropiada y útil.