Hacer un sistema de lectura rápida

En esta entrada voy a dar los pasos para crear un sistema de lectura rápida tipo spritz o spritzlet.

Estos sistemas se basan en poder leer de un vistazo sin mover los ojos. Para ello nos muestran las palabras una a una centradas de forma adecuada para no tener que mover los ojos. Con algo de práctica llegas a un punto en que lees las palabras casi sin darte cuenta. En mi experiencia personal puedo decir que en textos complejos cuesta seguir el hilo. Pero para lectura de textos sencillos o para una primera lectura resulta muy útil.

Punto de reconocimiento óptimo (ORP)

El primer paso es separar el texto en tokens. Usaremos los espacios y fin de línea como separadores.

Para cada token hemos de calcular el «punto de reconocimiento óptimo» (Optimal Recognition Point) ORP. Que es el punto donde se fijan los ojos al leer una palabra. Su cálculo es sencillo, es suficiente con saber la longitud de la palabra: (en la tabla la posición está indicada empezando a contar el primer carácter como posición 0)

LongitudPosición ORP
10
21
31
41
51
62
72
82
92
103
113
123
133
14+4

Con el ORP calculado hemos de calcular el tiempo que se mostrará ese token en pantalla. Ajustando el tiempo por carácter más un pequeño extra para cambiar de palabra y una parada un poco más larga en los signos de puntuación (o se pueden mostrar estos de forma individual).

Interfaz de usuario

Con eso ya tenemos todo lo necesario para mostrar la palabras una por una. Para ello elegiremos un punto de la pantalla donde no suponga un gran esfuerzo mirar fijamente. Por lo general o el centro de la pantalla o un poco por encima de este.

Hay que elegir unos colores para el texto y su fondo que se lean correctamente. Podemos oscurecer el resto de la pantalla para que no distraiga.

¿Os acordáis del ORP? Ahora hay que asegurarse de que todas las palabras se presentan centradas en ese carácter. Puede ser buena idea marcarlo de alguna manera, generalmente se marca en algún color llamativo, aunque usar alguna ayuda más como subrayar o ponerla en negrita permite que sea más accesible para personas que no distingan colores o desde dispositivos que sean en blanco y negro.

Algunas versiones cambian el tamaño de las letras según lo que ocupe la palabra, pero a mí esa opción me parece incómoda cuando saltas de palabras pequeñas a muy largas y eso supone un gran cambio del tamaño de letra.

Tiempo de lectura

Es necesario permitir al lector ajustar la velocidad de lectura en palabras por minuto. Habitualmente la velocidad se permite ajustar de 100 a 700 palabras por minuto.

Para calcular el tiempo que hemos de tener cada palabra en pantalla hay dos formas. Tener todas las palabras el mismo tiempo en pantalla, para ello se calcula el tiempo por palabra dividiendo 60 segundos entre el número de palabras por minuto seleccionado. Es un sistema simple y que da buenos resultados. Si se quiere hilar un poco más fino se puede calcular el tiempo por letra, para ello se supone que el tiempo por palabra se refiere a una palabra media de 5 letras y se divide por 5 para obtener el tiempo por letra, ahora se multiplica este tiempo por el total de letras en la palabra y así se obtiene el tiempo que tiene que mostrarse la palabra. Es buena idea fijar un tiempo mínimo o en casos de lecturas muy rápidas las palabras muy cortas podrían ser difíciles de leer.

Palabras muy largas

Aquí tenemos un problema. Si la palabra es muy larga, algo del estilo de «esternocleidomastoideo», mostrarla de una sola vez obliga a mover los ojos. Hay que dividirla, lo recomendable es no pasar de las tres o cuatro sílabas. Pero ojo, no partas sílabas, eso complica la lectura de la misma. Es recomendable señalar de alguna forma que el texto que muestras es parte de una palabra. Compara:

«Esternoc» «leidomast» «oideo»

«Esterno~» «~cleidomas~» «~toideo»

Conclusión

Aunque, dada la cantidad de librerías y aplicaciones que implementan este sistema de lectura spritz, no es necesario programar desde cero un lector rápido las ideas aquí expuestas pueden servir para entender como funciona y para aplicarlas a otras funcionalidades.

Requisitos para usar big data o I.A. para clasificar personas

El big data esta de moda, la cantidad de empresas que anuncian que usan big data para mejorar los resultados del servicio que ofrecen no para de crecer. Muchas de ellas no tienen muy claro de que hablan o se dedican a entrenar algún modelo de aprendizaje máquina lanzandole datos sin limpiar ni procesar y esperan obtener algo que funcione. Por supuesto hay muchas que saben lo que hacen. Aún haciendo todo de forma correcta el big data y la I.A. corren el riesgo convertirse en los oráculos modernos. Le metes datos, esperas y obtienes una respuesta y sin la necesidad de sacrificar una cabra a ningún dios. El problema es que quienes acuden a estos oráculos toman las respuestas como verdades absolutas, sin entender de donde ha salido esa respuesta. Muchos de estos modelos se empiezan a aplicar para valorar a personas: concederles una hipoteca, un trabajo, la libertad condicional o una tarjeta de crédito, son solo algunos ejemplos. Aplicar estos modelos de caja negra a asuntos humanos es arriesgado y puede llegar a causar bastantes injusticias.

En esta entrada voy a tratar de describir algunos principios que deberían de cumplir los modelos obtenidos a partir de grandes cantidades de datos para que su uso con personas sea justo. Describe un ideal de las características que debería de tener un sistema así.

Ser transparente

Si se va a emplear un modelo obtenido a través de big data sobre alguna persona está debería ser correctamente informada de ello. Además debe de saber lo eficaz que es ese sistema. Su tasas de falsos positivos y negativos.

Ser entendible

Se ha de entender el proceso de decisión del sistema. Si no se entiende se corre el riesgo de estar tomando decisiones basadas en datos anecdóticos o sesgos en los datos del entrenamiento.

Para estar seguro de esto un humano experto ha de ser capaz de entender el funcionamiento del sistema y las decisiones que toma..

Ofrecer explicaciones

Tiene doble función, primero ayudar al punto anterior y segundo que la persona que ha sido evaluada por el sistema sepa que motivos han llevado a considerarla «apta» o «no apta».

Puede parecer que con que un sistema ofrezca un resultado es suficiente, pero la realidad es que no lo es. Si no sabes porque estas descartando a una persona no puedes decirselo y esta persona no sabe que tiene que cambiar para «pasar la prueba».

Resulta algo extremadamente frustrarte. Si no sabes que tienes que cambiar la sensación es que «estas marcado de por vida». Si una persona es informada de cuales han sido los motivos por los que es «no apta» puede valorar si trata de cambiarlos o no. Lo cual puede ser una ventaja para ambas partes. Imagínate que un banco te niega una hipoteca o un crédito por el único motivo de que no tienes un aval. Pero en realidad si que lo tienes o lo puedes pero no consta en los datos. Ambos estáis perdiendo una oportunidad beneficiosa.

Validación continua

Es necesario tener validación de su correcto funcionamiento permanentemente. Es fundamental comprobar que las conclusiones que ha tomado el sistema son correctas. La sociedad y el mundo cambia pudiendo hacer que el modelo quede obsoleto y falle si no se adapta correctamente. Hay que tener un mecanismo de revisión y validación para asegurarse de que sigue funcionando.

Asociado a esto tiene que tener un mecanismo de corrección. Si por ejemplo se descubre que el sistema tiene en cuenta algún dato que ya no se puede usar ha de poder descartarse este dato. En los últimos años hemos vivido varios cambios en las leyes sobre protección de datos. Un dato que se puede usar hoy en unos años puede ser ilegal usarlo, los sistemas han de ser capaces de adaptarse a eso.

Saber que datos nuestros se han usado

Tenemos derechos sobre nuestros datos y el mínimo de ellos es saber cuales se han usado y de donde provienen. Con más motivo si esos datos se usan para tomar decisiones sobre nosotros.

No solo saber que datos se usan, también El origen de los datos es importantes. La fuente que provee de datos pueden preferir cantidad a calidad y no verificarlos correctamente o ahorrar costes no verificando si datos de hace años aún son ciertos.

Muchas veces los datos tienen una historia detrás. No es lo mismo estar en una lista de morosos por tener varios créditos sin pagar que por tener pendiente una factura de un servicio tras discutir con el proveedor del mismo.

Gestión de casos extraordinarios

Solo con modelos muy simples el sistema acertará siempre. En el resto de las situaciones habrá casos extraordinarios que serán mal clasificados. Hay que saber como gestionar estos casos. No basta con justificarse en «lo dice el ordenador». Tiene que haber formas de saber si estamos ante un caso mal clasificado y es el oráculo ha hecho mal su trabajo.

Objeciones

«Una empresa privada ¿Por qué ha de seguir estas reglas?» Primero porque trabaja en la sociedad y tiene que seguir sus reglas y colaborar en mantenerlas. Segundo porque estos sistemas tienen el riesgo de extenderse. Un sistema realmente bueno puede ser vendido como servicio, que las empresas empiecen a contratarlo y entonces afectaría a millones de personas.

«Si las estadísticas dicen que algo es así será por algo». Si, obvio que es por algo. Pero antes de empezar a valorar a un grupo de personas por ser peores trabajadores o más delincuentes o menos confiables o cualquier prejuicio similar piensa que según las estadísticas un hospital es un lugar donde muere mucha gente y es mejor no ir y menos aún si estas enfermo. El que un hospital es un sitio peligroso para los enfermos es un prejuicio causado por un una visión parcial de la realidad fijándose solo en datos.

«Es un gran avance y puede producir un gran beneficio, no merece la pena frenarlo por unos pocos casos en os que resultaría injusto». Lo de sacrificar a unos pocos para obtener un bien mayor ha justificado muchas barbaridades. No es una cuestión de prohibirlo, si no de buscar un equilibrio.

«Con el tiempo mejorara y alcanzara una precisión absoluta». Es difícil que eso ocurra en los próximos años y posiblemente décadas. La realidad es demasiado compleja para separar fácilmente todos los casos sin cometer ningún error. De hecho incluso seria discutible que es un error y que no lo es.

Tablas de consulta (lookup table)

Más que un algoritmo de visión por computador es una forma de acelerar los cálculos. La idea es reemplazar todos los cálculos aplicados a un pixel por un simple acceso a memoria. Suena bien ¿verdad?. Se puede ganar bastante velocidad pero por desgracia está limitado y solo sirve para operaciones que afecten a un solo canal del pixel. Si el resultado se ve influido por algo más como la posición, el valor de los vecinos o del resto de los canales este método no sirve. Aun con estas limitaciones resulta útil para optimizar operaciones como el umbral, el ajuste de brillo y/o contraste o corrección del color.

Empecemos por la idea básica. A partir de ahora cuando hable de pixel me refiero a un pixel de un solo canal en escala de grises, para el caso de color RGB seria en realidad uno de los canales de color. Y habría que tener una tabla de consulta por cada canal

Un pixel tiene un número limitado de valores, de 0 a 255. Eso significa que podemos precalcular esos 256 valores en una tabla y luego simplemente consultar el valor del pixel en esta en lugar de repetir los calculos para cada pixel.

Por tanto necesitamos generar una tabla con indices de 0 a 255. Calculamos el resultado para cada uno de los 256 posibles valores de un pixel. Cada resultado se almacenará en la posición correspondiente al valor original del pixel.

Por ejemplo si nuestra funcion suma diez al valor del pixel, la tabla seria:

T[0]=10;
T[1]=11;

T[254]=255;
T[255]=255;

Si os fijais hay un detalle a tener en cuenta. Los valores de la tabla no pueden ser mayores de 255 que es el valor máximo de un pixel, tampoco pueden ser menores de 0, que es el valor mínimo.

Vale, ya tenemos los 256 valores posibles. Para usar esta tabla solo hemos de recorrer la imagen leyendo el valor de cada pixel y remplazarlo el valor que tenga la tabla para ese índice. Por ejemplo, para un pixel P con valor I y una tabla de consulta T

Image[P] = T[I]

Pero esto no es todo, puedes combinar varias de estas tablas en una sola tabla y calcular varias operaciones con un coste en tiempo ridiculo. Vamos a ver cómo.

Cuando operamos varias veces sobre un pixel de valor p realmente lo que estamos haciendo es.

funN(…func2(func1(p)))

Para cada cada pixel solo hay 256 valores posibles (del 0 al 255), eso quiere decir para cada función habra como mucho 256 resultados distintos. Si ademas limitamos que cada una de esas funciones solo pueda devolver valores entre 0 y 255. Podemos usar el resultado de una función como entrada de la siguiente. Por lo tanto podriamos precalcular esos 256 valores y convertir todas esas funciones en una sola que relacione cada valor del pixel con su resultado…efectivamente eso es lo mismo que hacer un array con los 256 resultados y usar el valor original como indice.

Repito, esto solo se cumple cuando sobre la función que aplicamos solo influye el valor del propio pixel y los valores que devuelve están comprendidos entre 0 y 255.

Si tenemos dos tablas de T1 y T2 calcular una tabla T3 que combine ambas en una sola operación es muy sencillo:

for(var i = 0; i < 256; i++){
    T3[i]=T2[T1[i]];
}

Se pueden combinar tantas tablas como se quiera.

Aunque en los procesadores actuales resulta casi igual de rápido realizar un par de operaciones simples que recurrir a estas tablas, cuando se acumulan varias funciones en una sola tabla el aumento de rendimiento es más que apreciable.

Detectar nombres propios en un texto

En el análisis de un texto detectar los nombres propios es importante ya que aporta información de que se habla en el texto. Permite extraer nombres e personas empresas y de hecho es una tarea habitual en muchos sistemas inteligentes de gestión de documentos.

Empiezan por mayúscula

Detectar nombres propios en español parece una tarea sencilla, lo primero que se nos ocurre es: «Empiezan por mayúscula» y es cierto, cualquier palabra que empiece por mayúsculas en un texto es sospechoso de ser un nombre propio. As que nuestro primer paso es recopilar esas palabras.

No es suficiente con que empiece por mayúscula. Cualquier palabra al principio de una oración también empieza por mayúscula y precisame el principio de la oración es un lugar muy habitual para los nombres (propios o comunes). En ese caso la mayúscula no servirá de pista. Es necesario obtener la información de si una palabra «sospechosa de se un nombre» va o no al principio de una frase.

Pero no es el único caso en que una palabra que no sea un nombre propio empieza por mayúscula. Siglas, meses, días de la semana, notas musicales, cargos, períodos históricos….. Hay muchos casos en los que correcta o erróneamente (los días de la semana no deberían ir en mayúsculas pero no es raro verlos así) se suelen poner la letra inicial en mayúscula.

Siglas y acrónimos

Como caso especial están las siglas y acrónimos. El problema aquí es distinguir los que generalmente indican nombres propios de otros que no lo son, por ejemplo ONU, OTAN, USA son nombres propios mientras que SOS, WTF, OMG no lo son. Para distinguir siglas del resto de palabras de un texto es sencillo, están completamente escritas en mayúsculas y a veces tiene puntos entre ellas. Sin embargo, por motivos esteticos, puede darse el caso de encontrar siglas con minúsculas, sobre todos cuando son nombres de empresas.

Números Romanos

Son fáciles de confundir con las siglas. De hecho a veces son indistinguibles, por ejemplo CC puede ser 200 o significar «con copia».

Los números romanos van sin punto al final y solo pueden contener las letras M,D,C,L,X,I.

Diccionarios

Necesitamos dos diccionarios, uno de palabras comunes que van en mayúsculas y no son nombres y otro de nombres.

Si una palabra empieza por mayúscula y está en el diccionario de nombres se puede considerar un nombre. Este diccionario a veces es difícil de crear ya que no se sabe que nombres se buscan, sin embargo cuando se sabe exactamente lo qué se busca puede ser una herramienta muy potente.

El diccionario de términos que pueden ir en mayúsculas y no son nombres es más genérico. Está formado por palabras que se suelen escribir en mayúsculas y otras que pueden ir al principio de una frase. Podemos incluir:

  • Meses del año
  • Días de la semana
  • Festivos
  • Notas musicales
  • Abreviaturas
  • Títulos, cargos y nombres de dignidad
  • Signos del zodíaco
  • Puntos cardinales
  • Siglas y acrónimos de nombres comunes o expresiones
  • Palabras que a veces se escriben con mayúsculas: patria, gobierno, biblia, dios,….
  • Onomatopeyas
  • Determinantes
  • Pronombres

Ojo que hay casos en que un nombre propio puede confundirse con alguno de los casos anteriores. Por ejemplo: Abril o Domingo son nombres de personas.

Hay que tener en cuenta que en el caso de los nombres compuestos pueden empezar por alguno de los elementos que están en este diccionario. Por ejemplo: «El Dorado, Los Ángeles»

Hay una mejora al diccionario de nombres y es añadir dinámicamente los nombres que vamos encontrando en el texto. Los nombres generalmente se repiten varias veces en el texto y puede ayudar a despejar las dudas sobre alguna palabra.

Palabras dudosas

Vamos a repasar los pasos que tenemos hechos hasta ahora.

  1. Seleccionar palabras que empiezan por mayúscula.
  2. Del paso anterior seleccionar aquellas que no están detrás de un punto o al inicio de una frase.
  3. Descartar excepciones usando reglas (como los números romanos) o el diccionario de palabras en mayúsculas que no son nombres.
  4. Las restantes del paso anterior se consideran nombres.
  5. Se añaden al diccionario de nombres
  6. Se toman las palabras del paso 1 que van detrás de un punto o al principio de una frase.
  7. Si están en el diccionario de nombres se consideran nombres.

Tras estos pasos nos quedan un conjuntos de palabras que no sabemos si son nombres o no. Podemos usar alguna heurística más como considerarlo un nombre si van dos palabras con mayúsculas seguidas o si son siglas.

Al final nos quedan palabras que dudamos si son nombres o no. Si el texto ha de pasar a revisión por un humano lo mejor es marcarlos como «posibles nombres», si no hay más opciones que marcarlo como nombre o no hay que valorar que opción es menos costosa, detectar como nombres palabras que no lo son o dejarse nombres sin detectar.

Nombres compuestos

Por ahora hemos tratado los nombres como si solo fueran una palabra, pero eso es muy irreal, gran cantidad de nombres están compuestos por más de una palabra. Para detectarlos vamos juntar todos aquellas palabras que empiecen por mayúscula y vayan seguidas (sin otras palabras o signos de puntuación entre ellas).

Si una de esas palabras cumple los requisitos para ser nombre se extiende a las demás palabras en mayúsculas que la rodean.

Mejoras

Uno de los elementos más importantes de este enfoque son los diccionarios. Cuando el sistema solo va a trabaja con textos de una temática concreta unos buenos diccionarios pueden dar resultados muy exactos.

Algo parecido pasa con reglas propias para textos de ciertos ámbitos. Por ejemplo si se buscan nombres de empresas se podría usar como pista que terminen en «S.A.», «S.L.», «INC», …

Hay nombres como los títulos de libros o películas que entrañan bastante dificultad ya que las reglas ortográficas dicen que tienen que ir en mayúsculas solo la primera palabra. Suelen ir entrecomilladas, en cursiva o en negrita, pero aún así no es un problema sencillo.

Inteligencia Artificial y los límites de la razón

En muchos artículos que leo se da por hecho que con los coches autónomos los accidentes desaparecerán y con ellos los seguros de coche que quedarán relegados a reparaciones y atención en carretera. Aunque muchas veces se de a entender lo contrario los primeros que celebrarían que esto ocurriese serían las aseguradoras, ellas ganan dinero cuando no hay accidentes. Desgraciadamente es una imagen irreal, los accidentes seguirán ocurriendo con los coches autónomos. En menor número ya que solo con eliminar los conductores cansados, temerarios, que miran el movil o bajo los efectos del alcohol o/y las drogas ya caerá bastante el número de accidentes. Pero seamos sinceros los buenos conductores, aquellos que están atentos, respetan todas las normas y son cautelosos lo hacen realmente bien. Los coches autónomos van a permitir gestionar y organizar el tráfico como nunca antes pero no van a ser perfectos. Vamos a usarlos como ejemplo para ver cuáles son los límites de la I.A.

Límites físicos para ejecución

Nuestro coche autónomo va circulando por una calle de un solo carril con coche aparcados a los lados cuando sin previo aviso aparece un viandante de detrás de una furgoneta a escasos tres o cuatro metros delante del coche. Por mucho que la I.A. frene la inercia va a arrastrar el coche hasta que atropelle al peatón, la otra opción es dar un volantazo y chocar con los coches aparcados. Ambas opciones son un accidente y es físicamente imposible evitarlo por muy eficaz que sea la I.A.

Límites físicos para el cálculo

Posiblemente el límite más conocido sea la capacidad de cálculo del sistema. Toda I.A. para ser útil ha de dar la respuesta en un tiempo finito y breve. Un sistema que tarde cuatrocientas millones de veces la vida del universo en dar una respuesta puede dar con la solución perfecta pero no resulta muy útil. Cuando juegas al ajedrez contra un software este responde con un movimiento suficientemente bueno pero no sé sabe si el mejor. En el caso de los coches autónomos cada elemento que tengan que «vigilar» aumenta la complejidad del problema (aumenta el espacio de búsqueda) y aumenta el tiempo que el sistema tiene que usar en detectarlo (reconocerlo, encontrar su límites, situarlo en el espacio, predecir su movimiento para anticiparse). Sin embargo el tiempo que tiene para reaccionar no aumenta.

Hay muchos más límites físicos, espacio, memoria, no-aleatoriedad, ….

Los sentidos nos engañan

O más bien «los sentidos están limitados». Descartes creía que no podemos confiar plenamente en los sentidos ya que nos pueden engañar. Lo cierto es que percibimos el mundo a través de ellos y nos dan una percepción muy limitada de la realidad. Los sensores tienen límites de alcance, precisión, exactitud, cometen errores y por supuesto se estropean dando medidas falsas

La sonda Schiaparelli se estrelló al tratar de aterrizar en Marte, la causa un error en las medidas de un sensor debido a que se saturo por el ruido indicaba que estaba bajo tierra así que apagó los motores.

Un fallo un sensor fue también la causa de los problemasdel Boeing 737 max.

Incertidumbre

Hay algoritmos para tratar con la incertidumbre. Pero generalmente acaban trabajando con probabilidades y tratando de decidir valorando beneficios y costes respecto a lo probable que sean. Pero algo sea improbable no quiere decir que no vaya a ocurrir.

Un coche autónomo puede suponer que es improbable que un ciervo cruce la carretera de repente y lo atropelle, todos conducimos sin plantearnos cada segundo si un animal va a saltar sobre nuestro capó, pero sabemos que no es imposible y que ha se han dado casos.

Funcionamos con la suposición de que lo improbable no va a pasar, el coche de al lado no va a abalanzarse sobre nosotros sin previo aviso (incluso los conductores agresivos dejan claras sus intenciones confiando que los demás cedan por precaución y les dejen cambiarse), que nadie va a ir circulando en dirección contraria por mi carril o que los demás van a respetar el semáforo en el cruce. Por supuesto que a veces estas reglas se incumplen pero es tan improbable que difícilmente se pueden tener en cuenta si no hay otras señales que nos hagan pensar que es probable (el conductor de al lado hace unas «eses» sospechosas mientras trata de mantenerse en el carril o el coche que llega al cruce va demasiado rápido como para frenar de golpe en el semáforo).

Aprende de la experiencia

El aprendizaje máquina trata de sacar unas reglas generales a partir de un montón de ejemplos particulares. El problema está en que la I.A. no va a poder tratar casos que no haya «visto». Por ejemplo una I.A. que ha aprendido a reconocer peatones puede fallar si el peatón va disfrazado de platano, por ejemplo. Eso no quiere decir que no tenga que frenar si se cruza, pero para la I.A. sería un obstáculo en la vía, no un peatón

Los agentes inteligentes están altamente especializados. Un programa que aprende a jugar al ajedrez no sirve para aprender a conducir. Los coches autónomos se mueven en el mundo real en una sociedad creada por humanos que tienen sus reglas de convivencia y un entorno muy complejo.

Por ejemplo algunos modelos de coches autónomos han tenido problemas con su forma de conducir porque marea a los pasajeros. Un conductor humano siente lo mismo que los pasajeros y evita sensaciones desagradables a los mismos (frenazos muy bruscos, giros repentinos, aceleraciones bruscas,…). Pero nadie había entrenado a la I.A. del coche para ello.

Otro ejemplo es el de un coche autónomo que buscando ahorrar dinero en lugar de aparcar en una zona de pago prefiera seguir circulando despacito de tal forma que el coste de circular sea menor que el del aparcamiento. Desde un punto de vista cívico eso es una barbaridad, consumir energía gratuitamente y empeorar el tráfico. Si la inteligencia no ha sido entrenada para tener en cuenta eso puede caer en soluciones erróneas.

Límites del sistema

Es parecido al punto de los límites físicos, pero en este caso los motivos no son físicos si no la organización o estructura del sistema. En muchos casos la solución es reorganizar el sistema pero eso queda más allá de las opciones del agente inteligente. Un ejemplo son algunos atascos. Hace años trabajé en un polígono industrial con solo dos salidas. Los viernes en verano la mayoría de las empresas salíamos entre las tres y las tres media de la tarde lo que suponía soportar atascos de 20 minutos. Y no hay forma de evitarlos. Aunque todos los coches fueran un agente inteligente y se coordinasen seguiría habiendo atascos. Se lo que estáis pensando: «Los coches se podrían coordinar para no intentar salir todos a la vez». Pero la consecuencia es la misma que un atasco, me va a costar 20 minutos salir de ahí. Me da igual si estoy atascado o esperando con el coche o con el coche dando vueltas o esperando que me avise al móvil que ya podemos irnos.

Riesgos calculados

En la vida real hay que tomar riesgos. Generalmente por dos motivos, falta de información e imposibilidad de conseguirla o que no hay más remedio para evitar una situación peor.

Un ejemplo es llegar a un cruce donde un camión mal aparcado tapa la visión. El coche autónomo no puede quedarse parado hasta que retiren el camión. Tendrá que moverse lentamente minimizando los riesgos pero asumiendo que ni el ve ni es visto y eso podría causar un accidente.

Decisiones irracionales

Actualmente la inteligencia artificial no puede decidir si no tiene una forma de comparar opciones. Eso no quiere decir que no pueda simplemente elegir al azar una opción. El mismo problema tiene si varias opciones son igual de buenas.

Al final hemos diseñado la I.A. para que haga decisiones racionales pero la vida humana esta llena de decisiones no racionales.

Ciborgs y control mental

El título suena completamente a ciencia ficción, pero solo parte de este texto es especulativo, la realidad es que ya se han hecho experimentos para controlar animales usando interfaces máquina cerebro. Aunque pueda parecer algo complicado la idea básica es muy fáciles de entender.

Primero hemos de poder comunicar al animal que tiene que hacer. Se conectan electrodos a alguno de los nervios sensitivos del animal. Por ejemplo a la antena derecha y a la antena izquierda. No hay límite a la cantidad de «zonas» que podemos estimular, pero el animal ha de poder distinguir claramente entre los distintos estímulos. Si no es así podría malinterpretarlos.

Es importante que el estímulo este asociado con la acción. Si por ejemplo queremos que una cucaracha de volteretas laterales cuando reciba un estímulo en la antena derecha, difícilmente va a ocurrir. Sin embargo si queremos que gire a la derecha va a ser muy probable que ocurra.

Tras realizar la acción que queremos que ocurra hay que recompensarle. Por ejemplo estimulando sus centros de placer. Este video lo explica mejor que yo

En resumen, asociamos un estímulo con una recompensa al realizar una acción. Es lo que se conoce como condicionamiento operante con refuerzo positivo y no es nada nuevo, lo que es nuevo es estimular directamente el cerebro para lograrlo.

Desde el punto de vista externo al sujeto del experimento los pasos son:

  1. Decidir la acción
  2. Enviar el estímulo
  3. Verificar la realización de la acción
  4. Recompensar

Hay que tener algunos detalles en cuenta como que no puede pasar demasiado tiempo entre el estimulo, la acción y la recompensa o el animal no sera capaz de asociarlos entre ellos.

Con este sistema el animal sigue teniendo libre albedrío (si es que existe) y puede decidir oponerse a los estímulos. Sin embargo la sensación de placer tras cumplir la acción es lo que les motiva. Realmente no es muy distinto a dar una golosina a un perro cuando realiza correctamente un truco. Y de hecho se podría usar junto con entrenamiento tradicional para conseguir acciones más complejas.

Hay que tener cuidado con los comportamientos repetitivos para conseguir retroalimentacion positiva. Son causados cuando repetir una acción te genera una recompensa, haciendo que el sujeto repita todo el rato la misma acción para conseguir la recompensa. Supongamos que queremos que una rata se levante y se rasque los bigotes. Para ello le damos una recompensa al levantarse y otra mayor al rascarse los bigotes. La rata puede descubrir que si se levanta, se sienta y se vuelve levantar experimenta placer continuamente, mientras que si se rasca lo bigotes experimenta un placer mayor pero solo una vez. Esto da lugar conductas repetititas. Se podrían debilitar la recompensa en cada repitición para reducir el número de repeticiones. Más adelante veremos los refuerzos negativos que podrian usarse para evitar estos comportamientos castigando las repeticiones.

Mejoras poco éticas

Ahora entramos en un tema delicado. No apoyo que se realicen experimentos con ninguna de las opciones que voy a contar aquí. De hecho son experimentos que dudo que recibiesen aprobación por motivos éticos. Pero tampoco le veo sentido a negar la posibilidad de su existencia o a censurarlas.

Hay más formas de mejorar el aprendizaje y asegurarse de la obediencia de las instrucciones. En los experimentos se usa el refuerzo positivo pero se puede usar refuerzo negativo. Causar dolor o molestias si no se realiza la acción. Pero a se puede refinar más el sistema siendo un poco retorcido se puede crear una molestia que vaya creciendo hasta que se cumpla la acción deseada.

La lista de pasos para el proceso no ético seria:

  1. Decidir la acción
  2. Enviar el estímulo
  3. Generar una molestia
  4. Verificar la realización de la acción
  5. Si no se realiza la acción castigar
  6. Si se realiza la acción recompensar

Desde el punto de vista del sujeto lo que se percibiría es que se siente una molestia que crece hasta el dolor y que desaparece, sintiendose un gran placer, cuando se realiza cierta acción. Tiene similitudes con algunos comportamientos compulsivos.

¿Qué tiene que ver esto con la inteligencia artificial?


Poco, pero lo he visto relacionado con la tematica del blog y me apetecia hablar de ello. Además hay un hueco para ella (siempre hay hueco para poner una I.A.), tras realizar la accion y antes de entregar la recompensa un agente externo tiene que evaluar que la acción es adecuada para entregar la recompensa. Si recurrimos a la versión no etica aun tiene más trabajo gestionando castigos.

¿Lo puede hacer una I.A.? Depende de la complejidad de las acciones. La I.A. ha de ser capaz de percibilas sin errores, hay que tener cuidado con los falsos negativos y falsos positivos ya que recompensas o castigos sin sentido podria causar confusión en el sujeto.
¿Debe de hacerlo una I.A.? tiendo a pensar que las implicaciones éticas de tener una máquina dirigiendo las acciones de un ser vivo nos impediria hacerlo. No se me ocurre ningun caso en que sea justificable.

¿Es aplicable para humanos?

Físicamente nada impide usar estas técnicas en humanos. Pero hay que recordar que este sistema no afecta a la voluntad del individuo solo le castiga/recompensa para que realice ciertas acciones. Un ser humano es consciente de la manipulación a la que es sometido y puede elegir desobedecer. La historia está llena de personas resistiendo torturas horribles sin doblegarse.

Sin embargo supongamos que el sujeto no es consciente de que tiene insertado este sistema (dejemos de lado problemas de como puede ser eso posible o de cuánto le duraría la batería). Algo le impulsaría a realizar acciones y sentiría un gran alivio y placer al realizarlas y un terrible dolor al resistirse. Sin embargo ya hay transtornos con estos comportamientos y se tratan, consiguiendo cierto grado de control sobre ellos.

Leyendo hasta aqui parece una historia de terror, pero las teconolgías usadas en estos experimentos tambien se han empleado, por ejemplo, en el tratamiento de enfermedades como el Parkinson realizando estimulación sobre la corteza motora. Esta tecnología puede servir para ayudar con diversas enfermedades y trastornos graves estimulando diversas areas cerebrales, que no tiene que ser los circuitos de recompensa. El cuando sea ético o no aplicarlas es otro tema.

Dinero como función de utilidad

Los agentes inteligentes necesitan alguna forma de comparar resultados para basar sus decisiones. Es decir saber de forma numérica «lo útil» que es cada decisión. Es algo complicado. Muchas veces podemos estar tentados en tomar atajos. Uno de los más habituales es usar el valor económico como media de este valor. Sin embargo los seres humanos tienen un relación curiosa con el dinero.

¿Por qué es importante el dinero para la I.A.?

El dinero es importante para la I.A. por el sencillo motivo de que es importante para los humanos. Si necesitamos que los agentes inteligentes interaccionen con nosotros han de tener en cuenta nuestras peculiaridades.

También resulta curioso comparar como actuamos con el dinero. El dinero actúa como una función de utilidad para nosotros y al ser tan fácilmente interpretable (es un simple valor numérico) podemos comparar como actuamos respecto a cómo esperaríamos que actúe una inteligencia artificial.

¿Eso quiere decir que algo falla en nosotros o en los agentes? No, simplemente quiere decir que hemos llegado por caminos distintos y valoramos el dinero de forma diferente. Para los agentes es simplemente un número que usar como función de utilidad, mejor cuánto mayor sea el número. Para nosotros todo es más complicado. El dinero es una mezcla de algo natural y conocido como es el acumular bienes materiales con algo nuevo y desconocido que es el valorar algo abstracto e inmaterial como es el dinero.

Los humanos entendemos que acumular bienes es beneficioso, pero en la naturaleza la mayoría de los bienes importantes no son acumulables más allá de cierto punto. La comida se estropea y tener cien lanzas en lugar de dos o tres solo te supone una carga. De hecho repartir las cosas que te sobra entre tus amigos y familia puede ser una buena inversión ya que te conseguirá su simpatía y cierto estatus social y quién sabe si en un futuro necesitarás un favor y te lo podrán devolver. Además ayuda al grupo y estar en un grupo fuerte también es beneficioso. Al final compartir puede resultar la mejor forma de usar los bienes y el reconocimiento del grupo más valioso a largo plazo que los bienes.

Sin embargo. El dinero puede acumularse sin límites, sin suponer una carga o que se eche a perder con el tiempo (se devalúa pero no es comparable). El dinero permite mejorar nuestra calidad de vida y nos proporciona seguridad para el futuro. Pero esta claro que no sabemos muy bien como valorarlo de forma intuitiva lo que da resultado a comportamientos contradictorios.

El valor del dinero y la justicia

El valor del dinero es relativo, depende de lo que tengas, de lo que tengan los que te rodean o incluso tus esperanzas de beneficio. De primeras todos podemos pensar que si sales ganando dinero has ganado. De hecho las matemáticas nos apoyan. Ganar dinero es mejor que no ganarlo y desde luego mucho mejor que perderlo desde la teoría de juegos está claro. Sin embargo para el ser humano no es tan simple.

Hay un juego llamado «ultimátum», sus reglas son sencillas: Hay dos jugadores, a uno se le da una cantidad de dinero, supongamos 100€, su función es decidir cómo repartirlo, cuánto se queda el y cuánto el otro jugador. El otro jugador solo tiene una función, decir si acepta o no el trato. Si lo acepta ambos se quedan con su parte del dinero, si no lo acepta los dos pierden su dinero. Lo lógico sería aceptar cualquier trato cuyo valor sea mayor que 0. Algo siempre es mejor opción que nada. Pero los humanos no somos tan simples y tendemos a rechazar repartos que no sean lo suficientemente «justos», parece que podemos asumir cierta cantidad de injusticia a cambio de un beneficio pero «sin pasarse». Es decir mucha gente estaria dispuesta a aceptar un reparto 60-40 pero muy poca un reparto 90-10.

Para entenderlo vamos a comparar dos casos, supongamos que alguien te regala 10€, estarás agradecido. Ahora estás jugando al juego del ultimátum y te ofrecen 10€. El valor intrínseco del dinero es el mismo. Pero nuestra forma de valorarlo no. La injusticia del reparto hace que el dinero pierda valor, tanto como para llegar a rechazarlo. Ojo que al actuar así nos aseguramos que el reparto se acerque a lo justo. Incluso en el juego del dictador, una versión en la que el segundo jugador no puede decir que no, el reparto se aleja más de lo que sería justo pero no llega a los 0€ que sería lo óptimo en este caso. Esta claro que valoramos algo más que el simple beneficio económico

Se suele decir que «todos tenemos un precio», no estoy seguro si todos lo tenemos, pero algunos desde luego. Si el ultimátum se jugará con millones de euros estoy seguro que mucha gente se trataría su orgullo y aceptaría un reparto de 99 millones a 1 millón aunque fuera injusto.

Valor del dinero en el entorno social

Hay estudios que demuestran que la gente esta más o menos satisfecha con su salario o su bienes en relación a lo que tengan la gente que le rodea. Es decir valoras el dinero como indicador de estatus social. Y aprovechándose de eso muchos productos caros se publicitan como indicadores de estatus social. Se venden como si fueran la cola de un pavo real.

Mucha gente paga más de lo que corresponde en la relación beneficio/costo solo por aparentar. Comprarse un producto caro que no va a aprovechar. Se podría discutir que se compensa por el incremento de estatus social. También se podría cuestionar lo beneficioso que es entrar en esas dinámicas absurdas donde el único beneficio real lo saca el vendedor.

El hecho que haya gente que por aparentar se endeude quiere decir que valoramos el reconocimiento social como una valor en si mismo

Valor del dinero y necesidad

Para hacer un algoritmo que valore lo beneficiosa económicamente que es una acción podemos usar cálculos como la esperanza que son independientes de tu situación, solo dependen del beneficio que se pueda esperar.

En los humanos el valor que damos al dinero depende de la necesidad que tengamos de él. A mayor necesidad mayor valor le damos al dinero, sobre todo si es inmediato. De ello viven esas empresas que dan créditos rápidos a intereses altos. Cuando necesitamos dinero no valoramos correctamente los costes de obtenerlo. De hecho cuando la deuda alcanza un nivel que es imposible de pagar mucha gente opta por adoptar el punto de vista «de perdidos al río» tomando decisiones arriesgadas que pueden hacer que la deuda crezca ¿Pero que más da si ya no podemos pagarla?

Cuando tienes mucho dinero también resulta difícil evaluar el riego y eso hace que mucha gente acabe perdiendo su fortuna. Se da en muchos casos de gente que le ha tocado mucho dinero en la lotería que lo gestiona mal y lo pierde en la llamada maldición de la lotería. Posiblemente debida a que según vas acumulando cosas la felicidad que obtienes de ello disminuye muy rápidamente y acabas gastando más de lo debido. Parece que el acumular cosas por encima de un limite no produce más felicidad.

¿Ocurre solo con el dinero?

Realmente no, ocurre con cualquier cosa que tenga valor para nosotros. Estudios con primates han demostrado comportamientos parecidos con frutas o juguetes. Parece ser que valoramos más cosas que el simple beneficio material de nuestras acciones. Que la justicia, el reconocimiento o el grupo social nos interesa más de lo que consciente mente percibimos.

Cualquier inteligencia, artificial o no, que quiera vivir en la sociedad humana ha de tener en cuenta estos valores o no logrará predecir nuestro comportamiento. Como ejemplo, el caso de un colegio que cansado de que los padres llegaran tarde a buscar a los hijos decidió multarlos. Resultado, los padres empezaron a llegar aun más tarde. Al pagar por ello dejaron de sentirse tan culpables por llegar tarde, el coste social fue reemplazado por el económico

Procesar un texto carácter a carácter

Una de las formas más básicas y relativamente simple para procesar texto es el análisis de carácteres uno a uno. Es un sistema computacionalmente muy simple y que se puede ejecutar con muy poco coste, tan poco que yo he llegado a usarlo en un Arduino con una shield ethernet para procesar peticiones HTTP. El proceso consiste en analizar el texto carácter a carácter clasificando cada carácter en uno o varios tipos y aplicar reglas según esos tipo.

Un ejemplo de tokenizador muy simple sería un sistema que clasifica los caracteres en letras (a-zA-Z), números (0-9) y símbolos (el resto).

for char c in text {
  if tipo(c) == tipoAnteriorSimbolo {
     token += c;
  } else {
    guardarToken(token);
    token = c;
  }
  tipoAnteriorSimbolo = tipo(c);
}

Múltiples tipos por carácter.

El sistema anterior puede ser útil para tratar con lenguajes artificiales muy estrictos como como  ser el uso de comandos o protocolos, pero tiene problemas con lenguajes más «humanos». Por ejemplo si tratamos de sacar los números de la frase : «Debe 1.000,00€ desde el día 10 de junio.» obtendremos «1», «000», «00», «10». Cuando lo correcto es: «1.000,00» y «10». Podemos ver en este caso como hay caracteres que no son números pero deberían considerarse como tales «.,» . Una solución es que en lugar de considerar cada carácter de un solo tipo que puedan ser de varios. En este caso los caracteres «.,» pueden ser considerados signo de puntuación y número.

for char c in text {
  if tipos(c).estaEn(tiposAnteriorSimbolo) {
     token += c;
  } else {
    guardarToken(token);
    token = c;
  }
  tiposAnteriorSimbolo = tipo(c);
}

Ventana de caracteres

Cambiemos de caso, ahora miremos el texto: «Quedamos a las 10. No vino». Aquí el problema es que nuestro sistema vera «10.» como un número, vale que luego en un procesamiento posterior podemos eliminar el punto que sobra. Pero también podemos solucionar ese problema aumentando «la ventana» que ve el algoritmo. Actualmente el algoritmo juzga el carácter actual y el anterior, se puede modificar para que además vea el siguiente carácter, de tal forma que disponga de los tipos de los tres caracteres para comparar.

Luego hay que definir reglas. Por ejemplo para que un punto cuente ha de estar rodeado de otros dos números. Si está rodeado de un número y un espacio el punto no forma parte del número.

Ventajas e inconvenientes

La principal ventaja de este algoritmo son los pocos recursos que necesita para ejecutarse. Para casos limitados puede funcionar perfectamente. Por eso puede ser ideal para usar en microcontroladores.

Su inconveniente es que no es suficiente flexible para procesar lenguajes humanos y que las reglas pueden llegar a ser muy complicadas.

Sin embargo en caso de que no puedas procesar algoritmos más complicados puede ser la única posibilidad.

Problemas con procesamiento de lenguaje natural en Español

Todos los lenguajes tienen sus particularidades que resultan problemáticas a la hora de ser procesados por un algoritmo. Pero como yo me he centrado en el español puedo resumir los problemas que me he encontrado a distintos niveles del proceso. Estas son las características más habituales que se atragantan a la hora de procesar el español:

Verbos

Nuestros verbos son un horror para muchos estudiantes y para su procesamiento por las máquinas. Literalmente cientos de formas verbales según el tiempo, número, género, aspecto y modo. Formas compuestas, perífrasis verbales, pronombres clíticos y cuando tienes todas las reglas modeladas descubres la cantidad de verbos irregulares que hay.

Tildes

aquí la «diversión» viene por dos lados. Primero que para algunos algoritmos hay que tenerlas en cuenta, para otros no. Por ejemplo para los stemmer no se tienen en cuenta para saber la conjugación verbal hay que considerarlas. Por otro lado «olvidarse» de ponerlas es muy habitual (pueden usarse como ejemplo cualquiera de mis post) y más ahora que puede ser correcto escribir la misma palabra con o sin tilde.

Ñ

La ñ, la mayoría de los lenguajes de programación y librerías están pensadas para el alfabeto inglés, por lo que la ñ (al igual que las vocales con tilde) es la gran olvidada del alfabeto español.

Flexiones

Dependiendo la función que haga una palabra puede tener distintas flexiones y hay que tenerlas en cuenta todas. Por ejemplo si quiero buscar referencias a colores hay que tener en cuenta la palabras «rojo, roja, rojos, rojos, rojizo, rojiza, rojizas, rojizos»

Las reglas que hay tiene gran cantidad de excepciones y hay que contemplar otros casos como términos cuyas palabras son distintas para cuando cambias de número o genero (toro – vaca), que las reglas aplican pero el significado es distinto (rata – rato) o con múltiples formas para la misma flexión como puede ser los aumentativos (-azo, -ton) y diminutivos (-ita, -illa, -ica) que además pueden cambiar el sentido de la palabra (listo – listillo) complicándolo todo un poco más.

Reglas poco estrictas para formar frases

Libertad al configurar las frases. Nuestras reglas para componer frases no son muy estrictas. Lo mismo podemos decir «El coche rojo de Juan», «Es rojo el coche de Juan».

Variantes

El español está muy extendido por todo el mundo por lo que hay distintas variantes. Pero como vivimos en un mundo muy interconectado es fácil encontrar esas variantes mezcladas, sobre todo en Internet.

Localización en interiores usando redes WiFi

Ya hemos visto que usar la distancia al emisor para posicionarte dentro de casa es muy difícil, al menos sin usar hardware especializado. ¿Nos hemos quedado sin opciones?. Somos gente ingeniosa, no nos quedamos sin opciones. Si no podemos usar la distancia por la gran variación que tiene la potencia de la señal en interiores, le daremos la vuelta al problema y lo usaremos como ventaja. Si a la gran variación que hay en la potencia de la señal le sumamos la gran cantidad de nodos WiFi que hay alrededor nuestro, resulta muy poco probable que en dos puntos que no estén muy próximos se den los mismos valores para todas las redes.

Vamos a empezar por la idea básica y luego desarrollaremos los distintos problemas que surgen en la vida real.

Primero vamos a movernos por nuestra casa midiendo la potencia de las redes WiFi que se reciben en distintos puntos que consideramos interesantes para localizarnos. Obtendremos una lista de tuplas {SSID, potencia} para cada punto.

Una vez tengamos esa base de datos creada vamos a tratar de saber lo «cerca» que estamos de esos puntos sabiendo solo la potencia de los wifi que nos rodean. En este caso «cerca» no se refiere a distancia física en metros si no a lo parecidas que son las mediciones en dos puntos. Aunque no tenga que ver con la distancia física a este concepto también se le llama distancia.

Para medir esta distancia es fundamental saber que valor o valores vamos a usar, en este caso la potencia de la señal del WiFi. Vamos a compararla con las potencias almacenadas en nuestras mediciones anteriores. Para ello tomaremos las potencias medidas en los nodos con el mismo SSID y las compararemos, sumando luego todas para saber como de «próximos» están esos dos puntos.

Siendo Pi[ssid] la potencia en la base de datos para el nodo con ese SSID en el punto i y Pm[ssid] para la potencia medida de ese mismo nodo la distancia seria:

Dist(Pi) = ∑ √ (Pi[ssid] – Pm[ssid])²

O una forma menos exacta pero también computacionalmente menos costosa (y que a mi me a servido perfectamente)

Dist(Pi) = ∑ ABS(Pi[ssid] – Pm[ssid])

Siendo ABS la función que calcula el valor absoluto.

Que la i no despiste, en ambas formulas el sumatorio se refiere a sumar la diferencias de los distintos SSID medidos de cada punto.

Podemos determinar de que punto estamos más cerca comparando estas distancias y quedándonos con aquel punto Pi cuyo valor sea menor.

Para aplicar esta idea dividí mi casa (realmente solo dos habitaciones contiguas y un trozo de pasillo para probar) en una matriz de cuadrados de un metro de lado y establecí comos puntos de referencia el centro (a ojo) de cada cuadrado.

¿Funciono bien? La sorpresa es que, tras corregir problemas de los que hablo más adelantem mucho mejor de lo que esperaba. Buscando los puntos más cercanos me resultaba fácil saber donde estaba. No siempre me daba como más cercano el punto del que más cerca estaba pero nunca se fue muy lejos, así que podía saber mi posición con bastante precisión.

Problemas

Desgraciadamente de la teoría a la practica suele haber un camino lleno de baches. Por lo que siempre surgen problemas para aplicar la teoría tal cual y que hay que resolver.

Nodos que aparecen y desaparecen

Si los nodos WiFi que usas como referencia están siempre encendidos el hecho de que un nodo no esté entre tus mediciones indica que potencia es 0 y es un gran indicador de donde estamos. Pero si usas los WiFis de tus vecinos el que se apaguen a lo largo del día es algo más habitual de lo que parece. Por lo que tenemos nodos que aparecen y desaparecen. Así que si un nodo no esta entre tus mediciones no se puede considerar que su potencia es 0 (aunque lo sea en ese momento) ya que puedes estar falseando los resultados. Mi experiencia es que si no tienes medición de un nodo lo descartes y no lo tengas en cuenta en tus cálculos.

Ruido en las mediciones

Los valores de potencia pueden variar muchísimo al realizar una medición, mi consejo es que realices varias medidas (yo uso 3) y te quedes con la mediana o la moda de las mismas. Es muy importante sobretodo que realices esto al generar la base de datos de los puntos de referencia.

Otro problema es que no todas los nodos se ven sometidos a las mismas variaciones, contra menor potencia tengan en ese punto más propensas son a sufrir variaciones y más amplias son estas. En algunos casos resulta conveniente fijar un umbral mínimo de potencia para tener en cuenta ese nodo.

Variación de las medidas usando distintos aparatos.

Es recomendable usar el mismo «aparato» para generar la base de datos de puntos que el que luego se va a intentar localizar. Las medidas entre mi portátil, mi smartphone y mi placa Node MCU eran suficientemente distintas como para causar errores si intentaba comprar unas con otras