logo

Dot CSV

Inteligencia Artificial, Tecnología, Ciencia y Futuro! Bienvenidos a la 4ª Revolución Industrial 🚀 Inteligencia Artificial, Tecnología, Ciencia y Futuro! Bienvenidos a la 4ª Revolución Industrial 🚀

Transcribed podcasts: 213
Time transcribed: 5d 22h 50m 3s

This graph shows how many times the word ______ has been mentioned throughout the history of the program.

Hola chicos y chicas, bienvenidos a DotsCV, tu canal sobre Inteligencia Artificial que
te trae todo lo importante sobre este mundo, ya sea teórico, ya sea práctico, como lo
que vamos a hacer hoy en este nuevo IA Notebook, el número 3, si no me equivoco, sí, el
número 3 y en el que vamos a tratar un poquito el tema del gradient descent, el descenso
del gradiente que es un vídeo que subí ya hace dos semanas y que bueno que ya en ese
vídeo recomiendo verlo, muy importante porque todo lo que vayamos a ver hoy está fundamentado
en la teoría que vimos en ese vídeo aunque daremos un repaso de nuevo y bueno antes de
empezar quería comentar un par de cosas, la primera, estoy un poco ronco, se me nota
la voz un poco cascada por muchos motivos entre ellos porque a lo mejor no es la primera
vez que intento hacer el vídeo hoy, pero bueno, la otra cosa que quería comentar es
importante, bueno, si han visto la portada del vídeo, que la están viendo por algún
lado de esto, se habrán fijado que en la esquina superior derecha aparecen ahora tres
puntitos y ¿qué significan esos tres puntos? Bueno, esos tres puntos son una forma orientativa
de poder saber cuál es la dificultad del tutorial que vamos a hacer antes de entrar
al vídeo. Son tres puntos, tenemos fácil, medio, difícil y bueno, básicamente es eso.
A nivel orientativo, realmente la dificultad depende un poco también de las capacidades
de cada uno, del nivel de conocimiento que tenga sobre programación, sobre inteligencia
artificial, pero en general, bueno, lo pueden usar de manera orientativa para saber cómo
se va a plantear el vídeo que viene. ¿Qué vamos a hacer? Bueno, el descenso del gradiente.
Recordemos qué era esto. Esto es una técnica muy importante dentro del mundillo de la inteligencia
artificial. Es un algoritmo que vamos a encontrar dentro de, por ejemplo, las redes neuronales
que ya empezaremos a ver dentro de muy poquito. ¿Y para qué sirve? Bueno, el método del
descenso del gradiente es una técnica de optimización. Si dejaramos aparte todo el
mundo de la inteligencia artificial, una técnica de optimización se engloba dentro del campo
de las matemáticas y lo que hacemos es buscar en una función cuáles son los puntos críticos,
los puntos mínimos y máximos. ¿Para qué nos puede servir eso a nosotros? Bueno, si
nuestra función, lo que está representando es la función de coste, pues por ejemplo,
si tenemos un sistema de inteligencia artificial y queremos que este sistema resuelva una
tarea determinada, pues la evaluamos con una función de coste y si conseguimos que esa
función de coste se minimice en función del valor de unos parámetros, pues lo que estamos
consiguiendo es que esa tarea se haga mejor, que básicamente lo que llamamos aprender en
el mundo de la inteligencia artificial. Entonces, una de las técnicas que existen es el descenso
del gradiente, que se suele utilizar bastante para optimizar funciones no convexas, que
es lo que vamos a ver en el vídeo de hoy. Si recuerdan del vídeo, la analogía que
tratábamos era que el descenso del gradiente, pues como que era el equivalente a que tú
te encuentras en una montaña, en un punto aleatorio de una montaña, con los ojos vendados
y tienes que avanzar para descender por esa montaña. ¿Cuál es la estrategia que seguiría?
Bueno, ahora la iremos viendo paso a paso, pero básicamente lo que hacíamos era pues
utilizar las matemáticas, las derivadas, para encontrar la pendiente y movernos en contra
de la pendiente y así poco a poco descender. Bueno, vamos a empezar y lo primero que vamos
a usar, lo primero que vamos a hacer es importar las librerías que vamos a usar. Tenemos Numpy
como siempre, tenemos SciPy como siempre y tenemos MatplotLive, Pipelot, Aspelete, como
siempre. La ejecutamos y las tenemos. Recordemos, Numpy la utilizamos como una librería de
cálculo numérico donde tenemos matrices, tipos de datos numéricos, funciones para
álgebra lineal, un montón de cosas chulas que podemos utilizar en nuestra labor con
datos, SciPy es una extensión de Numpy, es decir, se basa en Numpy y te ofrece un montón
de funciones científicas que son de bastante utilidad también y MatplotLive es para visualización
de datos ¿vale? Hoy simplemente vamos a trabajar con estas tres librerías. Bueno, lo primero
que necesitamos, queremos hacer optimización de funciones. En este caso vamos a empezar
con un ejemplo de cómo optimizar una función, con lo cual que necesitamos una función.
Podemos optimizar cualquier tipo de función mientras sea derivable. Bueno, eso es un concepto
matemático que se lo dejo a los matemáticos que lo expliquen, pero eso necesitamos una
función que podamos optimizar. En este caso he elegido una cualquiera, aunque no corresponde
a una función de coste determinada ni a un tipo de modelo ni nada, es una función de
coste, o sea una función matemática cualquiera que he encontrado en la Wikipedia en un artículo
sobre gradient descent y que la he elegido básicamente porque ya me aportaban esto de
aquí que es la visualización tridimensional y me ahorraban trabajo. Entonces esta función
es la siguiente. Vamos a declararla como una función anónima y eso en Python se hace con
la palabra reservada lambda. Con esto lo que le está diciendo es que quieres crear una
función anónima y ya veremos cómo se utiliza. A esta función anónima le vamos a pasar
un argumento, que en este caso va a ser th. th es la nomenclatura que yo suelo utilizar
para referirme al vector de parámetros porque th hace referencia a z, que es la letra griega
con la que se suele utilizar en machine learning para referenciar esto a un vector de parámetros.
Voy a escribir la fórmula en función de x y y y luego cambiamos al valor de th para
que sea más sencillo de entender. Entonces la función sería seno de un medio por, si
ven que me equivoco con los símbolos es que tengo, me he acostumbrado últimamente a programar
con el teclado en finlandés y los caracteres están en posiciones diferentes y todavía
no me acostumbro. Pero bueno, x al cuadrado menos un cuarto, lo tengo apuntado aquí en
un posit, por eso estoy mirando aquí abajo, de y al cuadrado más tres. Todo esto por
coseno de 2x más uno menos e elevado a y. Vale, esta sería la función que queremos
optimizar. Como he dicho, lo que le estamos pasando como variable de entrada es un vector
de parámetros th, que como verán en nuestra fórmula no aparece en ningún lado, pero
también porque lo he puesto en función de x y y. Lo que vamos a hacer ahora es sustituir,
es como si nosotros ya cuando ya fuéramos a llamar a nuestra función le vamos a pasar
un vector que contiene la x y que contiene la y. Es decir, aquí en vez de la x pues
sería th sub 0, aquí sería th sub 1, de nuevo la x aquí sería th sub 0 y esto sería th sub 1. Vale, ejecutamos
esto con control enter y ya tendríamos nuestra función creada. De hecho ahora ya la tenemos
creada y como es una función anónima pues podríamos llamarla. Si le pasamos el vector
como es un vector usamos corchetes y le tenemos que pasar dos valores que serían la x y la y.
Por ejemplo le pasamos 2 y 3, lo ejecutamos y nos da un valor. 2 y 5, 5 y 3 menos 0, 59. Vale, con lo
cual ya tendríamos nuestra función definida. En este caso lo que vamos a optimizar, como hemos
visto la imagen, es esta función de aquí y es una visualización en tres dimensiones. ¿Por qué?
Porque tenemos dos parámetros que serían nuestro eje x y nuestro eje y. Y luego tendríamos para
cada uno de los valores de x e y un valor asignado por nuestra función de coste o por nuestra función
que sería la altura. Es decir, esta superficie tridimensional en tres dimensiones se corresponde
a tener dos parámetros. Como ya sabemos podríamos tener muchos más parámetros. Podríamos tener
mil parámetros y entonces sería una figura mil y una dimensional, pero claro eso no lo podríamos
visualizar. Así que bueno, vamos a trabajar con esto hoy. ¿Qué vamos a hacer ahora? Bueno, vamos a
intentar sacar, no sé si se acuerdan del vídeo que teníamos en la parte final cuando yo les enseñaba
la parte del learning rate, el ratio de aprendizaje, que veíamos cómo la figura tridimensional
normalmente la podríamos ver a vista de pájaro, ¿no? Visto desde arriba y podríamos ver los
desniveles en función de los aros que se veían. Bueno, vamos a intentar generar esa visualización
para que sea mejor trabajar con esta función. Y para eso lo que vamos a hacer es pues vamos a
generar un vector con una secuencia de valores de x, un vector con una secuencia de valores de y,
y para cada una de las combinaciones de esos valores la vamos a evaluar con nuestra función.
Eso lo vamos a representar luego en una gráfica y deberíamos de ver el desnivel de nuestra función.
Entonces lo que acabo de comentar se hace muy fácilmente. Utilizamos la función espacio
lineal, linear space, de Numpy para decirle que queremos que nos genere un vector que vaya de
menos 2 a 2 y que genere 100 valores, ¿vale? Pero bueno, en vez de 100 valores vamos a ponérselo
como una variable para tenerlo más organizado, que va a ser una variable resolution, ¿vale? La
resolución del mapa que estamos generando. Entonces es como decirle, en el eje x queremos 100
coordenadas, queremos 100 coordenadas. Y lo mismo queremos para el vector y. O sea, si no conocen lo
que hace esta función para que la puedan ver, estos son los valores que nos está generando. Nos
está generando 100 valores, 100 porque es lo que hemos asignado a la variable res, que va desde menos
2 hasta 2. Es una interpolación de los valores que hemos puesto aquí. Y lo mismo tendríamos en la
variable y. Lo que queremos ahora es que para cada combinación de x e y nos genere, nos evalúe la
función y nos genere un nuevo valor. Con lo cual, ¿cuántos valores vamos a tener? Pues tendríamos
100%. Vamos a tener una matriz de 100%. Con lo cual, antes de generarla, tenemos que crear
una variable para guardar todos esos valores. Con lo cual vamos a crear una matriz de 0 con
elementos nulos, que tenga tamaño res por res. Ahora lo que tenemos que hacer simplemente pues
sería recorrer los elementos de, vamos a usar enumerate, los elementos del vector x. Cuando
utilizamos aquí enumerate, lo que hace es recorrer el vector y para cada elemento devuelve su índice y
su valor. El índice lo estamos guardando en ix y el valor lo guardamos en x. Lo mismo vamos a hacer
porque tenemos que hacer dos bucles para el elemento i. Y ahora simplemente lo que tenemos
que hacer es guardar los valores de nuestra función, es decir, vamos a llamar a nuestra función y le
vamos a pasar el elemento x y el elemento y. Y recordemos que esto se pasa como un vector de
parámetros. ¿Vale? ¿Es correcto? Sí. Vale, lo que nos faltaría aquí decirle es en qué índice queremos
guardar, en qué posición de nuestra matriz z que hemos creado aquí arriba, vamos a guardar el valor.
Y me he parado en este punto porque puede causar confusión. Porque piensen, la variable z es una
matriz y una matriz tú el primer índice lo usas para referirte al número de filas y el segundo
índice para referirte al número de columnas. Es decir, primero las filas que sería el eje y y
luego las columnas que sería el eje x. Con lo cual aquí los índices habría que poner primero
índice de y e índice de x. Porque si lo hiciéramos de otra manera pues saldría mal. Ejecutamos esto
y ya tendríamos en nuestra variable z, vamos a comprobarlo, efectivamente tenemos todos los
valores asignados por la función. Lo que vamos a usar ahora para visualizar esta vista de pájaro
que comentaba es una función de la librería matplotlib que se llama contour. Vamos a ver cómo
funciona. Recuerdan que si utilizamos el nombre de la función y la interrogación pues podemos ver
una ventana con la documentación que nos dice cómo podríamos utilizarla. En este caso pues
te dice pásale la variable x, la variable y y la variable z. Y en la variable z pues tienen que
estar los valores correspondientes a la función que queremos representar, que es exactamente lo
que tenemos. Pues eso vamos a hacer. Cogemos x, cogemos y y cogemos z. Y esto lo vamos a mostrar.
Vamos a cerrar la ventana documentación, ejecutamos y aquí tendríamos las anillas.
Como vemos no se ve muy bien exactamente la superficie, pero podemos incrementar la resolución,
el número de anillas que tenemos en nuestra visualización con el siguiente parámetro
de la función contour. Y como ven así se podría ver mejor. A mí me gusta más una versión de esta
función que es contour f, que lo que nos daría sería la versión sólida, una malla sólida de
este plano. Entonces para que entiendan bien lo que estamos viendo sería la superficie
tridimensional que les he enseñado antes, pero vista desde arriba, donde pues cada color representa
diferentes niveles de altura en nuestra función de coste. Para que esta visualización sea mejor
estaría bien añadirle un colorbar que nos va a indicar la leyenda de exactamente de la altura.
Entonces vemos que aquí las zonas amarillas se corresponden a valores de 0,88 seguramente llegue
hasta 1 y las zonas azules a zonas de menos 0,88, zonas negativas. Con lo cual esto serían nuestros
picos y estos serían nuestros valles, nuestros barrancos. Nuestro método de gradient descent,
por ejemplo, si estuviera aquí arriba pues tendría que buscar alguna forma de llegar a alguna zona de
ésta de aquí, ¿vale? Muy bien, pues ya tenemos creado el entorno sobre el cual vamos a trabajar.
¿Qué tendríamos que incluir ahora? Bueno, vamos a generar un punto aleatorio sobre esta superficie.
Para eso pues vamos a utilizar, vamos a generar un vector que vamos a llamar z,
vamos a utilizar la librería Numpy con el módulo random para generar dos valores aleatorios.
Aquí le estaríamos pidiendo estos dos valores. Lo que pasa es que estos valores irían del rango
01, pero sin embargo nosotros hemos definido aquí la visualización de menos 2 a 2, con lo cual para
que el punto pueda aparecer en ese rango, pues si estamos en 01 lo que tendríamos que hacer sería
multiplicar esto por 4, multiplicar por 4 y ahí tendríamos rango 04 y restarle 2 para que se nos
quede en el rango menos 2, 2, ¿vale? Vale, módulo Numpy no tiene random porque esto es random, ¿vale?
Entonces vamos a visualizar ahora sobre nuestra superficie esta variable que acabamos de crear,
esto sería z sub 0 y z sub 1, que me lo muestre como un punto gordo y de color rojo. Lo ejecutamos y no
pasa nada porque nos ha faltado añadir un plot show y de hecho tendríamos que quitar este de aquí
para que se nos ponga en la misma gráfica. ¿Vale? Por algún motivo no ha cogido el color.
Ah, vale, porque me ha faltado añadirle la variable color. Ahí estaría, perfecto.
¿Ves? Cada vez que ejecutamos pues el punto aparecería en una zona diferente. Con esto ya
tendríamos todo listo para empezar a generar nuestro sistema de gradient descent. Entonces,
para tener un poco claro lo que estamos haciendo, ahora mismo tenemos generado un punto que tiene
dos combinaciones de nuestros parámetros, dos valores de nuestros parámetros. Eso sería el
equivalente a las coordenadas norte-sur o bueno, mejor dicho, las coordenadas latitud-longitud.
Latitud y longitud, ¿vale? Tendríamos dos valores que nos llevarían a una superficie del mapa.
Ahora lo que queremos hacer es hacer los pasos que vimos en el vídeo. Si tú te encuentras en
una montaña y tienes que descender con los ojos cerrados, tú en ese punto en el que te encuentras,
lo que tendrías que hacer, una idea sería tantear a tu alrededor con el pie, tantear por ejemplo hacia
la dirección longitud, tantear con el pie hacia adelante o hacia atrás, y detectas cuál es la
inclinación del terreno en el que te encuentras. Si detectas que la pendiente está hacia una
dirección, pues tú lo que tienes que hacer es moverte hacia la dirección contraria. Y lo
mismo harás en la otra dimensión, en la latitud. Y esto de manera combinada, pues poco a poco te
va a hacer ir hacia una superficie cada vez más baja. Pues eso es lo que queremos hacer aquí.
Para hacer esto la herramienta que vamos a utilizar son las derivadas parciales, ¿vale? Con la derivada
parcial, como vimos en el vídeo, pues lo que consigues es calcular la pendiente de la función
en dicho punto, y esa información la podemos utilizar para poco a poco ir descendiendo la
pendiente. Entonces la derivada parcial lo que te permite es obtener la pendiente, pero para cada
uno de los ejes de tu vector de parámetros. Con lo cual lo que vamos a hacer en este caso
pues será evaluarlo también para cada uno de los elementos de dicho vector. Entonces vamos a usar de
nuevo enumerate de nuestro vector z, para recorrer cada uno de los componentes dentro de nuestro
vector. Y en este caso la derivada parcial la vamos a calcular utilizando un método que es un
aproximación de la derivada parcial, que es un método de pequeñas diferencias, de diferencias
mínimas, creo que se llama. Y bueno, en este caso lo estamos haciendo por el propósito del
tutorial, pero normalmente lo que utilizaríamos sería cualquier librería que te ofrezca
cálculo numérico como Numpy o SciPy, te ofrecen módulos de autodiferenciación, con lo cual podrías
utilizar eso automáticamente para derivar cualquier función que le proporcione. Pero bueno, en este
caso como el método que vamos a utilizar tampoco es muy complicado, pues lo vamos a hacer. Ese método
consiste en calcular pequeñas diferencias entre los parámetros de entrada de tu función y eso
te va a proporcionar la derivada. Es decir, una derivada al fin y al cabo es un pequeño incremento,
o sea, cuánto varía tu output de la función en función de un pequeño incremento en el input,
con lo cual tú podrías calcular un ratio de la diferencia entre la función de x más un pequeño
incremento menos la función de x. Y así podrías saber cuánto es la diferencia de la salida de la
función en función de un pequeño cambio de la entrada. Bueno, un poco rollo, pero ya verán que
programado es muy sencillito. Entonces lo que estamos haciendo es recorrer nuestro vector z,
y de hecho lo que vamos a hacer antes es generar una copia, porque si no, como vamos a manipular
valores dentro de nuestro vector, va a ser bastante complicado. Lo que queremos es coger
primero el primer componente de nuestro vector, el que nos indique el índice de nuestro bucle,
vamos a seleccionar un elemento y vamos a incrementarlo en una pequeña cantidad. Esta
pequeña cantidad la vamos a llamar ach y lo vamos a definir aquí fuera como una variable,
que es más correcto. Vale, y con eso lo que hemos hecho es incrementar un poquito uno de
los componentes de nuestro vector z. Ahora vamos a calcular nuestra derivada evaluando cómo varía
nuestra función si le pasamos este vector manipulado con este pequeño incremento frente
al input original que sería el que tendríamos guardado en nuestro valor z. Esta diferencia es
un ratio y se tiene que dividir por el incremento que estás calculando. Si hiciéramos esto, tendríamos
la derivada parcial, por ejemplo, si estuviéramos evaluando el primer componente de nuestro vector,
tendríamos la derivada parcial del primer vector, es decir, la pendiente de movernos en el eje
de z sub 0, pues ahí tendríamos la pendiente que vamos a utilizar. En la siguiente iteración,
pues lo hará lo mismo con el componente z1 y ahí ya tendríamos los dos componentes que
tendríamos que calcular. Eso es lo que va a conformar nuestro vector que vamos a llamar gradiente.
Le llamamos grad, que va a ser un vector que tenga tantos componentes como, en este caso
sabemos que tenemos dos, pues vamos a poner todos directamente. Y entonces pues en esta
iteración vamos a coger y vamos a decirle que no guarde el valor que hemos calculado, ¿vale?
Con lo cual, tras dos iteraciones, pues tendremos un vector gradiente que podremos utilizar para
actualizar nuestros parámetros y así minimizar poco a poco nuestra función. Vamos a verlo. Si
nos vamos fuera de la función, podemos utilizar, podemos actualizar el valor de z,
decrementando el valor de nuestro vector gradiente. Esto sería la fórmula que vimos en el vídeo,
si se acuerdan. Solo faltaría un componente para añadir que sería el ratio de aprendizaje,
learning rate. Y que lo vamos a definir también aquí arriba. Ahora hablamos del learning rate, ¿vale?
¿Qué sucede? Bueno, tal y como lo hemos definido esto aquí, solo se ejecutaría una iteración. Es
decir, calcularíamos el gradiente para una iteración y se acabaría la función. Sin embargo,
gradient descent es un método de optimización iterativo, con lo cual tendríamos que repetir
esta lógica de aquí más de una vez. Y eso lo vamos a hacer añadiendo otro bucle más.
Y vamos a hacer que se repita, por ejemplo, mil veces.
Entonces, si esto funcionara correctamente, podríamos ver como nuestro vector z en cada
iteración se va actualizando y si lo evaluamos con nuestra función, pues poco a poco el valor
de nuestra función va decrementando. Porque es la lógica que estamos generando y que sabemos
del vídeo que ya hemos visto. Entonces, vamos a hacer un print en cada iteración para ver cómo
este valor se decrementa. A ver, vale, esto estaría mal porque le falta una s. Aquí estaría.
Vale, por lo que veo los valores son un poco aleatorios, así que o una de dos o hay algún
fallo aquí o hay que ponerle de momento un learning rate más bajo. Vale, sí, correcto.
Bueno, correcto parcialmente. Por un momento decrementa y luego vuelve a incrementar. No,
tampoco. Vamos a ponerle uno más bajo y si no, buscamos ver si hay algún fallo.
Vale, aquí sí parece que está poco a poco decrementando, ¿lo ven? Efectivamente, ahí estaría.
De repente toma valores un poco extraños, que no sea que se deben. Vale, parece que
parece que decrece, pero en algunos momentos incrementa y ya por ejemplo detectado un fallo
aquí en el código que si se fijan aquí cuando recorremos cada uno de los componentes de nuestro
vector, en la primera iteración efectivamente incrementamos el primer componente con h,
pero luego cuando vamos al siguiente componente el primer componente todavía sigue con ese
incremento, con lo cual lo estaríamos haciendo mal. Lo que habría que hacer es que cada vez que
llegamos a una iteración de éstas tenemos que asignarle de nuevo el valor original de
el vector z. Esto sería más, bueno, sería la forma correcta de hacerlo. Ejecutamos de nuevo y
vamos a comprobar. Vale, parece que decrece más lentamente, así que ahora vamos a incrementarle
el ratio de aprendizaje. Parece que sí está funcionando correctamente. Yo creo que una
forma guay de ver este proceso que estamos haciendo sería graficar de cuando en cuando los puntos
sobre la visualización que teníamos antes. Entonces vamos a coger nuestra función de plot,
vamos a llevarnos esto para arriba antes de hacer el proceso de optimización para que nos muestre
el punto de partida y le vamos a poner un color un poco más llamativo y que sea diferente,
vamos a ponerlo en blanco, vamos a ponerle un punto final que será el punto con el que
cabe nuestro vector z, vamos a hacer que sea verde y cada cierto tiempo vamos a ponerle, por ejemplo,
cuando el número de iteraciones que lo hemos puesto como barra baja, que lo tenemos aquí arriba,
bueno, cuando el número de iteraciones, el módulo, sea igual a 0, es decir, cada 100
iteraciones vamos a dibujar aquí un puntito y con eso poco a poco podremos ver el recorrido
que hace nuestro punto sobre nuestra superficie, así podremos saber exactamente si está funcionando
como debido. Vamos a verlo, podemos quitar ya este print para afuera, ejecutamos. Vale, en este caso
vemos que recorre muy poquita distancia, vamos a ejecutar de nuevo, muy muy poca distancia. ¿Eso
que se debe? Pues si se acuerdan del vídeo, a tener un ratio de aprendizaje muy pequeño. Vamos
a incrementar, sin embargo, el número de iteraciones también porque son muy bajas. Vale, aquí lo vemos,
hay un recorrido un poco mayor pero sigue siendo muy pequeño, vamos a incrementar el ratio de
aprendizaje, vamos a ponerlo así, ahí estaría. Recordemos, nuestro punto de partida es el blanco,
que sería esta superficie de aquí, como vemos, sería como la falda de una montaña, que sería
esta montaña de aquí, y el punto baja baja baja y luego llega hasta aquí y detecta este barranco y
se va hacia esta zona, que como vemos aquí es una zona mínima de nuestra función, es decir,
está funcionando correctamente. Vamos a ver qué pasaría si incrementamos el ratio de aprendizaje.
Recuerden que esto, el ratio de aprendizaje es un valor, un parámetro de nuestro modelo,
que tenemos que ajustar correctamente para que la optimización funcione correctamente. Hay que
diferenciar que este parámetro no es equivalente a los parámetros que estamos optimizando, sino que
es un parámetro del modelo y a esto en Machine Learning se le suele llamar hiperparámetro y suele
ser también un campo bastante interesante, que es la optimización de los hiperparámetros. Pero bueno,
recuerden que un ratio de aprendizaje muy pequeñito lo que va a hacer es que demos muchos pasos para
movernos en muy poca distancia, eso va a ser muy ineficiente, que es lo que estamos viendo que pasaba,
por ejemplo en este caso. Aquí apenas nos moveríamos, ¿ves? Poca distancia. Pero sin embargo,
si ponemos un valor que es muy elevado, a ver 0,1 cómo funciona, vamos a poner un poquito menos,
0,01. Vale, en este caso estaría funcionando. Vamos a bajarle la cantidad de iteraciones que
dibujo un punto para que podamos ver más puntos. Ahora va a tardar más porque tiene que hacer más
dibujos por iteración. A ver, estoy buscando un ejemplo que nos sirva. Vale, bueno, de momento con
este valor del learning rate todavía funciona bien. Vamos a incrementarlo a 0,05. Vale, todavía sigue
funcionando bien. Vamos con 0,05. Ejecutamos de nuevo. Vale, ¿qué ha pasado aquí? Bueno,
si se fijan, esta superficie de aquí que está dibujada es el área en el que estamos visualizando
nuestra función, que estaba en menos 2,2. Sin embargo, de repente nuestro gradient descent ha
decidido que los puntos pues no, tiene que ir a zonas de menos 60, menos 50, menos 30, o en el
eje X pues también hasta 30. Es decir, lo que ha pasado es que hemos puesto un learning rate tan
elevado que el punto, en vez de converger en una zona mínima, pues ha empezado a pegar saltos por
nuestra superficie y ha acabado yéndose a fuera del dominio que estamos visualizando. Es decir,
esto era el otro problema que veíamos que pasaba con el learning rate. Si tienes un valor muy elevado
pues vas a tener complicaciones en cuanto a la convergencia de este algoritmo. Pues aparentemente
ya estaría funcionando. Esto sería el algoritmo del gradient descent. Como ven es muy muy sencillo,
se programa en cuatro líneas de código sin ninguna dificultad y como digo esto es una de
las piezas claves dentro del mundo de las redes neuronales que empezaremos a ver poco a poco.
Antes de acabar les quería enseñar este ejemplo de aquí que si recuerdan está basado en el primer
ya notebook que hicimos. Acuerdan que vimos el método de regresión lineal y que lo resolvíamos,
hacemos el proceso de optimización con el método de mínimos cuadrados ordinarios. Como sabrán del
vídeo que ya presentaste un par de semanas, el método de cuadrados ordinarios se podía resolver
de forma analítica con una función, con una ecuación, porque se trataba de una función
convexa que simplemente tenía un mínimo global y que podíamos encontrar pues eso aplicando
simplemente una ecuación. Sin embargo eso no significa que no puedas resolver el método de
regression lineal, el modelo de regresión lineal utilizando el método del gradient descent que es
un método iterativo y como podemos ver aquí pues tenemos nuestra nube de datos, tenemos nuestra
línea dibujada y si dejamos que el método de gradient descent opere en cada iteración pues
veremos cómo la línea poco a poco, ahí estaría, se reajusta a la nube de puntos. Como ven la
diferencia con el método de mínimos cuadrados ordinarios es que aquí la solución se va
aproximando en cada iteración, es un método iterativo. Claro si tú fueras a tratar el método
de regresión lineal pues dependería de las circunstancias, si tienes muchos muchos datos a
lo mejor te interesa utilizar gradient descent pero la mayoría de ocasiones el método de cuadrados
ordinarios sería lo fundamental. Pero gradient descent como ya hemos visto pues es el método
optimización clave para funciones no convexas. Nada más quería simplemente enseñaros esta
cosa porque era la otra forma de resolver el modelo de regresión lineal y bueno y eso sería
todo por el tutorial de hoy yo creo que ha sido algo interesante de ver, hemos programado lo que
habíamos visto en el vídeo y bueno y nada más quiero saber vuestros comentarios quiero saber
si les ha gustado este tutorial si más o menos les ha quedado claro estudien bien todo el contenido
del canal porque dentro de una semana una semana y media ya llegará el vídeo donde empezaremos a
meternos un poquito con las redes neuronales y efectivamente pues todos estos vídeos tendrán
asociados también un IAN Notebook en el que iremos poco a poco también programando este tipo de
redes que yo sé que más de uno está interesado. Nada más dejen un like dejen vuestro apoyo pueden
seguirme por twitter por facebook también tenemos la página de facebook también agradecer a mis
patreons que en el pasado vídeo agradecía tanto a junior como a laura por estar apoyando el canal
financieramente y este mes han sumado tres personas más a esta labor de financiación del canal que la
verdad que es bastante motivador a ver qué gente quiere apoyar el canal la verdad que bastante
motivador y en este caso pues también le agradezco a Débora que se ha añadido a Pablo Ibar y a Santi
García Cremades que pues me hace mucha ilusión que estén todos ellos apoyando el canal nada más
nos vemos en el próximo vídeo y pues nada a seguir programando