viernes, 11 de mayo de 2018

Aprendiendo convoluciones

La convolución es una operación matemática  que se aplica a dos funciones (en $L^p$)en donde se obtiene como resultado el valor de solapamiento de una función respecto a la otra.
$$ u*v (t)= \int_{\mathbb{R} } u(x)v(t-x) dx$$

Esta operación matemática, nos genera una función continua cuando alguna de las funciones está acotada.Se le llama kernel o filtro a una función fija($v$) que se convoluciona con la función variable($u$) para obtener características(en procesamiento de señales se llama respuesta al impulso) de $u$ respecto al filtro $g$.

En aprendizaje automático se requieren describir el objeto que queremos clasificar (algún tipo de señal como un audio o imagen) mediante sus características para luego proceder a usar algún algoritmo de clasificación(redes neuronales o SVM).


En aprendizaje profundo, estás características que describen al objeto son aprendidas automáticamente mediante algún algoritmo de optimización(gradiente descendiente o adam optimizer). Una de las redes más populares son las redes neuronales convolucionales (CNN), que utilizan el concepto de convolución para ir obteniendo características del objeto para su descripción.

Vamos a ver su parte computacional en Python3 para entender con ejemplos este concepto:

Sean $u$ y $v$ vectores , el producto de convolucíon es:
$$ (u*v)[i] = \sum_{j=0}^{\infty}  u[j]v[i-j] = \sum_{s+t=i} u[s]v[t] $$

ejemplo: 
Sea $u = [2, 5, 0, 4]$ y $v = [4, 1, 3]$
Si decimos que $v$ es el filtro, entonces haremos un barrido del filtro para recoger características de $u$

Para hacer el barrido en los bordes se debe completar con ceros el vectocon el filtro al revés $u$
Sean los indices:
$$ u=[u[0],u[1],u[2],u[3]] $$
$$ v=[v[0],v[1],v[2]] $$

$$ (u*v)[0] = \sum_{j=0}^{\infty} u[j][0-j] = u[0]v[0] + u[1]v[-1] + u[2]v[-2]+ u[3]v[-3] + ... = u[0]v[0] = 8 $$

debido a que los indices $-1,-2,-3$  no están definidos, lo podemos definir con ceros ,y así en los démas casos

$$ u[5] =0 , v[-1] = 0, u[-8] = 0, ... etc $$

De igual forma con los demás términos
$$ (u*v)[1] = \sum_{j=0}^{\infty} u[j][1-j] =u[0]v[1] + u[1]v[0] +... = 22 $$
$$ (u*v)[2] = \sum_{j=0}^{\infty} u[j][2-j] =u[0]v[2] + u[1]v[1] + u[2]v[0]... = 11 $$
$$ (u*v)[3] = \sum_{j=0}^{\infty} u[j][3-j] =u[0]v[3] + u[1]v[2] + u[2]v[1]+ u[3]v[0] =31$$
$$ (u*v)[4] = \sum_{j=0}^{\infty} u[j][3-j] =u[0]v[4] + u[1]v[3] + u[2]v[2]+ u[3]v[1] =4$$
$$ (u*v)[5] = \sum_{j=0}^{\infty} u[j][3-j] =u[0]v[5] + u[1]v[4] + u[2]v[3]+ u[3]v[2] =12$$


# Definimos los vectores
u = [2, 5, 0, 4]  #vector de entrada
v = [4, 1, 3]   #filtro
print(u)
print(v)
[2, 5, 0, 4]
[4, 1, 3]

conv = []  
for j in range(len(u)+len(v)-1):
    suma = 0
    for i in range(len(u)):
        if (j-i)>=0 and (j-i)<len(v):
            suma = u[i]*v[j-i] + suma
    conv.append(suma)
conv
[8, 22, 11, 31, 4, 12]

Podemos agruparlo en una función.
# Función de convolución
def convolucion(u,v):
    conv = []
    m = len(u)
    n = len(v)
    for j in range(m+n-1):  #m+n-1 es el tamaño de la convolucion
        suma = 0
        for i in range(m):
            if (j-i)>=0 and (j-i)<n:
                suma = u[i]*v[j-i] + suma
        conv.append(suma)
    return conv

print(convolucion(u,v))
[8, 22, 11, 31, 4, 12]

Usando Numpy

En numpy , ya se obtiene está función con el comando convolve Esta función es un poco más rapido
import numpy as np
print(np.convolve(u,v))  #se obtiene el mismo resultado
[ 8 22 11 31  4 12]

Usando Scipy

from scipy import signal
signal.convolve(u,v)
array([ 8, 22, 11, 31,  4, 12])


Usando el mismo concepto se puede extender a n-dimensiones.
Este concepto de convoluciones explica las funciones waveletes que tienen un mayor concepto en las matemáticas.


No hay comentarios.:

Publicar un comentario