Redes neuronales en JavaScript con Brain.js

R

 

Introducción

Especialmente en los últimos años, las redes neuronales (NN) realmente han despegado como una forma práctica y eficiente de resolver problemas que no se pueden resolver fácilmente con un algoritmo, como la detección de rostros, el reconocimiento de voz y el diagnóstico médico. Esto se debe en gran parte a los descubrimientos recientes sobre cómo entrenar y sintonizar mejor una red, así como al aumento de la velocidad de las computadoras.

Recientemente, un estudiante del Imperial College London creó un NN llamado Jirafa que podría entrenarse en solo 72 horas para jugar al ajedrez al mismo nivel que un Maestro Internacional de la FIDE. Las computadoras que juegan al ajedrez en este nivel no son realmente nuevas, pero la forma en que se creó este programa es nueva. Estos programas suelen tardar años en construirse y se ajustan con la ayuda de un gran maestro real, mientras que Giraffe, por otro lado, se creó simplemente utilizando una red neuronal profunda, algo de creatividad y un enorme conjunto de datos de juegos de ajedrez. Este es otro ejemplo más de la promesa que las redes neuronales han mostrado recientemente, y solo van a mejorar.

Brain.js

La desventaja de las NN, y de la inteligencia artificial en general, es que el campo es muy pesado en matemáticas, lo que tiende a asustar a las personas antes de que empiecen. La naturaleza altamente técnica de las NN y toda la jerga que las acompaña hace que sea difícil para los no iniciados aprovecharlas. Aquí es donde Brain.js entra en juego. Brain.js hace un gran trabajo simplificando el proceso de creación y entrenamiento de una NN utilizando la facilidad de uso de JavaScript y limitando la API a unas pocas llamadas y opciones de métodos.

No me malinterpretes, todavía necesitas conocer algunos de los conceptos detrás de las NN, pero esta simplificación lo hace mucho menos abrumador.

Por ejemplo, para entrenar una red para aproximar el XOR función (que es uno de los ejemplos estándar de NN), todo lo que necesita es:

var brain = require('brain');

var net = new brain.NeuralNetwork();

net.train([{input: [0, 0], output: [0]},
           {input: [0, 1], output: [1]},
           {input: [1, 0], output: [1]},
           {input: [1, 1], output: [0]}]);

var output = net.run([1, 0]);  // [0.933]

Este código solo crea una nueva red (net), trains la red usando una serie de ejemplos, y luego runs la red con una entrada de [1, 0], que correctamente da como resultado [0.933] (también conocido como 1).

Si bien Brain.js no tiene un montón de opciones que le permitan personalizar sus redes, la API acepta suficientes parámetros para que sea útil para aplicaciones simples. Puede establecer el número y el tamaño de sus capas ocultas, el umbral de error, la tasa de aprendizaje y más:

var net = new brain.NeuralNetwork({
	hiddenLayers: [128,64]
});

net.train({
	errorThresh: 0.005,  // error threshold to reach before completion
	iterations: 20000,   // maximum training iterations 
	log: true,           // console.log() progress periodically 
	logPeriod: 10,       // number of iterations between logging 
	learningRate: 0.3    // learning rate 
});

Consulte la documentación para obtener una lista completa de opciones.

Si bien está limitado en los tipos de redes que puede construir, eso no significa que no pueda hacer nada significativo. Tomar este proyecto por ejemplo. El autor reunió un montón de imágenes captcha para su conjunto de datos, usó un procesamiento de imágenes simple para preprocesar las imágenes y luego usó Brain.js para crear una red neuronal que identifica a cada personaje individual.

Ventajas

Como ya mencioné, Brain.js es excelente para crear rápidamente una NN simple en un lenguaje de alto nivel donde puede aprovechar la gran cantidad de bibliotecas de código abierto. Con un buen conjunto de datos y algunas líneas de código, puede crear algunas funciones realmente interesantes.

Las bibliotecas altamente científicas / computacionales escritas en JavaScript como esta tienden a criticado bastante, pero personalmente creo que Brain.js tiene su lugar en JS siempre que tenga las expectativas y la aplicación adecuadas. Por ejemplo, JS es el lenguaje dominante (¿único?) Que se ejecuta en el lado del cliente en el navegador, así que ¿por qué no aprovechar esta biblioteca para cosas como juegos en el navegador, colocación de anuncios (aburrido, lo sé) o reconocimiento de personajes?

Desventajas

Si bien definitivamente podemos obtener algo de valor de una biblioteca como esta, no es perfecta. Como mencioné, la biblioteca limita la arquitectura de su red a un punto en el que solo puede hacer aplicaciones simples. No hay muchas posibilidades de capas Softmax u otra estructura. Sería bueno tener al menos la opción de personalizar más la arquitectura en lugar de ocultarle todo.

Probablemente mi mayor queja es que la biblioteca está escrita en JavaScript puro. Entrenar a una NN es un proceso lento que puede llevar miles de iteraciones (es decir, millones o miles de millones de operaciones) para entrenar en millones de puntos de datos. JavaScript no es un lenguaje rápido de ninguna manera y realmente debería tener plugins para cosas como esta para acelerar los cálculos durante el entrenamiento. El cracker de captcha de arriba tomó un tiempo de entrenamiento sorprendentemente bajo de 20 minutos, pero todo lo que se necesita son algunas entradas más y algunos datos más para aumentar el tiempo de entrenamiento en unas pocas horas o incluso días, como verá en mi ejemplo a continuación.

Desafortunadamente, esta biblioteca ya ha sido abandonada por su autor (la descripción de Github está precedida por “[UNMAINTAINED]”). Si bien entiendo que puede ser difícil mantener las demandas de una biblioteca de código abierto popular, es decepcionante verlo, y solo podemos esperar que alguien calificado pueda llenar el vacío. Estoy seguro de que hay una buena fork ya está en proceso, pero puede ser necesario buscarlo para encontrarlo.

Ejemplo

Aquí les mostraré un ejemplo un poco más complicado de cómo usar Brain. En este ejemplo, creé un NN que puede reconocer un solo dígito escrito a mano (0-9). El conjunto de datos que estoy usando es el popular MNIST conjunto de datos, que contiene más de 50.000 muestras de dígitos escritos a mano. Este tipo de problema se conoce como reconocimiento óptico de caracteres (LOC), que es una aplicación popular de NN.

El reconocimiento funciona tomando una imagen en escala de grises de 28×28 de un dígito escrito a mano y generando el dígito que la red cree que “vio”. Esto significa que tendremos 784 entradas (una para cada píxel) con valores entre 0-255, y habrá 10 salidas (una para cada dígito). Cada salida tendrá un valor de 0-1, que actúa esencialmente como el nivel de confianza de que ese dígito en particular es la respuesta correcta. El valor de confianza más alto es entonces nuestra respuesta.

En el código:

var brain = require('brain');
var fs = require('fs');

var getMnistData = function(content) {
	var lines = content.toString().split('n');

	var data = [];
	for (var i = 0; i < lines.length; i++) {
		var input = lines[i].split(',').map(Number);

		var output = Array.apply(null, Array(10)).map(Number.prototype.valueOf, 0);
		output[input.shift()] = 1;

		data.push({
			input: input,
			output: output
		});
	}

	return data;
};

fs.readFile(__dirname + '/train.csv', function (err, trainContent) {
	if (err) {
		console.log('Error:', err);
	}

	var trainData = getMnistData(trainContent);

	console.log('Got ' + trainData.length + ' samples');

	var net = new brain.NeuralNetwork({hiddenLayers: [784, 392, 196]});

	net.train(trainData, {
		errorThresh: 0.025,
		log: true,
		logPeriod: 1,
		learningRate: 0.1
	});
});

los train.csv El archivo es solo un CSV con una imagen por línea. El primer valor es el dígito que se muestra en la imagen y los siguientes 784 valores son los datos de píxeles.

La cantidad de capas y nodes que elegí fue un poco arbitraria y probablemente innecesariamente alta para esta aplicación de OCR. Sin embargo, cuando no puede aprovechar cosas como softmaxes o pooling, es posible que tenga más suerte aumentando el número de capas y el recuento de nodes.

El entrenamiento tomó fácilmente más de una hora para obtener resultados decentes. Si bien esto era lo esperado, todavía me decepcionó un poco tener que esperar tanto tiempo para probar una nueva estructura de red o nuevos parámetros de aprendizaje. Una aplicación simple como esta no debería tomar tanto tiempo, pero ese es el precio que paga por una implementación de JavaScript.

Para probar la red, cargué otro archivo, test.csv, y lo usó como base para comparar redes. De esa manera, tenemos una mejor idea del rendimiento, ya que estamos probando entradas en las que la red aún no ha sido entrenada.

Así es como probé la red (solo estoy mostrando las partes relevantes):

// Require packages...

fs.readFile(__dirname + '/test.csv', function (err, testContent) {
	if (err) {
		console.log('Error:', err);
	}

	// Load training data...

	// Train network...

	// Test it out
	var testData = getMnistData(testContent);

	var numRight = 0;

	console.log('Neural Network tests:');
	for (i = 0; i < testData.length; i++) {
		var resultArr = net.run(testData[i].input);
		var result = resultArr.indexOf(Math.max.apply(Math, resultArr));
		var actual = testData[i].output.indexOf(Math.max.apply(Math, testData[i].output));

		var str="(" + i + ') GOT: ' + result + ', ACTUAL: ' + actual;
		str += result === actual ? '' : ' -- WRONG!';

		numRight += result === actual ? 1 : 0;

		console.log(str);
	}

	console.log('Got', numRight, 'out of 350, or ' + String(100*(numRight/350)) + '%');
});

Conclusión

Si bien hay algunas deficiencias, en general creo que Brain.js puede ser muy útil y agregar mucho valor a las aplicaciones JavaScript / Node. Su facilidad de uso debería permitir que casi cualquier persona se inicie en las redes neuronales.

En caso de que desee algo con más flexibilidad o le moleste la falta de compatibilidad con Brain.js, eche un vistazo a Sináptico, lo que permite una personalización mucho mayor en la arquitectura de su red. No tiene la popularidad / atención que tiene Brain, pero parece ser la siguiente mejor opción para redes neuronales en JavaScript.

¿Cuál es tu experiencia con Brain.js? ¿Hay algún otro paquete de IA que recomiende? ¡Háznoslo saber en los comentarios!

.

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad