<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Programming on Matias Di Bernardo</title><link>https://dibernardo.netlify.app/es/categories/programming/</link><description>Recent content in Programming on Matias Di Bernardo</description><generator>Hugo -- gohugo.io</generator><language>es</language><copyright>Matías Di Bernardo</copyright><lastBuildDate>Wed, 17 Apr 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://dibernardo.netlify.app/es/categories/programming/index.xml" rel="self" type="application/rss+xml"/><item><title>Generador de ruitnas de entrenamiento automáticas</title><link>https://dibernardo.netlify.app/es/p/generador-de-ruitnas-de-entrenamiento-autom%C3%A1ticas/</link><pubDate>Wed, 17 Apr 2024 00:00:00 +0000</pubDate><guid>https://dibernardo.netlify.app/es/p/generador-de-ruitnas-de-entrenamiento-autom%C3%A1ticas/</guid><description>&lt;h1 id="generador-automático-de-rutinas-de-ejercicio">Generador Automático de Rutinas de Ejercicio
&lt;/h1>&lt;p>Este proyecto fue el trabajo final para la asignatura Algoritmos y Programación II en la UNTREF. La idea de la aplicación es funcionar como una planificación inteligente de rutinas de ejercicio, donde el usuario ingresa ciertos criterios y el programa establece la mejor rutina para maximizar las preferencias del usuario. El programa fue escrito en el lenguaje de programación Go.&lt;/p>
&lt;h2 id="gestión-de-datos">Gestión de Datos
&lt;/h2>&lt;p>Este curso no se centra en bases de datos, por lo que optamos por usar un archivo CSV para simular una base de datos. Este archivo contiene toda la información sobre las diferentes rutinas y sus atributos. Esto sirve como un archivo de persistencia mientras que toda la lógica es manejada por el programa.&lt;/p>
&lt;p>Los diferentes ejercicios están categorizados por temáticas. Hay dos entidades en el programa que están representadas como structs en Go: los Ejercicios y las Rutinas.&lt;/p>
&lt;h3 id="ejercicio">Ejercicio
&lt;/h3>&lt;p>Todos los ejercicios tienen los siguientes atributos:&lt;/p>
&lt;ul>
&lt;li>Nombre: Nombre del ejercicio.&lt;/li>
&lt;li>Descripción: Descripción detallada del ejercicio.&lt;/li>
&lt;li>Duración: Duración estimada del ejercicio.&lt;/li>
&lt;li>Calorías: Número de calorías quemadas durante el ejercicio.&lt;/li>
&lt;li>Tipo: Tipo de ejercicio (por ejemplo, cardio, fuerza, flexibilidad).&lt;/li>
&lt;li>Grupo Muscular: Grupo muscular objetivo del ejercicio.&lt;/li>
&lt;li>Puntos: Puntos asignados al ejercicio según sus tipos.&lt;/li>
&lt;li>Dificultad: Nivel de dificultad del ejercicio.&lt;/li>
&lt;/ul>
&lt;h3 id="rutinas">Rutinas
&lt;/h3>&lt;p>Todas las rutinas son una colección de ejercicios. Estas se procesan como una lista enlazada de ejercicios. Además, las rutinas tienen los siguientes atributos:&lt;/p>
&lt;ul>
&lt;li>Nombre: Nombre de la rutina.&lt;/li>
&lt;li>Ejercicios: Cadena que almacena los IDs de los ejercicios en la rutina, separados por comas.&lt;/li>
&lt;li>EjerciciosDisponibles: Lista enlazada de los ejercicios disponibles para crear la rutina.&lt;/li>
&lt;/ul>
&lt;h2 id="algoritmo">Algoritmo
&lt;/h2>&lt;p>La idea es maximizar diferentes parámetros, por ejemplo, la cantidad máxima de calorías quemadas en el menor tiempo posible, o la duración mínima para un grupo muscular o tipo de ejercicio específico. Para encontrar las mejores soluciones basadas en los datos existentes, proponemos un algoritmo de programación dinámica que busca todas las posibilidades a partir de los datos y encuentra el máximo o mínimo según las especificaciones del usuario. El enfoque de programación dinámica utiliza memoria para evitar recalcular combinaciones que ya fueron computadas, lo que optimiza el algoritmo lo suficiente como para generar las rutinas en milisegundos (con el conjunto de datos de prueba evaluado).&lt;/p>
&lt;h2 id="interfaz-de-usuario">Interfaz de Usuario
&lt;/h2>&lt;p>Actualmente, el programa está diseñado para ser utilizado desde la terminal como una aplicación CLI. El usuario puede crear un ejercicio y una rutina, listar las opciones disponibles y generar una rutina personalizada basada en las especificaciones que elija.&lt;/p>
&lt;p>Esta es la primera iteración del proyecto y es completamente funcional, pero planeamos crear una interfaz gráfica para que sea más amigable para el usuario. Para este propósito, sería mejor usar un framework diferente y utilizar esta aplicación en Go como backend para un servicio web o una aplicación.&lt;/p>
&lt;h2 id="conclusiones">Conclusiones
&lt;/h2>&lt;p>Con este proyecto, solidifiqué mis conocimientos sobre temas de programación como estructuras de datos y algoritmos, ya que aplicamos la teoría vista en clase a un caso real. También me ayudó a familiarizarme con el lenguaje Go, que se convirtió en un lenguaje que disfruto mucho programar. El código de este proyecto está disponible en este &lt;a class="link" href="https://github.com/MatiasDiBernardo/Workout-routine-generator" target="_blank" rel="noopener"
>repositorio&lt;/a>.&lt;/p></description></item><item><title>Z-Plane Visualizer</title><link>https://dibernardo.netlify.app/es/p/z-plane-visualizer/</link><pubDate>Sat, 12 Aug 2023 00:00:00 +0000</pubDate><guid>https://dibernardo.netlify.app/es/p/z-plane-visualizer/</guid><description>&lt;img src="https://dibernardo.netlify.app/p/z-plane-visualizer/frontz.PNG" alt="Featured image of post Z-Plane Visualizer" />&lt;p>En el curso de &lt;em>Procesamiento Digital de Señales&lt;/em> (DSP) en la UNTREF, exploramos el plano Z para el diseño de filtros con variables discretas. Durante la clase, el profesor presentó una herramienta construida en MatLab que visualiza los gráficos de transferencia y fase en relación con las posiciones de los ceros y polos en el plano Z.&lt;/p>
&lt;p>Inspirado en esto, decidí recrear esta herramienta en Python. Aprovechando mi experiencia con la biblioteca PyGame, logré construir una aplicación en tiempo real que permite mover los polos y ceros, permitiendo a los usuarios ver cómo cambia la función de transferencia en tiempo real.&lt;/p>
&lt;h2 id="cómo-funciona">Cómo Funciona
&lt;/h2>&lt;p>Primero, mapeo las posiciones de los píxeles en el plano Z a coordenadas de acuerdo con la representación del círculo unitario. Luego, construyo la función de transferencia, donde cada cero $z_{n}$ es un término en el numerador y cada polo $z_{i}$ es un término en el denominador. Con la función de transferencia $H(z)$, puedo graficar tanto el magnitud como el gráfico de fase, que también son representaciones mapeadas de la respuesta normalizada dentro de la aplicación.&lt;/p>
$$
H(z) = \frac{\sum_{n=0}^{N} (z - z_{n})}{\sum_{i=0}^{N} (z - z_{i})}
$$&lt;p>Cada fotograma recalcula la función de transferencia. El programa funciona de manera eficiente porque almaceno los ceros y polos en arreglos, lo que permite cálculos más rápidos gracias a numpy, que ya está altamente optimizado. Esto permite visualizar los cambios en tiempo real y proporciona una comprensión más intuitiva del comportamiento del plano Z. El siguiente fragmento de código muestra como se calcula la magnitud y fase utilizando exponenciales complejas.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">e&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">root&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">root&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">transfer_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">zeros&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">poles&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">w&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">linspace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">RES&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">zero&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">zeros&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">zero&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">pole&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">poles&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pole&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">H_z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">num&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">den&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mag&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">abs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">H_z&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ang&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">angle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">H_z&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">mag&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ang&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Este proyecto está diseñado como material educativo, proporcionando a los estudiantes una herramienta práctica para comprender mejor las interacciones entre los polos y ceros en el plano Z. No está destinado como una herramienta profesional para el diseño de filtros.&lt;/p>
&lt;h2 id="funcionalidad">Funcionalidad
&lt;/h2>&lt;p>La aplicación ofrece las siguientes características:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Mostrar y mover polos/ceros&lt;/strong>: Los usuarios pueden seleccionar y mover los polos y ceros en el plano Z. Cuando la opción de simetría está activa, todos los polos y ceros seleccionados o movidos se colocan de manera simétrica respecto al eje imaginario.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Orden&lt;/strong>: Los usuarios pueden ajustar el orden de los polos y ceros desplazando la rueda del mouse. El orden puede incrementarse o disminuirse, con soporte hasta un orden de 4. El color de cada polo o cero cambia según su orden.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Información&lt;/strong>: Al pasar el cursor sobre un polo o cero, se muestra información sobre su posición, simetría y orden.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Zoom&lt;/strong>: El usuario puede acercar o alejar el plano Z usando los botones de más y menos.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Eliminar&lt;/strong>: El ícono de la papelera elimina todos los polos y ceros del plano. Los usuarios también pueden eliminar polos o ceros individuales haciendo clic derecho sobre ellos.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Gráfico de Magnitud&lt;/strong>: El espectro de magnitud mostrado en la aplicación está normalizado. Esta decisión asegura que el enfoque permanezca en la forma de la magnitud, haciendo que el gráfico sea visualmente significativo para los usuarios. Sin embargo, no captura la diferencia en los valores máximos.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Gráfico de Fase&lt;/strong>: La fase se muestra sin envolver entre $-\pi$ y $\pi$.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="demo">Demo
&lt;/h2>&lt;p>Aquí tienes una demostración rápida de la aplicación en acción:&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
&lt;iframe src="https://player.vimeo.com/video/1045497647" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="vimeo video" webkitallowfullscreen mozallowfullscreen allowfullscreen>&lt;/iframe>
&lt;/div>
&lt;p>El código fuente de este proyecto se encuentra en este &lt;a class="link" href="https://github.com/MatiasDiBernardo/Z-Plane_Visualizer" target="_blank" rel="noopener"
>repositorio&lt;/a>.&lt;/p></description></item><item><title>Algorítmos de modificación de escala temporal</title><link>https://dibernardo.netlify.app/es/p/algor%C3%ADtmos-de-modificaci%C3%B3n-de-escala-temporal/</link><pubDate>Thu, 09 Mar 2023 00:00:00 +0000</pubDate><guid>https://dibernardo.netlify.app/es/p/algor%C3%ADtmos-de-modificaci%C3%B3n-de-escala-temporal/</guid><description>&lt;img src="https://dibernardo.netlify.app/p/time-scale-modification-algorithms/tsm.PNG" alt="Featured image of post Algorítmos de modificación de escala temporal" />&lt;p>Los algoritmos de modificación de escala temporal se utilizan para acelerar o desacelerar la velocidad de reproducción de un audio. Cuando se cambia la tasa de muestreo de un audio, la velocidad cambia, pero también lo hace el tono (al acelerar el audio, suena con un tono más alto). Existen diferentes algoritmos que permiten modificar la velocidad del audio manteniendo constante el tono.&lt;/p>
&lt;p>La principal referencia para este estudio es el siguiente artículo, donde se describen en detalle los distintos algoritmos.&lt;/p>
&lt;blockquote>
&lt;p>A Review of Time-Scale Modification of Music Signals.&lt;br>
— &lt;cite>Jonathan Driedger y Meinard Müller&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;h2 id="comparación-de-algoritmos">Comparación de algoritmos
&lt;/h2>&lt;p>Existen dos algoritmos principales, el &lt;em>Overlap-and-add&lt;/em> (OLA) y el &lt;em>Phase Vocoder&lt;/em> (PV). Ambos logran buenos resultados bajo diferentes señales y condiciones. Para aprovechar las ventajas de ambos métodos, se utiliza una implementación final basada en la &lt;em>Separación Armónico-Percusiva&lt;/em> (HPS), que combina ambos algoritmos y logra los mejores resultados.&lt;/p>
&lt;h3 id="ola">OLA
&lt;/h3>&lt;p>Este método trabaja en el dominio del tiempo, superponiendo secciones del audio (ventanas) y reorganizándolas para lograr un cambio deseado en la velocidad. Este método funciona bien para señales percusivas, pero introduce artefactos cuando se utiliza con señales armónicas o tonales.&lt;/p>
&lt;h3 id="pv">PV
&lt;/h3>&lt;p>Este método opera en el dominio de la frecuencia, combinando fragmentos de audio en este dominio para lograr el cambio deseado en el tiempo. Utiliza el principio del vocoder de fase para propagar la fase entre ventanas, garantizando la continuidad al aplicarse a señales armónicas. Sin embargo, no es efectivo para señales percusivas, ya que el proceso de propagación de fase elimina los transitorios en las señales.&lt;/p>
&lt;p>Creé visualizaciones usando &lt;em>Manim&lt;/em> para mejorar mi presentación en clase. El primer video muestra cómo el algoritmo PV alinea las ventanas para garantizar transiciones suaves en la señal generada a lo largo del tiempo. Para lograrlo, se aplica una ventana gaussiana que mantiene la continuidad y suavidad, incluso al inicio y al final de la secuencia.&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
&lt;iframe src="https://player.vimeo.com/video/1045495557" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="vimeo video" webkitallowfullscreen mozallowfullscreen allowfullscreen>&lt;/iframe>
&lt;/div>
&lt;p>El segundo video muestra los efectos de aplicar el algoritmo PV a una señal que contiene transitorios.&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
&lt;iframe src="https://player.vimeo.com/video/1045495634" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="vimeo video" webkitallowfullscreen mozallowfullscreen allowfullscreen>&lt;/iframe>
&lt;/div>
&lt;p>Como predice la teoría, los transitorios desaparecen porque el algoritmo PV interrumpe la alineación vertical de la fase. Aunque estos ejemplos utilizan señales idealizadas, demuestran de manera efectiva las principales fortalezas y limitaciones del algoritmo.&lt;/p>
&lt;h3 id="hps">HPS
&lt;/h3>&lt;p>Para utilizar ambos métodos con las señales ideales, se emplea el algoritmo HPS. Este algoritmo separa la señal en sus componentes armónicas y percusivas. Funciona comparando la continuidad de la señal en la representación STFT, utilizando un filtro que compara la presencia vertical contra la horizontal en el espectrograma. Con un umbral, se puede definir una máscara binaria sobre el espectrograma para separar las partes percusivas de las secciones armónicas.&lt;/p>
&lt;h2 id="resultados">Resultados
&lt;/h2>&lt;p>Implementamos con éxito todos los algoritmos y los comparamos, verificando los contenidos teóricos presentados en el artículo de referencia. Durante el proceso, desarrollamos un conjunto de herramientas para utilizar estos algoritmos con el lenguaje de programación Python. Todo el código está disponible en este &lt;a class="link" href="https://github.com/MatiasDiBernardo/TSM_Toolkit" target="_blank" rel="noopener"
>repositorio&lt;/a>.&lt;/p>
&lt;h2 id="presentación-académica">Presentación académica
&lt;/h2>&lt;p>El estudio fue presentado junto a mis compañeros en las &lt;em>JAAS&lt;/em> (Jornadas de Acústica, Audio y Sonido). Las principales ideas y conclusiones se expusieron en la conferencia. En el siguiente informe se encuentran todos los detalles y análisis realizados para este proyecto (en español).&lt;/p>
&lt;blockquote>
&lt;p>ALGORITMOS DE MODIFICACIÓN DE ESCALA TEMPORAL.&lt;br>
— &lt;cite>Matías Di Bernardo; Matías Vereertbruhggen; Sebastían Carro&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>A Review of Time-Scale Modification of Music Signal &lt;a class="link" href="https://www.researchgate.net/publication/295082364_A_Review_of_Time-Scale_Modification_of_Music_Signals" target="_blank" rel="noopener"
>paper&lt;/a>.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>JAAS 2023 - Algoritmos de Modificación de Escala Temporal &lt;a class="link" href="https://drive.google.com/file/d/12kPB3qBjczyx7X2XV3ZpBDo1GDO2u4qR/view?usp=sharing" target="_blank" rel="noopener"
>paper&lt;/a>.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>IA aprende a jugar 2048</title><link>https://dibernardo.netlify.app/es/p/ia-aprende-a-jugar-2048/</link><pubDate>Fri, 17 Feb 2023 00:00:00 +0000</pubDate><guid>https://dibernardo.netlify.app/es/p/ia-aprende-a-jugar-2048/</guid><description>&lt;img src="https://dibernardo.netlify.app/p/ai-learns-to-play-2048-game/game_img.jpg" alt="Featured image of post IA aprende a jugar 2048" />&lt;p>Usé este proyecto como introducción al Aprendizaje por Refuerzo (Reinforcement Learning). Habiendo trabajado principalmente con aprendizaje supervisado y no supervisado, quería comenzar con un proyecto pequeño y sencillo para comprender rápidamente las ideas principales y crear algo divertido. Seguí este &lt;a class="link" href="https://youtu.be/L8ypSXwyBds" target="_blank" rel="noopener"
>video de YouTube&lt;/a> como referencia, el cual explica cómo usar Aprendizaje por Refuerzo (RL) para entrenar un modelo capaz de jugar al juego de la serpiente. Para hacerlo más desafiante, apliqué la misma red al juego 2048.&lt;/p>
&lt;h2 id="código">Código
&lt;/h2>&lt;p>El código tiene tres componentes principales:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>El Juego&lt;/strong>: Implementa la lógica del juego y la interfaz gráfica (GUI).&lt;/li>
&lt;li>&lt;strong>Agente&lt;/strong>: Controla la jugabilidad.&lt;/li>
&lt;li>&lt;strong>Modelo de IA&lt;/strong>: Una red neuronal que aprende a jugar y guía al agente.&lt;/li>
&lt;/ul>
&lt;h3 id="estado-del-juego">Estado del Juego
&lt;/h3>&lt;p>Modelé el estado del juego como una matriz de 4x4 que representa el tablero. Las acciones del juego están representadas por un vector con las siguientes posibilidades:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Izquierda&lt;/strong>: [1, 0, 0, 0]&lt;/li>
&lt;li>&lt;strong>Derecha&lt;/strong>: [0, 1, 0, 0]&lt;/li>
&lt;li>&lt;strong>Arriba&lt;/strong>: [0, 0, 1, 0]&lt;/li>
&lt;li>&lt;strong>Abajo&lt;/strong>: [0, 0, 0, 1]&lt;/li>
&lt;/ul>
&lt;h3 id="recompensa">Recompensa
&lt;/h3>&lt;p>El modelo de RL funciona con recompensas para cuantificar cuándo el agente actúa bien o mal. Inicialmente, definí las siguientes recompensas:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>+10 puntos&lt;/strong>: Cuando el agente duplica los puntos. Esto es crucial porque, en 2048, los puntos aumentan exponencialmente.&lt;/li>
&lt;li>&lt;strong>-10 puntos&lt;/strong>: Cuando se pierde el juego. Esto sirve como una penalización sencilla.&lt;/li>
&lt;/ul>
&lt;p>Al principio, el modelo mostraba una mejora lenta. Para solucionarlo, añadí una recompensa adicional:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>+2 puntos&lt;/strong>: Cuando se incrementan los puntos. Esta recompensa incentiva acciones que maximicen la limpieza del tablero y el progreso.&lt;/li>
&lt;/ul>
&lt;h2 id="cómo-funciona-el-modelo">Cómo Funciona el Modelo
&lt;/h2>&lt;p>El modelo es una red neuronal lineal simple. Toma el estado del juego como entrada y predice la mejor acción siguiente para maximizar la recompensa.&lt;/p>
&lt;p>Las recompensas se gestionan utilizando una técnica llamada Q-Learning. Un &lt;em>valor Q&lt;/em> representa la calidad de una decisión basada en la función de pérdida. La función de pérdida se deriva de la &lt;em>Ecuación de Bellman&lt;/em>:&lt;/p>
$$
NewQ(s, a) = Q(s, a) + \alpha [R(s, a) + \lambda \, \text{max}Q'(s', a') - Q(s, a)]
$$&lt;p>Donde:&lt;/p>
&lt;ul>
&lt;li>$Q(s, a)$: El &lt;em>valor Q&lt;/em> para un estado y acción específicos.&lt;/li>
&lt;li>$\alpha$: Tasa de aprendizaje.&lt;/li>
&lt;li>$R(s, a)$: Recompensa para un estado y acción específicos.&lt;/li>
&lt;li>$\lambda$: Tasa de descuento.&lt;/li>
&lt;li>$\text{max}Q&amp;rsquo;(s&amp;rsquo;, a&amp;rsquo;)$: Recompensa futura máxima esperada.&lt;/li>
&lt;/ul>
&lt;h2 id="experimentos-y-resultados">Experimentos y Resultados
&lt;/h2>&lt;h3 id="prueba-aleatoria-como-línea-base">Prueba Aleatoria como Línea Base
&lt;/h3>&lt;p>Para establecer una línea base, probé el puntaje promedio que se puede lograr tomando acciones aleatorias. Después de 1,000 iteraciones, el puntaje promedio fue de &lt;strong>170&lt;/strong>, muy por debajo de los 2048 puntos necesarios para ganar el juego.&lt;/p>
&lt;h3 id="resultados-iniciales">Resultados Iniciales
&lt;/h3>&lt;p>Mis primeros intentos fueron desalentadores. El modelo tenía un desempeño peor que los movimientos aleatorios. Aquí algunos resultados iniciales:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Juego 1,000&lt;/strong> | Puntaje: 208 | Récord: 416 | Puntaje Promedio: 200 | Recompensa: 640&lt;/li>
&lt;li>&lt;strong>Juego 1,000&lt;/strong> | Puntaje: 116 | Récord: 346 | Puntaje Promedio: 161 | Recompensa: 310&lt;/li>
&lt;li>&lt;strong>Juego 1,000&lt;/strong> | Puntaje: 112 | Récord: 348 | Puntaje Promedio: 146 | Recompensa: 320&lt;/li>
&lt;/ol>
&lt;p>En estos intentos, el agente desarrolló una estrategia subóptima de llenar el tablero antes de incrementar los puntos.&lt;/p>
&lt;h3 id="mejoras">Mejoras
&lt;/h3>&lt;p>Tras experimentar con los parámetros de recompensa, me centré en la fase de exploración. Inicialmente, el parámetro de &lt;em>juegos de exploración&lt;/em>, que elige movimientos aleatorios, estaba configurado en 25 juegos. Al aumentar este parámetro, el agente pudo explorar más estrategias, logrando mejores resultados:&lt;/p>
&lt;ol start="4">
&lt;li>&lt;strong>Juego 1,000&lt;/strong> | Puntaje: 478 | Récord: 478 | Puntaje Promedio: 230&lt;/li>
&lt;li>&lt;strong>Juego 1,000&lt;/strong> | Puntaje: 514 | Récord: 964 | Puntaje Promedio: 382&lt;/li>
&lt;/ol>
&lt;p>A medida que el modelo mejoraba, extendí el entrenamiento a más juegos:&lt;/p>
&lt;ol start="6">
&lt;li>&lt;strong>Juego 3,796&lt;/strong> | Puntaje: 770 | Récord: 1,366 | Puntaje Promedio: 469&lt;/li>
&lt;li>&lt;strong>Juego 4,852&lt;/strong> | Puntaje: 631 | Récord: 1,462 | Puntaje Promedio: 483&lt;/li>
&lt;/ol>
&lt;p>Finalmente, con 200 juegos de exploración y 5,000 juegos de entrenamiento, los resultados fueron los siguientes:&lt;/p>
&lt;ol start="8">
&lt;li>&lt;strong>Juego 5,000&lt;/strong> | Puntaje: 840 | Récord: 1,678 | Puntaje Promedio: 512&lt;/li>
&lt;/ol>
&lt;p>Aunque el modelo no logró ganar el juego, quedé satisfecho con el progreso. Creo que con más tiempo de entrenamiento (el último intento duró 4 horas) y capas adicionales en la red, sería posible ganar el juego con esta arquitectura.&lt;/p>
&lt;h2 id="demo">Demo
&lt;/h2>&lt;p>Aquí tienes una demostración de la aplicación, mostrando el proceso de aprendizaje del agente:&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
&lt;iframe src="https://player.vimeo.com/video/1045495533" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="vimeo video" webkitallowfullscreen mozallowfullscreen allowfullscreen>&lt;/iframe>
&lt;/div>
&lt;p>Implementé atajos de teclado para controlar la velocidad del juego, ofreciendo tres opciones:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Rápida&lt;/strong>: Para un entrenamiento acelerado.&lt;/li>
&lt;li>&lt;strong>Lenta&lt;/strong>: Para observar y analizar el progreso del agente y sus errores.&lt;/li>
&lt;li>&lt;strong>Media&lt;/strong>: Casi no la utilicé.&lt;/li>
&lt;/ul>
&lt;p>El código completo para este proyecto está disponible en este &lt;a class="link" href="https://github.com/MatiasDiBernardo/RF_2048-game" target="_blank" rel="noopener"
>repositorio&lt;/a>.&lt;/p></description></item></channel></rss>