AWS で銀行向け説明可能な商品推薦システムを構築
AWS Machine Learning Blog は、Amazon SageMaker AI と PyTorch を活用した銀行向け説明可能な次期最適商品推奨システムのアーキテクチャと設計思想を詳述している。
AIニュース価値スコアβ
技術分析AI関連度、新規性、日本での有用性など6軸を公開検証中です。現在、掲載順には使用していません。
- AI関連度
- 75
- 情報源の信頼性
- 100
- 新規性
- 25
- 検索具体性
- 75
- 重複の少なさ
- 100
- 日本での有用性
- 25
深層学習モデルの設計やアテンション機構の説明可能性といった具体的な技術的知見が含まれているため、AI 関連度と検索機会は高いが、これは既存の AWS サービスを用いた導入事例・アーキテクチャ紹介であり、世界初の新規発表ではないため新規性は低め。また、日本固有の規制や企業事例に言及がないため日本関連性は低い。
キーポイント
多層ニューラルネットワークの採用
顧客データの複雑な時系列パターンを捉えるため、従来のルールベースや協調フィルタリングに代わる多層構造(multi-tower)のニューラルネットワークアーキテクチャを採用している。
アテンションによる説明可能性
学習されたアテンション(attention)メカニズムを活用し、個々の顧客に対して推奨理由を明確に示す「説明可能性」を実現する仕組みを提供している。
AWS 統合による実装フロー
SageMaker AI、Amazon S3、AWS Glue、CloudWatch を連携させることで、研究段階のモデルから本番環境へのスムーズな移行と運用を可能にするアーキテクチャを示している。
要件と権限管理
実装に必要な AWS アカウント設定や、SageMaker AI、S3、Glue などの各サービスに対する最小権限の IAM ロール構成について具体的な要件を提示している。
多塔アーキテクチャの採用理由
顧客データの構造(時系列、数値集計、カテゴリカルなど)が異なるため、単一のネットワークで処理するとモデル容量を浪費するため、各データタイプに特化した4つの専用タワーを使用します。
シーケンスタワーによる順序の捉え方
GRU(Gated Recurrent Unit)を採用することで、顧客がどの製品を持っているかだけでなく、製品を順次採用した「順序」のパターンを捉えることが可能です。
バッチ処理とリソース管理
大規模データ処理において、マルチプロセス並列実行(ProcessPoolExecutor)を活用し、バッチ間のメモリ解放のために明示的に garbage collection を実行します。
重要な引用
Building a deep learning-based explainable next-best-product recommendation system helps banking institutions predict which product a customer needs next.
Traditional rule-based systems and collaborative filtering approaches often fail to capture the complex temporal patterns in customer product adoption journeys.
We explain the reasoning behind a multi-tower neural network architecture, how learned attention provides per-customer explainability, and how AWS services work together to take this solution from research to production.
Different types of customer data have fundamentally different structures. Forcing all these through the same layers wastes model capacity.
The Sequence Tower... captures the order in which customers adopt products, not just which products they own.
GRU has two gates (reset, update) versus LSTM's three (input, forget, output), resulting in approximately 33% fewer parameters.
影響分析・編集コメントを表示
影響分析
この記事は、金融機関が直面する「説明可能性」という重要な課題に対し、深層学習の最新アーキテクチャとクラウドネイティブな実装パターンを提供しています。特に、規制対応や顧客信頼の確保が求められる銀行業界において、AI の判断根拠を明確に示す手法の具体例として、実務家にとって非常に価値のある指針となります。
編集コメント
金融分野におけるAIの導入において、精度だけでなく「なぜその推奨が行われたのか」を説明できることは、コンプライアンスと顧客信頼の観点から極めて重要です。本記事は、技術的な実装手法だけでなく、ビジネス上の課題解決に向けた具体的なアーキテクチャ設計を示しており、実務への応用可能性が高い内容です。
深層学習を活用した説明可能な次期最適商品レコメンデーションシステムを構築することで、金融機関は顧客が次に必要とする商品を予測できるようになります。銀行には取引履歴、保有製品記録、人口統計プロファイル、行動パターンなど、膨大な量の顧客データが存在します。しかし、これらのデータを具体的なアクションにつながるパーソナライズされた商品推薦に変換することは依然として大きな課題です。
従来のルールベースのシステムや協調フィルタリング手法では、顧客が製品を採用していく過程における複雑な時間的パターンを捉えきれていないのが実情です。
本稿では、Amazon SageMaker AI と PyTorch を活用した次期最適商品(NBP)レコメンデーションシステムのアーキテクチャと設計思想について解説します。なぜ多層構造のニューラルネットワークを採用するのか、学習されたアテンションが顧客ごとの説明可能性をどう実現するか、そして AWS の各サービスが連携して研究段階から本番環境への移行をどのように支えるのかについて詳述します。
これはステップバイステップのデプロイガイドではなく、アーキテクチャの概要です。金融サービスに限らず、多様な顧客データを持つ他の分野でレコメンデーションシステムを構築する方々にとっても、ここで紹介するアーキテクチャパターンは、より精度が高く解釈可能なモデルを設計するための指針となるでしょう。
前提条件
本稿のアーキテクチャパターンやコード例を実践するには、以下の準備が必要です。
- SageMaker AI、Amazon Simple Storage Service (Amazon S3)、AWS Glue、Amazon CloudWatch へのアクセス権限を持つ AWS アカウントが必要です。
- このソリューションを実行するには、以下の AWS サービスにアクセスできる AWS Identity and Access Management (IAM) の実行ロールが必要です。このソリューションに必要なリソースのみを対象とした、最小権限のポリシーを作成してください。
- SageMaker AI – トレーニングジョブ、処理ジョブ、バッチ変換ジョブ、モデル、エンドポイント、エンドポイント構成、パイプライン、実験、モニタリングスケジュールの作成、説明、開始、停止、削除。リアルタイム推論のための InvokeEndpoint 呼び出し。
- Amazon S3 – データバケットへの読み書きアクセス。バケットの作成と削除。オブジェクトの一覧表示、アップロード、ダウンロード、削除。
- AWS Glue – ETL ジョブの作成、実行、削除。クローラーの作成と削除。データカタログのデータベースおよびテーブルの作成と削除。
- CloudWatch – ロググループ、ログストリーム、メトリクスへの読み書きアクセス。クリーンアップ時にロググループを削除。
- IAM – ロールの作成と削除。ポリシーのアタッチとデタッチ。PassRole(指定された実行ロール ARN に制限され、sagemaker.amazonaws.com および glue.amazonaws.com に対してスコープが設定されている)。
SageMaker AI に対する最小権限の IAM ポリシー作成に関するガイドについては、SageMaker AI の「Identity-based policy examples」を参照してください。
- Python 3.11 および PyTorch の基本的な知識
- このレコメンダーシステムを構築するために必要なパッケージ:
- Python 3.11+
- PyTorch 2.9+
- Pandas 2.3+
- NumPy 2.3+
- scikit-learn 1.7+
- Dask 2025.11+
**
デプロイ前に、仮想環境の使用と pip-audit などのツールによる既知の脆弱性のスキャンを推奨します。
- 深層学習の基本概念(埋め込み表現、リカレントネットワーク、アテンション機構など)に関する基礎知識
注意:このソリューションをデプロイすると、SageMaker AI のトレーニングジョブ(ml.g5.12xlarge GPU インスタンス)、SageMaker AI エンドポイント、Amazon S3 ストレージ、AWS Glue ジョブなど、課金対象の AWS リソースが作成されます。継続的な課金を避けるため、本記事末尾のクリーンアップ手順に従ってください。
ソリューション概要
このソリューションでは、顧客データの異なる側面をそれぞれ処理する 4 つの専門化されたニューラルネットワークタワー(多層構造)を持つマルチタワー型深層学習アーキテクチャを採用しています。各タワーは、学習されたアテンション機構によって融合され、高い精度と顧客ごとの説明可能性を両立します。
以下の図は、本ソリューションの高レベルなアーキテクチャを示しています。

本アーキテクチャは、銀行業界で頻繁に直面する課題に対処します。具体的には、クレジットカード、預金、保険、ローン、住宅ローンなど複数の商品カテゴリーの中から、顧客が次に購入する可能性が高い商品を予測し、かつ規制要件を満たす説明可能な結果を提供することです。
テックスタック
以下の表は、本ソリューションにおける技術選定とその役割を要約したものです。
| コンポーネント | 技術 | 目的 |
|---|---|---|
| ETL & データ処理 | AWS Glue (PySpark) | スケールするデータ統合、サービスマッピング、特徴量エンジニアリングのためのサーバーレス Spark ベースの ETL |
| ディープラーニングフレームワーク | PyTorch | 動的計算グラフ、研究から本番環境への柔軟な移行、ネイティブ GPU サポート |
| 特徴量エンジニアリング | Pandas, Dask, PyArrow | シーケンス作成やウィンドウ集計など、機械学習に特化した特徴量の構築 |
| ML ユーティリティ | scikit-learn | ラベルエンコーディング、標準化スケーリング、トレーニング/テスト分割、評価指標の算出 |
| トレーニング計算リソース | SageMaker AI (ml.g5.12xlarge) | 192 GB RAM、4 枚の NVIDIA A10G GPU を搭載 |
| データストレージ | Amazon S3 | 生データ、中間データ、処理済みデータを保存するための Snappy 圧縮 Parquet ファイル |
| データカタログ | AWS Glue Data Catalog | スキーマ管理、テーブルメタデータの保持、自動発見のためのクローラー機能 |
| モデルレジストリ | SageMaker AI model registry | バージョン管理されたモデルアーティファクトと承認ワークフローの管理 |
推論
SageMaker AI のバッチ変換機能やエンドポイントを活用し、バッチ処理とニアリーリアルタイムの予測に対応します。
オーケストレーション
Amazon SageMaker Pipelines を用いて、機械学習パイプライン全体を一元管理・自動化します。
モニタリング
CloudWatch でトレーニングメトリクス、推論レイテンシ、モデルドリフトの検出を常時監視します。
なぜ PyTorch か?
本ソリューションでは、可変長のシーケンス処理に必要な pack_padded_sequence に対応する動的計算グラフの実装や、複数のアーキテクチャ段階での迅速な試行錯誤、そして SageMaker AI のトレーニングジョブや推論コンテナとのネイティブ統合を実現するため、PyTorch を採用しています。
なぜ Amazon S3 で Parquet か?
データは Snappy 圧縮された Parquet 形式で Amazon Simple Storage Service (Amazon S3) に保存されます。Parquet の列指向フォーマットにより、広大なファイルの一部のみを読み込む「カラムプルーニング」や、不要な行グループをスキップする「述語プッシュダウン」が可能となり、CSV と比較して 3〜5 倍の圧縮効率を実現します。また、データ型を保持したまま読み込み時に再解析する必要もありません。
なぜ AWS Glue で ETL か?
本プロジェクトでは、サーバーレスかつ自動スケーリング可能なデータ処理のために、PySpark を実行する AWS Glue ジョブを活用しています。AWS Glue はネイティブな Spark 統合、柔軟なスキーマを扱える DynamicFrame API、自動的な Data Catalog 登録、増分処理のためのジョブブックマーク機能を提供し、DPU(Data Processing Unit)課金に基づくコスト効率を実現します。
データパイプラインのアーキテクチャ
データパイプラインは 2 つの段階で構成されています。まず AWS Glue の ETL ジョブでデータを統合し、続いて Amazon SageMaker の処理ジョブで機械学習に特化した特徴量のエンジニアリングを行います。
AWS Glue を用いたデータ統合
銀行のデータは、スキーマがバラバラな複数のソースシステムから流入することが一般的です。AWS Glue の ETL ジョブでは、これらのスキーマを正規化し、生取引データを統一されたサービスカテゴリにマッピングします。さらに、全データを顧客ごとに時系列順に結合し、時間軸を考慮した特徴量を抽出します。処理済みの出力は Parquet 形式で Amazon S3 に保存され、AWS Glue データカタログに登録されます。
Amazon SageMaker Processing を活用した ML 特化型の特徴量エンジニアリング
AWS Glue ジョブで統合履歴が完成した後、Amazon SageMaker Processing ジョブが実行されます。ここでは顧客ごとの商品採用シーケンスを生成し、Dask を用いた並列処理によって、7 日、30 日、60 日、180 日、365 日の各期間における取引集計値を計算します。また、モデルへの入力として扱うために、シーケンスを固定長にパディングします。
大規模データの処理戦略
利用可能なメモリを超える大規模データを扱う場合、本ソリューションでは並列チャンク処理戦略を採用しています。メタデータ確認には PyArrow を、並列処理には ProcessPoolExecutor を使用し、バッチ間の明示的なガベージコレクションと増分マージを行うことで、メモリの急激な増加を防ぎます。
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
Note: When working with real customer data, see the Security considerations section for guidance on PII handling, regulatory compliance, and data governance.
Model architecture
The model uses a multi-tower approach where each tower specializes in processing one type of customer data, followed by an attention-based fusion mechanism.
Why multi-tower over a single network?
Different types of customer data have fundamentally different structures. Sequences are ordered lists of discrete IDs. Transactions are numerical aggregations. Demographics are a mix of categorical and numerical features. Behavioral segments are categorical codes.
Forcing all these through the same layers wastes model capacity. Instead, the architecture uses four specialized towers, each designed for its data type:
Tower
Input Type
Architecture
Output
Sequence Tower
商品導入履歴(固定長にパディング済み)
nn.Embedding → 2層 GRU → アクティブ保有商品数との融合
64 次元ベクトル
Transaction Tower
時間窓を設けた取引特徴量
ReLU と Dropout を用いた 2 層 MLP(128→64)
64 次元ベクトル
Customer Tower
人口統計、収入、家族構成、口座特性
ReLU と Dropout を用いた 2 層 MLP(128→64)
64 次元ベクトル
Behavioral Tower
セグメントコード、ロイヤリティ、利用パターン
ReLU と Dropout を用いた 2 層 MLP(128→64)
64 次元ベクトル
Sequence Tower: 時系列パターンの抽出
Sequence Tower は、2 層の Gated Recurrent Unit(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))
なぜ GRU を LSTM よりも選ぶのか
GRU はリセットゲートと更新ゲートの 2 つしか持たないのに対し、LSTM は入力・忘却・出力の 3 つを備えています。その結果、パラメータ数は約 33% 削減されます。20 項目以内といった短いシーケンスにおいては、GRU の精度は LSTM と同等でありながら、学習速度はより速くなります。また、更新ゲートによる補間機構が、自然な残差のような勾配パスを形成する点も特徴です。
なぜ pack_padded_sequence を使うのか
顧客の行動シーケンスには長さのばらつきがあります。パディング済みシーケンスをパック(pack)することで、GRU はパディングトークンを無視し、ゼロ埋めされた位置からノイズを学習することを防ぎます。
タワーアテンション機構:説明可能性を備えた学習による融合
単純な結合ではなく、このアーキテクチャでは学習されたアテンション機構を用いてタワーの出力を融合します。これにより、SHAP や 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
塔の重みは顧客ごとに異なります。取引履歴が豊富な顧客には「取引」タワーの重みを高く設定し、取引数は少ないものの属性情報が明確な新規顧客には「顧客情報」タワーの重みを高く設定します。この適応性により精度が向上するだけでなく、担当者と規制当局にとって自然な説明可能性も提供されます。
コンテキスト認識融合:安定した学習のための残差ブロック
重み付けされた塔の出力は、残差接続を備えた融合ネットワークに入力されます。残差接続は学習中の勾配の流れを助け、追加的な深さが必要ない場合にネットワークが恒等写像(アイデンティティマッピング)を学習できるようにします。
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
Feature Importance Module: Built-in explainability
Banking regulators require model explainability. Rather than relying on post-hoc methods, the architecture includes a Feature Importance Module that produces per-customer importance scores summing to 1.0 as part of the 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)
)
必ずJSON形式で返してください。translation フィールドのみ。他のフィールドは一切追加しないこと — 余計なフィールドを書こうとして本文がトークン上限で打ち切られる事故を防ぐため:
{"translation": "リライト全文"}
def forward(self, fused_features, tower_weights):
feature_importance = self.feature_contribution(fused_features)
return feature_importance * tower_weights
この処理により、以下のような説明が出力されます。
「この顧客への推奨は、製品の利用順序が 40%、取引パターンが 30%、人口統計データが 20%、行動セグメントが 10% の要因となっています」
関係者はこの情報を基に、顧客一人ひとりに合わせた対話を行うことができます。
トレーニング戦略
以下の表は、各設定の値とその選択理由をまとめたものです。
| パラメータ | 値 | 選択理由 |
|---|---|---|
| オプティマイザ | Adam (lr=0.001, weight_decay=1e-5) | パラメータごとの適応的な学習率と、軽い L2 正則化を実現 |
| ロス関数 | CrossEntropyLoss | 多クラス分類の標準であり、数値的に安定しているため |
| LR スケジューラ | ReduceLROnPlateau (factor=0.5, patience=3) | 検証ロスが頭打ちになった際に学習率を自動的に半分に下げる |
| グラディエントクリップ | | 学習の安定性を確保し、グラディエント爆発を防ぐため
原文を表示
Building a deep learning-based explainable next-best-product recommendation system helps banking institutions predict which product a customer needs next. Banks hold vast amounts of customer data, including transaction histories, product ownership records, demographic profiles, and behavioral patterns. Translating this data into actionable, personalized product recommendations remains a significant challenge. Traditional rule-based systems and collaborative filtering approaches often fail to capture the complex temporal patterns in customer product adoption journeys.
In this post, we present the architecture and design decisions behind a Next-Best-Product (NBP) recommendation system using Amazon SageMaker AI and PyTorch. We explain the reasoning behind a multi-tower neural network architecture, how learned attention provides per-customer explainability, and how AWS services work together to take this solution from research to production. This is an architectural overview, not a step-by-step deployment guide. Whether you are building recommendation systems for financial services or other domains with heterogeneous customer data, the architectural patterns described here can help you design more accurate and interpretable models.
Prerequisites
To follow along with the architectural patterns and code examples in this post, you need:
- An AWS account with permissions for SageMaker AI, Amazon Simple Storage Service (Amazon S3), AWS Glue, and Amazon CloudWatch
- This solution requires an AWS Identity and Access Management (IAM) execution role with access to the following AWS services. Create policies with least-privilege permissions scoped to only the resources needed for this solution.
- SageMaker AI – Create, describe, start, stop, and delete training jobs, processing jobs, batch transform jobs, models, endpoints, endpoint configurations, pipelines, experiments, and monitoring schedules. InvokeEndpoint for real-time inference.
- Amazon S3 – Read and write access to the data bucket. Create and delete bucket. List, upload, download, and delete objects.
- AWS Glue – Create, run, and delete ETL jobs. Create and delete crawlers. Create and delete Data Catalog databases and tables.
- CloudWatch – Read and write access to log groups, log streams, and metrics. Delete log groups during cleanup.
- IAM – Create and delete roles. Attach and detach policies. PassRole (restricted to the named execution role ARN, scoped to sagemaker.amazonaws.com and glue.amazonaws.com).
For guidance on writing least-privilege IAM policies for SageMaker AI, see Identity-based policy examples for SageMaker AI.
- Familiarity with Python 3.11+ and PyTorch
- Required packages to create this recommender system:
Python 3.11+
- PyTorch 2.9+
- Pandas 2.3+
- NumPy 2.3+
- scikit-learn 1.7+
- Dask 2025.11+
We recommend using a virtual environment and scanning dependencies for known vulnerabilities using tools like pip-audit before deployment.
- Basic understanding of deep learning concepts (embeddings, recurrent networks, attention mechanisms)
Note: Deploying this solution creates billable AWS resources including SageMaker AI training jobs (ml.g5.12xlarge GPU instances), SageMaker AI endpoints, Amazon S3 storage, and AWS Glue jobs. Follow the clean up instructions at the end of this post to avoid ongoing charges.
Solution overview
The solution uses a multi-tower deep learning architecture with four specialized neural network towers, each processing a different aspect of customer data. The towers are fused using a learned attention mechanism that provides both high accuracy and per-customer explainability.
The following diagram illustrates the high-level architecture of the solution.

The architecture addresses a common challenge in banking: predicting which product a customer is most likely to purchase next from multiple product categories (such as credit cards, deposits, insurance, loans, and mortgages), while providing explainable results that satisfy regulatory requirements.
Tech stack
The following table summarizes the technology choices and their roles in the solution.
Component
Technology
Purpose
ETL & Data Processing
AWS Glue (PySpark)
Serverless Spark-based ETL for data unification, service mapping, feature engineering at scale
Deep Learning Framework
PyTorch
Dynamic computation graphs, research-to-production flexibility, native GPU support
Feature Engineering
Pandas, Dask, PyArrow
ML-specific feature engineering (sequence creation, windowed aggregations)
ML Utilities
scikit-learn
Label encoding, standard scaling, train/test split, evaluation metrics
Training Compute
SageMaker AI (ml.g5.12xlarge)
192 GB RAM, 4× NVIDIA A10G GPUs
Data Storage
Amazon S3
Snappy-compressed Parquet files for raw, intermediate, and processed data
Data Catalog
AWS Glue Data Catalog
Schema management, table metadata, crawlers for auto-discovery
Model Registry
SageMaker AI model registry
Versioned model artifacts, approval workflows
Inference
SageMaker AI Batch Transform / endpoint
Batch and near-real-time predictions
Orchestration
Amazon SageMaker Pipelines
End-to-end ML pipeline orchestration
Monitoring
CloudWatch
Training metrics, inference latency, model drift detection
Why PyTorch?
This solution uses PyTorch for dynamic computation graphs (needed for variable-length sequences with pack_padded_sequence), rapid iteration across multiple architectural phases, and native integration with SageMaker AI training jobs and inference containers.
Why Parquet on Amazon S3?
The solution stores data as Snappy-compressed Parquet on Amazon Simple Storage Service (Amazon S3). Parquet’s columnar format enables column pruning (reading a fraction of a wide file), predicate pushdown (skipping irrelevant row groups), 3-5× compression over CSV, and type preservation without re-parsing on every read.
Why AWS Glue for ETL?
The project uses AWS Glue jobs running on PySpark for serverless, auto scaling data processing. AWS Glue provides native Spark integration, the DynamicFrame API for flexible schemas, automatic Data Catalog registration, job bookmarks for incremental processing, and pay-per-DPU cost efficiency.
Data pipeline architecture
The data pipeline consists of two stages: an AWS Glue ETL job for data unification, followed by an Amazon SageMaker Processing job for ML-specific feature engineering.
Data unification with AWS Glue
Banking data typically arrives from multiple source systems with inconsistent schemas. The AWS Glue ETL job normalizes schemas, maps raw transaction types to unified service categories, combines all data into a single chronological record per customer, and engineers temporal features. The processed output is written as Parquet to Amazon S3 and registered in the AWS Glue Data Catalog.
ML-specific feature engineering with Amazon SageMaker Processing
After the AWS Glue job produces the unified history, an Amazon SageMaker Processing job creates product adoption sequences per customer, computes time-windowed transaction aggregations (across 7, 30, 60, 180, and 365-day windows) using Dask for parallelism, and pads sequences to a fixed length for model input.
Handling large scale data
For large datasets that exceed available memory, the solution uses a parallel chunked processing strategy with PyArrow for metadata inspection, ProcessPoolExecutor for parallel chunk processing, explicit garbage collection between batches, and incremental merging to avoid memory spikes.
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 batchesNote: When working with real customer data, see the Security considerations section for guidance on PII handling, regulatory compliance, and data governance.
Model architecture
The model uses a multi-tower approach where each tower specializes in processing one type of customer data, followed by an attention-based fusion mechanism.
Why multi-tower over a single network?
Different types of customer data have fundamentally different structures. Sequences are ordered lists of discrete IDs. Transactions are numerical aggregations. Demographics are a mix of categorical and numerical features. Behavioral segments are categorical codes.
Forcing all these through the same layers wastes model capacity. Instead, the architecture uses four specialized towers, each designed for its data type:
Tower
Input Type
Architecture
Output
Sequence Tower
Product adoption history (padded to fixed length)
nn.Embedding → 2-layer GRU → Fusion with active product count
64-dim vector
Transaction Tower
Time-windowed transaction features
2-layer MLP (128 → 64) with ReLU and Dropout
64-dim vector
Customer Tower
Demographics, income, family, account features
2-layer MLP (128 → 64) with ReLU and Dropout
64-dim vector
Behavioral Tower
Segmentation codes, loyalty, usage patterns
2-layer MLP (128 → 64) with ReLU and Dropout
64-dim vector
Sequence Tower: Capturing temporal patterns
The Sequence Tower processes the customer’s product adoption history using a 2-layer Gated Recurrent Unit (GRU). This is the core architectural component because it captures the order in which customers adopt products, not just which products they own.
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))Why GRU over LSTM?
GRU has two gates (reset, update) versus LSTM’s three (input, forget, output), resulting in approximately 33% fewer parameters. For short sequences (20 items or fewer), GRU performs comparably to LSTM while training faster. The update gate’s interpolation mechanism also creates a natural residual-like gradient path.
Why pack_padded_sequence?
Customer sequences have variable lengths. Packing tells the GRU to ignore padding tokens, preventing the model from learning noise from zero-padded positions.
Tower Attention Mechanism: Learned fusion with explainability
Instead of simple concatenation, the architecture uses a learned attention mechanism to fuse tower outputs. This is what provides per-customer explainability without requiring post-hoc interpretation methods like SHAP or 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_weightsThe tower weights are per-customer. A customer with rich transaction history gets a high transaction tower weight, while a new customer with few transactions but clear demographics gets a high customer tower weight. This adaptivity improves accuracy and provides natural explainability for relationship managers and regulators.
Context-Aware Fusion: Residual blocks for stable training
The weighted tower outputs pass through a fusion network with residual connections. Residual connections help with gradient flow during training and allow the network to learn identity mappings when additional depth is not needed.
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 out2Feature Importance Module: Built-in explainability
Banking regulators require model explainability. Rather than relying on post-hoc methods, the architecture includes a Feature Importance Module that produces per-customer importance scores summing to 1.0 as part of the 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_weightsThis produces outputs like: “For this customer, 40% of the recommendation was driven by their product sequence, 30% by transaction patterns, 20% by demographics, 10% by behavioral segment.” Relationship managers can use this to tailor their conversations with each customer.
Training strategy
The following table summarizes the training configuration and the rationale behind each choice.
Parameter
Value
Rationale
Optimizer
Adam (lr=0.001, weight_decay=1e-5)
Adaptive per-parameter learning rates, light L2 regularization
Loss
CrossEntropyLoss
Standard for multi-class classification, numerically stable
LR Scheduler
ReduceLROnPlateau (factor=0.5, patience=3)
Automatically halves LR when validation loss plateaus
Gradient Clippi
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み