Graph Convolutional Memory using Topological Priors
Description
Graph convolutional memory (GCM) is graph-structured memory that may be applied to reinforcement learning to solve POMDPs, replacing LSTMs or attention mechanisms. GCM allows you to embed your domain knowledge in the form of connections in a graph. See the full paper for further details. This repo contains the GCM library implementation for use in your projects. To replicate the experiments from the paper, please see this repository instead.
If you use GCM, please cite the paper!
@article{morad2021graph,
title={Graph Convolutional Memory using Topological Priors},
author={Morad, Steven D and Liwicki, Stephan and Kortvelesy, Ryan and Mecca, Roberto and Prorok, Amanda},
journal={arXiv preprint arXiv:2106.14117},
year={2021}
}
Installation
GCM is installed using pip
. The dependencies must be installed manually, as they target your specific architecture (with or without CUDA).
Conda install
First install torch >= 1.8.0
and torch-geometric
dependencies, then gcm
:
conda install torch
conda install pytorch-geometric -c rusty1s -c conda-forge
pip install graph-conv-memory
Pip install
Please follow the torch-geometric install guide, then
pip install graph-conv-memory
Quickstart
Below is a quick example of how to use GCM in a basic RL problem:
import torch
import torch_geometric
from gcm.gcm import DenseGCM
from gcm.edge_selectors.temporal import TemporalBackedge
graph_size = 128
class GNN(torch.nn.Module):
"""A simple two-layer graph neural network"""
def __init__(self, obs_size, hidden_size=32):
super().__init__()
self.gc0 = torch_geometric.nn.DenseGraphConv(obs_size, hidden_size)
self.gc1 = torch_geometric.nn.DenseGraphConv(hidden_size, hidden_size)
self.act = torch.nn.Tanh()
def forward(self, x, adj, weights, B, N):
x = self.act(self.gc0(x, adj))
return self.act(self.gc1(x, adj))
obs_size = 8
gnn = GNN(obs_size)
gcm = DenseGCM(gnn, edge_selectors=TemporalBackedge([1]), graph_size=graph_size)
m_t = None
for t in train_timestep:
belief, m_t = gcm(obs, m_t)
action_logits = logits_nn(belief)
state_value = vf_nn(belief)
We provide a few edge selectors, which we briefly detail here:
gcm.edge_selectors.temporal.TemporalBackedge
gcm.edge_selectors.dense.DenseEdge
gcm.edge_selectors.distance.EuclideanEdge
gcm.edge_selectors.distance.CosineEdge
gcm.edge_selectors.distance.SpatialEdge
gcm.edge_selectors.learned.LearnedEdge
Ray Quickstart (WIP)
We provide a ray rllib wrapper around GCM, see the example below for how to use it
import unittest
import torch
import torch_geometric
import ray
from ray import tune
from gcm.ray_gcm import RayDenseGCM
from gcm.edge_selectors.temporal import TemporalBackedge
class GNN(torch.nn.Module):
"""A simple two-layer graph neural network"""
def __init__(self, obs_size, hidden_size=32):
super().__init__()
self.gc0 = torch_geometric.nn.DenseGraphConv(obs_size, hidden_size)
self.gc1 = torch_geometric.nn.DenseGraphConv(hidden_size, hidden_size)
self.act = torch.nn.Tanh()
def forward(self, x, adj, weights, B, N):
x = self.act(self.gc0(x, adj))
return self.act(self.gc1(x, adj))
ray.init(
local_mode=True,
object_store_memory=3e10,
)
input_size = 16
hidden_size = 32
cfg = {
"framework": "torch",
"num_gpus": 0,
"env": "CartPole-v0",
"num_workers": 0,
"model": {
"custom_model": RayDenseGCM,
"custom_model_config": {
"graph_size": 20,
"gnn_input_size": input_size,
"gnn_output_size": hidden_size,
"gnn": GNN(input_size),
"edge_selectors": TemporalBackedge([1]),
"edge_weights": False,
}
}
}
tune.run(
"A2C",
config=cfg,
stop={"info/num_steps_trained": 100}
)