O desafio de recomendar produtos bancários com inteligência
Bancos acumulam volumes enormes de dados sobre seus clientes: histórico de transações, produtos contratados, perfil demográfico e padrões de comportamento. Transformar tudo isso em recomendações personalizadas e acionáveis, no entanto, continua sendo um dos maiores desafios do setor. Sistemas baseados em regras e abordagens tradicionais de filtragem colaborativa frequentemente não conseguem capturar os padrões temporais complexos presentes na jornada de adoção de produtos por parte dos clientes.
Para endereçar esse problema, a AWS publicou uma visão arquitetural completa de um sistema de recomendação de Próximo Melhor Produto — ou Próximo Melhor Produto (NBP) — voltado ao setor bancário. A solução usa Amazon SageMaker AI e PyTorch, com foco em precisão e, principalmente, em explicabilidade — requisito fundamental para atender a reguladores financeiros.
Vale reforçar: este é um guia de arquitetura e decisões de design, não um tutorial passo a passo de implantação.
Visão geral da solução
A solução é construída sobre uma arquitetura de aprendizado profundo com quatro torres neurais especializadas, cada uma processando um tipo diferente de dado do cliente. As saídas dessas torres são combinadas por um mecanismo de atenção aprendida, que oferece tanto alta acurácia quanto explicabilidade por cliente.
O objetivo central é prever qual produto um cliente tem maior probabilidade de contratar a seguir — entre categorias como cartão de crédito, depósitos, seguros, empréstimos e financiamentos imobiliários — enquanto fornece justificativas compreensíveis para os resultados, satisfazendo exigências regulatórias.
Stack tecnológica
A arquitetura combina diversos serviços e bibliotecas com papéis bem definidos:
- Processamento e Transformação, Extração e Carregamento de Dados (ETL): AWS Glue com PySpark para unificação e engenharia de features em escala
- Framework de aprendizado profundo: PyTorch com grafos de computação dinâmicos e suporte nativo a GPU
- Engenharia de features: Pandas, Dask e PyArrow para agregações temporais e criação de sequências
- Utilitários de ML: scikit-learn para codificação, normalização e avaliação
- Computação de treinamento: SageMaker AI com instâncias
ml.g5.12xlarge(192 GB de RAM, 4× GPUs NVIDIA A10G) - Armazenamento: Amazon S3 com arquivos Parquet comprimidos com Snappy
- Catálogo de dados: AWS Glue Data Catalog para gerenciamento de esquemas
- Registro de modelos: SageMaker AI model registry com versionamento e fluxos de aprovação
- Inferência: SageMaker AI Batch Transform e endpoints em tempo real
- Orquestração: Amazon SageMaker Pipelines para o pipeline de ML de ponta a ponta
- Monitoramento: Amazon CloudWatch para métricas de treinamento, latência de inferência e detecção de drift
A escolha do PyTorch se justifica pelos grafos de computação dinâmicos — necessários para sequências de comprimento variável com pack_padded_sequence — além da integração nativa com jobs de treinamento e contêineres de inferência do SageMaker AI. Já o formato Parquet no S3 oferece vantagens como leitura colunar seletiva, pushdown de predicados, compressão de 3 a 5 vezes em relação ao CSV e preservação de tipos sem necessidade de reprocessamento.
Pipeline de dados
O pipeline de dados é dividido em duas etapas principais.
Unificação de dados com AWS Glue
Dados bancários geralmente chegam de múltiplos sistemas com esquemas inconsistentes. O job ETL do AWS Glue normaliza esses esquemas, mapeia tipos de transação para categorias unificadas, combina todos os dados em um registro cronológico único por cliente e gera features temporais. O resultado é gravado como Parquet no S3 e registrado no AWS Glue Data Catalog.
Engenharia de features com Amazon SageMaker Processing
Após a unificação, um job de processamento do SageMaker AI cria sequências de adoção de produtos por cliente, calcula agregações de transações em janelas temporais de 7, 30, 60, 180 e 365 dias usando Dask para paralelismo, e padroniza as sequências para um comprimento fixo como entrada do modelo.
Para datasets que excedem a memória disponível, a solução adota uma estratégia de processamento paralelo em chunks, com ProcessPoolExecutor, inspeção de metadados via PyArrow, coleta de lixo explícita entre batches e merge incremental para evitar picos de memória:
import gc
from concurrent.futures import ProcessPoolExecutor
chunksize = 5_000_000
n_workers = 4
for batch_start in range(0, total_chunks, n_workers):
with ProcessPoolExecutor(max_workers=n_workers) as executor:
futures = [
executor.submit(process_chunk_range, input_path, output_path, i, start_row, end_row)
for i in range(batch_start, min(batch_start + n_workers, total_chunks))
]
for future in futures:
future.result()
gc.collect() # Force garbage collection between batches
Arquitetura do modelo
Por que múltiplas torres em vez de uma rede única?
Diferentes tipos de dados do cliente têm estruturas fundamentalmente distintas: sequências são listas ordenadas de IDs discretos, transações são agregações numéricas, dados demográficos misturam variáveis categóricas e numéricas, e segmentos comportamentais são códigos categóricos. Forçar todos esses dados pela mesma camada desperdiça capacidade do modelo. A arquitetura usa quatro torres especializadas:
- Torre de Sequência: Processa o histórico de adoção de produtos com embedding + GRU de 2 camadas, produzindo um vetor de 64 dimensões
- Torre de Transações: Processa features de transações em janelas temporais com MLP de 2 camadas (128 → 64), com ReLU e Dropout
- Torre de Cliente: Processa dados demográficos, renda, família e conta com MLP de 2 camadas (128 → 64)
- Torre Comportamental: Processa códigos de segmentação, fidelidade e padrões de uso com MLP de 2 camadas (128 → 64)
Torre de Sequência: capturando padrões temporais
A Torre de Sequência é o componente central da arquitetura. Ela captura a ordem em que os clientes adotam produtos — não apenas quais produtos possuem. Usa uma Unidade Recorrente com Portão de 2 camadas (GRU):
class SequenceTower(nn.Module):
def __init__(self, num_products, embedding_dim=32, hidden_dim=64, dropout=0.2):
super().__init__()
self.embedding = nn.Embedding(num_products + 1, embedding_dim, padding_idx=0)
self.gru = nn.GRU(
input_size=embedding_dim,
hidden_size=hidden_dim,
num_layers=2,
batch_first=True,
dropout=dropout
)
self.active_count_layer = nn.Sequential(
nn.Linear(1, hidden_dim // 2),
nn.ReLU(),
nn.Dropout(dropout)
)
self.fusion = nn.Sequential(
nn.Linear(hidden_dim + hidden_dim // 2, hidden_dim),
nn.ReLU(),
nn.Dropout(dropout)
)
def forward(self, sequence, seq_length, active_count):
embedded = self.embedding(sequence)
packed = nn.utils.rnn.pack_padded_sequence(
embedded, seq_length.cpu().clamp(min=1),
batch_first=True, enforce_sorted=False
)
_, hidden = self.gru(packed)
seq_features = hidden[-1]
active_features = self.active_count_layer(active_count)
return self.fusion(torch.cat([seq_features, active_features], dim=1))
A escolha do GRU em vez do LSTM se deve ao menor número de parâmetros (aproximadamente 33% a menos), desempenho comparável para sequências curtas de até 20 itens, treinamento mais rápido e menor tamanho de modelo (~5 MB contra ~15 MB de um Transformer equivalente). O uso de pack_padded_sequence garante que o modelo ignore tokens de padding, evitando que aprenda ruído de posições com zeros.
Mecanismo de atenção entre torres
Em vez de simplesmente concatenar as saídas das torres, a arquitetura usa um mecanismo de atenção aprendida para combiná-las. Esse é o componente que fornece explicabilidade por cliente sem depender de métodos post-hoc como SHAP ou LIME:
class TowerAttentionMechanism(nn.Module):
def __init__(self, hidden_dim=64, num_heads=4, dropout=0.1):
super().__init__()
self.tower_attention = nn.MultiheadAttention(
embed_dim=hidden_dim, num_heads=num_heads,
dropout=dropout, batch_first=True
)
self.context_weighting = nn.Sequential(
nn.Linear(hidden_dim * 4, 4),
nn.Softmax(dim=1)
)
def forward(self, tower_outputs):
stacked = torch.stack(tower_outputs, dim=1) # [batch, 4, 64]
attended, _ = self.tower_attention(stacked, stacked, stacked)
stacked = stacked + attended # Residual connection
concat = torch.cat(tower_outputs, dim=1) # [batch, 256]
tower_weights = self.context_weighting(concat) # [batch, 4]
weighted_outputs = [
tower_outputs[i] * tower_weights[:, i:i+1]
for i in range(4)
]
return weighted_outputs, tower_weights
Os pesos das torres são calculados por cliente. Um cliente com histórico transacional rico recebe peso alto na Torre de Transações, enquanto um cliente novo com poucos dados transacionais mas perfil demográfico claro recebe peso alto na Torre de Cliente. Essa adaptabilidade melhora a acurácia e fornece explicabilidade natural para gerentes de relacionamento e reguladores.
Fusão contextual com blocos residuais
As saídas ponderadas das torres passam por uma rede de fusão com conexões residuais, que ajudam no fluxo de gradiente durante o treinamento e permitem que a rede aprenda mapeamentos de identidade quando profundidade adicional não é necessária:
class ContextAwareFusion(nn.Module):
def __init__(self, hidden_dim=64, dropout=0.2):
super().__init__()
self.initial_projection = nn.Linear(hidden_dim * 4, hidden_dim)
self.fusion1 = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim * 2),
nn.LayerNorm(hidden_dim * 2),
nn.ReLU(),
nn.Dropout(dropout),
nn.Linear(hidden_dim * 2, hidden_dim)
)
self.layer_norm1 = nn.LayerNorm(hidden_dim)
self.fusion2 = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Dropout(dropout)
)
self.layer_norm2 = nn.LayerNorm(hidden_dim)
def forward(self, weighted_outputs):
concat = torch.cat(weighted_outputs, dim=1)
projected = self.initial_projection(concat)
out1 = self.layer_norm1(projected + self.fusion1(projected)) # Residual
out2 = self.layer_norm2(out1 + self.fusion2(out1)) # Residual
return out2
Módulo de importância de features: explicabilidade nativa
Reguladores bancários exigem explicabilidade dos modelos. Em vez de depender de métodos externos, a arquitetura inclui um módulo que produz scores de importância por cliente — com soma igual a 1,0 — como parte do próprio forward pass:
class FeatureImportanceModule(nn.Module):
def __init__(self, hidden_dim=64):
super().__init__()
self.feature_contribution = nn.Sequential(
nn.Linear(hidden_dim, 4),
nn.Softmax(dim=1)
)
def forward(self, fused_features, tower_weights):
feature_importance = self.feature_contribution(fused_features)
return feature_importance * tower_weights
O resultado é uma saída como: “Para este cliente, 40% da recomendação foi baseada na sequência de produtos, 30% em padrões de transações, 20% em dados demográficos e 10% no segmento comportamental.” Gerentes de relacionamento podem usar essa informação para personalizar suas abordagens com cada cliente.
Estratégia de treinamento
O treinamento é configurado com as seguintes escolhas e suas justificativas:
- Otimizador: Adam (lr=0,001, weight_decay=1e-5) — taxas de aprendizado adaptativas por parâmetro com regularização L2 leve
- Função de perda: CrossEntropyLoss — padrão para classificação multiclasse, numericamente estável
- Scheduler de LR: ReduceLROnPlateau (fator=0,5, paciência=3) — reduz a taxa automaticamente quando a perda de validação estagna
- Clipping de gradiente: max_norm=1,0 — previne explosão de gradiente com GRU e atenção
- Early stopping: paciência=5 — interrompe o treinamento quando a perda de validação para de melhorar
- Batch size: 32 — cabe confortavelmente na VRAM das A10G
- Divisão dos dados: 80% treino / 10% validação / 10% teste
Todas as seeds aleatórias são fixadas (PyTorch, NumPy, CUDA) para reprodutibilidade total entre execuções. O treinamento usa instâncias ml.g5.12xlarge do SageMaker AI:
from sagemaker.pytorch import PyTorch
estimator = PyTorch(
entry_point='train.py',
source_dir='src/',
role=role,
instance_count=1,
instance_type='ml.g5.12xlarge',
framework_version='2.5.0',
py_version='py311',
hyperparameters={
'epochs': 50,
'batch_size': 32,
'learning_rate': 0.001,
},
)
Métricas de avaliação
O modelo é avaliado com métricas diretamente ligadas ao valor de negócio:
- Acurácia Top-1: O modelo previu exatamente o produto correto?
- Acurácia Top-3: O produto correto está entre os 3 primeiros? (lista curta para o gerente)
- Acurácia Top-5: O produto correto está no carrossel de recomendações?
- Classificação Recíproca Média (MRR): Qual a posição média do produto correto nas recomendações?
- F1 ponderado: O modelo prevê bem todos os tipos de produto?
O modelo de produção alcançou desempenho forte em todas as métricas, com o produto correto aparecendo consistentemente entre as 3 primeiras recomendações. O módulo de importância de features confirmou que a Torre de Sequência contribui com o maior sinal, seguida por padrões de transações, dados demográficos e segmentação comportamental.
Inferência e implantação
O pipeline de inferência suporta tanto scoring em lote quanto predições em tempo real via SageMaker AI.
Para scoring em lote, o SageMaker AI Batch Transform processa toda a base de clientes diariamente, gerando recomendações top-k com scores de explicabilidade para cada cliente. Os resultados são armazenados como JSON no S3 para consumo por sistemas de CRM e dashboards de gerentes de relacionamento.
Para predições em tempo real, um endpoint do SageMaker AI serve recomendações sob demanda quando um cliente acessa o app de mobile banking ou quando um gerente abre o perfil de um cliente. Cada recomendação inclui o ID do produto com score de probabilidade, o detalhamento de importância de features por torre e um indicador de confiança baseado na entropia da distribuição de probabilidades.
def generate_batch_recommendations(model, dataloader, top_k=5):
with torch.no_grad():
for batch in dataloader:
outputs, feature_importance = model(
batch['sequence'], batch['seq_length'], batch['active_count'],
batch['transaction'], batch['customer'], batch['behavioral']
)
probabilities = F.softmax(outputs, dim=1).cpu().numpy()
# Generate top-k recommendations with explainability scores
Os trechos de código ilustram padrões arquiteturais e não estão prontos para produção. Para ambientes produtivos, é necessário adicionar validação de entradas, tratamento de erros e logging de inferência. Configure o Amazon SageMaker Model Monitor para alertar sobre drift na distribuição de entradas.
Considerações operacionais e de segurança
Para garantir reprodutibilidade, todas as seeds aleatórias são fixadas. Artefatos do modelo, hiperparâmetros e versões de dados são rastreados via Amazon SageMaker Experiments. O Amazon SageMaker Model Monitor detecta drift de dados, drift do modelo e potencial viés por dependência excessiva de features demográficas. O pipeline do Amazon SageMaker Pipelines retreina o modelo mensalmente com os dados mais recentes dos clientes, implantando automaticamente apenas se as métricas melhorarem em relação ao modelo em produção.
Para implantações com dados bancários reais, a AWS recomenda implementar roles de Gerenciamento de Identidade e Acesso (IAM) com privilégio mínimo, criptografar dados em repouso com chaves gerenciadas pelo cliente no AWS KMS, aplicar TLS para todos os dados em trânsito, implantar jobs de treinamento e endpoints em sub-redes privadas de Nuvem Privada Virtual (VPC) sem gateway de internet, e usar endpoints VPC via AWS PrivateLink para comunicação com serviços AWS. Para orientações completas, consulte a documentação de segurança do SageMaker AI.
Principais decisões de design
O artigo original detalha as razões por trás de cada escolha arquitetural:
- Múltiplas torres vs. rede única: Torres separadas permitem que cada uma se especialize em seu tipo de dado, com a fusão por atenção aprendendo a combinação ótima por cliente.
- GRU vs. Transformers em produção: Para sequências curtas (até 20 itens), GRU é suficiente, mais interpretável, evita a computação quadrática da atenção e produz um modelo menor.
- Pesos de atenção vs. concatenação: Com concatenação, o modelo trata todas as torres igualmente para todos os clientes. Com atenção aprendida, o modelo se adapta por cliente.
- Features de transação em janelas temporais: Janelas de 7 dias capturam intenção imediata, 30 dias capturam padrões mensais, 180 dias capturam padrões sazonais e 365 dias capturam padrões anuais.
Conclusão
A arquitetura de múltiplas torres com fusão por atenção aprendida publicada pela AWS demonstra como é possível combinar alta acurácia preditiva com a explicabilidade exigida por reguladores bancários. Torres especializadas para diferentes tipos de dados superam arquiteturas monolíticas para dados heterogêneos. O processamento de sequências com GRU captura padrões temporais que agregações planas de features não conseguem. E a atenção aprendida entre torres fornece ganhos de acurácia e explicabilidade por cliente sem necessidade de métodos de interpretação post-hoc.
O SageMaker AI oferece a infraestrutura de ponta a ponta para treinamento, gerenciamento de modelos e inferência em escala. Para começar, explore a documentação do SageMaker AI.
Fonte
Build an explainable next-best-product recommendation system for banking on AWS (https://aws.amazon.com/blogs/machine-learning/build-an-explainable-next-best-product-recommendation-system-for-banking-on-aws/)
Leave a Reply