Definição do Limiar

Nesta página será realizada a análise do limiar de inferência, onde todas as amostras que tiverem o erro absoluto (mean absolute error - MAE) maior que este valor será considerada anomalia.

Configurações

As variáveis de ambiente, bibliotecas e caminhos serão aqui definidos.

Montando Google Drive

Para acessar os dados é necessário criar um link do google drive dentro da máquina do google colab, para isso fazemos:

[1]:
from google.colab import drive
import os
drive.mount('/content/drive')
Mounted at /content/drive

Clonando a biblioteca easy_lstm

[2]:
!git clone https://github.com/GabrielLima1995/easy_lstm.git
Cloning into 'easy_lstm'...
remote: Enumerating objects: 12, done.
remote: Counting objects: 100% (12/12), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 12 (delta 4), reused 11 (delta 3), pack-reused 0
Unpacking objects: 100% (12/12), done.

Caminhos necessários

Definimos também os caminhos necessários para os dados de interesse.

[3]:
lib_path = '/content'
[4]:
main_path = '/content/drive/MyDrive/IG2021/'

Import das bibliotecas utilizadas

Importando as bibliotecas e dependências necessárias:

[5]:
import pandas as pd
import numpy as np
import joblib
import matplotlib.pyplot as plt
from keras.models import load_model
import seaborn as sns
[6]:
import sys
sys.path.insert(0,lib_path)
[7]:
from easy_lstm import preparation
from easy_lstm import operations

Váriaveis uteis

Seção para definição de alguns parâmetros e variáveis necessárias.

[8]:
cols = ['DataTimeStamp','GPSLong','GPSLat','Vel','ExernalAcelX','ExernalAcelY',
 'ExernalAcelZ','ExernalGyroscopeX','ExernalGyroscopeY','ExernalGyroscopeZ',
 'Pitch','Roll','Yaw']
[9]:
used_cols = ['Vel','ExernalAcelX','ExernalAcelY','ExernalAcelZ',
             'ExernalGyroscopeX','ExernalGyroscopeY',
             'ExernalGyroscopeZ','Pitch','Roll','Yaw']
[10]:
train_files = os.listdir(main_path + 'train/')

Definições e inicializações graficas

Seção para inicialização do tema de background e afins.

[11]:
plt.style.use("dark_background")

Carregamento dos dados

Dados de Treino

Os dados de Treino serão aqui lidos pela biblioteca pandas.

[12]:
filepath_train = [pd.read_csv(main_path + 'train/' + f,delimiter=';', usecols= cols) for f in train_files ]

Dados da normalização pré treino

Na preparação do treino os dados foram normalizados e seus parâmetros foram salvos. Utilizaremos então esses parâmetros.

[13]:
my_scaler = joblib.load(main_path + 'file_train/scaler.save')

Rede LSTM Autoencoder Treinada

Após o treino a rede foi salva e seu carregamento é feito a seguir:

[14]:
model = load_model(main_path + 'file_train/treino_1.h5')

Podemos ainda verificar sua estrutura.

[15]:
model.summary()
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         [(None, 30, 10)]          0
_________________________________________________________________
lstm (LSTM)                  (None, 30, 16)            1728
_________________________________________________________________
lstm_1 (LSTM)                (None, 4)                 336
_________________________________________________________________
repeat_vector (RepeatVector) (None, 30, 4)             0
_________________________________________________________________
lstm_2 (LSTM)                (None, 30, 4)             144
_________________________________________________________________
lstm_3 (LSTM)                (None, 30, 16)            1344
_________________________________________________________________
time_distributed (TimeDistri (None, 30, 10)            170
=================================================================
Total params: 3,722
Trainable params: 3,722
Non-trainable params: 0
_________________________________________________________________

Preparação dos dados

Os dados precisam ser preparados para inferência na rede.

Criação de Janelas (time_steps)

[16]:
print('Há {} arquivos de treino'.format(len(filepath_train)))
soma = 0
for i in range(len(filepath_train)):
  soma += filepath_train[i].shape[0]
  print('O arquivo {} possui {} linhas e {} colunas'.\
        format(i+1,filepath_train[i].shape[0],filepath_train[i].shape[1]))
print('Total de pontos para treino: {} linhas '.format(soma))
Há 6 arquivos de treino
O arquivo 1 possui 5978 linhas e 13 colunas
O arquivo 2 possui 6006 linhas e 13 colunas
O arquivo 3 possui 4731 linhas e 13 colunas
O arquivo 4 possui 7144 linhas e 13 colunas
O arquivo 5 possui 5805 linhas e 13 colunas
O arquivo 6 possui 8683 linhas e 13 colunas
Total de pontos para treino: 38347 linhas

Criaremos então as Janelas para cada ponto.

[17]:
train = preparation.to_lstm(filepath_train,30,used_cols)

Ao termino temos um total de:

[18]:
train.shape
[18]:
(38173, 30, 10)

Note que a diferença de pontos é de 29 linhas por arquivo (Tamanho da janela-1)

Normalização dos Dados

Com os dados da Normalização de treino será realizada a normalização para inferência.

[19]:
X_train = operations.normalize_transform(train,my_scaler)

Inferência dos Dados

Será realizado a inferência dos dados de treino.

[20]:
X_pred = model.predict(X_train)
X_pred = X_pred[:,1,:]
[21]:
X_pred = pd.DataFrame(X_pred,columns= used_cols)

Cálculo do erro absoluto

Será Calculado então o erro absoluto de cada ponto.

\(MAE=\frac{1}{n}\sum\limits_{i=1} ^{n}|Y_{i}-\hat{Y}_{i}|\)

onde:

n = número de pontos

Ŷ = valor predito

Y = valor real

[22]:
X_train = X_train[:,1,:]
X_train = pd.DataFrame(X_train,columns= used_cols)
[23]:
scored = pd.DataFrame(columns = ['Loss_MAE'])
[24]:
scored['Loss_MAE'] = np.mean(np.abs(X_pred - X_train), axis=1)
[25]:
scored.head(2)
[25]:
Loss_MAE
0 0.065925
1 0.068421
[26]:
scored.shape
[26]:
(38173, 1)

Distribuição do conjunto de Treino

Por fim plotaremos a distribuição do conjunto de treino afim de descobrir qual o valor indicado para o limiar.

[27]:
sns.displot(scored['Loss_MAE'],bins=20,kde=True,color='yellow').\
set(title='Distribuição do conjunto de Treino')
plt.show()
_images/Threshold_definition_65_0.png

Vemos que um valor acima de 0.15 é um bom valor para o limiar, pois o loss de treino está no intervalo de 0 a 0.15.