gCastleは、因果探索アルゴリズムが実装された因果の構造を学習するツールチェインです。Huaweiのリサーチラボから提供されています。パッケージは、Webアプリを含んでおり、因果探索アルゴリズムがGUIベースの操作で検証できるようになっています。
gCastle 概要
因果探索アルゴリズムが実装されており、Webアプリを使用してアルゴリズムの動作が検証できます。
- テスト用のサンプルデータをもとにしたDAGはランダムに生成されます。
- 生成したDAGとアルゴリズムで推定したDAGを出力して比較します。
- パッケージに含まれるアルゴリズムに、勾配法を下にした因果探索アルゴリズムを提案しています。
- バックエンドで深層学習、強化学習アルゴリズムを使っています。
- 勾配法を基にしたアルゴリズムはPyTorchでコーディングされています。
GCastleの名称は、Gradient-based Causal Structure Learning pipeline. の頭文字からとってあります。ニューラルネットの勾配法を基にした学習アルゴリズムを使って因果の構造を学習します。
パッケージがサポートしているアルゴリズムは、PCから勾配法を基にしたものまで含めて以下にリストしたアルゴリズムが実装されています。
- PC : Estimating high-dimensional directed acyclic graphs with the PC-algorithm
- ANN:Nonlinear causal discovery with additive noise models
- DirectLiNGAM: DirectLiNGAM: A direct method for learning a linear non-Gaussian structural equation model
- ICALiNGAM: A Linear Non-Gaussian Acyclic Model for Causal Discovery
- GES: Optimal Structure Identification With Greedy Search
- PNL: On the Identifiability of the Post-Nonlinear Causal Model
- NOTEARS: DAGs with NO TEARS: Continuous Optimization for Structure Learning
- NOTEARS-MLP: Learning Sparse Nonparametric DAGs
- NOTEARS-SOB: Learning Sparse Nonparametric DAGs
- NOTEARS-RANK: On Low Rank Directed Acyclic Graphs and Causal Structure Learning
- DAG-GNN: DAG-GNN: DAG Structure Learning with Graph Neural Networks
- GOLEM: On the Role of Sparsity and DAG Constraints for Learning Linear DAGs
- GraNDAG: Gradient-Based Neural DAG Learning
- MSCL: Masked Gradient-Based Causal Structure Learning
- GAE: A Graph Autoencoder Approach to Causal Structure Learning
- RL: Causal Discovery with Reinforcement Learning
- CORL: Ordering-Based Causal Discovery with Reinforcement Learning
- TTPM:Topological Hawkes Processes for Learning Causal Structure on Event Sequences
- HPCI: An Influence-based Approach for Root Cause Alarm Discovery in Telecom Networks
gCastleのインストール
インストールにはpipを使います。torchもインストールして下さい。
pip install gcastle==1.0.4rc1
Collecting gcastle==1.0.4rc1
Downloading gcastle-1.0.4rc1-py3-none-any.whl.metadata (7.6 kB)
Requirement already satisfied: matplotlib>=2.1.2 in /opt/anaconda3/lib/python3.12/site-packages (from gcastle==1.0.4rc1) (3.9.2)
Requirement already satisfied: networkx>=2.5 in /opt/anaconda3/lib/python3.12/site-packages (from gcastle==1.0.4rc1) (3.3)
...
..
pip install torch
Collecting torch
Downloading torch-2.6.0-cp312-none-macosx_11_0_arm64.whl.metadata (28 kB)
Requirement already satisfied: filelock in /opt/anaconda3/lib/python3.12/site-packages (from torch) (3.13.1)
....
..
gCastle パッケージの構成
gCastleのモジュール構成は、アルゴリズムを実装した部分とデータのシミュレーションを実行する部分、検証部分、デモ用GUIツールから構成されています。
シミュレーション、テストデータの生成は、以下のクラスからなっています。
- IIDSimulationクラス
IIDSimulation() 因果の構造を学習するためのIIDデータセットをシミュレートします。
- Topologyクラス
networkxを使って、ネットワークの構造を示す、adjacency matrixを返します。
exampleフォルダに各アルゴリズムのテスト例が含まれていますが、生成したDAGと推定したDAGを比較して検証できるように統一した仕様でテストコードが記載されています。
以下に例を示します。
例1 PCアルゴリズム
from castle.common import GraphDAG
from castle.metrics import MetricsDAG
from castle.datasets import IIDSimulation, DAG
from castle.algorithms import PC
# data simulation, simulate true causal dag and train_data.
weighted_random_dag = DAG.erdos_renyi(n_nodes=10, n_edges=10,
weight_range=(0.5, 2.0), seed=1)
dataset = IIDSimulation(W=weighted_random_dag, n=2000, method='linear',
sem_type='gauss')
true_causal_matrix, X = dataset.B, dataset.X
# structure learning
pc = PC()
pc.learn(X)
# plot predict_dag and true_dag
GraphDAG(pc.causal_matrix, true_causal_matrix, 'result')
# calculate metrics
mt = MetricsDAG(pc.causal_matrix, true_causal_matrix)
print(mt.metrics)

{'fdr': 0.1111, 'tpr': 0.8, 'fpr': 0.0286, 'shd': 2, 'nnz': 9, 'precision': 0.7273, 'recall': 0.8, 'F1': 0.7619, 'gscore': 0.5}
出力されるグラフがnodeを結ぶDAGのmatrixになっています。est_graphがアルゴリズムによる探索結果です。
例2 RLアルゴリズム
from castle.common import GraphDAG
from castle.metrics import MetricsDAG
from castle.datasets import DAG, IIDSimulation
from castle.algorithms import RL
#######################################
# rl used simulate data
#######################################
# simulate data for rl
weighted_random_dag = DAG.erdos_renyi(n_nodes=10, n_edges=20, weight_range=(0.5, 2.0), seed=1)
dataset = IIDSimulation(W=weighted_random_dag, n=2000, method='linear', sem_type='gauss')
true_dag, X = dataset.B, dataset.X
# rl learn
rl = RL(nb_epoch=2000)
rl.learn(X)
# plot est_dag and true_dag
GraphDAG(rl.causal_matrix, true_dag)
# calculate accuracy
met = MetricsDAG(rl.causal_matrix, true_dag)
print(met.metrics)


{'fdr': 0.0, 'tpr': 1.0, 'fpr': 0.0, 'shd': 0, 'nnz': 20, 'precision': 1.0, 'recall': 1.0, 'F1': 1.0, 'gscore': 1.0}
例2の勾配法を基にしたRLの推定結果は、元のgraphと一致しています。スコアを基にした因果探索アルゴリズムの強化学習の性能の良さが結果に表れています。
グラフ生成のためのニューラルネトワークのアーキテクチャは、以下の論文に記述されています。
Shengyu Zhu, et al. Causal Discovery with Reinforcement Learning
RL(Reinforcement Learning)のスケーラビリティを改善したアルゴリズムがCORLです。テストの例では元のDAGを再現しています。
例3 CORLアルゴリズム
import os
os.environ['CASTLE_BACKEND'] ='pytorch'
from castle.common import GraphDAG
from castle.metrics import MetricsDAG
from castle.datasets import DAG, IIDSimulation
from castle.algorithms import CORL
type = 'ER' # or `SF`
h = 2 # ER2 when h=5 --> ER5
n_nodes = 10
n_edges = h * n_nodes
method = 'linear'
sem_type = 'gauss'
if type == 'ER':
weighted_random_dag = DAG.erdos_renyi(n_nodes=n_nodes, n_edges=n_edges,
weight_range=(0.5, 2.0), seed=300)
elif type == 'SF':
weighted_random_dag = DAG.scale_free(n_nodes=n_nodes, n_edges=n_edges,
weight_range=(0.5, 2.0), seed=300)
else:
raise ValueError('Just supported `ER` or `SF`.')
dataset = IIDSimulation(W=weighted_random_dag, n=2000,
method=method, sem_type=sem_type)
true_dag, X = dataset.B, dataset.X
# rl learn
rl = CORL(encoder_name='transformer',
decoder_name='lstm',
reward_mode='episodic',
reward_regression_type='LR',
batch_size=64,
input_dim=64,
embed_dim=64,
iteration=2000,
device_type='cpu')
rl.learn(X)
# plot est_dag and true_dag
GraphDAG(rl.causal_matrix, true_dag)
# calculate accuracy
met = MetricsDAG(rl.causal_matrix, true_dag)
print(met.metrics)


{'fdr': 0.0, 'tpr': 1.0, 'fpr': 0.0, 'shd': 0, 'nnz': 17, 'precision': 1.0, 'recall': 1.0, 'F1': 1.0, 'gscore': 1.0}
アルゴリズムの詳細は以下の論文に記述されています。
Xiaoqiang Wang, et al. Ordering-Based Causal Discovery with Reinforcement Learning.
CastleBoard
flaskサーバーによるGUIツールがパッケージでサポートしているアルゴリズムの検証用に利用できるので、そのツールを使って各因果探索アルゴリズムの動作が確認できます。CastleBoardというWebアプリケーションです。
ローカルサイトで検証するには、gCastleの圧縮ファイルをダウンロードして、ローカルフォルダに展開し、fluskサーバーを動かします。
Webブラウザで該当ポートにアクセスすれば、操作できます。
ツールを使用する場合は、次項"CastleBoard のセットアップ"を参照して下さい。
図1 CastleBoardの画面

CastleBoardのセットアップ
パッケージには、CastleBoardというWebアプリがバンドルされています。インストールには以下の手続きを行います。
- 圧縮ファイルをダウンロードし、すべてのパッケージがインストールされていることを確認して下さい。
- コマンドラインからmain.pyを実行します。ファイルは、gcastleフォルダのweb/main.pyから実行します。
- ローカルのflaskサーバーが起動します。GUIにアクセスするには、ブラウザを起動し、ローカルのアドレスにアクセスして下さい。ローカルIPアドレスのPort:5000です。indexのhtmlを表示します。
Webアプリはflaskで起動しますが、パッケージがflaskの旧バージョンのAPIを使用しており、最新バージョンのflaskでは、起動時にエラーが発生します。
gCastleのコードで使用しているFlaskのAPIがバージョン2.3.0で削除されているためです。そのため、仮想環境を作るか、Flaskのバージョンを落としてgCastleをインストールします。gCastle自体には、Flaskのバージョン要件は1.1.1以上と指定されています。
CastleBoardを使う場合は、Flaskのバージョン2.2.5を用意して下さい。
仮想環境を作り、その上で旧バージョン(2.2.5)をインストールする場合、以下の手続きを参照して下さい。(base)環境のFlaskのバージョンを変更しても構わない場合は、バージョンを指定してFlaskをインストールして下さい。
仮想環境のセットアップとインストールは、以下の手続きを参照して下さい。
パッケージのダウンロード
以下のgit のWebサイトにアクセスし、zipファイルのパッケージをダウンロードします。
https://github.com/huawei-noah/trustworthyAI/tree/master

画面の右上にある緑色のcode
ボタンをクリックすると、以下の図2にあるようにポップアップメニューが表示されます。Download ZIP
を選択してファイルをダウンロードして下さい。
図2 Download ZIP

ダウンロードが開始され、ローカルフォルダの適当な場所において下さい。
パッケージのmain.pyを実行する前に、flaskの設定とpython3.9の仮想環境を作成します。
以下、flaskの旧バージョンの実行環境を作るために、パッケージの要件に合わせて、python 3.9の仮想環境を構築し、その上にflask の旧バージョンをインストールします。
仮想環境の構築 (python バージョン3.9)
gCastleの要件に合わせて、python3.9の環境を作ります。パッケージ管理ツールcondaのコマンドを実行して下さい。
conda create -n python39 python=3.9
conda activate python39
作った環境をactivateすると、コマンドプロンプトが以下のように(base)環境から(python39)に切り替わります。
(python39)$
仮想環境を解除する場合は、以下のコマンドを使います。
conda deactivate
これで元の(base)環境に戻ります。
(base)$
jupyter notebookで作成した仮想環境(python39)を実行できるように、ipykernelをインストールします。python39の仮想環境をactivateし、(python39)のプロンプトが表示された状態で、pipを使ってインストールします。
conda activate python39
pip install ipykernel
仮想環境のカーネルをjupyter notebookのメニューに追加します。
python -m ipykernel install --user --name=python39
仮想環境がjupyterに追加されているか確認します。
jupyter kernelspec list
jupyterのカーネルがインストールされてると、以下のようにnotebookから実行環境が選択できるようになります。
図3 jupter notebook 実行環境の選択

Flask バージョン2.2.5のインストール
Flask をバージョンを指定してインストールします。
conda install -c conda-forge flask==2.2.5
ライブラリのインストール
以下のパッケージも仮想環境にインストールします。
- tqdm (>= 4.48.2)
- numpy (>= 1.19.1)
- pandas (>= 0.22.0)
- scipy (>= 1.7.3)
- scikit-learn (>= 0.21.1)
- matplotlib (>=2.1.2)
- networkx (>= 2.5)
- sqlalchemy
- yaml
パッケージ管理ツール condaでインストールして下さい。バージョンの指定は不要です。
conda install -c conda-forge tqdm
conda install -c conda-forge numpy
conda install -c conda-forge pandas
conda install -c conda-forge scipy
conda install -c conda-forge scikit-learn
conda install -c conda-forge matplotlib
conda install -c conda-forge networkx
conda install -c conda-forge sqlalchemy
conda install -c conda-forge yaml
yamlのインストールだけ、追加の処理が必要となります。
yamlのインストール先がpythonの実行パスに入っていないので、インストール先をパスに追加します。
export PYTHONPATH="${PYTHONPATH}:/path/モジュール/のインストール先/のディレクトリ"
あるいは、インストールされたyamlのディレクトリをpythonの参照パスの下に移動します。
pythonを起動した時の参照パスは、以下のスクリプトで確認できます。
作った仮想環境からpythonを起動し、参照パスを出力します。
(python39)$python
import sys
print(sys.path)
['', '/opt/anaconda3/envs/python39/lib/python39.zip', '/opt/anaconda3/envs/python39/lib/python3.9', '/opt/anaconda3/envs/python39/lib/python3.9/lib-dynload', '/Users/tanakayoshinobu/.local/lib/python3.9/site-packages', '/opt/anaconda3/envs/python39/lib/python3.9/site-packages']
yamlは、以下のディレクトリにインストールされています。
/opt/anaconda3/envs/python39/lib/python3.9/site-packages/jedi/third_party/typeshed/third_party/2and3
ここでは、インストール先にあるyamlのディレクトリを仮想環境のデフォルトのパスで参照しているsite-packagesの直下にコピーします。
cd /opt/anaconda3/envs/python39/lib/python3.9/site-packages
cp -R jedi/third_party/typeshed/third_party/2and3/yaml .
main.pyの修正
gitのサイトからダウンロードした、zipファイルを展開すると、trustworthyAI-master
というディレクトリが作られます。
コマンドラインからこのディレクトリ内にあるgcastle
に移動します。
cd trustworthyAI-master/gcastle
このディレクトリの配下にwebディレクトリがあります。その中にmain.py
というファイルがあります。
このmain.pyのソースコードを一部修正します。Flaskを起動するときのホストのIPアドレスの内容です。
修正コード main.py 71行目
link.connect(('8.8.8.8',80))
上記コードを以下のように修正します。
link.connect('localhost', 80))
テキストエディタで修正した後、main.pyを保存して下さい。
gcastleのディレクトリから、以下のようにpython でmain.pyを実行します。
python web/main.py
コマンドラインに以下のメッセージが出力されていれば、Flaskがポート5000で起動してアクセス待ちになっています。
* Running on http://127.0.0.1:5000
普段使用しているブラウザからlocalhostのポート5000にアクセスして下さい。その際、index.htmlとファイル名も指定します。
urlへの入力アドレス
localhost:8000/index.html
ブラウザに次の画面が表示されます。
図4 CastleBoard 画面

右上のメニューをクリックすると、言語として英語が選択できます。
図5 CastleBoard 言語の選択

CastleBoardが使用できるようになりました。
参考資料
- Markus Kalisch, et al. Estimating high-dimensional directed acyclic graphs with the PC-algorithm
- Patrik O. Hoyer, et al. Nonlinear causal discovery with additive noise models
- Shohei Shimizu, et al. DirectLiNGAM: A direct method for learning a linear non-Gaussian structural equation model
- Shohei Shimizu, et al. A Linear Non-Gaussian Acyclic Model for Causal Discovery
- David Maxwell Chickering, et al. Optimal Structure Identification With Greedy Search
- Kun Zhang, et al. On the Identifiability of the Post-Nonlinear Causal Model
- Xun Zheng, et al. DAGs with NO TEARS: Continuous Optimization for Structure Learning
- Xun Zheng, et al. Learning Sparse Nonparametric DAGs
- Zhuangyan Fang, et al. On Low Rank Directed Acyclic Graphs and Causal Structure Learning
- Yue Yu, et al. DAG-GNN: DAG Structure Learning with Graph Neural Networks
- Ignavier Ng, et al. On the Role of Sparsity and DAG Constraints for Learning Linear DAGs
- Sébastien Lachapelle, et al. Gradient-Based Neural DAG Learning
- Ignavier Ng, et al. Masked Gradient-Based Causal Structure Learning
- Ignavier Ng, et al. A Graph Autoencoder Approach to Causal Structure Learning
- Shengyu Zhu, et al. Causal Discovery with Reinforcement Learning
- Xiaoqiang Wang, et al. Ordering-Based Causal Discovery with Reinforcement Learning
- Ruichu Cai, et al. THP: Topological Hawkes Processes for Learning Causal Structure on Event Sequences
- Keli Zhang, et al. An Influence-based Approach for Root Cause Alarm Discovery in Telecom Networks