Visão geral
Neste publish, treinaremos um autoencoder para detectar fraude no cartão de crédito. Também demonstraremos como treinar modelos de keras na nuvem usando Cloudml.
A base do nosso modelo será o kaggle Detecção de fraude de cartão de crédito conjunto de dados, que foi coletado durante uma colaboração de pesquisa da linha mundial e Grupo de aprendizado de máquina da ULB (Université Libre de Bruxelles) em mineração de large knowledge e detecção de fraude.
O conjunto de dados contém transações com cartão de crédito pelos portadores de cartão europeus feitos durante um período de dois dias em setembro de 2013. Existem 492 fraudes em 284.807 transações. O conjunto de dados é altamente desequilibrado, a classe positiva (fraudes) representa apenas 0,172% de todas as transações.
Lendo os dados
Depois de baixar os dados de Kagglevocê pode ler para r com read_csv()
:
As variáveis de entrada consistem apenas em valores numéricos que são o resultado de uma transformação de PCA. Para preservar a confidencialidade, não foram fornecidas mais informações sobre os recursos originais. Os recursos v1,…, V28 foram obtidos com PCA. No entanto, existem 2 recursos (Tempo e Quantia) que não foram transformados.
Tempo é o segundos decorridos entre cada transação e a primeira transação no conjunto de dados. Quantia é o valor da transação e pode ser usado para o aprendizado sensível ao custo. O Aula A variável assume o valor 1 no caso de fraude e 0 de outra forma.
AutoEncoders
Como apenas 0,172% das observações são fraudes, temos um problema de classificação altamente desequilibrado. Com esse tipo de problema, as abordagens de classificação tradicionais geralmente não funcionam muito bem porque temos apenas uma amostra muito pequena da classe mais rara.
Um AutoEncoder é uma rede neural usada para aprender uma representação (codificação) para um conjunto de dados, normalmente para fins de redução da dimensionalidade. Para esse problema, treinaremos um autoencoder para codificar observações que não são de fraude do nosso conjunto de treinamento. Como as fraudes devem ter uma distribuição diferente e depois transações normais, esperamos que nosso autoencoder tenha mais erros de reconstrução em fraudes em transações normais. Isso significa que podemos usar o erro de reconstrução como uma quantidade que indica se uma transação é fraudulenta ou não.
Se você quiser aprender mais sobre autoencoders, um bom ponto de partida é este Vídeo de Larochelle no YouTube e Capítulo 14 do Aprendizado profundo Livro de Goodfellow et al.
Visualização
Para que um autoencoder funcione bem, temos uma forte suposição inicial: que a distribuição de variáveis para transações normais é diferente da distribuição para as fraudulentas. Vamos fazer algumas parcelas para verificar isso. Variáveis foram transformadas em um (0,1)
intervalo para plotagem.
Podemos ver que as distribuições de variáveis para transações fraudulentas são muito diferentes que as normais, exceto para o Tempo variável, que parece ter exatamente a mesma distribuição.
Pré -processamento
Antes das etapas de modelagem, precisamos fazer algum pré -processamento. Vamos dividir o conjunto de dados em conjuntos de trens e testes e então iremos Min-max normalizando Nossos dados (isso é feito porque as redes neurais funcionam muito melhor com pequenos valores de entrada). Também iremos remover o Tempo variável, pois possui exatamente a mesma distribuição para transações normais e fraudulentas.
Com base no Tempo Variável usaremos as primeiras 200.000 observações para treinamento e o restante para testes. Isso é uma boa prática, porque ao usar o modelo, queremos prever fraudes futuras com base em transações que aconteceram antes.
Agora vamos trabalhar na normalização das entradas. Criamos 2 funções para nos ajudar. O primeiro recebe estatísticas descritivas sobre o conjunto de dados usado para escalar. Em seguida, temos uma função para executar a escala Min-Max. É importante observar que aplicamos as mesmas constantes de normalização para treinamento e conjuntos de testes.
library(purrr)
#' Will get descriptive statistics for each variable within the dataset.
get_desc <- perform(x) {
map(x, ~listing(
min = min(.x),
max = max(.x),
imply = imply(.x),
sd = sd(.x)
))
}
#' Given a dataset and normalization constants it would create a min-max normalized
#' model of the dataset.
normalization_minmax <- perform(x, desc) {
map2_dfc(x, desc, ~(.x - .y$min)/(.y$max - .y$min))
}
Agora vamos criar versões normalizadas de nossos conjuntos de dados. Também transformamos nossos quadros de dados em matrizes, pois esse é o formato esperado por Keras.
Agora definiremos nosso modelo em Keras, um autoencoder simétrico com 4 camadas densas.
___________________________________________________________________________________
Layer (kind) Output Form Param #
===================================================================================
dense_1 (Dense) (None, 15) 450
___________________________________________________________________________________
dense_2 (Dense) (None, 10) 160
___________________________________________________________________________________
dense_3 (Dense) (None, 15) 165
___________________________________________________________________________________
dense_4 (Dense) (None, 29) 464
===================================================================================
Complete params: 1,239
Trainable params: 1,239
Non-trainable params: 0
___________________________________________________________________________________
Em seguida, compilaremos nosso modelo, usando a perda média de erros ao quadrado e o Adam Optimizer para treinamento.
mannequin %>% compile(
loss = "mean_squared_error",
optimizer = "adam"
)
Treinando o modelo
Agora podemos treinar nosso modelo usando o match()
função. Treinamento O modelo é razoavelmente rápido (~ 14s por época no meu laptop computer). Somente alimentaremos para o nosso modelo as observações de transações normais (não fraudulentas).
Vamos usar callback_model_checkpoint()
Para salvar nosso modelo após cada época. Passando o argumento save_best_only = TRUE
Continuaremos no disco apenas a época com menor valor de perda no conjunto de testes. Nós também usaremos callback_early_stopping()
Para parar o treinamento se a perda de validação parar de diminuir para 5 épocas.
checkpoint <- callback_model_checkpoint(
filepath = "mannequin.hdf5",
save_best_only = TRUE,
interval = 1,
verbose = 1
)
early_stopping <- callback_early_stopping(persistence = 5)
mannequin %>% match(
x = x_train(y_train == 0,),
y = x_train(y_train == 0,),
epochs = 100,
batch_size = 32,
validation_data = listing(x_test(y_test == 0,), x_test(y_test == 0,)),
callbacks = listing(checkpoint, early_stopping)
)
Practice on 199615 samples, validate on 84700 samples
Epoch 1/100
199615/199615 (==============================) - 17s 83us/step - loss: 0.0036 - val_loss: 6.8522e-04d from inf to 0.00069, saving mannequin to mannequin.hdf5
Epoch 2/100
199615/199615 (==============================) - 17s 86us/step - loss: 4.7817e-04 - val_loss: 4.7266e-04d from 0.00069 to 0.00047, saving mannequin to mannequin.hdf5
Epoch 3/100
199615/199615 (==============================) - 19s 94us/step - loss: 3.7753e-04 - val_loss: 4.2430e-04d from 0.00047 to 0.00042, saving mannequin to mannequin.hdf5
Epoch 4/100
199615/199615 (==============================) - 19s 94us/step - loss: 3.3937e-04 - val_loss: 4.0299e-04d from 0.00042 to 0.00040, saving mannequin to mannequin.hdf5
Epoch 5/100
199615/199615 (==============================) - 19s 94us/step - loss: 3.2259e-04 - val_loss: 4.0852e-04 enhance
Epoch 6/100
199615/199615 (==============================) - 18s 91us/step - loss: 3.1668e-04 - val_loss: 4.0746e-04 enhance
...
Após o treinamento, podemos obter a perda last para o conjunto de testes usando o consider()
FUCNTION.
loss <- consider(mannequin, x = x_test(y_test == 0,), y = x_test(y_test == 0,))
loss
loss
0.0003534254
Ajuste com CloudML
Podemos obter melhores resultados ajustando nossos hiperparâmetros de modelo. Podemos ajustar, por exemplo, a função de normalização, a taxa de aprendizado, as funções de ativação e o tamanho das camadas ocultas. CloudML usa a otimização bayesiana para ajustar os hiperparâmetros de modelos, conforme descrito em esta postagem do weblog.
Podemos usar o pacote cloudml Para ajustar nosso modelo, mas primeiro precisamos preparar nosso projeto, criando um Bandeira de treinamento para cada hiperparâmetro e um tuning.yml
Arquivo que informará CloudML quais parâmetros queremos sintonizar e como.
O script completo usado para treinamento no CloudML pode ser encontrado em https://github.com/dfalbel/fraud-autoencoder-example. As modificações mais importantes para o código foram adicionar os sinalizadores de treinamento:
FLAGS <- flags(
flag_string("normalization", "minmax", "Considered one of minmax, zscore"),
flag_string("activation", "relu", "Considered one of relu, selu, tanh, sigmoid"),
flag_numeric("learning_rate", 0.001, "Optimizer Studying Fee"),
flag_integer("hidden_size", 15, "The hidden layer measurement")
)
Nós então usamos o FLAGS
Variável dentro do script para acionar os hiperparâmetros do modelo, por exemplo:
mannequin %>% compile(
optimizer = optimizer_adam(lr = FLAGS$learning_rate),
loss = 'mean_squared_error',
)
Nós também criamos um tuning.yml
Arquivo descrevendo como os hiperparâmetros devem variar durante o treinamento, bem como qual métrica queríamos otimizar (neste caso, foi a perda de validação: val_loss
).
tuning.yml
trainingInput:
scaleTier: CUSTOM
masterType: standard_gpu
hyperparameters:
objective: MINIMIZE
hyperparameterMetricTag: val_loss
maxTrials: 10
maxParallelTrials: 5
params:
- parameterName: normalization
kind: CATEGORICAL
categoricalValues: (zscore, minmax)
- parameterName: activation
kind: CATEGORICAL
categoricalValues: (relu, selu, tanh, sigmoid)
- parameterName: learning_rate
kind: DOUBLE
minValue: 0.000001
maxValue: 0.1
scaleType: UNIT_LOG_SCALE
- parameterName: hidden_size
kind: INTEGER
minValue: 5
maxValue: 50
scaleType: UNIT_LINEAR_SCALE
Descrevemos o tipo de máquina que queremos usar (neste caso, um standard_gpu
Instância), a métrica que queremos minimizar durante o ajuste e o número máximo de ensaios (ou seja, número de combinações de hiperparâmetros que queremos testar). Em seguida, especificamos como queremos variar cada hiperparâmetro durante o ajuste.
Você pode aprender mais sobre o arquivo tuning.yml no tensorflow para a documentação r e em Documentação oficial do Google no CloudML.
Agora estamos prontos para enviar o trabalho para o Google CloudML. Podemos fazer isso executando:
library(cloudml)
cloudml_train("prepare.R", config = "tuning.yml")
O pacote CloudML cuida do add do conjunto de dados e instalação de quaisquer dependências do pacote R necessárias para executar o script no CloudML. Se você estiver usando o RStudio v1.1 ou superior, ele também permitirá que você monitore seu trabalho em um terminal de segundo plano. Você também pode monitorar seu trabalho usando o Google Cloud Console.
Após o término do trabalho, podemos coletar os resultados do trabalho com:
Isso copiará os arquivos do trabalho com o melhor val_loss
Desempenho no CloudML para o seu sistema native e abrir um relatório resumindo a execução do treinamento.
Como usamos um retorno de chamada para salvar pontos de verificação do modelo durante o treinamento, o arquivo do modelo também foi copiado do Google CloudML. Os arquivos criados durante o treinamento são copiados para o subdiretório “execuções” do diretório de trabalho do qual cloudml_train()
é chamado. Você pode determinar este diretório para a corrida mais recente com:
(1) runs/cloudml_2018_01_23_221244595-03
Você também pode listar todas as execuções anteriores e suas perdas de validação com:
ls_runs(order = metric_val_loss, reducing = FALSE)
run_dir metric_loss metric_val_loss
1 runs/2017-12-09T21-01-11Z 0.2577 0.1482
2 runs/2017-12-09T21-00-11Z 0.2655 0.1505
3 runs/2017-12-09T19-59-44Z 0.2597 0.1402
4 runs/2017-12-09T19-56-48Z 0.2610 0.1459
Use View(ls_runs()) to view all columns
No nosso caso, o trabalho baixado do CloudML foi salvo para runs/cloudml_2018_01_23_221244595-03/
então o arquivo de modelo salvo está disponível em runs/cloudml_2018_01_23_221244595-03/mannequin.hdf5
. Agora podemos usar nosso modelo ajustado para fazer previsões.
Fazendo previsões
Agora que treinamos e sintonizamos nosso modelo, estamos prontos para gerar previsões com o nosso autoencoder. Estamos interessados no MSE para cada observação e esperamos que as observações de transações fraudulentas tenham MSE mais alto.
Primeiro, vamos carregar nosso modelo.
mannequin <- load_model_hdf5("runs/cloudml_2018_01_23_221244595-03/mannequin.hdf5",
compile = FALSE)
Agora vamos calcular o MSE para as observações de treinamento e conjunto de testes.
Uma boa medida do desempenho do modelo em conjuntos de dados altamente desequilibrados é a área sob a curva ROC (AUC). A AUC tem uma boa interpretação para esse problema, é a probabilidade de uma transação fraudulenta ter MSE mais alto do que um regular. Podemos calcular isso usando o Métricas Pacote, que implementa uma ampla variedade de métricas de desempenho do modelo de aprendizado de máquina comuns.
(1) 0.9546814
(1) 0.9403554
Para usar o modelo na prática para fazer previsões, precisamos encontrar um limiar (okay ) para o MSE, então se se (Mse> okay ) Consideramos essa transação uma fraude (caso contrário, a consideramos regular). Para definir esse valor, é útil olhar para a precisão e recordar enquanto varia o limiar (okay ).
possible_k <- seq(0, 0.5, size.out = 100)
precision <- sapply(possible_k, perform(okay) {
predicted_class <- as.numeric(mse_test > okay)
sum(predicted_class == 1 & y_test == 1)/sum(predicted_class)
})
qplot(possible_k, precision, geom = "line")
+ labs(x = "Threshold", y = "Precision")
recall <- sapply(possible_k, perform(okay) {
predicted_class <- as.numeric(mse_test > okay)
sum(predicted_class == 1 & y_test == 1)/sum(y_test)
})
qplot(possible_k, recall, geom = "line")
+ labs(x = "Threshold", y = "Recall")
Um bom ponto de partida seria escolher o limiar com a máxima precisão, mas também poderíamos basear nossa decisão sobre quanto dinheiro podemos perder de transações fraudulentas.
Suponha que cada verificação guide da fraude custe US $ 1, mas se não verificarmos uma transação e é uma fraude, perderemos esse valor da transação. Vamos encontrar para cada valor limite quanto dinheiro perderíamos.
cost_per_verification <- 1
lost_money <- sapply(possible_k, perform(okay) {
predicted_class <- as.numeric(mse_test > okay)
sum(cost_per_verification * predicted_class + (predicted_class == 0) * y_test * df_test$Quantity)
})
qplot(possible_k, lost_money, geom = "line") + labs(x = "Threshold", y = "Misplaced Cash")
Podemos encontrar o melhor limite neste caso com:
(1) 0.005050505
Se precisássemos verificar manualmente todas as fraudes, isso nos custaria ~ US $ 13.000. Usando nosso modelo, podemos reduzir isso para ~ US $ 2.500.