Conteúdo


Desenvolvendo soluções de IoT cognitivas para detecção de anomalias usando deep learning, Parte 3

Usando o Deeplearning4j para detecção de anomalia

Crie uma rede neural de deep learning no Apache Spark com Deeplearning4j

Comments

Conteúdos da série:

Esse conteúdo é a parte # de 5 na série: Desenvolvendo soluções de IoT cognitivas para detecção de anomalias usando deep learning, Parte 3

Fique ligado em conteúdos adicionais dessa série.

Esse conteúdo é parte da série:Desenvolvendo soluções de IoT cognitivas para detecção de anomalias usando deep learning, Parte 3

Fique ligado em conteúdos adicionais dessa série.

No primeiro artigo desta série, Apresentando deep learning e redes de memória de curto e longo prazo, eu dediquei um tempo para apresentar os conceitos sobre deep learning e redes neurais. Eu também descrevi um caso de uso demonstrativo sobre detecção de anomalia para dados de série temporal de IoT. Nossa tarefa é detectar anomalias nos dados do sensor de vibração (acelerômetro) em um rolamento, como é mostrado em Figura 1.

Figura 1. O sensor do acelerômetro em um rolamento registra as vibrações em cada um dos três eixos geométricos x, y e z
Accelerometer sensor on a bearing
Accelerometer sensor on a bearing

Como é improvável que você tenha um sistema desses, eu gerei dados de teste usando um modelo físico Lorenz Attractor, que é capaz de gerar um fluxo de dados tridimensional. Eu usei os dados gerados nesta demo para detectar anomalias, prevendo quando um rolamento está prestes a quebrar.

Vamos precisar realizar uma pequena configuração do ambiente de desenvolvimento, mas segue uma visão geral do processo:

  • Os dados de teste são gerados em Node-RED e executados na IBM Cloud (ou, como alternativa, em um gateway de IoT, como o Raspberry Pi, para simular um cenário ainda mais real).
  • O serviço Watson IoT Platform é usado como o message broker MQTT (também executado na nuvem).
  • O Eclipse, instalado no desktop e executando um sistema de deep learning, assina os dados do message broker MQTT.

Como vamos implementar os dados de teste do Node-RED na plataforma da IBM Cloud? Qual sistema de deep learning vamos usar? Existem várias tecnologias diferentes para implementar um sistema de deep learning. Como mencionado, estas soluções de software livre e padrão aberto podem ser executadas na IBM Cloud: Deeplearning4j, ApacheSystemML e TensorFlow (TensorSpark). Este artigo apresentará a solução Deeplearning4j.

O que será necessário para criar o aplicativo

  • Uma conta do Bluemix. (É possível solicitar uma avaliação grátis aqui, que poderá ser convertida em uma conta freemium posteriormente).
  • Eclipse (um ambiente de desenvolvimento integrado (IDE) para linguagens baseadas em JVM).
  • O plug-in Maven do Eclipse (ferramenta de construção automatizada e de gerenciamento de dependência).
  • O plug-in Scala do Eclipse (linguagem de programação).
  • O plug-in GIT do Eclipse (sistema de controle de versão).

Configurando o ambiente de desenvolvimento

Antes de falar sobre o caso de uso de deep learning, vamos realizar a configuração do ambiente de desenvolvimento.

  1. Instalar Eclipse Oxygen. Selecione o IDE para desenvolvedores Java.
  2. Instale os plug-in Mavem do Eclipse.
  3. Instale os plug-in Scala do Eclipse, conforme a descrição do Scala 2.10.
  4. Instale os plug-in GIT do Eclipse.
  5. Siga as instruções nos documentos de introdução em meu repositório deeplearning4j do GitHub para importar o código-fonte para este tutorial.
  6. Finalize a instalação.
    1. Mude para Scala Perspective. Clique com o botão direito do mouse no projeto dl4j-examples-spark e, em seguida, clique em Configurar > Incluir Scala Nature.
    2. Clique com o botão direito do mouse no projeto dl4j-examples-spark novamente e, em seguida, clique em Maven > Atualizar projeto.
      Observação: Ignore os erros do Maven. Se o Run.scala for compilado sem erros, estará tudo certo!
    3. Atualize o src/resources/ibm_watson_iot_mqtt.properties com as credenciais do IBM Watson IoT Platform. Especifique Organization-ID, Authentication-Method (apikey), API-Key e Authentication-Token. Você anotou essas credenciais em meu artigo "Geração de dados para detecção de anomalias".
  7. Execute o aplicativo Scala para testar a conexão.
    1. Abra o pacote Explorer do Eclipse.
    2. No projeto dl4j-examples-scala, expanda osrc/main/scala .
    3. Localize o arquivo Run.scala, clique com o botão direito do mouse no arquivo e selecione Executar como > Aplicativo Scala.

      A seguinte saída deverá ser exibida como é mostrada em Figura 2.

      Figura 2. Saída do aplicativo Scala
      Scala application output
      Scala application output

      Observação: Ignore os avisos de que o Vfs.Dir não foi localizado. São apenas avisos e não afetam o comportamento do aplicativo.

Parabéns, a parte mais importante está funcionando. Pare o aplicativo clicando no botão vermelho Parar no canto superior direito da janela, como é mostrado em Figura 2. Vamos executar esse aplicativo novamente durante um estágio posterior neste artigo.

O que é o Deeplearning4j?

Deeplearning4j é um kit de ferramentas baseado em Java. Ele é um software livre de deep learning distribuído que pode ser executado em diversos ambientes diferentes, incluindo o Apache Spark. O Deeplearning4j não exige que componentes adicionais sejam instalados porque ele é um aplicativo nativo do Apache Spark que usa as interfaces que o Apache Spark fornece.

Os componentes mais importantes da estrutura para este artigo são:

  • Tempo de execução do Deeplearning4j, que é o módulo principal. Com esse módulo de tempo de execução, é possível definir e executar todos os tipos de redes neurais com base no Apache Spark (mas não diretamente nele) usando uma biblioteca de tensores.
  • ND4J é uma biblioteca de computação científica para a JVM. Essa biblioteca de tensores é realmente o núcleo do Deeplearning4j. Ela pode ser usada de forma independente e fornece álgebra linear com base em CPUs e GPUs. Para portar o código para uma GPU, não é necessário realizar mudanças no código porque uma propriedade JVM configura o mecanismo de execução subjacente que também pode ser um backend CUDA para placas GPU nVidia.

A ND4J é uma biblioteca de tensores e de álgebra linear. Isso significa que as arrays multidimensionais (também chamadas de tensores) e as operações que ocorrem nelas são o propósito principal. As operações são simples, mas rápidas. As vantagens de usar a ND4J são:

  • Ao usar o Apache Spark, você permanece no mesmo processo da JVM e não precisa arcar com o gasto adicional da comunicação interprocessual (IPC).
  • A ND4J é capaz de usar conjuntos de instruções SIMD em CPUs modernas, o que dobra o desempenho da ND4J em relação a outras bibliotecas de tensores, como a NumPy. Isso é realizado usando o OpenBLAS, uma implementação de software livre da API Basic Linear Algebra Subprograms (BLAS).
  • A ND4J pode aproveitar as GPUs presentes em seu computador bastando apenas configurar uma propriedade do sistema na JVM (desde que haja uma versão recente das unidades e da estrutura CUDA instaladas no sistema).

Como a ND4J pode aproveitar as GPUs? Observe essa sintaxe do Scala para entender como isso 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 você pode ver, eu criei duas arrays v e o w do tipo INDArray usando Nd4j.create . Eu forneci uma array Scala aninhada do tipo double, que criei sequencialmente desta forma:

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

O código v.mul(w) aciona a multiplicação da array. Novamente, seja em uma CPU ou em uma GPU. Mas isso é totalmente transparente para nós.

Prática de treinamento de uma rede neural usando a operação XOR

Agora que você já sabe o que a ND4J pode fazer, eu quero mostrar como criar uma rede neural. Antes de começar com os dados da série temporal de IoT, comece com um exemplo de XOR. Primeiro, usando o Scala, gere alguns dados de treinamento sequenciais:

/*
* Lista de valores de entrada: quatro amostras de treinamento
com dados para dois neurônios de entrada cada.
*/
var input: INDArray = Nd4j.zeros(4, 2)
/*
* Lista correspondente com os valores de saída
esperados, quatro amostras de treinamento com * dados para dois
neurônios de saída cada.
*/
var labels: INDArray = Nd4j.zeros(4, 2);
/*
* Crie o primeiro conjunto de dados quando a primeira entrada
for igual a 0 e a segunda entrada for igual a 0.
*/
input.putScalar(Array(0, 0), 0);
input.putScalar(Array(0, 1), 0);
/*
* Em seguida, a primeira saída dispara como false e a segunda é
0 (veja o comentário da classe).
*/
labels.putScalar(Array(0, 0), 1);
labels.putScalar(Array(0, 1), 0);
/*
* Quando a primeira entrada
for igual a 1 e a segunda entrada for igual a 0.
*/
input.putScalar(Array(1, 0), 1);
input.putScalar(Array(1, 1), 0);
/*
* Em seguida, o XOR é true, portanto, o segundo
neurônio de saída é disparado.
*/
labels.putScalar(Array(1, 0), 0);
labels.putScalar(Array(1, 1), 1);
/*
* O mesmo que acima.
*/
input.putScalar(Array(2, 0), 0);
input.putScalar(Array(2, 1), 1);
labels.putScalar(Array(2, 0), 0);
labels.putScalar(Array(2, 1), 1);
/*
* Quando as duas entradas forem disparadas, o XOR será false
novamente. A primeira saída deverá ser disparada.
*/
input.putScalar(Array(3, 0), 1);
input.putScalar(Array(3, 1), 1);
labels.putScalar(Array(3, 0), 1);
labels.putScalar(Array(3, 1), 0);

Agora que você já criou duas arrays da ND4J, uma chamada input contendo os recursos e uma chamada labels contendo o resultado esperado. Apenas como lembrete, veja as entradas e saídas em Tablela 1.

Tablela 1. Entradas e saídas da tabela de funções XOR
Entrada 1Entrada 2Saída
000
011
101
110

Observação: A saída será somente 1 se somente uma entrada for 1.

Agora, vamos usar os dados que criei acima para o treinamento de rede neural.

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

A array DataSet, que não deve ser confundida com aquela do Apache Spark SQL, é uma estrutura de dados do Deeplearning4j que contém as arrays da ND4J para o treinamento. Aqui está um exemplo da representação matemática interna dessa array da ND4J:

===========INPUT===================
[[0.00, 0.00],
[1.00, 0.00],
[0.00, 1.00],
[1.00, 1.00]]
===========OUTPUT==================
[[1.00, 0.00],
[0.00, 1.00],
[0.00, 1.00],
[1.00, 0.00]]

Essa array reflete a estrutura da Tablela 1 tabela de funções XOR com duas diferenças:

  • A ND4J usa a flutuação como a representação do tipo de dados internos.
  • A saída está no formato binário, ou seja, uma array bidimensional. As arrays bidimensionais são muito práticas para treinar classificadores binários com redes neurais que têm dois neurônios de saída porque a classificação binária é realizada usando dois neurônios de saída em vez de um. Após o treinamento, cada neurônio de saída gera uma probabilidade de ser uma classe ou a outra.
1

Crie uma rede neural do Deeplearning4j para XOR

Ainda usando nossas entradas e saídas XOR, vamos definir e criar redes neurais no Deeplearning4j com o NeuralNetConfiguration.Builder .

É possível encontrar todos os códigos discutidos nas seções a seguir no XOrExampleScala .

1a

Configure os parâmetros globais

Basicamente, esse código configura os parâmetros globais para rede neural. O aprofundamento sobre cada um desses parâmetros não faz parte do escopo deste artigo.

/* * Defina a configuração da rede.
*/
var builder: NeuralNetConfiguration.Builder = new NeuralNetConfiguration.Builder();

/*
* Com que frequência o conjunto de treinamento deve ser
executado? Precisamos de uma taxa de aprendizado de
* 1000 ou superior. Eu descobri esse valor apenas por tentativa
e erro.
*/
builder.iterations(10000);

/*
* Taxa de aprendizagem.
*/
builder.learningRate(0.1);

/*
* Valor inicial fixo para o gerador aleatório. Todas as
execuções deste programa
* fornecem os mesmos resultados. Poderá não funcionar se
você executar algo como ds.shuffle()
*/
builder.seed(123);

/*
* Não se aplica porque essa rede é muito pequena, mas para
redes maiores
* pode ajudar que a rede seja menos propensa a uma
superadequação aos dados de treinamento.
*/
builder.useDropConnect(false);

/*
* Um algoritmo padrão para avançar o plano de erro. Este
funciona melhor
* para mim. LINE_GRADIENT_DESCENT ou CONJUGATE_GRADIENT também
* podem executar essa tarefa. É um valor empírico e um deles corresponde * ao seu problema.
*/
builder.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT);

/*
* Inicialize a propensão com 0; o valor empírico também.
*/
builder.biasInit(0);

/*
* De "http://deeplearning4j.org/architecture": as redes
podem * processar a entrada com mais rapidez e precisão *
ingerindo minilotes de 5 a 10 elementos de cada vez em
paralelo.
* Este exemplo é mais bem executado sem, porque o conjunto
de dados é menor que * o tamanho do minilote.
*/
builder.miniBatch(false);

/*
* Crie uma rede de várias camadas com duas delas (incluindo a
camada de saída, excluindo a camada de entrada)
*/
var listBuilder: ListBuilder = builder.list();
var hiddenLayerBuilder: DenseLayer.Builder = new DenseLayer.Builder();

/*
* Duas conexões de entrada definem simultaneamente o número de *
neurônios de entrada, porque se trata da primeira camada que
não é de entrada.
*/
hiddenLayerBuilder.nIn(2);

/*
* Número de conexões de saída, nOut define simultaneamente o *
número de neurônios nesta camada.
*/
hiddenLayerBuilder.nOut(4);

/*
* Coloque a saída na função sigmoide, para limitar o valor de *
saída entre 0 e 1.
*/
hiddenLayerBuilder.activation(Activation.SIGMOID);

/*
* Inicialize ponderações aleatoriamente com valores entre 0 e 1.
*/
hiddenLayerBuilder.weightInit(WeightInit.DISTRIBUTION);
hiddenLayerBuilder.dist(new UniformDistribution(0, 1));
1b

Configure as camadas da rede neural

Depois de configurar os parâmetros globais, será necessário incluir camadas individuais da rede neural para formar uma rede neural profunda. Este código inclui duas camadas na rede neural, uma camada de entrada com dois neurônios (cada um para uma coluna da tabela de funções XOR mostrada em Tablela 1) e em uma camada de saída com dois neurônios, um para cada classe (como temos o resultado zero e um na tabela de funções XOR).

Observação: é possível especificar inúmeros parâmetros específicos da camada, mas isso não faz parte do escopo deste artigo.

/*
* Desenvolver e configurar como camada 0.
*/
listBuilder.layer(0, hiddenLayerBuilder.build());

/*
* MCXENT ou NEGATIVELOGLIKELIHOOD (ambos são equivalentes
matematicamente) funciona para este exemplo. Esta
* função calcula o valor de erro (ou o "custo" ou o "valor
da função de perda") e quantifica o grau de precisão * de uma previsão, de uma maneira diferente.
* Para classificação (com classes mutuamente exclusivas, como
aqui), use entropia cruzada multiclasse, em conjunto * com a
função de ativação softmax.
*/
var outputLayerBuilder: Builder = new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD);

/*
* Deve ser a mesma quantidade de neurônios que na camada anterior.
*/
outputLayerBuilder.nIn(4);

/*
* Dois neurônios nesta camada.
*/
outputLayerBuilder.nOut(2);
outputLayerBuilder.activation(Activation.SOFTMAX);
outputLayerBuilder.weightInit(WeightInit.DISTRIBUTION);
outputLayerBuilder.dist(new UniformDistribution(0, 1));
listBuilder.layer(1, outputLayerBuilder.build());
1c

Crie a rede neural

Você já tem os parâmetros globais e as camadas da rede neural, agora, falta criar a rede neural.

/*
* Não há uma fase de pré-treinamento para esta rede.
*/
listBuilder.pretrain(false);

/*
* Parece ser obrigatório
* de acordo com o agibsonccc: geralmente isso apenas é
usado com * pretrain(true) quando se deseja executar
pré-treinamento ou ajuste preciso sem alterar
* os pesos ajustados precisamente das camadas anteriores.
Isso é indicado para codificadores automáticos e Mecanismos
Boltzmann Restritos (RBMs).
*/
listBuilder.backprop(true);

/*
* Crie e inicialize a rede e verifique se tudo está
configurado corretamente.
*/
varconf: MultiLayerConfiguration = listBuilder.build();
var net: MultiLayerNetwork = new MultiLayerNetwork(conf);
net.init();
1d

Treine a rede neural com dados XOR

Agora a variável da rede contém a nossa rede neural pronta para uso e basta apenas treiná-la com a tabela de funções XOR no código a seguir.

net.fit(ds)

Se observarmos a saída agora (sysout) veremos uma mensagem de depuração sobre como está o progresso do aprendizado.

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 você pode observar, há 9900 iterações em que a rede neural é treinada (basicamente, o mesmo conjunto de dados é mostrado para a rede neural várias vezes) e a cada 100 iterações, uma medida chamada score é impressa. Esse é o chamado RMSE (erro de valor quadrático médio), uma medida da adequação da rede neural aos dados, quanto menor melhor. Como você pode observar, após 10000 iterações, o RMSE decaiu para 0,001229131012223661, que é um valor muito bom nesse caso.

1e

Avalie o grau de desempenho do treinamento

É possível verificar nosso grau de desempenho, porque o Deeplearning4j tem um componente integrado para avaliação.

/* * Permita que a Avaliação imprima estatísticas sobre a
frequência em que a saída certa tem o rótulo correto.
*/
var eval: Evaluation = new Evaluation(2);
eval.eval(ds.getLabels(), output);
println(eval.stats());

O código gera as seguintes medidas de desempenho de previsão (classificação):

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

Obter um para todas as medidas significa que a pontuação foi de 100% e que criamos um classificador perfeito para calcular o XOR.

2

Crie uma rede neural do Deeplearning4j para detecção de anomalia

Aprender como treinar uma rede neural usando XOR como exemplo foi educativo, mas agora precisamos desenvolver algo mais útil no Apache Spark com o Deeplearning4j usando um conjunto de dados gerado. Lembre-se que usamos um modelo do Lorenz Attractor para obter dados do sensor de vibração simulado em tempo real. E precisamos colocar esses dados na plataforma da IBM Cloud, consulte meu artigo "Geração de dados para detecção de anomalias" para obter essas etapas.

Estou usando o Scala porque além de ser semelhante ao Java, ele é considerado uma linguagem de ciência de dados. Esse exemplo consiste em três classes do Scala.

  • O WatsonIoTConnector é responsável por assinar dados em tempo real do message broker MQTT.
  • IoTAnomalyExampleLSTMFFTWatsonIoT contém a configuração real da rede neural.
  • Executar contém uma vinculação entre o WatsonIoTConnector e na IoTAnomalyExampleLSTMFFTWatsonIoT.
2a

Assine o IBM Watson IoT Platform com o MQTT para ingerir o fluxo de dados do sensor de IoT em tempo real

Comece com o WatsonIoTConnector primeiro. Estou mostrando apenas os códigos relevantes aqui, mas é possível fazer o download do código completo em meu repositório do GitHub, dl4j-examples.

Primeiro, crie um aplicativo cliente do MQTT para adquirir um fluxo de dados de sensor do MQTT.

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

Agora é possível assinar os chamados eventos de dispositivo. Como obviamente nós não queremos receber todo o tráfego que percorre o barramento de mensagem, é interessante já filtrá-lo. Essa é uma maneira inteligente de desacoplar sensores anexados a dispositivos e gateways de IoT dos aplicativos reais de analytics, porque eles não precisam mais trocar informações entre si. Então, como reagir aos dados recebidos? Com um manipulador de retorno de chamada que é configurado na instância do ApplicationClient myClient.

myClient.setEventCallback(eventbk)

Veja esse manipulador de eventos definido no Executar .

object MyEventCallback extends EventCallback {

A primeira coisa a fazer é criar uma variável fifo para armazenar uma janela rolante de contagem de eventos.

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

Em seguida, implementamos o método processEvent, que é chamado sempre que uma mensagem chega da fila do MQTT.

override def processEvent(arg0: Event) {

Agora, converta o evento em uma array do tipo double e inclua-a no 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);

Depois que a janela rolante de contagem for preenchida, vamos aplicar a fast Fourier transformation (FFT) para obter o espectro de frequência dos sinais e, finalmente, transformá-lo em um NDArray, um tipo de dados interno do 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))))

Este é o momento de instanciar a rede neural.

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

Depois que isso for feito, será possível realmente enviar a janela rolante de contagem para que a rede neural detecte anomalias.

Observação: o treinamento e a detecção de anomalias ocorrem simultaneamente porque a rede neural aprende continuamente como são os dados normais e, quando identifica anomalias, gera um erro.

lstm.detect(fftXYZ)
2b

Crie o codificador automático LSTM da rede neural profunda para detecção de anomalia

Mas como essa mágica acontece? Vamos observar a implementação da nossa rede neural em 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()

Primeiro definimos parâmetros globais para a rede neural, como a taxa de aprendizado, por exemplo. E, então, chegou o momento de incluir as camadas reais. Vamos começar com uma camada de memória de longo e curto prazo (LSTM) – a camada responsável por reconhecer padrões temporais no fluxo de dados do sensor de série temporal de IoT.

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

Para detectar anomalias, é fundamental usar um codificador automático, que vamos incluir como a segunda camada.

.layer(1, new VariationalAutoencoder.Builder()
.activation(Activation.LEAKYRELU)
.encoderLayerSizes(256, 256) 
//2 camadas de decodificador, cada uma do tamanho 256 .decoderLayerSizes(256, 256)
//2 camadas de decodificador, cada uma do tamanho 256
.pzxActivationFunction(Activation.IDENTITY)
//função de ativação p(z|data)
//Distribuição de reconstrução de Bernoulli + ativação de
sigmoide - para modelar dados binários (ou dados no intervalo de
0 a 1)
.reconstructionDistribution(new BernoulliReconstructionDistribution(Activation.SIGMOID))
.nIn(10) //Tamanho de entrada: 28 x 28
.nOut(10) //Tamanho do espaço variável latente: p(z|x) - 32
valores
.build())

Finalmente, vamos concluir com uma camada de saída e, assim, estará tudo pronto.

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

Execute a rede neural em uma única máquina local

Agora, vamos primeiro analisar como realmente é uma configuração de nó único.

val net = new MultiLayerNetwork(conf)

Isso é tudo. Basta usar a configuração e obter um objeto de rede neural no qual é possível treinar. Passar de um único nó para o Apache Spark é realmente muito fácil no Deeplearning4j.

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

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

Paralelize essa rede neural usando o Apache Spark

Vamos pular o TrainingMaster por enquanto e observar a assinatura do construtor de SparkDl4jMultiLayer. O parâmetro conf nós já conhecemos. Esta é a configuração da rede neural. Em seguida, sc significa SparkContext, que temos disponível ao usar o Apache Spark. Finalmente, vamos verificar o TrainingMaster. O treinamento paralelo de redes neurais ocorre usando média de parâmetro. Durante o treinamento, os parâmetros da rede neural, ou pesos, são atualizados em cada iteração do treinamento. Como várias redes neurais são treinadas em paralelo em diferentes partições de dados, os parâmetros aprendidos de cada rede neural individual são enviados ao servidor de parâmetros onde eles passam por um cálculo de média e são enviados de volta.

Vamos analisar o código-fonte a seguir para observar as diferenças mínimas nele, para mudar de execução local para paralela com base no Apache Spark.

se (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);
  }

If runLocal for false, um ParameterAveragingTrainingMaster será instanciado, executando no Apache Spark principal, ele é responsável pelo treinamento de rede neural paralela. Em seguida, o sparkNet é criado usando SparkContext, a configuração da rede neural real conf e a instância de treinamento principal que acabamos de criar, tudo usando o construtor do SparkDl4jMultiLayer. Se você desejar saber mais sobre como o cálculo de média de parâmetro funciona em detalhes, consulte a explicação sobre paralelismo de dados em meu vídeo, "Estratégias de paralelização de redes neurais de deep learning" (que está no ponto 8:19 neste vídeo de 32:11 minutos).

2e

Feche o loop

Vamos finalmente fechar o loop mostrando a implementação do método detect que é chamado diretamente do manipulador de retorno de chamada do MQTT quando a janela rolante de contagem estiver cheia.

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

Isso não faz nada além de mostrar os mesmos dados várias vezes para a rede neural. Na verdade, é melhor ter uma taxa de aprendizado menor e treinar repetidamente uma rede neural com o mesmo conjunto de dados. Aqui estamos mostrando à rede neural o mesmo conjunto de dados 1000 vezes.

3

Inicie a rede neural local e veja como ela reage aos dados recebidos

Vamos realmente iniciar o processo e ver o que acontece. Vamos realizar duas rodadas de treinamento com dados íntegros e, em seguida, finalmente mudar o gerador de dados de teste para um estado corrompido. Vamos ver uma diferença significativa no chamado erro de reconstrução que ocorre na rede neural quando de repente aparecem dados desconhecidos depois de um tempo de treinamento com dados normais.

Primeiro, execute a classe Run.scala novamente, como é descrito em Configurando o ambiente de desenvolvimento . Deverá aparecer uma saída semelhante à Figura 3.

Figura 3. Saída do aplicativo Scala

Essa saída significa que a rede neural foi instanciada localmente e estamos esperando que esses dados cheguem em tempo real do message broker MQTT do IBM Watson IoT Platform.

Em seguida, retorne à janela do navegador da instância do Node-RED na qual o gerador de dados de teste está sendo executado. Inicie o gerador de dados de teste clicando no botão Reconfigurar para produzir alguns dados.

Observação: Embora o modelo Lorenz Attractor gere dados continuamente (como um sensor de acelerômetro real conectado a um rolamento), é somente quando pressionamos o botão Reconfigurar que ele publicará outros 30 segundos de dados para o message broker MQTT do IBM Watson IoT Platform. Isso evita que a rede neural de execução local seja invalidada.

É possível observar na área de janela de depuração do Node-RED como os dados são transmitidos para o message broker, porque o fluxo contém nós que assinam e depuram o mesmo fluxo de dados que é mostrado no Figura 4.

Figura 4. fluxo do Node-RED que mostra os nós para assinar o fluxo de dados
Node-RED debug pane
Node-RED debug pane

Por último, retorne ao Eclipse, onde a rede neural está sendo executada. No console em Figura 5 são exibidas algumas mensagens de depuração que estão chegando. Estamos esperando que uma janela rolante baseada em contagem seja preenchida para que contenha 30 segundos de dados. Vamos enviar cada uma das janelas rolantes à rede neural.

Figura 5. A guia de depuração de fluxo do Node-RED que mostra os dados que estão chegando
Eclipse console debug tab

Figura 6 mostra a saída da rede neural durante o treinamento após o recebimento da primeira janela rolante para processamento. Ela imprime a iteração de treinamento real e o erro de reconstrução atual. Depois de um tempo, é importante que o número seja convergido para um mínimo local e que haja uma queda significativa de erros de reconstrução.

Figura 6. Saída da rede neural durante o treinamento
Neural                 network output
Neural network output

Em Figura 7 iniciamos a iteração 0 com um erro de reconstrução inicial igual a 392314.67211754626. O motivo é a inicialização aleatória dos parâmetros de peso da rede neural.

Figura 7. Saída do treinamento da rede neural com iterações de dados íntegros de 0 a 30
Healthy data iterations 0 to                 30
Healthy data iterations 0 to 30

Observação: A cada vez que esse exemplo for executado, serão obtidos números um pouco diferentes.

Em Figura 8 terminamos com um erro de reconstrução igual a 372.6741075529085 na iteração 999, que é significativamente inferior do que a iteração 0 em 392314.67211754626.

Figura 8. Saída do treinamento da rede neural com iterações de dados íntegros de 969 a 999
Healthy data iterations 969                 to 999
Healthy data iterations 969 to 999

Em Figura 9, depois de uma segunda rodada de treinamento e depois de processar a segunda janela rolante de contagem, terminamos com um erro de reconstrução igual a 77.8737141122287 na iteração 1999.

Observação: é possível ver que a pontuação na iteração 1999 é superior à iteração 1969. Isso ocorre devido a oscilações, mas não significa que há um problema, a não ser que você esteja convergindo para um valor inferior.

Figura 9. Saída do treinamento da rede neural com iterações de dados íntegros de 1969 a 1999
Healthy data iterations 1969                 to 1999
Healthy data iterations 1969 to 1999

Como você pode ver em Figura 10, agora inserimos dados anormais na rede neural e podemos ver claramente que o erro de reconstrução de 11091.125671441947 na iteração 2999 é significativamente superior do que em Figura 8 e Figura 9.

Figura 10. Saída do treinamento da rede neural com iterações de dados íntegros de 969 a 999
Healthy data iterations 969                 to 999
Healthy data iterations 969 to 999

Observação: Eu demonstrei este cenário completo na conferência HadoopSummit 17, que você pode assistir neste vídeo (eu começo a demo no ponto 25:06 deste vídeo de 34:47 minutos).

Conclusão

Isso conclui nosso primeiro tutorial de deep learning para dados de série temporal de IoT. Como você viu, definir e executar uma rede neural profunda é uma tarefa simples no DeepLearning4J. A estrutura do DeepLearning4j é cuidadosa com toda a matemática complexa envolvida no treinamento de rede neural paralela. Sendo executado no Apache Spark, ele se torna um candidato ideal para criar soluções de IoT cognitivas altamente escaláveis em ambientes de nuvem elásticos do Apache Spark, como a plataforma Data Science Experience da IBM Cloud, que apresenta a oferta Apache Spark escalável de forma elástica anexada "como serviço". Além disso, você não fica preso a um único provedor de nuvem específico e pode até executar esse sistema em sua própria nuvem privada ou no datacenter tradicional.

Nos próximos dois artigos eu vou trabalhar com os mesmos dados de teste gerados, mas com duas estruturas de deep learning diferentes: ApacheSystemML e TensorFlow (TensorSpark).


Recursos para download


Temas relacionados


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Internet of Things, Cognitive computing, Big data e análise de dados
ArticleID=1057952
ArticleTitle=Desenvolvendo soluções de IoT cognitivas para detecção de anomalias usando deep learning, Parte 3: Usando o Deeplearning4j para detecção de anomalia
publish-date=02082018