Skip to content

Commit ab49a0e

Browse files
committed
initial commit
1 parent c638b03 commit ab49a0e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+9407
-2
lines changed

LICENSE

+359
Large diffs are not rendered by default.

README.md

+242-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,242 @@
1-
# InductiveQE
2-
Official implementation of Inductive Logical Query Answering in Knowledge Graphs (NeurIPS 2022)
1+
# Inductive Logical Query Answering in Knowledge Graphs (NeurIPS 2022) #
2+
3+
<p align="center">
4+
<a href="https://arxiv.org/pdf/2210.08008.pdf"><img src="http://img.shields.io/badge/Paper-PDF-red.svg" alt="NeurIPS paper"></a>
5+
<a href="https://doi.org/10.5281/zenodo.7306046"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.7306046.svg" alt="InductiveQE dataset"></a>
6+
</p>
7+
8+
![InductiveQE animation](asset/inductive_qe.gif)
9+
10+
This is the official code base of the paper
11+
12+
[Inductive Logical Query Answering in Knowledge Graphs][paper]
13+
14+
[Mikhail Galkin](https://migalkin.github.io),
15+
[Zhaocheng Zhu](https://kiddozhu.github.io),
16+
[Hongyu Ren](http://hyren.me/),
17+
[Jian Tang](https://jian-tang.com)
18+
19+
[paper]: https://arxiv.org/abs/2210.08008
20+
21+
## Overview ##
22+
23+
**Important: the camera-ready NeurIPS'22 version was identified to have datasets with possible test set leakages.
24+
The new version including this repository and updated Arxiv submission have new datasets and experiments where this
25+
issue has been fixed. We recommend to use the latest version of datasets ([2.0 on Zenodo][dataset]) and experiments ([v2 on arXiv][paper]) for further
26+
comparisons.**
27+
28+
[dataset]: https://zenodo.org/record/7306046
29+
30+
Inductive query answering is the setup where at inference time an underlying graph can have new, unseen entities.
31+
In this paper, we study a practical inductive setup when a training graph **is extended** with more nodes and edges
32+
at inference time. That is, an inference graph is always a superset of the training graph.
33+
Note that the inference graph always shares the same set of relation types with the training graph.
34+
35+
The two big implications of the inductive setup:
36+
* test queries involve new, unseen nodes where answers can be both seen and unseen nodes;
37+
* training queries now might have more answers among new nodes.
38+
39+
The two inductive approaches implemented in this repo:
40+
1. **NodePiece-QE** (Inductive node representations): based on [NodePiece](https://github.com/migalkin/NodePiece) and [CQD](https://github.com/pminervini/KGReasoning/).
41+
Train on 1p link prediction, **inference-only** zero-shot logical query answering over unseen entities.
42+
The NodePiece encoder can be extended with the additional GNN encoder (CompGCN) that is denoted as **NodePiece-QE w/ GNN** in the paper.
43+
2. **Inductive GNN-QE** (Inductive relational structure representations): based on [GNN-QE](https://github.com/DeepGraphLearning/GNN-QE).
44+
Trainable on complex queries, achieves higher performance than NodePiece-QE but is more expensive to train.
45+
46+
We additionally provide a dummy Edge-type Heuristic (`model.HeuristicBaseline`) that only considers possible tails of the last relation projection step of any query pattern.
47+
48+
## Data ##
49+
50+
We created 10 new inductive query answering datasets where validation/test graphs extend the training graph and contain new entities:
51+
* Small-scale: 9 datasets based on FB15k-237 with the ratio of *inference-to-train nodes* varies from 106% to 550%, total of 15k nodes for various splits.
52+
* Large-scale: 1 dataset based on OGB WikiKG2 with the fixed ratio of 133% and 1.5M training nodes but with 500K new nodes and 5M new edges at inference.
53+
54+
<details>
55+
<summary>Datasets Description</summary>
56+
57+
Each dataset is a zip archive containing 17 files:
58+
59+
* `train_graph.txt` (pt for wikikg) - original training graph
60+
* `val_inference.txt` (pt) - inference graph (validation split), new nodes in validation are disjoint with the test inference graph
61+
* `val_predict.txt` (pt) - missing edges in the validation inference graph to be predicted.
62+
* `test_inference.txt` (pt) - inference graph (test splits), new nodes in test are disjoint with the validation inference graph
63+
* `test_predict.txt` (pt) - missing edges in the test inference graph to be predicted.
64+
* `train/valid/test_queries.pkl` - queries of the respective split, 14 query types for fb-derived datasets, 9 types for WikiKG (EPFO-only)
65+
* `*_answers_easy.pkl` - easy answers to respective queries that do not require predicting missing links but only edge traversal
66+
* `*_answers_hard.pkl` - hard answers to respective queries that DO require predicting missing links and against which the final metrics will be computed
67+
* `train_answers_valid.pkl` - the extended set of answers for training queries on the bigger validation graph, most of training queries have at least 1 more new answers. This is supposed to be an inference-only dataset to measure faithfulness of trained models
68+
* `train_answers_test.pkl` - the extended set of answers for training queries on the bigger test graph, most of training queries have at least 1 more new answers. This is supposed to be an inference-only dataset to measure faithfulness of trained models
69+
* `og_mappings.pkl` - contains entity2id / relation2id dictionaries mapping local node/relation IDs from a respective dataset to the original fb15k237 / wikikg2
70+
* `stats.txt` - a small file with dataset stats
71+
</details>
72+
73+
All datasets are available on [Zenodo](https://zenodo.org/record/7306046), please refer to v2.0 of the datasets.
74+
The datasets will be downloaded automatically upon the first run.
75+
76+
Additionally, we provide lightweight dumps ([Zenodo](https://zenodo.org/record/7306061)) just of those graphs (without queries and answers) for training simple link prediction and KG completion models.
77+
Please refer to v2.0 of the datasets.
78+
79+
## Installation ##
80+
81+
The dependencies can be installed via either conda or pip. NodePiece-QE and GNN-QE are compatible
82+
with Python 3.7/3.8/3.9 and PyTorch >= 1.8.0.
83+
84+
### From Conda ###
85+
86+
```bash
87+
conda install torchdrug pytorch cudatoolkit -c milagraph -c pytorch -c pyg
88+
conda install pytorch-sparse pytorch-scatter -c pyg
89+
conda install easydict pyyaml -c conda-forge
90+
```
91+
92+
### From Pip ###
93+
94+
```bash
95+
pip install torchdrug torch
96+
pip install easydict pyyaml
97+
pip install wandb tensorboardx
98+
```
99+
100+
Then install `torch-scatter` and `torch-sparse` following the instructions in the [Github repo](https://github.com/rusty1s/pytorch_sparse).
101+
For example, for PyTorch 1.10 and CUDA 10.2:
102+
103+
```bash
104+
pip install torch-scatter torch-sparse -f https://data.pyg.org/whl/torch-1.10.0+cu102.html
105+
```
106+
107+
108+
## Usage ##
109+
110+
### NodePiece-QE ###
111+
112+
Conceptually, running NodePiece-QE consists of two parts:
113+
1. Training a neural link predictor using NodePiece (+ optional GNN), saving materialized embeddings of the test graph.
114+
2. Running CQD over the saved embeddings.
115+
116+
**Step 1: Training a Link Predictor**
117+
118+
Use the `NodePiece` model with the task `InductiveKnowledgeGraphCompletion` applied to the dataset of choice.
119+
120+
We prepared 5 configs for FB15k-237-derived datasets in the `config/lp_pretraining` directory, 2 for NodePiece w/o GNN
121+
and 3 for NodePiece w/ GNN, following the reported hyperparameters in the paper.
122+
`_550` configs have a higher `input_dim` so we decided to have a dedicated file for them to send less params to the
123+
training script.
124+
125+
We also provide 2 configs for the WikiKG graph and recommend running pre-training in the multi-gpu mode due to the size
126+
of the graph.
127+
128+
Example of training a vanilla NodePiece on the 175% dataset:
129+
130+
```bash
131+
python script/run.py -c config/lp_pretraining/nodepiece_nognn.yaml --ratio 175 --temp 0.5 --epochs 2000 --gpus [0] --logger console
132+
```
133+
134+
NodePiece + GNN on the 175% dataset:
135+
```bash
136+
python script/run.py -c config/lp_pretraining/nodepiece_gnn.yaml --ratio 175 --temp 1.0 --epochs 1000 --gpus [0] --logger console
137+
```
138+
139+
For datasets of ratios 106-150 use the 5-layer GNN config `config/lp_pretraining/nodepiece_gnn.yaml`.
140+
141+
* Use `--gpus null` to run the scripts on a CPU.
142+
* Use `--logger wandb` to send training logs to wandb, don't forget to prepend env variable `WANDB_ENTITY=(your_entity)`
143+
before executing the python script.
144+
145+
After training, materialized entity and relation embeddings of the test graph will be stored in the `output_dir` folder.
146+
147+
WikiKG training requires a vocabulary of mined NodePiece anchors, we ship a precomputed
148+
vocab `20000_anchors_d0.4_p0.4_r0.2_25sp_bfs.pkl` together with the `wikikg.zip` archive.
149+
You can mine your own vocab playing around with the `NodePieceTokenizer` -- mining is implemented on a GPU and
150+
should be much faster than the original NodePiece implementation.
151+
152+
An example WikiKG link prediction pre-training config should contain `--vocab` param to the mined vocab, e.g.,
153+
```bash
154+
python script/run.py -c config/lp_pretraining/wikikg_nodepiece_nognn.yaml --gpus [0] --vocab /path/to/pickle/vocab.pkl
155+
```
156+
157+
We highly recommend training both no-GNN and GNN versions of NodePiece on WikiKG using several GPUs, for example
158+
```bash
159+
python -m torch.distributed.launch --nproc_per_node=2 script/run.py -c config/lp_pretraining/wikikg_nodepiece_nognn.yaml --gpus [0,1] --vocab /path/to/pickle/vocab.pkl
160+
```
161+
162+
**Step 2: CQD Inference**
163+
164+
Use the pre-trained link predictor to run CQD inference over EPFO queries (negation is not supported in this version of CQD).
165+
166+
Example of running CQD on the pre-trained 200d NodePiece w/ GNN model over the 175% dataset
167+
* Note that we need to specify a 2x smaller embedding dimension of the training model as by default we train a
168+
ComplEx model with two parts - real and complex;
169+
* Use the full path to the **embeddings** of the pre-trained models, they are named smth like `/path/epoch_1000_ents`
170+
and `/path/epoch_1000_rels`, so just use the common prefix `/path/epoch_1000`.
171+
172+
```bash
173+
python cqd/main.py --cuda --do_test --data_path ./data/175 -d 100 -cpu 6 --log_steps 10000 --test_log_steps 10000 --geo cqd --print_on_screen --cqd-k 32 --cqd-sigmoid --tasks "1p.2p.3p.2i.3i.ip.pi.2u.up" --inductive --checkpoint_path /path/epoch_1000 --skip_tr
174+
```
175+
176+
To evaluate training queries on the bigger test graphs, use the argument `--eval_train`
177+
178+
```bash
179+
python cqd/main.py --cuda --do_test --data_path ./data/175 -d 100 -cpu 6 --log_steps 10000 --test_log_steps 10000 --geo cqd --print_on_screen --cqd-k 32 --cqd-sigmoid --tasks "1p.2p.3p.2i.3i.ip.pi.2u.up" --inductive --checkpoint_path /path/epoch_1000 --eval_train
180+
```
181+
182+
### GNN-QE ###
183+
184+
To train GNN-QE and evaluate on the valid/test queries and desired dataset ratio, use the `gnnqe_main.yaml` config.
185+
Example on the 175% dataset:
186+
187+
```bash
188+
python script/run.py -c config/complex_query/gnnqe_main.yaml --ratio 175 --gpus [0]
189+
```
190+
191+
Alternatively, you may specify `--gpus null` to run GNN-QE on a CPU.
192+
193+
The hyperparameters are designed for 32GB GPUs, but you may adjust the batch size in the config file
194+
to fit a smaller GPU memory.
195+
196+
To run GNN-QE with multiple GPUs or multiple machines, use the following commands
197+
198+
```bash
199+
python -m torch.distributed.launch --nproc_per_node=2 script/run.py -c config/complex_query/gnnqe_main.yaml --gpus [0,1]
200+
```
201+
202+
```bash
203+
python -m torch.distributed.launch --nnodes=4 --nproc_per_node=4 script/run.py -c config/complex_query/gnnqe_main.yaml --gpus [0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3]
204+
```
205+
206+
To evaluate training queries on the bigger test graphs, use the config `gnnqe_eval_train.yaml` and specify the
207+
checkpoint `--checkpoint` of the trained model. The best performing checkpoint is written in the log files after training the `main` config.
208+
For example, if the best performing 175% model is `model_epoch_1.pth` then the path will be:
209+
```bash
210+
python script/run.py -c config/complex_query/gnnqe_eval_train.yaml --ratio 175 --gpus [0] --checkpoint /path/to/model/model_epoch_1.pth
211+
```
212+
213+
### Heuristic Baseline ###
214+
215+
Finally, we provide configs for the inference-only rule-based heuristic baseline
216+
that only considers possible tails of the last relation projection step of any query pattern.
217+
The two configs are `config/complex_query/heuristic_main.yaml` and `config/complex_query/heuristic_eval_train.yaml`.
218+
219+
To run the baseline on test queries (for example, on the 175% dataset):
220+
221+
```bash
222+
python script/run.py -c config/complex_query/heuristic_main.yaml --ratio 175 --gpus [0]
223+
```
224+
225+
To run the baseline on train queries over bigger test graphs:
226+
```bash
227+
python script/run.py -c config/complex_query/heuristic_eval_train.yaml --ratio 175 --gpus [0]
228+
```
229+
230+
## Citation ##
231+
232+
If you find this project useful in your research, please cite the following paper
233+
234+
```bibtex
235+
@inproceedings{galkin2022inductive,
236+
title={Inductive Logical Query Answering in Knowledge Graphs},
237+
author={Mikhail Galkin and Zhaocheng Zhu and Hongyu Ren and Jian Tang},
238+
booktitle={Advances in Neural Information Processing Systems},
239+
year={2022},
240+
url={https://openreview.net/forum?id=-vXEN5rIABY}
241+
}
242+
```

asset/inductive_qe.gif

3.27 MB
Loading
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
output_dir: .~/git/InductiveQE/experiments
2+
3+
dataset:
4+
class: InductiveFB15k237CompExtendedEval # special task to evaluate train queries on the bigger test graph
5+
path: ~/git/InductiveQE/data
6+
ratio: {{ ratio }} # specify dataset ratio here or when running the script
7+
8+
task:
9+
class: InductiveLogicalQuery
10+
model:
11+
class: GNN-QE
12+
model:
13+
class: NBFNet
14+
input_dim: 32 # Hyperparams from Table 14 (Appendix D of the paper)
15+
hidden_dims: [32, 32, 32, 32]
16+
message_func: distmult
17+
aggregate_func: pna
18+
short_cut: yes
19+
layer_norm: yes
20+
dependent: yes
21+
logic: product
22+
dropout_ratio: 0.5
23+
criterion: bce
24+
sample_weight: no
25+
adversarial_temperature: 0.1
26+
27+
optimizer:
28+
class: Adam
29+
lr: 5.0e-3
30+
31+
engine:
32+
gpus: {{ gpus }}
33+
batch_size: 64 # reduce if doesn't fit on a GPU
34+
35+
train:
36+
num_epoch: 0 # no training, just run the inference
37+
batch_per_epoch: 1000 # number of batches to be considered as "one epoch"
38+
39+
checkpoint: {{ checkpoint }} # path to the checkpoint of the trained model
40+
metric: mrr
41+
skip_eval_on_train: False # here, we do run evaluation of train queries on training and test graphs
42+
save_embs: False # doesn't work for GNN-QE as it saves its checkpoints automatically

config/complex_query/gnnqe_main.yaml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
output_dir: ~/git/InductiveQE/experiments
2+
3+
dataset:
4+
class: InductiveFB15k237Comp
5+
path: ~/git/InductiveQE/data
6+
ratio: {{ ratio }} # specify dataset ratio here or when running the script
7+
8+
task:
9+
class: InductiveLogicalQuery
10+
model:
11+
class: GNN-QE
12+
model:
13+
class: NBFNet
14+
input_dim: 32 # Hyperparams from Table 14 (Appendix D of the paper)
15+
hidden_dims: [32, 32, 32, 32]
16+
message_func: distmult
17+
aggregate_func: pna
18+
short_cut: yes
19+
layer_norm: yes
20+
dependent: yes
21+
logic: product
22+
dropout_ratio: 0.5
23+
criterion: bce
24+
sample_weight: no
25+
adversarial_temperature: 0.1
26+
27+
optimizer:
28+
class: Adam
29+
lr: 5.0e-3
30+
31+
engine:
32+
gpus: {{ gpus }}
33+
batch_size: 64 # reduce if doesn't fit on a GPU
34+
35+
train:
36+
num_epoch: 10 # total number of optimization steps will be num_epochs * batch_per_epoch
37+
batch_per_epoch: 1000 # number of batches to be considered as "one epoch"
38+
39+
metric: mrr
40+
fast_test: 1000 # GNN-QE is slow in inference, use this option for a random subsample of valid data
41+
skip_eval_on_train: True # do not run evaluation on the training data, use the gnnqe_eval_train config instead
42+
save_embs: False # doesn't work for GNN-QE as it saves its checkpoints automatically
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
output_dir: ~/git/InductiveQE/experiments
2+
3+
dataset:
4+
class: InductiveFB15k237CompExtendedEval
5+
path: ~/git/InductiveQE/data
6+
ratio: {{ ratio }}
7+
8+
task:
9+
class: InductiveLogicalQuery
10+
model:
11+
class: HeuristicBaseline
12+
inverse_mode: "2x"
13+
criterion: bce
14+
sample_weight: no
15+
adversarial_temperature: 0.1
16+
17+
optimizer:
18+
class: Adam
19+
lr: 5.0e-3
20+
21+
engine:
22+
gpus: {{ gpus }}
23+
batch_size: 512
24+
25+
train:
26+
num_epoch: 0 # Heuristic baseline doesn't need any training
27+
batch_per_epoch: 0
28+
29+
metric: mrr
30+
skip_eval_on_train: True # We run inference directly on the bigger test graph
31+
save_embs: False
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
output_dir: ~/git/InductiveQE/experiments
2+
3+
dataset:
4+
class: InductiveFB15k237Comp
5+
path: ~/git/InductiveQE/data
6+
ratio: {{ ratio }}
7+
8+
task:
9+
class: InductiveLogicalQuery
10+
model:
11+
class: HeuristicBaseline
12+
inverse_mode: "2x"
13+
criterion: bce
14+
sample_weight: no
15+
adversarial_temperature: 0.1
16+
17+
optimizer:
18+
class: Adam
19+
lr: 5.0e-3
20+
21+
engine:
22+
gpus: {{ gpus }}
23+
batch_size: 512
24+
25+
train:
26+
num_epoch: 0 # Heuristic baseline doesn't need any training
27+
batch_per_epoch: 0
28+
29+
metric: mrr
30+
skip_eval_on_train: True # No eval on train queries needed here
31+
save_embs: False

0 commit comments

Comments
 (0)