viernes, 14 de octubre de 2011

Computación evolutiva: Ejemplo VI

Abstract

Para el ejemplo VI de la serie práctica de algoritmos evolutivos, he implementado un OCR básico, a partir del ejemplo anterior donde realizamos un algoritmo capaz de reconocer los patrones de las vocales mediante aprendizaje evolutivo.

El OCR es bastante básico, pero permite comprobar la potencia de la computación evolutiva en relación al mundo del reconocimiento de patrones.

Ejemplo práctico VI: OCR básico

El programa que os presento a continuación; programado en un applet de Java para que podáis probarlo de primera mano, consigue precisamente eso: aprender a reconocer los patrones de las vocales, en formato Times New Roma, y un tamaño de 8 (8 x 5 = 40 píxeles). Se utiliza una red neuronal cuyos pesos se ajustan mediante una estrategia evolutiva.

El programa actua como un OCR, consiguiendo capturar la información textual dentro de una imagen (en formato GIF), y transcribiendo dicha información en una caja de texto.

Para agilizar la programación necesaria, el OCR sólo reconoce vocales en formato Times New Roman, y un tamaño de letra de 8.

En cualquier momento del entrenamiento, podemos pulsar en el botón Cancelar, y comprobar cómo va mejorando el reconocimiento del patrón.

Una vez entrenada la red neuronal, debemos introducir la ruta url de la imagen a procesar (en formato GIF), y pulsar sobre el botón Pasar OCR.

Las instrucción de uso se pueden esquematizar así:

1) Pulsa sobre el botón Entrenar para que la red neuronal aprenda a reconocer las vocales (espera hasta obtener una media de 120 en la función de evaluación).
2) Abre el Paint de Windows.
3) Crea un nuevo documento, y escribe con la herramienta de texto (con formato Times New Roman, y tamaño 8) todas las vocales que quieras, en cualquier lugar del documento (que pueden no ser consecutivos ni estar alineadas).
4) Guarda la imagen en formato GIF.
5) Sube la imagen a un hosting gratuito de imágenes. Por ejemplo: www.imgur.com.
6) Copia la ruta de la imagen subida (comprueba que la url termina en extensión ".gif").
7) Pega la url en el applet, donde dice URL de la imagen a procesar.
8) Pulsar sobre el botón Pasar OCR.

¡Y listo! Si todo va bien, el applet reconocerá todas las vocales del texto, y las introducirá en orden (y manteniedo los espacios en blanco entre ellas).


Debajo del siguiente applet encontrarás un enlace con el código fuente del ejemplo:

No puede ejecutar applets de Java. Instale la JVM, y vuelva a recargar la página, por favor.

Podéis descargar el código fuente del ejemplo VI desde este enlace.


martes, 11 de octubre de 2011

Computación evolutiva: Ejemplo V

Abstract

El siguiente ejemplo práctico, consiste en una revisión del ejemplo anterior donde realizamos un algoritmo capaz de reconocer las vocales mediante aprendizaje evolutivo.

En esta versión, hemos introducido algo de ruido durante el entrenamiento y prueba del reconocimiento conseguido. El ruido consiste en la introducción o borrado de píxeles en la imagen de la vocal a reconocer.

Ejemplo práctico V: Proyecto evolutivo de reconocimiento de patrones con ruido

El programa que os presento a continuación; programado en un applet de Java para que podáis probarlo de primera mano, consigue precisamente eso: aprender a reconocer los patrones de las vocales, en formato Times New Roma, y un tamaño de 8 (8 x 5 = 40 píxeles). No se usa ninguna técnica estratégica mediante heurística, sólo una red neuronal cuyos pesos se ajustan mediante una estrategia evolutiva.

El programa, al ejecutarse inicialmente el applet, sólo no tiene "conocimiento" alguno, y se limita a dar una respuesta aleatoria, cuando se le presenta los píxles de la imagen de una vocal en Times New Roman.

Para conseguir, de manera on-line; que el programa aprenda a reconocer el patrón de las vocales, debemos pulsar sobre el botón Entrenar. En ese momento, el programa comenzará a seleccionar evolutivamente, los individuos que mejor aproximen sus respuestas cuando se le interroga por las vocales.

En cualquier momento del entrenamiento, podemos pulsar en el botón Cancelar, y comprobar cómo va mejorando el reconocimiento del patrón.

Debajo del siguiente applet con el ejemplo V, explicaré más en profundidad la teoría que sigue el proyecto de aprendizaje automático, y encontrarás un enlace con el código fuente del ejemplo:

No puede ejecutar applets de Java. Instale la JVM, y vuelva a recargar la página, por favor.

Podéis descargar el código fuente del ejemplo V desde este enlace.


Explicación técnica del ejemplo


El proyecto de ejemplo V, tiene las siguientes características técnicas:

Todo el aprendizaje corre a cuenta de una red neuronal; con conexión hacia delante y una capa oculta (hidden layer).

La capa de entrada contiene 40 nodos; uno por cada posible contenido dentro del array que forma el conjunto de píxles de la imagen de la vocal. Hay 5 nodos de salida, los cuales indican la probabilidad de que la vocal pasada sea la que representa sicho nodo de salida.

Inicialmente, los pesos wij de la red neuronal son marcados aleatoriamente, por lo que la respuesta de la red neuronal ante el problema será aleatorio.

Hay pues que entrenar al programa para que aprenda, lo que vamos a conseguir ajustando evolutivamente los pesos de la red neuronal utilizada. Dicho entrenamiento evolutivo se realizará mediante una estrategia evolutiva.

La estrategia evolutiva será representada por un vector de 210 elementos de tipo real. Esos elementos o individuos de selección se van a corresponder con los pesos de los nodos que contiene la red neuronal, de manera que serán esos pesos los que irán evolucionando.

Así pues, la población en evolución, consistirá en n individuos (con n = 15), que tendrán n hijos, con variación exclusiva por mutación -sin recombinación- y cuya función de desempeño (fitness fuction) será calculada mediante competición -selección por torneo-.
Para el proceso de mutación, hay que tener en cuenta que cada individuo; además de un vector de pesos, contiene un vector de variables de ajuste, que también irá evolucionando junto con los pesos.

La mutación es de la forma:



Con alpha igual 0.2f, y donde xi indica el peso en la posición i del vector de pesos, y N(0,1) indica un valor tomado aleatoriamente de una distribución normal de desviación típica igual a 1, y media igual a 0. La otra variable que interviene en el proceso se corresponde con la variable de ajuste del elemento i, que; como se puede ver, muta antes de que lo haga el peso xi.

La evaluación de un individuo se realiza mediante el recuento de los aciertos conseguidos cuando se le pasa las 5 vocales. Se sumará uno cuando se acierta, y se restará uno si falla en el reconocimiento.

Finalmente, el proceso de selección consistirá en tomar los 15 mejores individuos de entre los 30 (15 padres + 15 hijos) individuos de la generación en curso. En caso de empate en la función de desempeño, se favorecerá a los individuos más longevos.

El paso de generaciones tendrá como resultado un ajuste en los pesos de la red neuronal, lo que dará lugar a un entrenamiento de la misma, que será lo que permitirá; a su vez, al programa a reconocer los patrones de las vocales dadas en una imagen GIF.


lunes, 10 de octubre de 2011

Computación evolutiva: Ejemplo IV

Abstract

Siguiendo con la serie de ejemplos prácticos -pulsa aquí para ver el ejemplo III: Aprendizaje automático en el juego 4 en raya- y disponibles con licencia GPL, de algoritmos evolutivos, voy a mostrar ahora otro ejemplo práctico. En esta ocasión se trata de diseñar un algoritmo capaz de aprender a reconocer las letras de las vocales dadas en un archivo GIF.

El esquema principal seguido es el mismo del ejemplo II y III de la serie de ejemplos evolutivos prácticos que estoy desarrollando. Es decir; haciendo uso de estrategias evolutivas y una red neuronal se consigue un apndizaje automático por parte de un programa.

Ejemplo práctico IV: Proyecto evolutivo de reconocimiento de patrones

El programa que os presento a continuación; programado en un applet de Java para que podáis probarlo de primera mano, consigue precisamente eso: aprender a reconocer los patrones de las vocales, en formato Times New Roma, y un tamaño de 8 (8 x 5 = 40 píxeles). No se usa ninguna técnica estratégica mediante heurística, sólo una red neuronal cuyos pesos se ajustan mediante una estrategia evolutiva.

El programa, al ejecutarse inicialmente el applet, sólo no tiene "conocimiento" alguno, y se limita a dar una respuesta aleatoria, cuando se le presenta los píxles de la imagen de una vocal en Times New Roman.

Para conseguir, de manera on-line; que el programa aprenda a reconocer el patrón de las vocales, debemos pulsar sobre el botón Entrenar. En ese momento, el programa comenzará a seleccionar evolutivamente, los individuos que mejor aproximen sus respuestas cuando se le interroga por las vocales.

En cualquier momento del entrenamiento, podemos pulsar en el botón Cancelar, y comprobar cómo va mejorando el reconocimiento del patrón.

Debajo del siguiente applet con el ejemplo IV, explicaré más en profundidad la teoría que sigue el proyecto de aprendizaje automático, y encontrarás un enlace con el código fuente del ejemplo:

No puede ejecutar applets de Java. Instale la JVM, y vuelva a recargar la página, por favor.

Podéis descargar el código fuente del ejemplo IV desde este enlace.


Explicación técnica del ejemplo


El proyecto de ejemplo IV, tiene las siguientes características técnicas:

Todo el aprendizaje corre a cuenta de una red neuronal; con conexión hacia delante y una capa oculta (hidden layer).

La capa de entrada contiene 40 nodos; uno por cada posible contenido dentro del array que forma el conjunto de píxles de la imagen de la vocal. Hay 5 nodos de salida, los cuales indican la probabilidad de que la vocal pasada sea la que representa sicho nodo de salida.

Inicialmente, los pesos wij de la red neuronal son marcados aleatoriamente, por lo que la respuesta de la red neuronal ante el problema será aleatorio.

Hay pues que entrenar al programa para que aprenda, lo que vamos a conseguir ajustando evolutivamente los pesos de la red neuronal utilizada. Dicho entrenamiento evolutivo se realizará mediante una estrategia evolutiva.

La estrategia evolutiva será representada por un vector de 210 elementos de tipo real. Esos elementos o individuos de selección se van a corresponder con los pesos de los nodos que contiene la red neuronal, de manera que serán esos pesos los que irán evolucionando.

Así pues, la población en evolución, consistirá en n individuos (con n = 15), que tendrán n hijos, con variación exclusiva por mutación -sin recombinación- y cuya función de desempeño (fitness fuction) será calculada mediante competición -selección por torneo-.
Para el proceso de mutación, hay que tener en cuenta que cada individuo; además de un vector de pesos, contiene un vector de variables de ajuste, que también irá evolucionando junto con los pesos.

La mutación es de la forma:



Con alpha igual 0.2f, y donde xi indica el peso en la posición i del vector de pesos, y N(0,1) indica un valor tomado aleatoriamente de una distribución normal de desviación típica igual a 1, y media igual a 0. La otra variable que interviene en el proceso se corresponde con la variable de ajuste del elemento i, que; como se puede ver, muta antes de que lo haga el peso xi.

La evaluación de un individuo se realiza mediante el recuento de los aciertos conseguidos cuando se le pasa las 5 vocales. Se sumará uno cuando se acierta, y se restará uno si falla en el reconocimiento.

Finalmente, el proceso de selección consistirá en tomar los 15 mejores individuos de entre los 30 (15 padres + 15 hijos) individuos de la generación en curso. En caso de empate en la función de desempeño, se favorecerá a los individuos más longevos.

El paso de generaciones tendrá como resultado un ajuste en los pesos de la red neuronal, lo que dará lugar a un entrenamiento de la misma, que será lo que permitirá; a su vez, al programa a reconocer los patrones de las vocales dadas en una imagen GIF.


lunes, 3 de octubre de 2011

Cómo desaparecer completamente


Tristeza. Es lo único que desde hace años veo en sus ojos.

Esa que está ahí no es ella (That there, that's not she), porque ella siempre va donde quiere (She goes, where she pleases). Ella ya no está aquí (She’s not here), aunque parezca mentira (This isn't happening). Y en poco tiempo se irá (In a little while she'll be gone). Su tiempo ya ha pasado (The moment's already passed). Ya no está aquí (She’s not here), y no me lo puedo creer (This isn't happening).

La vida es dura, y cruel. Eso lo sabemos todos. Y sin embargo, tenemos motivaciones para luchar. Pero llega un momento; y, por supuesto, con suerte, en el que éstas desaparecen. Lo que nos hacía levantarnos cada mañana, aquello que nos hacía soportar la vida tal y como es.

Debe ser tan sencillo como levantarse un día, y darse cuenta de que ya no eres el que solías ser. Que ese que está ahí, no eres tú (That there, that’s not me). Dejas de ser útil a la sociedad, y te conviertes en una carga, en un ser inválido (The moment's already passed Yeah, it's gone).

Casi sin darte cuenta, ya no puedes hacer nada por ti mismo, no puedes cruzar la puerta
(I go where I please. I walk through walls).

Tormento. No creo que exista otra palabra que describa mejor vivir una vida sin motivaciones. Tormento que podemos ver en los ojos de cualquier anciano, en los ojos de cualquier persona no válida. Desesperación. Tristeza. Se puede casi palpar su constante lucha por querer vivir. Y no hay posible consuelo. Sólo podemos besarles, abrazarles, y; por supuesto, en cuanto podamos mirar hacia otro lado.

No es sólo una muestra más, sino la muestra más clara de la insoportable levedad del ser.

Nota:

La canción que has podido escuchar de fondo, es “How to disappear completely” del grupo Radiohead. A continuación tenéis la letra completa:

That there, that's not me
I go where I please
I walk through walls
I float down the Liffey

I'm not here
This isn't happening
I'm not here, I'm not here

In a little while
I'll be gone
The moment's already passed
Yeah, it's gone

I'm not here
This isn't happening
I'm not here, I'm not here

Strobe lights and blown speakers
Fireworks and hurricanes

I'm not here
This isn't happening
I'm not here, I'm not here....



sábado, 1 de octubre de 2011

Computación evolutiva: Ejemplo III

Abstract

Siguiendo con la serie de ejemplos prácticos -pulsa aquí para ver el ejemplo II: Aprendizaje de estrategias no-loss en el juego 3 en raya o Tic-tac-toe- y disponibles con licencia GPL, de algoritmos evolutivos, voy a mostrar ahora otro ejemplo práctico. En esta ocasión se trata de diseñar un algoritmo capaz de aprender por si solo a jugar bien al famoso juego Conecta 4 -o cuatro en línea-.

El esquema principal seguido es el mismo del ejemplo II de la serie de ejemplos evolutivos prácticos que estoy desarrollando. Es decir; se sigue la idea detrás de Blondie24; un juego de damas, implementado por David B. Fogel, que; haciendo uso de Estrategias Evolutivas y una red neuronal, consiguió que el programa aprendiera, tras 8 meses de entrenamiento, a jugar bien a las damas. Y tan bien aprendió, que consiguió un rating de 2048 –un 99,6% mejor que cualquier jugador humano-.

Ejemplo práctico III: Proyecto Evolutivo para el juego Cuatro en Línea -o Conecta 4-

El programa que os presento a continuación; programado en un applet de Java para que podáis probarlo de primera mano, consigue precisamente eso: aprender a jugar al Cuatro en Línea, sin enseñarle a priori ninguna técnica estratégica mediante heurística, sólo usando una red neuronal cuyos pesos se ajustarán mediante una estrategia evolutiva.

El programa, al ejecutarse inicialmente el applet, sólo "conoce" las reglas básicas del juego, cuándo termina la partida y el resultado de la misma, y sólo sabe prever si tu próximo movimiento la hará perder. Pero no entiende de estrategias, ni es capaz de jugar demasiado bien.

Si pulsamos en el botón Estadísticas, podremos ver cuántas partidas empata o pierde en este momento el programa tras jugar 150 veces contra un jugador que puede ver 6 jugadas hacia delante (ply =6).

Si pulsamos sobre el botón Jugar, veremos que, en cuanto pensamos un poco y aplicamos una estrategia correcta, comenzamos a ganar partidas.

Para conseguir, de manera on-line; que el programa aprenda a jugar, debemos pulsar sobre el botón Entrenar. En ese momento, el programa comenzará a competir consigo mismo una y otra vez, mejorando con el paso de tiempo –de las generaciones- de manera automática su juego. Irá aprendiendo buenas estrategias de juego.

En cualquier momento del entrenamiento, podemos pulsar en el botón Cancelar, y comprobar cómo va mejorando el juego del programa. Si jugamos contra él, veremos que estrategias con las que antes le ganábamos, ahora ya no son efectivas, o que, si pulsamos sobre el botón Estadísticas, el porcentaje de partidas perdidas va disminuyendo.

Debajo del siguiente applet con el ejemplo III, explicaré más en profundidad la teoría que sigue el proyecto de aprendizaje automático, y encontrarás un enlace con el código fuente del ejemplo:

No puede ejecutar applets de Java. Instale la JVM, y vuelva a recargar la página, por favor.

Podéis descargar el código fuente del ejemplo III desde este enlace.


Explicación técnica del ejemplo


El proyecto de ejemplo III, tiene las siguientes características técnicas:

Toda la estrategia de juego, corre a cuenta de una red neuronal; con conexión hacia delante y una capaa oculta (hidden layer).

La capa de entrada contiene 42 nodos; uno por cada posible contenido dentro del array que forma el tablero de juego –con un 1 si la ficha de una casilla es propia, un -1 si la ficha es del adversario, y un 0 si la casilla está vacía-, y un nodo de salida, responsable de devolver el resultado del proceso neuronal: expresando lo bueno o malo que un movimiento concreto es.

Inicialmente, los pesos wij de la red neuronal son marcados aleatoriamente, por lo que la respuesta de la red neuronal ante el problema sobre qué buena o mala es una jugada será también aleatoria.

Hay pues que entrenar al programa para que aprenda a evaluar las jugadas, lo que vamos a conseguir ajustando evolutivamente los pesos de la red neuronal utilizada. Dicho entrenamiento evolutivo se realizará mediante una estrategia evolutiva.

La estrategia evolutiva será representada por un vector de 1848 elementos de tipo real. Esos elementos o individuos de selección se van a corresponder con los pesos de los nodos que contiene la red neuronal, de manera que serán esos pesos los que irán evolucionando.

Así pues, la población en evolución, consistirá en n individuos (con n = 15), que tendrán n hijos, con variación exclusiva por mutación -sin recombinación- y cuya función de desempeño (fitness fuction) será calculada mediante competición -selección por torneo-.
Para el proceso de mutación, hay que tener en cuenta que cada individuo; además de un vector de pesos, contiene un vector de variables de ajuste, que también irá evolucionando junto con los pesos.

La mutación es de la forma:



Con alpha igual 0.2f, y donde xi indica el peso en la posición i del vector de pesos, y N(0,1) indica un valor tomado aleatoriamente de una distribución normal de desviación típica igual a 1, y media igual a 0. La otra variable que interviene en el proceso se corresponde con la variable de ajuste del elemento i, que; como se puede ver, muta antes de que lo haga el peso xi.

La evaluación de un individuo se realiza mediante q partidas (con q = 15), jugadas entre el individuo a evaluar, y otro individuo de la población, tomado aleatoriamente sin reemplazamiento. Cada partida ganada le sumará 1 punto, las perdidas le restará 2, y los empates no suman nada. El valor final será su función de desempeño.

Finalmente, el proceso de selección consistirá en tomar los 15 mejores individuos de entre los 30 (15 padres + 15 hijos) individuos de la generación en curso. En caso de empate en la función de desempeño, se favorecerá a los individuos más longevos.

El paso de generaciones tendrá como resultado un ajuste en los pesos de la red neuronal, lo que dará lugar a un entrenamiento de la misma, que será lo que permitirá; a su vez, al programa a jugar bien, sin intervención heurística alguna.

Detalles adicionales


1º) Para que el aprendizaje automático tenga lugar, es necesario; al menos, prever un movimiento del contrario por adelantado -qué hará él si yo muevo aquí-. Esto se consigue mediante el uso de un árbol min-max de profundidad 2 (ply=2 ), lo que es insuficiente para que la máquina comprenda estrategias, pero que sí permite una base para el ajuste de pesos de la red neuronal. Pero siempre evaluar lo bueno o malo de una jugada será objeto de la red neuronal. Es decir; aunque hay un árbol min-max de ply igual a dos, la evaluación de la tabla de tu movimiento y el mejor movimiento del contrario, la desempeña la red neuronal y no ninguna regla a priori.

2º) La red neuronal utilizada va a devolver siempre un valor real en el rango [-1,1]. Un -1 sólo cuando el movimiento a evaluar termina siendo una victoria del adversario, un 1 si la victoria es suya, y un valor entre (-1, 1) indicando lo bueno que es una jugada para el programa (valores cercanos a 1) o para el contrario (valores cercanos a 1).

3º) El campo llamado Info, en el lateral superior derecho del applet, contiene información sobre el estado del entrenamiento. Conforme pasan las generaciones, la pantalla se actualiza, y muestra datos sobre el mejor individuo de la última generación: su función de desempeño, su edad -cuanto tiempo lleva en el pool evolutivo-, y la media de su juego -resultados/edad-. Cuando juegues contra la máquina, te mostrará la misma información, pero sobre jugador contra el que estás jugando -el mejor que se encontró-.


viernes, 2 de septiembre de 2011

Computación evolutiva: Ejemplo II

Abstract

Siguiendo con la serie de ejemplos prácticos -pulsa aquí para ver el ejemplo I- y disponibles con licencia GPL, de algoritmos evolutivos, voy a mostrar ahora algo que, bien entendido; se comprende es un logro importante, que debemos a dos fundamentales ramas de la IA; como son la computación evolutiva y las redes neuronales.

Estoy hablando de la posibilidad de crear programas que adquieran “conocimiento” estratégico automáticamente sin necesidad de que un programador humano implemente ninguna regla heurística de aprendizaje.

La idea de este ejemplo parte de Blondie24; un juego de damas, implementado por David B. Fogel, que; haciendo uso de Estrategias Evolutivas y una red neuronal, consiguió que el programa aprendiera, tras 8 meses de entrenamiento, a jugar bien a las damas. Y tan bien aprendió, que consiguió un rating de 2048 –un 99,6% mejor que cualquier jugador humano-.

Lo increíble de Blondie24, era que el programador, en ningún momento implementó reglas heurísticas para el correcto funcionamiento del programa. No se escribió qué jugadas son mejores que otras, ni se propuso ningún mecanismo de recompensa por buenas jugadas, ni hizo falta la intervención humana en el aprendizaje en modo alguno. El programador sólo implementó de forma prestablecida las reglas básicas del juego: qué movimientos están permitidos hacer y cuándo alguien ha ganado el juego, y fue Blondie24 la que “aprendió” a jugar, como lo hace cualquier jugador humano –al que nadie le enseñe estrategias sino que aprenda por si mismo-: progresivamente mediante ensayo y error.

Ejemplo práctico II: Proyecto Noelia

Utilizando la teoría tras Blondie24, y algunos de los detalles geniales que David B. Fogel introdujo en su proyecto, me propuse hacer algo similar, pero a menor escala; para poder afrontarlo en poco tiempo, aunque sin perder su esencia.

Para conseguirlo, opté por implementar un programa que “aprenda” por si sólo buenas estrategias de un juego, mucho más elemental que las damas, y bastante utilizado en los ejemplos teóricos de IA: el juego del tres en raya, también conocido como tic-tac-toe. Aunque; tengo que reconocer, finalmente, me propuse algo un poco más ambisioso que eso, consguir no sólo que juegue buenas estrategias, sino que alcance estrategias con las que nunca pierda (no-loss-strategy).

El programa que os presento a continuación; programado en un applet de Java para que podáis probarlo de primera mano, consigue precisamente eso: aprender a jugar al tres en raya, sin enseñarle a priori ninguna técnica estratégica mediante heurística, sólo usando una red neuronal cuyos pesos se ajustarán mediante una estrategia evolutiva.

El programa, al ejecutarse inicialmente el applet, sólo "conoce" las reglas básicas del juego, cuándo termina la partida y el resultado de la misma, y sólo sabe prever si tu próximo movimiento la hará perder. Pero no entiende de estrategias, ni es capaz de jugar bien. Al comienzo, el programa tiene el nivel de una persona muy novata en el juego.

Si pulsamos en el botón Estadísticas, podremos ver cuántas partidas empata o pierde en este momento el programa tras jugar 50 veces contra un jugador experto -simulado mediante heurística, con un árbol min-max y profundidad (ply) de 9 movimientos-. De media, antes de entrenar, el programa perderá un 50% de sus partidas contra dicho jugador experto.

Si pulsamos sobre el botón Jugar, veremos que, en cuanto pensamos un poco y aplicamos una estrategia correcta, comenzamos a ganar partidas.

Para conseguir, de manera on-line; que el programa aprenda a jugar, debemos pulsar sobre el botón Entrenar. En ese momento, el programa comenzará a competir consigo mismo una y otra vez, mejorando con el paso de tiempo –de las generaciones- de manera automática su juego. Irá aprendiendo buenas estrategias de juego.

En cualquier momento del entrenamiento, podemos pulsar en el botón Cancelar, y comprobar cómo va mejorando el juego del programa. Si jugamos contra él, veremos que estrategias con las que antes le ganábamos, ahora ya no son efectivas, o que, si pulsamos sobre el botón Estadísticas, el porcentaje de partidas perdidas va disminuyendo.

Pasadas las generaciones –si se le permite entrenar bastante tiempo-, el programa será igual de efectivo que un jugador humano. Lo que significa que; lo mejor que podrás conseguir contra él serán tablas. El aprendizaje ocurrirá poco a poco, lo que significa que verás una mejora gradual en su calidad de juego. Por poner un ejemplo; es de notar que, tras pasar algunas generaciones de entrenamiento; el programa "comprende" que la mejor estrategia de juego consiste en mover a la casilla central siempre que esté libre.

Hay de tener en cuenta, que sólo notarás una mejora realmente significativa en la calidad de juego a partir de trascurridas algunas generaciones, y que un juego de estrategia no-loss suele llegar aproximadamente en 150 generaciones.

Debajo del siguiente applet con el ejemplo II, explicaré más en profundidad la teoría que sigue el proyecto de aprendizaje automático, y encontrarás un enlace con el código fuente del ejemplo:

No puede ejecutar applets de Java. Instale la JVM, y vuelva a recargar la página, por favor.

Podéis descargar el código fuente del ejemplo II desde este enlace.


Explicación técnica del ejemplo


El proyecto de ejemplo II, tiene las siguientes características técnicas:

Toda la estrategia de juego, corre a cuenta de una red neuronal; con conexión hacia delante y dos capas ocultas (hidden layer).

La capa de entrada contiene nueve nodos; uno por cada posible contenido dentro del array que forma el tablero de juego –con un 1 si la ficha de una casilla es propia, un -1 si la ficha es del adversario, y un 0 si la casilla está vacía-, y un nodo de salida, responsable de devolver el resultado del proceso neuronal: expresando lo bueno o malo que un movimiento concreto es.

Tenemos así una red neuronal compuesta de 9 nodos de entrada xi, 21 nodos en las capas ocultas, y un nodo de salida. Más otros 9 nodos de activación (nodos bias).

Inicialmente, los pesos wij de la red neuronal son marcados aleatoriamente, por lo que la respuesta de la red neuronal ante el problema sobre qué buena o mala es una jugada será también aleatoria.

Hay pues que entrenar al programa para que aprenda a evaluar las jugadas, lo que vamos a conseguir ajustando evolutivamente los pesos de la red neuronal utilizada. Dicho entrenamiento evolutivo se realizará mediante una estrategia evolutiva.

La estrategia evolutiva será representada por un vector de 9 elementos de tipo real. Esos elementos o individuos de selección se van a corresponder con los pesos de los nodos que contiene la red neuronal, de manera que serán esos pesos los que irán evolucionando.

Así pues, la población en evolución, consistirá en n individuos (con n = 15), que tendrán n hijos, con variación exclusiva por mutación -sin recombinación- y cuya función de desempeño (fitness fuction) será calculada mediante competición -selección por torneo-.
Para el proceso de mutación, hay que tener en cuenta que cada individuo; además de un vector de pesos, contiene un vector de variables de ajuste, que también irá evolucionando junto con los pesos.

La mutación es de la forma:



Con alpha igual 0.2f, y donde xi indica el peso en la posición i del vector de pesos, y N(0,1) indica un valor tomado aleatoriamente de una distribución normal de desviación típica igual a 1, y media igual a 0. La otra variable que interviene en el proceso se corresponde con la variable de ajuste del elemento i, que; como se puede ver, muta antes de que lo haga el peso xi.

La evaluación de un individuo se realiza mediante q partidas (con q = 15), jugadas entre el individuo a evaluar, y otro individuo de la población, tomado aleatoriamente sin reemplazamiento. Cada partida ganada le sumará 1 punto, las perdidas le restará 2, y los empates no suman nada. El valor final será su función de desempeño.

Finalmente, el proceso de selección consistirá en tomar los 15 mejores individuos de entre los 30 (15 padres + 15 hijos) individuos de la generación en curso. En caso de empate en la función de desempeño, se favorecerá a los individuos más longevos.

El paso de generaciones tendrá como resultado un ajuste en los pesos de la red neuronal, lo que dará lugar a un entrenamiento de la misma, que será lo que permitirá; a su vez, al programa a jugar bien, sin intervención heurística alguna.

Detalles adicionales


1º) Para que el aprendizaje automático tenga lugar, es necesario; al menos, prever un movimiento del contrario por adelantado -qué hará él si yo muevo aquí-. Esto se consigue mediante el uso de un árbol min-max de profundidad 2 (ply=2 ), lo que es insuficiente para que la máquina comprenda estrategias, pero que sí permite una base para el ajuste de pesos de la red neuronal. Pero siempre evaluar lo bueno o malo de una jugada será objeto de la red neuronal. Es decir; aunque hay un árbol min-max de ply igual a dos, la evaluación de la tabla de tu movimiento y el mejor movimiento del contrario, la desempeña la red neuronal y no ninguna regla a priori.

2º) La red neuronal utilizada va a devolver siempre un valor real en el rango [-1,1]. Un -1 sólo cuando el movimiento a evaluar termina siendo una victoria del adversario, un 1 si la victoria es suya, y un valor entre (-1, 1) indicando lo bueno que es una jugada para el programa (valores cercanos a 1) o para el contrario (valores cercanos a 1).

3º) Hay un check box llamado no-loss, que, cuando se activa, indica que el proceso de entrenamiento, se hará jugando contra el jugador experto simulado mediante heurística. De esa manera, el aprendizaje es más rápido y siempre termina (tras unas 100 generaciones aproximadamente) alcanzando una estrategia no-loss. Cuando el check está desactivado, el entrenamiento se realiza contra sí mismo y podría ser que la estrategia no-loss no se alcance -aunque siempre quedará cerca-.

4º) El campo llamado Info, en el lateral superior derecho del applet, contiene información sobre el estado del entrenamiento. Conforme pasan las generaciones, la pantalla se actualiza, y muestra datos sobre el mejor individuo de la última generación: su función de desempeño, su edad -cuanto tiempo lleva en el pool evolutivo-, y la media de su juego -resultados/edad-. Cuando juegues contra la máquina, te mostrará la misma información, pero sobre jugador contra el que estás jugando -el mejor que se encontró-.

5º) La mejor manera de saber si hemos llegado a una estrategia no-loss, es ir mirando la pantalla de información, y esperar a que aparezcan datos en los que el mejor jugador encontrado tiene f = 0.0 y una edad avanzada (más de 20). Si pulsamos sobre el botón cancelar, y luego sobre el botón Estadísticas, deberá devolver siempre un 100% de empates contra el jugador experto.

Conclusión

Lo que pensé iba a ser un ejemplo fácil de conseguir, ha resultado ser una verdadera pesadilla, que me ha llevado un par de semanas de mi tiempo libre.

Mi cabezonería me ha impedido abandonar, y ahora me alegro, porque aprendí muchísimo sobre redes neuronales, y he podido avanzar en este campo de la IA que me parece fundamental, y que creo hace un muy buen equipo con la computación evolutiva. Es más, me atrevería a decir, que el futuro desarrollo de ambas ramas podría llegar a conseguir una verdadera inteligencia artificial. No sé si viviré para verlo, pero aquí queda dicho :).

Gracias por compartir vuestro tiempo conmigo, espero que el proyecto les haya gustado, y el código fuente les pueda servir de ejemplo.

domingo, 21 de agosto de 2011

Computación evolutiva: Ejemplo I

Abstract

Entendemos por un algoritmo evolutivo, a aquel cuya técnica resolutiva se inspira en la evolución biológica de la naturaleza; imitando de esa manera, el proceso de selección natural que, desde Darwin, es aceptado como motor del proceso evolutivo de los seres vivos.
Existe en la red, abundante información teórica al respecto de la computación evolutiva, pero en muy pocos casos, me he encontrado con ejemplos prácticos concretos, donde se pongan en práctica dichos principios.

De manera que me he propuesto intentar poner mi granito de arena práctico en esta rama tan interesante de la inteligencia artificial, iniciando lo que espero sea una serie de artículos con ejemplos funcionales -de código abierto-, para ayudar a cualquiera que quiera adentrarse en la materia. Además, espero que realizar esta propuesta, me ayudará a profundizar en mis conocimientos sobre el tema, y prepararme así para realizar el doctorado en ingeniería, que me gustaría algún día tener tiempo de hacer.

Composición y funcionamiento de un algoritmo evolutivo (AE)

Sin duda, el mejor recurso bibliográfico para iniciarse en el mundo de la CE -compuactión evolutiva- es el magnífico libro Introduction to Evolutionary Computing, de los autores Agoston E. Eiben, y J.E. Smith.

Hemos dicho que la computación evolutiva es una ciencia computacional en la que sus algoritmos imitan el proceso evolutivo de la naturaleza. Veamos de qué partes consta, y cómo funcionan:

Cualquier AE seguirá el siguiente pseudocódigo:



Existe una población de n individuos, los cuales expresan una posible solución. La población es pues, un multiconjunto de genotipos, y forman la unidad de evolución.

Los individuos de la población se van renovando en sucesivas generaciones, que van convergiendo evolutivamente hacia la meta deseada, que no es otra que encontrar una solución a un problema determinado. La evolución se produce durante el paso de las generaciones, y cada generación cumple con el siguiente procedimiento:

La primera generación es especial, y sólo consiste en la generación (y evaluación) de una población inicial de n individuos, normalmente generados aleatoriamente.

El resto de generaciones comienzan con la selección de los individuos que se van a reproducir. Es decir, se seleccionan los padres que conformarán la descendencia.
Y dicha descendencia, será el resultado de un proceso de recombinación y mutación de esos padres previamente seleccionados. Tras la creación de la descendencia, se procede a evaluar su adaptabilidad. Es decir; se calcula, lo bien o mal que se adapta el nuevo individuo a las condiciones del medio ambiente. Este proceso se suele realizar, mediante el uso de una funcion de desempeño (fitness function). Dicha función representará la adaptabilidad del fenotivo expresado por el genotipo en cuestión. Una vez evaluada la progenie, se procede a seleccionar los individuos que finalmente prevalecerán para formar la siguiente generación.

Todo este proceso generacional, se repetirá mientras no se cumpla una condición de parada. La condición de parada normalmente será, o bien que uno o varios genomas expresan un fenotipo que es solución óptima del problema a resolver, o que se alcanzó el máximo de generaciones previstos programáticamente.

Ejemplo I: Proyecto Paula

A continuación, vamos a ver en acción un algoritmo evolutivo, que he escrito en un applet de Java, y que tenéis embebido justo debajo de estas líneas –a continuación del applet tenéis un manual de uso- :

No puede ejecutar applets de Java. Instale la JVM, y vuelva a recargar la página, por favor.

Podéis descargar el código fuente del ejemplo desde este enlace.

El mismo algoritmo escrito completamente en Javascript, utilizando hilos mediante la nueva clase Worker nativa de HTML5 (puedes obtener el código fuente en los recursos del navegador, ya que no hay código ofuscado):


Manual de uso

Mediante el algoritmo del ejemplo, vamos a intentar encontrar la solución óptima -si existe-, o la mejor aproximación posible, al siguiente problema:

Tenemos como entrada (inputs), una serie de puntos definidos para ciertos valores de una variable, y queremos buscar la función de interpolación que sea óptima -que pase por todos los puntos dados como entrada- o lo más aproximada posible.

Para introducir los inputs en el applet, debemos rellenar el campo de texto "Datos de interpolación", añadiendo cuantos puntos deseemos. Una entrada válida sería, por ejemplo:

f0 = 0, f1 = 1, f2 = 4, f3 = 9

Si ahora, pulsamos sobre el botón Ejecutar algoritmo evolutivo, el programa finalizará, encontrando una de las muchas funciones que interpolan esos puntos, por ejemplo:

f(x) = x*x ó f(x) = x*x+x-x

Para recalcar la potencia del proceso evolutivo por selección, se propone la posibilidad de intentar encontrar la solución, sin realizar la recombinación, mutación y selección de los más aptos, lo que resulta en un algoritmo completamente aleatorio que muy poco probablemente llegará a solucionar el problema. Para probar dicho algoritmo aleatorio, hay que pulsar sobre el botón Ejecutar algoritmo aleatorio.

Para probar la potencia del programa, se ha habilitado la posibilidad de calcular automáticamente los puntos a interpolar, a partir de una función de nuestra elección. Con esto, nos aseguramos además, de que existe solución óptima. Sólo hay que pulsar sobre el botón Buscar datos de interpolación, y se nos abrirá una ventana donde deberemos escribir la función generadora de n términos de interpolación.

Es importante señalar, que sólo se permite los operadores + - * /, y que la prioridad de los mismos es la tradicional. Se permiten números con decimales (con el punto como separador, y una precisión máxima de cuatro decimales), pero no el operador unitario -.

Al finalizar la ejecución del algoritmo, se abrirá una nueva ventana emergente con un par de gráficas, la primera representando los puntos de interpolación, y una segunda con los puntos representados por la función encontrada por el programa. Ambas gráficas coincidirán siempre y cuando se encuentre una solución óptima -si es que existe-.

Análisis del algoritmo

La representación del genotipo en nuestro ejemplo, consiste en un array de caracteres, conformando una cadena de texto, con los siguientes símbolos permitidos:{[0-9],x,+,-,/,*}

Además, los símbolos deben respetar un patrón que forme cadenas con sentido aritmético (pero no se permite usar el símbolo - como operador unitario), permitiéndose genotipos como 2*x*x-1/2*x+23, pero no otros como 2+-x/*.

El AE del ejemplo I responde al siguiente pseudocódigo:


t <- 0
Inicialización P(t)
Evaluación P(t)
hacer
S <- Seleccion_padres[P(t)]
Q = Operacion_variación[S]
Evaluación[Q)]
P(t+1) <- selección[P(t) U Q]
t <- t + 1
mientras no condición de parada



donde S, Q, y P son poblaciones de individuos, y t es una variable de tipo entera.

El algoritmo comienza creando aleatoriamente una población P de n individuos, y evaluando la función de desempeño de sus individuos -lo cerca o lejos que están de ser una solución óptima al problema-.

Posteriormente se entra en un bucle del que sólo se saldrá cuando se cumpla que, o bien en la población P(t) hay un individuo que es solución óptima, o bien se ha llegado al máximo de iteraciones previsto en la configuración del programa.

Cada iteración del bucle, se va a corresponder con una nueva generación de individuos, formada por parte de los padres de la generación anterior y por parte de su progenie.

Para realizar una generación se procede como sigue:

1) Se forma una población S con los individuos que van a poder procrear. En el caso concreto de mi ejemplo, todos los miembros de la población P van a tener descendencia. Es decir; S = P(t).

2) Se procede a crear la descendencia mediante recombinación, y mutación. En el ejemplo, se van seleccionando pares de individuos de S y se recombinan dando lugar a cuatro hijos.

Para recombinar, seleccionamos al padre y lo dividimos por un punto aleatorio p (quedando el padre partido en dos partes: padre1 y padre2). Hacemos lo mismo con la madre en un punto p', y se crean los hijos de la siguiente manera:

h1 = padre1 + madre2
h2 = madre1 + padre2
h3 = padre1
h4 = padre2


Posteriormente, cada hijo, sufrirá -con 100% de probabilidad- algún tipo de mutación puntual, que podrá ser más o menos leve, y que podrá modificar algún valor concreto del genotipo del individuo, o añadir o eliminar partes del mismo.

El proceso de reproducción, se repetirá 16 veces por cada par de padres, lo que dará un total de n*16*4 hijos en cada generación -siendo n el número de individuos en la población-.

3) El siguiente paso es evaluar la adaptabilidad de esta población Q que conforman la nueva descendencia.

4) Por último, se procede a seleccionar aquellos individuos que mejor se adaptan al medio de la unión del conjunto de padres de la generación anterior P(t) y el conjunto de sus hijos Q. Como resultado, se obtiene el conjunto P de la generación siguiente, con los supervivientes del proceso de selección.

En nuestro ejemplo, la evaluación de un genotipo se procesa mediante la aplicación de una función de desempeño (fitness function) al mismo. En este caso, la función será el resultado de sumar la diferencia en valor absoluto entre g(x) y el input en dicho punto: abs(y-g(x)).

Un genotipo óptimo, será aquel cuya función de desempeño tenga valor 0.

Para el AE del ejemplo, la selección generacional, se hace ordenando los individuos de [P(t) U Q] según su valor de adaptación -cuanto menos diferencia entre g(x) y los puntos de interpolación mejor-, y seleccionando los s primeros, desechándose de esa manera el resto.

Resumen

El algoritmo evolutivo propuesto, es capaz de encontrar; si existe, una solución óptima al problema con bastante frecuencia, aunque; como en todo AE existe la posibilidad de que la evolución generacional se localice en torno a una solución local no óptima -pero muy cercana de serlo-. Sin embargo, la aleatoriedad de la fase de mutación, permite teóricamente recomenzar un nuevo camino evolutivo en cualquier momento -aunque es menos probable que esto ocurra conforme pasan las generaciones-.

viernes, 15 de octubre de 2010

Divina Metafísica


La metafísica estudia los aspectos de la realidad que son inaccesibles a la investigación científica. Según Immanuel Kant, una afirmación es metafísica cuando afirma algo sustancial o relevante sobre un asunto ("cuando emite un juicio sintético sobre un asunto") que por principio escapa a toda posibilidad de ser experimentado sensiblemente por el ser humano.

La metafísica aborda problemas centrales de la filosofía, como lo son los fundamentos de la estructura de la realidad y el sentido y finalidad última de todo ser, todo lo cual se sustenta en el llamado principio de no contradicción.

El principio de no contradicción, o a veces llamado principio de contradicción, es un principio clásico de la lógica y la filosofía, según el cual una proposición y su negación no pueden ser ambas verdaderas al mismo tiempo y en el mismo sentido. El principio también tiene una versión ontológica: nada puede ser y no ser al mismo tiempo y en el mismo sentido; y una versión doxástica: nadie puede creer al mismo tiempo y en el mismo sentido una proposición y su negación. El principio de no contradicción es, junto con el principio de identidad y el principio del tercero excluido, una de las leyes clásicas del pensamiento.


Introducción.

El estudio sobre la existencia de Dios como causa última de la realidad o, lo que es lo mismo, la teológica, es uno de los tópicos fundamentales de la metafísica tradicional. Y es, además, universalmente aceptado que dicho estudio forma parte del mundo metafísico.

Podemos inferir esta afirmación de la siguiente manera:

(1) Toda afirmación metafísica escapará siempre a cualquier tipo de experimentación, ya que no puede haber experiencias sensibles sobre la misma [por definición de metafísica].

(2) Una afirmación que no puede ser contrastada experimentalmente no es una afirmación científica [por definición de ciencia].

Luego:

(3) La ciencia no puede conocer cuestiones metafísicas, por lo que no tiene sentido hablar de ellas desde la ciencia [a partir de 1 y 2].

Y esto es así, es algo incuestionable. La única forma de negarlo lógicamente es cambiando las definiciones de ciencia y de metafísica. De no hacerlo, deberemos aceptar inmediatamente, que cuando un científico, por muy importante y famoso que sea, se pone a interpretar teorías o a hablar sobre cuestiones metafísicas, está filosofando y no haciendo ciencia.

Por poner el ejemplo más reciente, cuando Stephen Hawking afirma que Dios no es necesario para explicar el mundo, es evidente que está haciendo metafísica. Me explico:
Entendemos por el mundo a todo aquello de lo que tenemos experiencias directas o indirectas. Afirmar que no es necesario Dios para explicar el mundo, es equivalente a afirmar que no es necesario nada trascendente al mundo para explicarlo. Esta última afirmación es claramente metafísica. No hay NINGUNA experiencia sensible que indique que el mundo no necesita de una entidad o proceso transcendente como causa o que indique que no existe o no es necesaria tal causa. Por poner un ejemplo práctico y claro; nuestro mundo podría (y podría no) ser la consecuencia de, por ejemplo, el cómputo de un algoritmo por parte de un ordenador transcendente. Una especie de Matrix. Ese computador transcendente lo podemos tomar como una entidad de la que no tenemos experiencias, e incluso podríamos llamarlo Dios.
Ahora bien, para explicar el porqué esencial de nuestro mundo, en nuestro ejemplo, encestaríamos obligatoriamente hacer referencia a ese computador, porque explicar es relacionar causa y efecto, y; en este ejemplo, la causa de nuestro mundo, sería el computador transcendente.
Evidentemente, la existencia de tal Matrix es una cuestión metafísica; que se corresponderá o no con la realidad, pero pone de manifiesto que cuando Stephen Hawking afirma que Dios (entidad transcendente) no es necesario para explicar el mundo, está realmente filosofando.
Podremos conocer cómo funciona el mundo con mayor o menos exactitud, podemos aceptar incluso que llegaremos a una infinita exactitud si alcanzamos la teoría del todo, pero seguiremos sin saber el porqué todo funciona como funciona. Para ello encestaríamos conocer la causa transcendente que produce ese comportamiento, y eso entra dentro de la metafísica. Afirmar que no existe tal causa transcendente o que no es necesaria es pues filosofar, y es lo que Sthepen Hawkins hace con su afirmación.

En resumen:

Incluso si conseguimos explicar toda la realidad sólo a partir de leyes naturales, todavía nos quedará explicar dichas leyes naturales. Y conocer lo que causa la existencia de dichas leyes, o justificar que nada causa dichas leyes, es algo que entra dentro del campo de la metafísica.


¿Conocimiento metafísico?

Parece entonces que la única forma que tenemos de conocer la realidad de la que no tenemos experiencias (o de conocer que no existe tal realidad transcendente) es mediante la metafísica pero, ¿realmente nos lleva la metafísica a algún tipo de conocimiento? Pues; desgraciadamente, no al tipo de conocimiento que nos gustaría.

Es innegable que el ser humano busca y desea conocimientos universales y necesarios. Ese tipo de conocimiento es el que nos proporciona la ciencia sobre lo tangible, y ese tipo de conocimiento es el que desearíamos conseguir sobre lo transcendente. Es decir; queremos conocimientos objetivos, ¿puede la metafísica ofrecernoslos?

Mucho me temo que no. La ciencia basa toda su potencia de universalidad y objetividad en la inducción de experiencias. Lo que ha pasado mil veces, suponemos (sin justificación) que pasará mil y una veces. Esta suposición no justificada ha dado numerosos frutos y a conducido a la tecnología actual. Es útil y sus teorías y leyes se suponen universales y necesarias (aunque sólo sea por conveniencia). Como todos podemos contrastar una teoría cuando queramos y (probablemente) obtendremos que se cumple la inducción, tomamos dicho conocimiento como objetivo.

La metafísica no tiene experiencias con las que trabajar, por lo que no podemos usar el “truco” de la inducción para aparentar universalidad y objetividad en sus afirmaciones. La razón humana es una herramienta evolutiva aparecida en el transcurso de millones de años para mejorar nuestras espectativas de supervivencia. No parece que una herramienta creada para solucionar problemas del mundo sensible pueda servir para mucho más. De momento, no se ha encontrado ninguna otra forma de conocimiento “objetivo” -y objetivo con comillas- que no se base -o utilice al menos- experiencias sensibles.


Lo subjetivo.

Lo que se suele hacer es renunciar a obtener dicho conocimiento objetivo desde la razón, e intentar imponer la objetividad de manera irracional. Es lo que se suele llamar fe. Si todos compartimos una fe concreta, ese “conocimiento” se volverá objetivo. Entonces surge el problema de quién decide que es lo que se debe creer y sobretodo, qué es lo que se debe creer. Aparecen así los “conocimientos” dogmáticos, y la guerra entre distintos grupos rivales por imponer sus dogmas. Es una guerra compleja donde entran en juego intereses políticos, y sociales en general. Pero eso no es lo esencial del asunto.

Lo esencial es que; al no poderse contrastar experimentalmente, una argumentación metafísica, puede ser tan válida y Real como su opuesta, y no hay nada que podamos hacer para decidir objetivamente cuál es la que se corresponde con la realidad (incluso la supuesta teoría de que no hay nada metafísico, es una afirmación metafísica, con lo que ello supone).

Es decir; aceptar una u otra metafísica es algo completamente arbitrario, y que; finalmente, "creamos" una afirmación o su contraria, es una cuestión subjetiva, siempre motivadas y dirigidas por nuestras necesidades.


Escepticismo metafísico.

¿Qué actitud queda, pues, tomar; si queremos seguir comportándonos racionalmente? Lo más razonable es resignarse a nuestra incapacidad de conocer objetivamente la verdad transcendente (o resignarse a nuestra incapacidad de conocer objetivamente que no existe ninguna verdad transcendente).

Es una actitud compleja de tomar, porque supone una rendición, y, es evidente, al ser humano no le gusta perder. Además, no es una actitud evolutivamente estable para aquellas personas que tienen más necesidad de consuelo; aquellas que menos tienen y que más sufren -un gran porcentaje, por cierto, del total de personas que vivimos actualmente-.


Conclusión.

Para todos aquellos a los que su orgullo no se lo impida, y para aquellos a los que no se lo impida su necesidad de consuelo, la actitud que parece más razonable y noble, resulta ser la actitud escéptica.

Sobre las Verdades metafísicas, sólo sé que no sé nada, y sobre las demás, no sé ni lo que realmente sé.


Nota. Adicionalmente, cabría nombrar el revés que ha supuesto para el principio de no contradicción en que se basa la metafísica, el descubrimiento de la mecánica cuántica y lo mal que se lleva con el sentido común. Por ejemplo; la superposición de estados supone que un ente es y no es - y está y no está- al mismo tiempo hasta que colapse la función de onda.

miércoles, 13 de octubre de 2010

Alegría y euforia por los 33 mineros salvados o la hipócrita doble moral de occidente


Es la noticia del día, de la semana, casi del mes; los 33 mineros chilenos serán rescatados con vida. Todos los medios retratan la felicidad del pueblo chileno y de occidente en general. La euforia se contagia porque aunque ha supuesto mucho esfuerzo y se ha necesitado gran cantidad de recursos, se han salvado 33 vidas.

Ahora bien, nadie cae en la cuenta -o el que cae, mira hacia otro lado- de que esa gran cantidad de recursos que se han invertido en dicho rescate, podrían haber sido usados para otros fines. Por ejemplo; con todo lo invertido en el famoso rescate, se podrían haber salvado la vida de miles de personas del tercer mundo.
Y es un hecho, todo esos recursos podrían haber salvado miles de vidas, en lugar de sólo 33. ¿Por qué entonces tanta felicidad? ¿No deberíamos de estar tristes e incluso enfadados con el pueblo chileno que ha dejado morir a miles de personas por salvar a sólo 33? Si se supone que todos los humanos somos iguales, y que la vida de todos tiene el mismo valor -principal tesis de la moral occidental-; destinar recursos en salvar a 33, cuando se podrían haber salvado a miles, no puede ser tomado como algo moralmente correcto, ¿por qué estamos entonces tan contentos?

Lo primero que nos vendrá a la mente para salvar la contradicción moral, es que lo que se debería haber hecho es salvar a los 33 mineros, y a los miles de subdesarrollados al mismo tiempo. Muy bonito, pero evidentemente es una salida utópica. Es un hecho obvio y objetivo que los recursos del mundo son limitados -muy limitados incluso-, no hay de todos para todos, y hay que elegir. Occidente acapara gran parte de los recursos del planeta en detrimento del resto, y occidente debe elegir, y elige, como repartirlos. Nuestros medios de comunicación nos muestran claramente lo que finalmente hacemos con ellos: preferimos proveer a unos pocos de “los nuestros” antes de ayudar con la misma cantidad de recursos a “muchos más de los otros”. Y, además, esta actitud no debería -ni debe- tomarse como algo malo, al contrario; es algo natural -y por lo tanto esencialmente bueno- ayudar a los más próximos; a “los nuestros”. De hecho, nosotros actuamos de la misma forma en nuestro ámbito más personal. Si nos ponen entre la espada y la pared, y nos piden elegir entre salvar de una muerte anunciada a un hermano o a un completo desconocido (en este caso concreto, el recurso escaso es que sólo podemos salvar a uno), evidentemente el 99,9% de nosotros salvaremos a nuestro pariente -salvo enfemedad mental que nos impida actuar razonadamente-. Y este es un hecho objetivo y autoevidente. Y repito, no es nada malo salvar a nuestro hermano antes que a un extraño, es algo natural -bueno-.

Lo que es malo -metafóricamente malo, ya que en un mundo natural no hay nada esencialmente malo- es esa doble moral hipócrita de la que occidente hace gala. Preferimos salvar a los nuestros antes de a los demás, ¿por qué lo negamos? Por favor, dejemos de engañar y autoengañarnos; somos egoístas. Somos unos hipócritas egoístas. De todas formas, es lo que cabe esperar ahora que sabemos lo que somos, lo que es el hombre; simplemente una máquina de reproducir genes. No existe ninguna moral esencial. Estamos programados para sobrevivir y reproducir nuestros genes a toda costa. Y eso es todo. Nuestro comportamiento se reduce a estrategias evolutivas destinadas a maximizar ese objetivo. Y si nos engañamos -autoengañamos- negando lo evidente, es porque actualmente el comportamiento evolutivamente estable así lo requiere.

Nota:

Es evidente que sí existen recursos en occidente para haber salvado simulténamente a los 33 chilenos y a los miles de subdesarrollados que han muerto en su lugar, pero lo que debe quedar claro es lo siguiente: 1º No se ha hecho. Se salvó a 33 mineros en vez de a miles de africanos que finalmente murieron esta semana. 2º aunque se hubiese hecho, o se haga en el futuro, en casos similares, lo que debe ser evidente es que occidente jamás destinará al resto subdesarrollado mas que lo necesario para sacar provecho de ello. El 99% de los recursos de occidente se destinan -y destinarán no cabe duda- a occidente, y el 1% se presta al resto sólo como estrategia, y nunca de manera puramente altruista. Siempre se esperará algo a cambio, aunque sea de manera tan indirecta como obtener una buena publicidad favorable “mostrando” que somos muy buenos y altruistas.

Conclusión:

Aunque la hipócrita doble moral de occidente no puede tomarse como algo malo -esencialmente malo-, puesto que forma parte de la estrategia evolutiva -natural- que nos favorece a todos y cada uno de nosotros; si que me parece reprochable el no aceptarla; el negarla. Desde la ciencia natural es un hecho “objetivo” que dicha doble moral es un acto evolutivo, un autoengaño que todos compartimos, y que hemos desenmascarado desde la ciencia natural. Pero claro, como no podemos cambiar lo que somos -máquinas al servicio del gen-, lo único que nos queda es resignarnos y aceptar nuestra “verdadera moral”. Debemos dejar de ser hipócritas. Si finalmente llega ese día, el día que todos aceptemos la evidencia, ya no será necesario el autoengaño, y; aunque no seremos más “buenos” -porque no hay moral esencial de referencia-, al menos sí seremos menos hipócritas.

Nota. Está claro que ser menos hipócrita no es ningún objetivo esencial del ser humano -porque no existen tales objetivos-, pero, sin embargo; podría ser nuestra “salvación”, nuestro deseado “paraíso”. Me explico:
Desde las ciencias naturales, sabemos que existe una carrera armamentística evolutiva entre “engañar” y “detectar el engaño” para maximizar nuestro acopio de recursos y favorecer así nuestra supervivencia y la de los nuestros. El que mejor engaña obtendrá más beneficios en el mundo de altruismo recíproco del que formamos parte. Y, además, es evidente que la mejor forma de engañar es engañar “sin saberlo” -autoengaño-. Es la forma más eficaz de engaño y lo que da forma a gran parte de nuestro comportamiento. En particular, es lo que nos hace negar nuestra doble moral. No podemos aceptar que preferimos salvar a unos pocos de “los nuestros” antes que a muchos de “los otros”. No es algo evolutivamente estable...por ahora.
Lo crucial es que, ese estar atentos a los engaños y ese esfuerzo por engañar mejor, nos produce estrés y ansiedad. Un sufrimiento que se ve agravado por nuestra autoconciencia que no es más que una herramienta aparecida como medio para mejorar el engaño y la detección del engaño, pero con la triste disfunción añadida de permitirnos ser conscientes de nuestro sufrimiento -no sólo sufrimos sino que sufrimos porque sabemos que sufrimos y sufriremos hasta nuestra muerte-.
Y; aquí viene lo bueno, aunque está claro que jamás dejaremos de estar al servicio de los genes -luchando por su supervivencia y replicación-, si que podríamos crear conscientemente una estrategia evolutivamente estable que minimizase nuestro sufrimiento.
Si todos fuésemos sinceros con nuestras intenciones, si dejáramos el autoengaño -y el engaño consciente-, no sería necesario estar alerta constantemente. Podríamos homogeneizar el medio infinitamente, dejaríamos de necesitar verlas venir. Podríamos relajarnos, vivir en un mundo mejor, más sincero; donde no haría falta una moral “de cuarto de baño” para mantener la cohesión social.
Viviríamos como hormigas, sí; y, con el tiempo, dejaríamos el lastre que supone la autoconciencia. Volveríamos a la animalidad, y; aunque seguiríamos sufriendo, al menos no seríamos conscientes de ese sufrimiento. Eso es lo más parecido a un paraíso terrenal, y lo mejor a lo que puede aspirar el ser humano.

Pero vamos, soy consciente de que llevar a cabo este plan es una tarea titánica, que incluso podría no ser jamás viable como EEE. Pero, bueno; de utopías vive el hombre. Además, como dice Castrodeza, quizás la tecnociencia nos lleve al mismo fin, aunque por otros medios, claro.



- Bibliograífa recomendada:

Para aquellos que no hayan entendido mi argumento, o que quieran profundizar en el mismo, os recomiendo la siguiente bibliografía:

  • “El Gen Egoísta” - Richard Dawkins.
  • Nihilismo y Supervivencia - Carlos Castrodeza.
  • La Darwinización del mundo - Carlos Castrodeza.


También os recomiendo el resto de libros de Richard Dawkins -especialmente sus primeros libros-, y las extensas referencias bibliográficas que traen los dos libros de Carlos Castrodeza.