O Keras é uma API de redes neurais em Python, fácil de usar e capaz de rodar em cima das bibliotecas de linguagens de aprendizagem profundas (deep learning), como TensorFlow, CNTK ou Theano. Ela provê uma estrutura que permite compilar redes neurais combinando camadas de diferentes dimensões e funções de ativação, tornando o ciclo de desenvolvimento de novos modelos de aprendizado de máquina muito mais rápido.
O modelo sequencial permite inserir camadas de uma rede neural em série, onde o output da primeira camada serve como input da segunda, e assim por diante. Para “instanciar” (criar um objeto alocando um espaço na memória para posteriormente usar os métodos e atributos que ele dispõe), devem ser usadas as seguintes linhas:
from keras.models import Sequential from keras.layers import Dense model = Sequential()
Você pode criar um modelo sequencial passando uma lista de instâncias de camada para o construtor diretamente dentro dos parênteses ou adicionando camadas através do método “.add()” – forma adotada, por ficar mais didático. Dos tipos de camadas do Keras, a “Dense” é a mais utilizada. Ela tem como objetivo calcular uma função de ativação em conjunto com os dados de entrada e pesos.
O número de colunas de features selecionadas no conjunto de dados define a dimensão da camada de entrada (parâmetro/variável “input_shape”). Também é costume informar o número de neurônios (variável “neurons”) e o tipo de função de ativação (parâmetro/variável “activation”), conforme o exemplo a seguir:
model.add(Dense(neurons, activation=activation, input_shape=input_shape))
O parâmetro “input_shape” é uma tupla para qualquer dimensão – por exemplo, “input_shape=(6, 8)”. Para série unidimensional, pode-se usar “input_dim” recebendo um número inteiro positivo.
Dentre as funções de ativação (“activation”), estão a relu (“Rectified Linear Unit”), tanh (tangente hiperbólica) e sigmoid – veja mais no item “Usage of activations” da documentação do Keras.
A presença de duas ou mais camadas possibilita redes neurais aprender qualquer função, inclusive funções não-lineares.
A camada de saída deve ter como dimensão de output o número de classes a serem conhecidas – por exemplo, para uma classificação binária “Verdadeiro/Falso”, é usada somente 1 dimensão de saída.
A compilação serve para configurar o processo de aprendizagem. Devem ser informadas a função que define como os pesos da rede neural são atualizados (“optimizer”), a função de calcula a diferença entre os dados de teste e os dados de validação (“loss”) e uma lista de métricas a ser usada para avaliação (“metrics”), conforme o exemplo a seguir:
model.compile(optimizer=optimizer, loss=loss, metrics=metrics)
Dentre os valores de “optimizer” mais usados, estão o SQG (“Stochastic gradient descent”), e Adam; para os valores de “loss“, estão o MSE (“mean squared error”) e o MAE (“mean absolute error”); para “metric“, “binary_accuracy” e outras métricas comuns – mais informações nos respectivos links.
Por fim, o método “fit” treina o modelo para um determinado número de “epochs” (iterações em um conjunto de dados) com determinado “batch_size” (tamanho do lote que define o número de amostras que serão propagadas pela rede). Os modelos Keras são treinados em matrizes Numpy de dados e de rótulos de entrada. Os dados de entrada devem ser dividido em “x_train” e “y_train” (domínio e imagem de uma parte dos dados do conjunto) para treino, assim como “x_test” e “y_test” (domínio e imagem da outra parte dos dados) para validação.
Além do “Dense”, outro tipo de camada é a LSTM (“Long Short Term Memory”). As redes LSTM podem ser empilhadas da mesma maneira que outros tipos de camadas. Uma adição à configuração necessária é que uma camada LSTM antes de cada camada LSTM subsequente retorne a sequência, o que pode ser feito definindo o parâmetro “return_sequences = True” na(s) camada(s) anterior(es).
Ainda é possível usar o parâmetro “stateful=True”. “Stateful”, de modo geral, significa que o programa monitora o estado da interação, geralmente definindo valores em um campo de armazenamento designado para essa finalidade. Ter um LSTM “stateful” em Keras significa que uma variável Keras será usada para armazenar e atualizar o estado e, de fato, você pode verificar o valor do(s) vetor(es) de estado a qualquer momento (isto é, até você chamar reset_states ()). Um modelo não-stateful, por outro lado, usará um estado zero inicial toda vez que processar um lote, então é como se você sempre chamasse reset_states() depois de train_on_batch, test_on_batch e predict_on_batch.
A explicação sobre o estado sendo reutilizado para o próximo lote em modelos “stateful” é apenas sobre essa diferença com não-stateful; é claro que o estado sempre fluirá dentro do lote e você não precisa ter lotes de tamanho 1 para que isso aconteça. Isso é útil para treinar em sequências divididas de dados muito longas e que não seria prático treinar em toda a sua extensão ou também ao fazer uma previsão, onde você deseja recuperar a saída para cada ponto de tempo na sequência, não apenas no final (seja porque você deseja realimentá-lo de volta na rede ou porque sua aplicação precisa disso). Mais informações no item “How can I use stateful RNNs?” da documentação do Keras.
Persistência
Uma boa “baseline” para a previsão de séries temporais é o modelo de persistência. Este é um modelo de previsão em que a última observação é persistida, ou seja, a observação da etapa de tempo anterior (t-1) é usada para prever a observação na etapa de tempo atual (t). Por causa de sua simplicidade, é frequentemente chamada de previsão ingênua ou “naive forecast”.
Se sua série temporal prevista está um passo atrás da série temporal atual, parece que o modelo aprendeu uma previsão de persistência. A previsão de persistência é o melhor que podemos fazer em problemas de previsão de séries temporais desafiadores, como as séries que são uma caminhada aleatória (“randon walk”), como movimentos de curto alcance dos preços das ações. Se seu modelo sofisticado, como uma rede neural, estiver gerando uma previsão de persistência, isso pode significar que o modelo requer mais ajuste, que o modelo escolhido não pode resolver seu conjunto de dados específico ou que seu problema de série temporal não é previsível.
Dicas finais
Para evitar a confusão de modelos/camadas antigos, use os seguintes comandos para destruir o atual grafo do TensorFlow e criar um novo:
from keras import backend backend.clear_session()
O modelo final pode ser salvo no formato de arquivo HDF5, que armazena eficientemente grandes matrizes de números. Para isso, é necessário possuir instalada a biblioteca Python do h5py – “sudo pip install h5py”. Após adicionar camadas “.add()”, compilar “.compile()” e ajustar “.fit()” o modelo, execute a função “.save(‘nome_arquivo.h5’)” para salvar um arquivo único com a arquitetura, os pesos do modelo, a especificação do algoritmo de perda e otimização escolhido, para que você possa retomar o treinamento:
# Definir modelo model = Sequential() model.add(LSTM(...)) # Compilar modelo model.compile(...) # Ajustar modelo model.fit(...) # Salvar modelo em arquivo model.save('nome_arquivo.h5')
O modelo pode ser carregado novamente (a partir de um script diferente em uma sessão diferente do Python ou na mesma sessão) usando a função “load_model(‘nome_arquivo.h5’)”:
from keras.models import load_model # Carregar modelo de arquivo model = load_model('nome_arquivo.h5')
Fontes
- Keras Documentation – Sequential model guide
- Machine Learning Mastery – How to Make Predictions with Long Short-Term Memory Models in Keras
- Machine Learning Mastery – FAQ
- Machine Learning Mastery – Time Series Prediction with LSTM Recurrent Neural Networks in Python with Keras
- Medium – introdução a classificadores binários usando Keras
- Medium – How to predict Bitcoin and Ethereum price with RNN-LSTM in Keras (aplicação interessante)