Herramientas de usuario

Herramientas del sitio


clase:iabd:pia:2eval:tema07-apendices

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
Próxima revisión Ambos lados, revisión siguiente
clase:iabd:pia:2eval:tema07-apendices [2022/01/16 19:51]
admin [Tipos de funciones de coste]
clase:iabd:pia:2eval:tema07-apendices [2024/03/19 14:04]
admin [Más métricas]
Línea 1: Línea 1:
-====== 7. Entrenamiento de redes neuronales d) Apéndices ======+====== 7. Entrenamiento de redes neuronales e) Apéndices ======
  
 ===== Tipos de funciones de coste ===== ===== Tipos de funciones de coste =====
Línea 38: Línea 38:
   * [[https://en.wikipedia.org/wiki/Huber_loss|Huber loss en Wikipedia]]   * [[https://en.wikipedia.org/wiki/Huber_loss|Huber loss en Wikipedia]]
  
 +
 +===== Backpropagation =====
 +El Backpropagation es el algoritmo que optimiza el entrenamiento de la red. Calcular el gradiente (o derivada) de toda la red es muy costoso. Se basa en la idea de que los parámetros de una capa no dependen de la capa anterior.
 +
 +
 +Si volvemos a ver nuestra red neuronal de ejemplo, podemos calcular los pesos de la neurona 5 sin que influya en como van a ser los pesos de las neuronas 2, 3 y 4. Es decir que empezamos con las neuronas de las capas más hacía la salida y una vez calculados sus pesos , calculamos los parámetros de las capa anterior (más hacia la entrada) , y eso significa ir hacia atrás o //backpropagation//.
 +
 +{{ :clase:iabd:pia:2eval:backpropagation_1.gif?direct |}}
 +
 +{{ :clase:iabd:pia:2eval:backpropagation_2.gif?direct |}}
 +
 +{{ :clase:iabd:pia:2eval:backpropagation_3.mp4?700 |}}
 +
 +Con backpropagation acabamos de ver el orden en el que se calculan los parámetros de cada neurona y a continuación vamos a ver con el descenso de gradiente como calculamos los parámetros de una neurona.
 +
 +Junto con el backpropagation  aparece otro concepto llamado //regla de la cadena// o //chain rule// que se usa para junto al backpropagation para hacer menos cálculos. Está relacionado con el cálculo de derivadas.
 +
 +En los siguientes videos está explicado perfectamente el backpropagation y la //chain rule//:
 +  * [[https://www.youtube.com/watch?v=eNIqz_noix8|¿Qué es una Red Neuronal? Parte 3 : Backpropagation | DotCSV]]: Video
 +  * [[https://www.youtube.com/watch?v=M5QHwkkHgAA|¿Qué es una Red Neuronal? Parte 3.5 : Las Matemáticas de Backpropagation | DotCSV]]: Video
 +
 +===== Creación de los gráficos del descenso de gradiente =====
 +Durante el tema hemos visto los gráficos que explican el descenso de gradiente. Veamos ahora como se pueden hacer dichos gráficos en Python.
 +
 +La función que coste que hemos usado es la siguiente
 +
 +$$
 +loss(w_0,w_1)=3(1-w_0)^2e^{-w_0^2-(w_1+1)^2}-10(\frac{w_0}{5}-w_0^3-w_1^5)e^{-w_0^2-w_1^2}-\frac{1}{3}e^{-(w_0+1)^2-w_1^2}
 +$$
 +
 +cuya gráfica es la siguiente:
 +
 +{{:clase:iabd:pia:2eval:descenso_gradiente_normal_3d.png?direct|}}
 +
 +
 +En python la función $loss(w_0,w_1)$ con **NumPy** sería así:
 +
 +<sxh python>
 +def loss(w_0,w_1):
 +    return  3*(1 - w_0)**2 * np.exp(-w_0**2 - (w_1 + 1)**2)  - 10*(w_0/5 - w_0**3 - w_1**5)*np.exp(-w_0**2 - w_1**2) - 1./3*np.exp(-(w_0 + 1)**2 - w_1**2) 
 +</sxh>
 +
 +Y el algoritmo que calcula cada uno de los $w_0,w_1$ del descenso de gradiente es el siguiente:
 +
 +<sxh python>
 +def get_puntos_descenso_gradiente(epochs,learning_rate,w_0_original,w_1_original):
 +
 +    w_0=w_0_original
 +    w_1=w_1_original
 +
 +    puntos_descenso_gradiente=np.array([[w_0,w_1]])
 +    
 +    for epoch in range(epochs): 
 +        h=0.00001
 +        
 +        gradiente_w_0=(loss(w_0+h,w_1)-loss(w_0,w_1))/h
 +        gradiente_w_1=(loss(w_0,w_1+h)-loss(w_0,w_1))/       
 +
 +        #Nuevos valores de los pesos
 +        w_0=w_0-learning_rate*gradiente_w_0
 +        w_1=w_1-learning_rate*gradiente_w_1
 +
 +        puntos_descenso_gradiente=np.append(puntos_descenso_gradiente,[[w_0,w_1]], axis=0)           
 +
 +    return puntos_descenso_gradiente
 +
 +</sxh>
 +
 +
 +Si ejecutamos lo siguiente:
 +<sxh python>
 +get_puntos_descenso_gradiente(5,0.03,-0.35,-0.67)
 +</sxh>
 +
 +El resultado es:
 +<sxh base>
 +array([[-0.35      , -0.67      ],
 +       [-0.26931594, -0.72470447],
 +       [-0.13292324, -0.838827  ],
 +       [ 0.0654496 , -1.06459902],
 +       [ 0.24087009, -1.40749396],
 +       [ 0.2657862 , -1.59573582]])
 +</sxh>
 +
 +Que son cada uno de los valores de $w_0,w_1$ que empiezan en ''-0.35, -0.67'' y acaban en ''0.2657862, -1.59573582$''
 +
 +Pasamos ahora a mostrar los valores dentro de la gráfica de la función, para ello hemos creado 2 funciones:
 +  * ''plot_loss_function'': Que dibuja la superficie con todos los colores
 +  * ''plot_descenso_gradiente'': Dibuja los puntos por donde va pasando el algoritmo del descenso de gradiente
 +
 +
 +<sxh python>
 +def plot_loss_function(axes,fontsize=25,title=""):
 +    rango_w_0=np.linspace(-3,3,100)
 +    rango_w_1=np.linspace(-3,3,100)
 +    rango_w_0,rango_w_1=np.meshgrid(rango_w_0,rango_w_1)
 +    loss=loss_function(rango_w_0,rango_w_1)
 +
 +    axes.contourf(rango_w_0,rango_w_1,loss,30,cmap="coolwarm")
 +    axes.set_xlabel('w₀',fontsize=fontsize,color="#003B80")  
 +    axes.set_ylabel('w₁',fontsize=fontsize,color="#003B80")
 +    axes.set_title(title)
 +
 +
 +def plot_descenso_gradiente(axes,puntos_descenso_gradiente):
 +    axes.scatter(puntos_descenso_gradiente[1:-1,0],puntos_descenso_gradiente[1:-1,1],13,color="yellow")
 +    axes.plot(puntos_descenso_gradiente[:,0],puntos_descenso_gradiente[:,1],color="yellow")
 +    axes.plot(puntos_descenso_gradiente[0,0],puntos_descenso_gradiente[0,1],"*",markersize=12,color="red")
 +    axes.plot(puntos_descenso_gradiente[-1,0],puntos_descenso_gradiente[-1,1],"*",markersize=12,color="blue")
 +
 +</sxh>
 +
 +Si ejecutamos el código:
 +
 +<sxh python>
 +figure=plt.figure(figsize=(16,15))
 +axes = figure.add_subplot()
 +plot_loss_function(axes)
 +
 +plot_descenso_gradiente(axes,get_puntos_descenso_gradiente(5,0.03,-0.35,-0.67))
 +</sxh>
 +
 +Vemos la siguiente gráfica donde se muestran los puntos que hemos obtenido de la función ''get_puntos_descenso_gradiente''
 +
 +{{ :clase:iabd:pia:2eval:descenso_gradiente_algoritmo_vanilla_1.png?direct |}}
 +
 +
 +<note>
 +  * La estrella roja es desde donde empieza el algoritmo.Es decir, el valor inicial de los parámetros $w_0,w_1$
 +  * La estrella azul es donde acaba el algoritmo.Es decir, el valor tras el entrenamiento de los parámetros $w_0,w_1$
 +  * Los puntos amarillo son los //pasos// por lo que se va moviendo el algoritmo. Cada uno de los valores intermedios de los parámetros durante el entrenamiento.
 +</note>
 +
 +
 +==== Optimizadores de Keras ====
 + Podemos mejorar nuestro código en Python haciendo que podamos usar directamente los [[https://keras.io/api/optimizers/|Optimizers]] de Keras y de esa forma ver como funciona cada uno de ellos. Para poder usarlos directamente vamos a creas las nuevas funciones ''loss_tf'' y ''get_puntos_descenso_gradiente_optimizer'' adecuadas a TensorFlow y Keras.
 +
 +
 +<sxh python>
 +def loss_tf(w_0,w_1):
 +    return  3*(1 - w_0)**2 * tf.exp(-w_0**2 - (w_1 + 1)**2)  - 10*(w_0/5 - w_0**3 - w_1**5)*tf.exp(-w_0**2 - w_1**2) - 1./3*tf.exp(-(w_0 + 1)**2 - w_1**2) 
 +
 +def get_puntos_descenso_gradiente_optimizer(epochs,optimizer_function,w_0_init,w_1_init):
 +
 +    puntos_descenso_gradiente=np.array([[w_0_init,w_1_init]])
 +
 +    w_0=w_0_init
 +    w_1=w_1_init
 +    for epoch in range(epochs): 
 +        var_w_0=tf.Variable(w_0)
 +        var_w_1=tf.Variable(w_1)
 +
 +        optimizer_function.minimize(lambda: loss_tf(var_w_0,w_1),  var_list=[var_w_0])
 +        optimizer_function.minimize(lambda: loss_tf(w_0,var_w_1),  var_list=[var_w_1])
 +
 +        w_0=var_w_0.numpy()
 +        w_1=var_w_1.numpy()      
 +
 +        puntos_descenso_gradiente=np.append(puntos_descenso_gradiente,[[w_0,w_1]], axis=0)           
 +
 +    return puntos_descenso_gradiente
 +</sxh>
 +
 +Lo que ha cambiado principalmente es la función ''get_puntos_descenso_gradiente_optimizer''  no hace cálculo  del gradiente (derivada) ni actualiza los parámetros, sino que llama a la función de Keras de optimización.
 +
 +
 +Si usamos ''get_puntos_descenso_gradiente_optimizer'' ahora con ''tf.keras.optimizers.SGD''
 +<sxh python>
 +get_puntos_descenso_gradiente_optimizer(5,tf.keras.optimizers.SGD(learning_rate=0.03),-0.35,-0.67)
 +</sxh>
 +<sxh base>
 +array([[-0.35      , -0.67      ],
 +       [-0.269319  , -0.72470832],
 +       [-0.13292952, -0.83883744],
 +       [ 0.06544246, -1.06462073],
 +       [ 0.24086528, -1.40752137],
 +       [ 0.26578248, -1.59573841]])
 +</sxh>
 +Vamos que el resultado es prácticamente el mismo que cuando lo hicimos manualmente.
 +
 +Y podemos generar de la misma forma el gráfico:
 +<sxh python>
 +figure=plt.figure(figsize=(16,15))
 +axes = figure.add_subplot()
 +plot_loss_function(axes)
 +
 +plot_descenso_gradiente(axes,get_puntos_descenso_gradiente_optimizer(5,tf.keras.optimizers.SGD(learning_rate=0.03),-0.35,-0.67))
 +</sxh>
 +
 +
 +{{ :clase:iabd:pia:2eval:optimizer_sgd.png?direct |}}
 +
 +Y obviamente el resultado es el mismo
 +
 +===== Métricas =====
 +
 +==== Juntado dos Métricas Básicas ====
 +^  ^  Fórmula que usan  ^^^^^
 +^  Métricas básicas que usan  ^  Media aritmética  ^  Media armónica  ^  Media geométrica  ^  Suma-1  ^  Ratio  ^
 +| Sensibilidad (TPR) y Especificidad (TNR)  |    |    |    |  $Informedness=TPR+TNR-1$ |   |
 +| Sensibilidad (TPR) y FPR  |    |    |    |    $Positive \; likelihood \; ratio=\frac{TPR}{FPR}$ |
 +| Especificidad (TNR) y FNR  |    |    |    |    $Negative \; likelihood \; ratio=\frac{FNR}{TNR}$ |
 +| FPR y FNR  |    |    |     |
 +
 +
 +==== Juntado dos Métricas derivadas ====
 +
 +^  ^  Fórmula que usan  ^^^^^
 +^  Métricas básicas que usan  ^  Media aritmética  ^  Media armónica  ^  Media geométrica  ^  Suma-1  ^  Ratio  ^
 +| PPV y NPV  |    |    |    |  $Markdness=PPV+NPV-1$ |   |
 +| PPV y FOR  |    |    |    |     |
 +| NPV y FDR  |    |    |    |     |
 +| FDR y FOR  |    |    |    |     |
 +
 +
 +==== Métricas mixtas ====
 +Son métricas que juntan una métrica básica con una métrica derivada. Debido a que existen 16 combinaciones no vamos a mostrar todas las que existen, sino solo las que he considerado interesantes.
 +
 +  * La siguiente tabla son métricas que existen (Tienen nombre)
 +
 +^  ^  Fórmula que usan  ^^^^^
 +^  Métricas básicas que usan  ^  Media aritmética  ^  Media armónica  ^  Media geométrica  ^  Suma-1  ^  Ratio  ^
 +| PPV y Sensibilidad (TPR)  |    |  $F_{1}score=\frac{2}{\frac{1}{PPV}+\frac{1}{TPR}}$  |  $Fowlkes-Mallows \; index=\sqrt{PPV*TPR}$  |     |
 +| NPV y Especificidad (TNR)  |    |    |    |     |
 +
 +===== Más métricas =====
 +
 +
 +==== Indice Jaccard ====
 +Este índice es la división entre 2 probabilidades:
 +
 +$$
 +Indice \; Jaccard=\frac{P(Positivo \cap Enfermo)}{P(Positivo \cup Enfermo)}=\frac{TP}{TP+FP+FN}
 +$$
 +
 +  * Se deduce de la siguiente forma:
 +
 +$$
 +\frac{P(Positivo \cap Enfermo)}{P(Positivo \cup Enfermo)}=
 +$$
 +
 +$$
 +\frac{P(Positivo|Enfermo)*P(Enfermo)}{P(Positivo)+P(Enfermo)-P(Positivo \cap Enfermo)}=\frac{P(Positivo|Enfermo)*P(Enfermo)}{P(Positivo)+P(Enfermo)-P(Positivo|Enfermo)*P(Enfermo)}
 +$$
 +
 +  * Sabiendo que:
 +
 +$$
 +
 +\begin{array}
 +\\
 +P(Enfermo)&=&\frac{TP+FN}{TP+FN+FP+TN}
 +\\
 +P(Sano)&=&\frac{FP+TN}{TP+FN+FP+TN}
 +\\
 +P(Positivo)&=&\frac{TP+FP}{TP+FN+FP+TN}
 +\\
 +P(Negativo)&=&\frac{FN+TN}{TP+FN+FP+TN}
 +\\
 +P(Positivo|Enfermo)&=&\frac{TP}{TP+FN}
 +\end{array}
 +$$
 +
 +  * Entonces:
 +
 +$$
 +\frac{P(Positivo|Enfermo)*P(Enfermo)}{P(Positivo)+P(Enfermo)-P(Positivo|Enfermo)*P(Enfermo)}=
 +$$
 +
 +$$
 +\left ( \frac{TP}{TP+FN}*\frac{TP+FN}{TP+FN+FP+TN} \right ) \div    \left (\frac{TP+FP}{TP+FN+FP+TN}+\frac{TP+FN}{TP+FN+FP+TN}-\frac{TP}{TP+FN}*\frac{TP+FN}{TP+FN+FP+TN} \right )=
 +$$
 +
 +$$
 +\left ( \frac{TP}{TP+FN+FP+TN} \right ) \div    \left (\frac{TP+FP}{TP+FN+FP+TN}+\frac{TP+FN}{TP+FN+FP+TN}-\frac{TP}{TP+FN+FP+TN} \right )=
 +$$
 +
 +$$
 +\left ( \frac{TP}{TP+FN+FP+TN} \right ) \div    \left (\frac{TP+FP+TP+FN-TP}{TP+FN+FP+TN} \right )=\left ( \frac{TP}{TP+FN+FP+TN} \right ) \div    \left (\frac{TP+FP+FN}{TP+FN+FP+TN} \right )=
 +$$
 +
 +$$
 +\frac{TP}{TP+FP+FN}=Indice \; Jaccard
 +$$
 +
 +  * Sin embargo también podemos definir el Indice Jaccard en función de la sensibilidad, la especificidad y la prevalencia.Usando el teorema de bayes podemos definir P(Positivo) de la siguiente forma:
 +
 +$$
 +P(Positivo)=\frac{P(Positivo|Enfermo)*P(Enfermo)}{P(Enfermo|Positivo)}=
 +$$
 +
 +$$
 +\frac{P(Positivo|Enfermo)*P(Enfermo)}{1} \div \frac{P(Positivo|Enfermo)*P(Enfermo)}{P(Positivo|Enfermo)*P(Enfermo)+P(Positivo|Sano)*P(Sano)}=
 +$$
 +
 +$$
 +Sensibilidad*Prevalencia+(1-Especificidad)*(1-Prevalencia)
 +$$
 +
 +
 +  * Y ahora usamos la formula de P(Positivo) en la definición del Indice Jaccard
 +
 +$$
 +Indice \; Jaccard=\frac{P(Positivo|Enfermo)*P(Enfermo)}{P(Positivo)+P(Enfermo)-P(Positivo|Enfermo)*P(Enfermo)}=
 +$$
 +
 +$$
 +\frac{Sensibilidad*Prevalencia}{Sensibilidad*Prevalencia+(1-Especificidad)*(1-Prevalencia)+Prevalencia-Sensibilidad*Prevalencia}=
 +$$
 +
 +$$
 +\frac{Sensibilidad*Prevalencia}{(1-Especificidad)*(1-Prevalencia)+Prevalencia}
 +$$
 +
 +  * Por lo tanto
 +
 +$$
 +Indice \; Jaccard=\frac{Sensibilidad*Prevalencia}{(1-Especificidad)*(1-Prevalencia)+Prevalencia}
 +$$
 +
 +
 +
 +==== Prevalence threshold ====
 +La métrica de Prevalence threshold está explicada en [[https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7540853/|Prevalence threshold (ϕe) and the geometry of screening curves]].
 +
 +Lo único que diremos respecto a la formula es que en el artículo aparece como:
 +
 +$$
 +Prevalence \; threshold=\frac{\sqrt{Sensibilidad(1-Especificidad)}+(Especificidad-1)}{Sensibilidad+Especificidad+1}
 +$$
 +Que jugando un poco con los signos se obtiene la formula equivalente que aparece en Wikipedia:
 +$$
 +Prevalence \; threshold=\frac{\sqrt{Sensibilidad*FPR}-FPR}{Sensibilidad-FPR}
 +$$
 +
 +==== Diagnostic odds ratio ====
 +Se define como la división entre //Positive likelihood ratio (LR+)// y  //Negative likelihood ratio (LR-)//
 +
 +$$
 +DOR=\frac{LR+}{LR-}=\frac{TP*TN}{FP*FN}
 +$$
 +
 +  * Aunque también se puede definir en función de la sensibilidad y la especificidad
 +
 +$$
 +DOR=\frac{LR+}{LR-}=\frac{\frac{TPR}{1-TNR}}{\frac{1-TPR}{TNR}}=\frac{Sensibilidad*Especificidad}{(1-Sensibilidad)(1-Especificidad)}
 +$$
  
clase/iabd/pia/2eval/tema07-apendices.txt · Última modificación: 2024/03/19 17:04 por admin