Contenido


Cómo desarrollar soluciones cognitivas de IoT para la detección de anomalías mediante la utilización de aprendizaje profundo, Parte 3

Cómo utilizar Deeplearning4j para la detección de anomalías

Cree una red neural de aprendizaje profundo en Apache Spark con Deeplearning4j

Comments

Contenido de la serie:

Este contenido es la parte # de 5 de la serie: Cómo desarrollar soluciones cognitivas de IoT para la detección de anomalías mediante la utilización de aprendizaje profundo, Parte 3

Manténgase en contacto por contenidos adicionales de esta serie.

Este contenido es parte de la serie:Cómo desarrollar soluciones cognitivas de IoT para la detección de anomalías mediante la utilización de aprendizaje profundo, Parte 3

Manténgase en contacto por contenidos adicionales de esta serie.

En el primer artículo de esta serie, Introducción del aprendizaje profundo y de las redes de memoria de largo y corto plazo, pasé algún tiempo introduciendo los conceptos del aprendizaje profundo y de las redes neurales. También describí un caso de uso de demostración de detección de anomalías para datos de series temporales de IoT. Nuestra tarea es detectar las anomalías en los datos de sensores de vibración (acelerómetro) de un soporte tal como se muestra en Figura 1.

Figura 1. El sensor acelerómetro de un soporte registra las vibraciones de cada uno de los tres ejes geográficos "x", "y" y "z"
Accelerometer sensor on a bearing
Accelerometer sensor on a bearing

Debido a que es difícil portar un sistema de ese tipo, he generado datos de muestra mediante la utilización de un modelo físico Lorenz Attractor porque es capaz de generar un flujo de datos de tres dimensiones. Yo utilicé los datos que se generaron en esta demo para detectar anomalías, llegando a predecir cuando el soporte estaba a punto de romperse.

Tendremos que configurar un poco el entorno de desarrollo, a continuación, muestro una visión general del proceso:

  • Los datos de pruebas se generan en Node-RED y se ejecutan en IBM Cloud (o en un Gateway de IoT como Raspberry Pi para simular un escenario incluso más realista).
  • El Servicio Watson IoT Platform se utiliza como el intermediario de mensajería MQTT (que también se ejecuta en la nube).
  • Eclipse, que está instalado en su escritorio y que ejecuta un sistema de aprendizaje profundo, se suscribe a los datos del intermediario de mensajería MQTT.

¿Cómo vamos a desplegar los datos de prueba de Node-RED en la plataforma IBM Cloud? ¿Qué sistema de aprendizaje profundo vamos a utilizar? Existen varias tecnologías diferentes para implementar un sistema de aprendizaje profundo. Como ya se ha mencionado, estas soluciones de estándares y código abierto se pueden ejecutar en IBM Cloud: Deeplearning4j, ApacheSystemML y TensorFlow (TensorSpark). Este artículo presentará la solución Deeplearning4j.

Qué necesitará para construir su aplicación

  • Una cuenta de Bluemix. (Es posible solicitar una cuenta gratuita aquí, que posteriormente usted puede convertir en una cuenta freemium.)
  • Eclipse (un entorno de desarrollo integrado (IDE) para lenguajes basados en JVM).
  • Eclipse Maven Plugin (herramienta de gestión de dependencias y de construcción automática).
  • Eclipse Scala Plugin (lenguaje de programación).
  • Eclipse GIT Plugin (sistema de control de versiones).

Cómo configurar su entorno de desarrollo

Antes de que hablemos acerca del caso de uso de aprendizaje profundo, pasemos algo de tiempo configurando su entorno de desarrollo.

  1. Instale Eclipse Oxygen. Seleccione el IDE para Desarrolladores de Java.
  2. Instale el Eclipse Maven Plugin.
  3. Instale el Eclipse Scala Plugin tal como se describe para Scala 2.10.
  4. Instale el Eclipse GIT Plugin.
  5. Siga las instrucciones de los documentos de primeros pasos de mi repositorio deeplearning4j GitHub para importar el código fuente para este tutorial.
  6. Finalice la configuración.
    1. Cambie a Scala Perspective. Haga clic derecho en el proyecto dl4j-examples-spark, y después haga clic en Configurar > Añadir Scala Nature.
    2. Vuelva a hacer clic derecho en el proyecto dl4j-examples-spark, y después haga clic en Maven > Actualizar Proyecto.
      Nota: Ignore los errores de Maven. ¡Mientras Run.scala compile sin errores todo estará bien!
    3. Actualice src/resources/ibm_watson_iot_mqtt.properties con las credenciales de IBM Watson IoT Platform. Especifique Organization-ID, Authentication-Method (apikey), API-Key y Authentication-Token. Usted anotó esas credenciales en mi artículo "Cómo generar datos para la detección de anomalías".
  7. Ejecute la aplicación Scala para probar la conexión.
    1. Abra el explorador de paquetes de Eclipse.
    2. En el proyecto dl4j-examples-scala expanda la carpeta src/main/scala .
    3. Encuentre el archivo Run.scala, haga clic derecho en el archivo, y seleccione Ejecutar como > aplicación de Scala.

      Debería ver el siguiente resultado como se muestra en:Figura 2.

      Figura 2. el resultado de la aplicación Scala
      Scala application output
      Scala application output

      Nota: Ignore los avisos de que no se ha encontrado Vfs.Dir. Sólo son avisos y no afectan al comportamiento de la aplicación.

Felicidades, la parte más importante está funcionando. Pare la aplicación haciendo clic en el botón Parar rojo de la parte superior derecha de la ventana como se muestra en Figura 2. Volveremos a ejecutar esta aplicación en una parte posterior del artículo.

¿Qué es Deeplearning4j?

Deeplearning4j es un kit de herramientas basado en Java. Es aprendizaje profundo distribuido y de código abierto y se ejecuta en muchos entornos diferentes, entre ellos Apache Spark. Deeplearning4j no necesita tener instalados componentes adicionales porque es una aplicación de Apache Spark nativa que utiliza las interfaces de Apache Spark.

Los componentes más importantes de la infraestructura para este artículo son:

  • El tiempo de ejecución de Deeplearning4j es el módulo principal. Con este módulo de tiempo de ejecución, usted puede definir y ejecutar todo tipo de redes neurales encima de (pero no directamente en) Apache Spark mediante la utilización de una biblioteca de tensores.
  • ND4J son bibliotecas de computación científicas para JVM. Esta biblioteca de tensores realmente es el corazón de Deeplearning4j. Se puede utilizar de forma autónoma y proporciona álgebra lineal acelerada algebra sobre las CPUs y GPUs. Para transferir el código a una GPU no son necesarios cambios en el código porque una propiedad de JVM configura el motor de ejecución subyacente que también puede ser un backend de CUDA para tarjetas nVidia GPU.

ND4J es una biblioteca de tensores y de álgebra lineal. Esto significa que su principal propósito son las matrices multidimensionales (también llamadas tensores) y las operaciones que se realizan en ellas. Las operaciones son sencillas, pero rápidas. Las ventajas de utilizar ND4J son:

  • Cuando se utiliza Apache Spark, se permanece en el mismo proceso de JVM y no hay que sufrir la sobrecarga de la comunicación entre procesos (IPC).
  • El ND4J es capaz de utilizar conjuntos de instrucciones de SIMD en CPUs modernas, lo que dobla el rendimiento de ND4J en comparación con otra biblioteca de tensores como NumPy. Esto se logra con OpenBLAS, una implementación de código abierto de la API de Basic Linear Algebra Subprograms (BLAS).
  • El ND4J puede aprovechar las GPUs que están presentes en su máquina simplemente estableciendo una propiedad del sistema en el JVM (siempre que en su sistema tenga instalada una versión reciente de los controladores y de la infraestructura CUDA).

¿Cómo saca provecho ND4J de las GPUs? Eche un vistazo a esta sintaxis de Scala para entender cómo funciona.

import org.nd4j.linalg.factory.Nd4j
import org.nd4j.linalg.api.ndarray.INDArray
var v: INDArray = Nd4j.create(Array(Array(1d, 2d, 3d), Array(4d, 5d, 6d)))
var w: INDArray = Nd4j.create(Array(Array(1d, 2d), Array(3d, 4d), Array(5d, 6d)))
print(v.mul(w))

Como puede ver, he creado dos matrices v y w de tipo INDArray utilizando Nd4j.create . He brindado una matriz anidada de Scala del tipo doble, que puedo crear en línea de esta forma:

Array(Array(1d, 2d, 3d), Array(4d, 5d, 6d))

El código v.mul(w) lanza la multiplicación de matrices. De nuevo, en una CPU o GPU. Pero esto es totalmente transparente para nosotros.

Practique la capacitación en una red neural con el operador XOR

Ahora que puede ver lo que ND4J puede hacer, quiero mostrarle cómo se crea una red neural. Antes de que empecemos con los datos de nuestra serie temporal de IoT, empiece con un ejemplo XOR. Primero, genere con Scala algunos datos de capacitación en línea:

/*
* Lista de valores de entrada: 4 muestras de capacitación y cada una tiene datos para 2 neuronas de entrada.
*/
var input: INDArray = Nd4j.zeros(4, 2)
/*
* Lista correspondiente con los valores de salida esperados, 4 muestras de capacitación y cada una
* tiene datos para 2 neuronas de salida.
*/
var labels: INDArray = Nd4j.zeros(4, 2);
/*
* Crea el primer conjunto de datos cuando la primera entrada=0 y la segunda entrada=0.
*/
input.putScalar(Array(0, 0), 0);
input.putScalar(Array(0, 1), 0);
/*
* Después, la primera entrada lanza falso, y la segunda es 0 (ver el comentario de la clase).
*/
labels.putScalar(Array(0, 0), 1);
labels.putScalar(Array(0, 1), 0);
/*
* Cuando la primera entrada=1 y la segunda entrada=0.
*/
input.putScalar(Array(1, 0), 1);
input.putScalar(Array(1, 1), 0);
/*
* Entonces XOR es verdadero, por lo tanto, se lanza la segunda neurona de salida.
*/
labels.putScalar(Array(1, 0), 0);
labels.putScalar(Array(1, 1), 1);
/*
* Igual que antes.
*/
input.putScalar(Array(2, 0), 0);
input.putScalar(Array(2, 1), 1);
labels.putScalar(Array(2, 0), 0);
labels.putScalar(Array(2, 1), 1);
/*
* Cuando se lanzan las dos entradas, XOR vuelve a ser falso. Se debería lanzar el segundo resultado.
*/
input.putScalar(Array(3, 0), 1);
input.putScalar(Array(3, 1), 1);
labels.putScalar(Array(3, 0), 1);
labels.putScalar(Array(3, 1), 0);

Ahora que hemos creado las dos matrices de ND4Js, una llamada input que contiene las funciones, y la otra llamada labels que contiene el resultado esperado. Como recordatorio, vea las entradas y las salidas en Tabla 1.

Tabla 1. entradas y salidas de la tabla de la función XOR
Entrada 1Entrada 2Salida
000
011
101
110

Nota: El resultado sólo es 1 si sólo una entrada es 1.

Ahora vamos a usar los datos que creamos anteriormente para la capacitación de redes neurales.

var ds: DataSet = new DataSet(input, labels)
print(ds)

La matriz DataSet , que no se debe confundir con la de Apache Spark SQL, es una estructura de datos de Deeplearning4j que contiene matrices de ND4J para su capacitación. Esta es la apariencia de la representación matemática interna de esta matriz de ND4J:

===========ENTRADA===================
[[0.00, 0.00],
[1.00, 0.00],
[0.00, 1.00],
[1.00, 1.00]]
===========SALIDA==================
[[1.00, 0.00],
[0.00, 1.00],
[0.00, 1.00],
[1.00, 0.00]]

Esta matriz reflejar la estructura de la tabla de funciones de Tabla 1 XOR con dos diferencias:

  • ND4J utiliza flotante como representación del tipo de datos interno.
  • El resultado está en forma ordinaria, es decir, en una matriz de dos dimensiones. Las matrices de dos dimensiones son muy útiles para capacitar clasificadores binarios con redes neurales en las que tenemos dos neuronas de salida porque la clasificación binaria se realiza utilizando dos neuronas de salida en vez de una. Después de la capacitación, cada neurona de salida envía una probabilidad de ser de una o de otra clase.
1

Cree una red neural de Deeplearning4j para su XOR

Con nuestras entradas y salidas XOR también definiremos y crearemos redes neurales en Deeplearning4j con la clase NeuralNetConfiguration.Builder .

Puede encontrar todo el código del que hablo en las siguientes secciones de la clase XOrExampleScala .

1a

Establezca los parámetros globales

Este código básicamente establece los parámetros globales para la red neural. El examen a fondo de cada uno de esos parámetros está más allá del ámbito de este artículo.

/*
* Establecer la configuración de la red.
*/
var builder: NeuralNetConfiguration.Builder = new NeuralNetConfiguration.Builder();

/*
* ¿Con qué frecuencia se debería ejecutar el conjunto de la capacitación? Necesitamos algo por encima de
* 1000, o una tasa de aprendizaje mayor; he encontrado este valor mediante prueba y error.
*/
builder.iterations(10000);

/*
* Tasas de aprendizaje.
*/
builder.learningRate(0.1);

/*
* Semilla fija para el generador aleatorio. Cualquier ejecución de este programa
* proporciona los mismos resultados. Es posible que no funcione si usted hace algo como ds.shuffle()
*/
builder.seed(123);

/*
* No aplicable ya que esta red es demasiado pequeña, pero para redes mayores podría
* ayudar que la red sea menos propensa a sobreajustar los datos de la capacitación.
*/
builder.useDropConnect(false);

/*
* Un algoritmo estándar para continuar en el plano de errores. Este es el que mejor
* funciona para mí. LINE_GRADIENT_DESCENT y CONJUGATE_GRADIENT también pueden
* realizar el trabajo. es el valor empírico que mejor funciona para su
* problema.
*/
builder.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT);

/*
* Initialice el sesgo con 0; también es un valor empírico.
*/
builder.biasInit(0);

/*
* Desde "http://deeplearning4j.org/architecture": Las redes pueden
* procesar los datos de entrada de forma más rápida y precisa mediante la ingestión
* de mini lotes de 5-10 elementos cada vez en paralelo.
* Este ejemplo se ejecuta mejor sin ello, porque el conjunto de datos es menor que
* el tamaño del minilote.
*/
builder.miniBatch(false);

/*
* Crear una red multicapa de dos capas (incluida la capa de salida, y excluida la capa de entrada)
*/
var listBuilder: ListBuilder = builder.list();
var hiddenLayerBuilder: DenseLayer.Builder = new DenseLayer.Builder();

/*
* Las dos conexiones de entradas simultáneas definen el número de neuronas
* de entrada, porque es la primera capa que no es de entrada.
*/
hiddenLayerBuilder.nIn(2);

/*
* Número de conexiones salientes, nOut define simultáneamente
* el número de neuronas de esta capa.
*/
hiddenLayerBuilder.nOut(4);

/*
* Poner la salida a través de la función sigmoid, para limitar el valor
* de la salida entre 0 y 1.
*/
hiddenLayerBuilder.activation(Activation.SIGMOID);

/*
* Inicializar aleatoriamente ponderaciones con valores entre 0 y 1.
*/
hiddenLayerBuilder.weightInit(WeightInit.DISTRIBUTION);
hiddenLayerBuilder.dist(new UniformDistribution(0, 1));
1b

Establecer las capas de la red neural

Después de establecer los parámetros globales tenemos que añadir capas de redes neurales individuales para formar una red neural profunda. Este código añade dos capas a la red neural, una capa de entrada con dos neuronas (cada una para una columna de la tabla de funciones XOR que se muestra en Tabla 1) y una capa de salida con dos neuronas, una para cada clase (ya que tenemos resultados cero y uno en la tabla de funciones XOR).

Nota: Podemos especificar abundantes parámetros específicos a las capas, pero esto se encuentra más allá del ámbito de este artículo.

/*
* Construir y establecer como capa 0.
*/
listBuilder.layer(0, hiddenLayerBuilder.build());

/*
* MCXENT y NEGATIVELOGLIKELIHOOD (ambos son equivalentes matemáticos) valen para este ejemplo. Esta
* función calcula el valor del error (o 'costo' o 'valor de la función de pérdida'), y cuantifica la bondad * o la maldad de una predicción, de una forma diferenciable.
* Para la clasificación (con clases mutuamente excluyentes, como aquí), utilice la entropía cruzada multiclase, junto con la función
* de activación softmax.
*/
var outputLayerBuilder: Builder = new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD);

/*
* Debe ser la misma cantidad de neuronas que la capa anterior.
*/
outputLayerBuilder.nIn(4);

/*
* Dos neuronas en esta capa.
*/
outputLayerBuilder.nOut(2);
outputLayerBuilder.activation(Activation.SOFTMAX);
outputLayerBuilder.weightInit(WeightInit.DISTRIBUTION);
outputLayerBuilder.dist(new UniformDistribution(0, 1));
listBuilder.layer(1, outputLayerBuilder.build());
1c

Cree la red neural

Usted tiene los parámetros globales y las capas de la red neural, ahora cree la red neural.

/*
* Para esta red no hay fase de pretrain.
*/
listBuilder.pretrain(false);

/*
* Según agibsonccc
* esto parece ser obligatorio: Usted normalmente no usa con
* pretrain(true) cuando quiere realizar una capacitación previa/perfeccionamiento sin cambiar
* las ponderaciones perfeccionadas de las capas anteriores que son para los codificadores automáticos y para las máquinas Boltzmann restringidas (RBMs).
*/
listBuilder.backprop(true);

/*
* Construya e inicialice la red, y verifique si todo está configurado correctamente.
*/
varconf: MultiLayerConfiguration = listBuilder.build();
var net: MultiLayerNetwork = new MultiLayerNetwork(conf);
net.init();
1d

Capacite a la red neural con datos XOR

Ahora, la variable "net" contiene nuestra red neural preparada y la única cosa que tenemos que hacer para entrenarla con nuestra tabla de funciones XOR es utilizar el código siguiente.

net.fit(ds)

Si ahora observamos a la salida (sysout) veremos el mensaje de depuración sobre como avanza el aprendizaje.

08:52:56.714 [main] INFO o.d.o.l.ScoreIterationListener - Score at iteration 400 is 0.6919901371002197
08:52:56.905 [main] INFO o.d.o.l.ScoreIterationListener - Score at iteration 500 is 0.6902942657470703
08:52:57.085 [main] INFO o.d.o.l.ScoreIterationListener - Score at iteration 600 is 0.6845208406448364
....
08:53:11.720 [main] INFO o.d.o.l.ScoreIterationListener - Score at iteration 9700 is 0.0012604787480086088
08:53:11.847 [main] INFO o.d.o.l.ScoreIterationListener - Score at iteration 9800 is 0.0012446331093087792
08:53:11.994 [main] INFO o.d.o.l.ScoreIterationListener - Score at iteration 9900 is 0.001229131012223661

Como puede ver, hay 9900 iteraciones donde la red neural es capacitada (básicamente es el mismo conjunto de datos mostrado varias veces en la red neural) y cada 100 iteraciones se imprime una medida llamada score . A esto se lo denomina RMSE (error cuadrático medio), que es una medida sobre lo bien que en la red neural se ajusta a los datos; cuanto menor sea, mejor. Como puede observar, después de 10000 iteraciones el RMSE se redujo a 0,001229131012223661, lo que en este caso es un valor muy bueno.

1e

Evalúe qué tan buena fue la capacitación

Podemos verificar lo bien que lo estamos haciendo, porque Deeplearning4j tiene incorporado un componente para la evaluación.

/*
* Dejar que Evaluation imprima las estadísticas sobre la frecuencia en que la salida adecuada tenía la etiqueta correcta.
*/
var eval: Evaluation = new Evaluation(2);
eval.eval(ds.getLabels(), output);
println(eval.stats());

El código tiene como resultado las siguientes medidas sobre el rendimiento de la predicción (clasificación):

==========================Scores=========================
Accuracy:1
Precision: 1
Recall: 1
F1 Score: 1
=========================================================

Obtener un uno en todas las medidas significa que tenemos una puntuación del 100% y que hemos construido un clasificador perfecto para calcular el XOR.

2

Cree una red neural de Deeplearning4j para la detección de anomalías

La enseñanza sobre cómo capacitar una red neural utilizando XOR como ejemplo ha sido algo educacional, pero ahora tenemos que construir algo útil en Apache Spark con Deeplearning4j utilizando un conjunto de datos generado. Recuerde que hemos utilizado un modelo Lorenz Attractor para obtener en tiempo real datos simulados del sensor de vibraciones. Y tenemos que enviar esos datos a la plataforma IBM Cloud; para saber los pasos vea mi artículo "Cómo generar datos para la detección de anomalías".

Estoy utilizando Scala no sólo porque sea similar a Java, sino porque también está considerado como un lenguaje de ciencia de datos. Este ejemplo está formado por tres clases de Scala.

  • WatsonIoTConnector es el responsable de suscribir a los datos en tiempo real del intermediario de mensajería MQTT.
  • IoTAnomalyExampleLSTMFFTWatsonIoT contiene la configuración actual de la red neural.
  • Run contiene la unión entre WatsonIoTConnector y IoTAnomalyExampleLSTMFFTWatsonIoT.
2a

Utilice MQTT para suscribirse a IBM Watson IoT Platform para introducir en tiempo real el flujo de datos del sensor de IoT

Primero empiece con WatsonIoTConnector . Aquí sólo le estoy mostrando el código relevante, pero puede descargar todo el código desde mi repositorio de GitHub, dl4j-examples.

Primero, cree un cliente de la aplicación MQTT para suscribirse a un flujo de datos de sensores MQTT.

val props = new Properties()
props.load(getClass.getResourceAsStream("/ibm_watson_iot_mqtt.properties"))
val myClient = new ApplicationClient(props)
myClient.connect

Ahora, puede suscribirse a los denominados elementos del dispositivo. Como probablemente no querremos recibir todo el tráfico, que viene en el bus de mensajes, estamos bastante contentos de que ya esté filtrado. Esta es una forma muy inteligente de desacoplar de las aplicaciones analíticas los sensores que están incorporados a gateways y a dispositivos de IoT, porque ya no tienen que saber nada unos de los otros. Así que, ¿cómo reaccionamos a los datos entrantes? Mediante un manejador de devoluciones de llamada que se establece en la instancia de ApplicationClient myClient.

myClient.setEventCallback(eventbk)

Mire a este manejador de eventos que está definido en la clase Run .

object MyEventCallback extends EventCallback {

Lo primero que tenemos que hacer es crear una variable fifo para almacenar una ventana de eventos de recuento de volteos.

var fifo: Queue[Array[Double]] = new CircularFifoQueue[Array[Double]](windowSize)

Después, implementamos el método processEvent , al que se llama cuando llega un mensaje de la cola MQTT.

override def processEvent(arg0: Event) {

Ahora, convierta el evento a una matriz del tipo doble y añádala al objeto fifo .

val json = arg0.getData().asInstanceOf[JsonObject]
def conv = { v: Object => v.toString.toDouble }
val event: Array[Double] = Array(conv(json.get("x")), conv(json.get("y")), conv(json.get("z")))
fifo.add(event);

Después de que nuestra ventana de recuento de volteos esté llena aplicamos una transformación rápida de Fourier (FFT) para obtener el espectro de frecuencias de las señales y para finalmente transformarlo en un NDArray, que es un tipo de datos interno de Deeplearning4j.

val ixNd = Nd4j.create(fifo.toArray(Array.ofDim[Double](windowSize, 3)));
def xtCol = { (x: INDArray, i: Integer) => x.getColumn(i).dup.data.asDouble }
val fftXYZ = Nd4j.hstack(Nd4j.create(fft(xtCol(ixNd, 0))), Nd4j.create(fft(xtCol(ixNd, 1))), Nd4j.create(fft(xtCol(ixNd, 2))))

Ahora es el momento de instanciar la red neural.

val lstm: IoTAnomalyExampleLSTMFFTWatsonIoT = new IoTAnomalyExampleLSTMFFTWatsonIoT(windowSize * 6)

Después de hacer esto, podemos enviar nuestra ventana del recuento de volteos en sentido descendiente hacia la red neural para detectar anomalías.

Nota: La capacitación y la detección de anomalías se están realizando en el mismo momento porque la red neural aprende continuamente cuál es la apariencia de los datos y cuando ve anomalías lanza un error.

lstm.detect(fftXYZ)
2b

Crea el autocodificador LSTM de la red neural profunda para la detección de anomalías

Pero, ¿cómo se hace esta magia? Echemos un vistazo a la implementación de nuestra red neural en IoTAnomalyExampleLSTMFFTWatsonIoT:

val conf = new NeuralNetConfiguration.Builder()
.seed(12345)
.iterations(1)
.weightInit(WeightInit.XAVIER)
.updater(Updater.ADAGRAD)
.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
.learningRate(learningRate)
.regularization(true)
.l2(0.0001)
.list()

Primero, tenemos que establecer los parámetros globales para la red neural, como por ejemplo la tasa de aprendizaje. Y después es el momento de añadir las capas actuales. Empezaremos con una capa de memoria a corto y largo plazo (LSTM) – la capa es responsable del reconocimiento de patrones temporales en el flujo de datos de nuestro sensor de series temporales de IoT.

.layer(0, new GravesLSTM.Builder().activation(Activation.TANH).nIn(windowSize).nOut(10)
.build())

Para detectar anomalías es crucial que utilicemos un codificador automático, que añadiremos como segunda capa.

.layer(1, new VariationalAutoencoder.Builder()
.activation(Activation.LEAKYRELU)
.encoderLayerSizes(256, 256) 
//2 capas de codificadores, cada una con 256 de tamaño
.decoderLayerSizes(256, 256)
//2 capas de decodificadores, cada una con 256 de tamaño
.pzxActivationFunction(Activation.IDENTITY)
//p(z|datos) función de activación
//Distribución de la reconstrucción de Bernoulli + activación de sigmoid - para modelar datos binarios (o datos que están en el rango entre 0 y 1)
.reconstructionDistribution(new BernoulliReconstructionDistribution(Activation.SIGMOID))
.nIn(10) //Tamaño de la entrada: 28x28
.nOut(10) //Tamaño del espacio de la variable latente: p(z|x) - 32 valores
.build())

Finalmente, concluimos con una capa de salida y habremos acabado.

.layer(2, new RnnOutputLayer.Builder(LossFunctions.LossFunction.MSE)
      .activation(Activation.IDENTITY).nIn(10).nOut(windowSize).build())
2c

Ejecute la red neural en una única máquina local

Lo primero que haremos ahora será echar un vistazo a cuál es la apariencia real de la configuración de nodo único.

val net = new MultiLayerNetwork(conf)

Eso es todo. Sólo utilizamos la configuración y obtenemos un objeto de la red neural sobre el que podemos capacitar. En Deeplearning4j, pasar de un único nodo a Apache Spark es, de hecho, realmente fácil.

val tm = new ParameterAveragingTrainingMaster.Builder(batchSizePerWorker)
.averagingFrequency(5)
.workerPrefetchNumBatches(2)
.batchSizePerWorker(16)
.build();

val net = new SparkDl4jMultiLayer(sc, conf, tm);
2d

Paralelice esta red neural con Apache Spark

Vamos a ignorar por ahoraTrainingMaster y vamos a echar un vistazo a la firma del constructor de SparkDl4jMultiLayer. Ya conocemos al parámetro conf ; esta es la configuración de la red neural. Después, sc quiere decir SparkContext, que lo tenemos disponible cuando utilizamos Apache Spark. Finalmente, vamos a echar un vistazo a TrainingMaster. En la capacitación en paralelo de las redes neurales se utilizan los promedios de los parámetros. Durante la capacitación, los parámetros o las ponderaciones de las redes neurales se actualizan en cada interacción de la capacitación. Debido a que varias redes neurales se capacitan en paralelo en diferentes particiones de datos, los parámetros aprendidos con cada red neural individual se envían al servidor de parámetros y después se promedian y se envían de vuelta.

Vamos a revisar el siguiente código fuente para ver pocas diferencias que existen en el código de origen para cambiar de ejecución local a en paralelo encima de Apache Spark.

if (runLocal) {
    net = new MultiLayerNetwork(conf)
    net.setListeners(Collections.singletonList(new ScoreIterationListener(1).asInstanceOf[IterationListener]))
  } else {
    val tm = new ParameterAveragingTrainingMaster.Builder(20)
      .averagingFrequency(5)
      .workerPrefetchNumBatches(2)
      .batchSizePerWorker(16)
      .build();

    val sparkConf = new SparkConf()

    sparkConf.setAppName("DL4J Spark Example");
    sc = new JavaSparkContext(sparkConf);
    sparkNet = new SparkDl4jMultiLayer(sc, conf, tm);
  }

Si runLocal es falso, se instancia un ParameterAveragingTrainingMaster ; que se ejecuta en el maestro de Apache Spark y es responsable por la capacitación en paralelo de las redes neuronales. Después, se crea sparkNet con SparkContext, la configuración actual de la red neural conf y la instancia de Training Master que acabamos de crear, todo, utilizando el constructor SparkDl4jMultiLayer's. Si quiere saber más detalles sobre cómo funciona Parameter Averaging, eche un vistazo a la explicación del paralelismo de datos de mi video, "Estrategias para la Paralelización de Redes Neurales de Aprendizaje Profundo" (que está en el punto 8:19 de este video de 32:11 min).

2e

Cierre del bucle

Así que, finalmente vamos a cerrar el bucle mostrándole la implementación del método detect al que se llama directamente desde el manejador de devolución de llamadas de MQTT después de que la ventana de recuento de volteos esté completa.

def detect(xyz: INDArray): Double = {
 for (a <- 1 to 1000) {
   net.fit(xyz, xyz)
 }
 return net.score(new DataSet(xyz, xyz))
}

Esto no hace más que mostrar varias veces los mismos datos a la red neural. De hecho, funciona mejor tener una tasa de aprendizaje menor y capacitar repetidamente a una red neural con el mismo conjunto de datos. Aquí estamos mostrando a la red neural 1000 veces el mismo conjunto de datos.

3

Inicie la red neural local y vea cómo reacciona a los datos recibidos

De hecho, vamos a iniciar el proceso y a ver lo que ocurre. Realizaremos dos rondas de entrenamiento con datos sanos y después cambiaremos el estado del generador de datos a "roto". Veremos una considerable diferencia en los denominados errores de reconstrucción que experimenta la red neural cuando de repente vea datos desconocidos después de un tiempo de capacitarse con datos normales.

Primero, vuelva a ejecutar la clase Run.scala tal como se describe en la sección Cómo configurar su entorno de desarrollo . Debería ver un resultado similar a Figura 3.

Figura 3. resultado de la aplicación Scala

Este resultado significa que la red neural se ha instanciado localmente y que estamos esperando a que los datos lleguen en tiempo real desde el intermediario de mensajería de IBM Watson IoT Platform MQTT.

Después, vuelva a la ventana del navegador de su distancia de Node-RED donde se esta ejecutando el generador de datos de prueba. Inicie el generador de datos de prueba haciendo clic en el botón Restablecer para producir algunos datos.

Nota: Aunque el modelo Lorenz Attractor genera datos continuamente (como lo haría un sensor acelerómetro real que estuviese acoplado a un soporte), sólo cuando pulsemos el botón Restablecer publicará otros 30 segundos de datos hacia el intermediario de mensajería MQTT de IBM Watson IoT Platform; esto evitará la caída de nuestra red neural que se ejecuta localmente.

En el panel de depuración de Node-RED es posible observar cómo se transmiten los datos al intermediario de mensajería, porque el flujo contiene nodos que se suscriben y depuran los mismos flujos de datos, como se muestra en Figura 4.

Figura 4. el flujo de Node-RED que muestra los nodos para suscribirse al flujos de datos
Node-RED debug pane
Node-RED debug pane

Por último, vuelva al Eclipse donde se está ejecutando nuestra red neural. En la consola de Figura 5 ver a algunos mensajes de depuración que muestran que los datos están llegando. Estamos esperando que la ventana de volteo basada en recuentos se rellene para que contenga 30 segundos de datos. Enviaremos cada ventana de volteo a la red neural.

Figura 5. La pestaña de depuración del flujo de Node-RED que muestra que los datos están llegando
Eclipse console debug tab

Figura 6 muestra el resultado de la red neural durante la capacitación después de que haya recibido la primera ventana de volteo para su procesamiento. Imprime la integración de la capacitación real y el error de reconstrucción actual. Es importante que después de algún tiempo el número converja hacia un mínimo local y, también, que haya una disminución considerable en el error de reconstrucción.

Figura 6. Resultado de la red neural durante la capacitación
Neural                 network output
Neural network output

En Figura 7 hemos empezado una iteración 0 con un error de reconstrucción inicial de 392314,67211754626. Esto se debe a la inicialización aleatoria de los parámetros de ponderación de la red neural.

Figura 7. Salida de la capacitación de la red neural con entre 0 y 30 iteraciones de datos sanos
Healthy data iterations 0 to                 30
Healthy data iterations 0 to 30

Nota: Cada vez que ejecutemos este ejemplo obtendremos números ligeramente diferentes.

En Figura 8 acabamos con un error de reconstrucción de 372,6741075529085 en la iteración 999, lo que es bastante inferior que 392314,67211754626 de la iteración 0.

Figura 8. Salida de la capacitación de la red neural con entre 969 y 999 iteraciones de datos sanos
Healthy data iterations 969                 to 999
Healthy data iterations 969 to 999

En Figura 9, después de una segunda ronda de capacitación - y después de procesar la segunda ventana del recuento de volteos - acabamos con un error de reconstrucción de 77,8737141122287 en la iteración 1999.

Nota: Puede ver que la puntuación de la integración 1999 es superior al de la iteración 1969. Esto se debe a las oscilaciones, pero no significa que sea un problema a no ser que esté convergiendo hacia algún valor bajo.

Figura 9. Salida de la capacitación de la red neural con entre 1969 y 1999 iteraciones de datos sanos
Healthy data iterations 1969                 to 1999
Healthy data iterations 1969 to 1999

Como puede ver en Figura 10, ahora hemos alimentado a la red neural con datos anómalos y claramente podemos ver que el error de reconstrucción 11091,125671441947 de la iteración 2999 es considerablemente superior que el de Figura 8 y Figura 9.

Figura 10. Salida de la capacitación de la red neural con entre 969 y 999 iteraciones de datos sanos
Healthy data iterations 969                 to 999
Healthy data iterations 969 to 999

Nota: He demostrado este completo escenario en la conferencia HadoopSummit 17, que usted puede ver en este video (La demo empieza en el punto 25:06 de este video de 34:47 min).

Conclusión

Esto completa nuestro primer tutorial de aprendizaje profundo para datos de series temporales de IoT. Cómo se ha visto, es fácil definir y ejecutar una red neural profunda en DeepLearning4J. La infraestructura DeepLearning4j se ocupa de todas las matemáticas complejas que están implicadas en la capacitación en paralelo de redes neurales. Cuando se ejecuta en Apache Spark hace que sea un candidato ideal para construir soluciones de IoT cognitivas altamente escalables en entornos de nubes de Apache Spark como la plataforma IBM Cloud Data Science Experience, que tiene incorporado su Apache Spark escalable de forma elástica “como una oferta de Servicio”. Además, usted no se ata a un proveedor de nubes específico e incluso puede ejecutar este sistema en nuestra propia nube privada o en un centro de datos tradicional.

En los próximos dos artículos trabajaremos con los mismos datos de prueba que hemos generado, pero con dos infraestructuras de aprendizaje profundo diferentes: ApacheSystemML y TensorFlow (TensorSpark).


Recursos para Descargar


Temas relacionados


Comentarios

Inicie Sesión o Regístrese para agregar comentarios.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Internet of Things, Cognitive computing, Big data y analytics
ArticleID=1057963
ArticleTitle=Cómo desarrollar soluciones cognitivas de IoT para la detección de anomalías mediante la utilización de aprendizaje profundo, Parte 3: Cómo utilizar Deeplearning4j para la detección de anomalías
publish-date=02082018