IF YOU WOULD LIKE TO GET AN ACCOUNT, please write an email to s dot adaszewski at gmail dot com. User accounts are meant only to report issues and/or generate pull requests. This is a purpose-specific Git hosting for ADARED projects. Thank you for your understanding!
Browse Source

Start working on fastconv.

master
Stanislaw Adaszewski 4 years ago
parent
commit
36fe246ff1
1 changed files with 110 additions and 0 deletions
  1. +110
    -0
      src/icosagon/fastconv.py

+ 110
- 0
src/icosagon/fastconv.py View File

@@ -0,0 +1,110 @@
from typing import List, \
Union, \
Callable
from .data import Data
from .trainprep import PreparedData
import torch
from .weights import init_glorot
class FastConvLayer(torch.nn.Module):
adjacency_matrix: List[torch.Tensor]
adjacency_matrix_backward: List[torch.Tensor]
weight: List[torch.Tensor]
weight_backward: List[torch.Tensor]
def __init__(self,
input_dim: List[int],
output_dim: List[int],
data: Union[Data, PreparedData],
keep_prob: float = 1.,
rel_activation: Callable[[torch.Tensor], torch.Tensor] = lambda x: x
layer_activation: Callable[[torch.Tensor], torch.Tensor] = torch.nn.functional.relu,
**kwargs):
super().__init__(**kwargs)
self._check_params(input_dim, output_dim, data, keep_prob,
rel_activation, layer_activation)
self.input_dim = input_dim
self.output_dim = output_dim
self.data = data
self.keep_prob = keep_prob
self.rel_activation = rel_activation
self.layer_activation = layer_activation
self.adjacency_matrix = None
self.adjacency_matrix_backward = None
self.weight = None
self.weight_backward = None
self.build()
def build(self):
self.adjacency_matrix = []
self.adjacency_matrix_backward = []
self.weight = []
self.weight_backward = []
for fam in self.data.relation_families:
adj_mat = [ rel.adjacency_matrix \
for rel in fam.relation_types \
if rel.adjacency_matrix is not None ]
adj_mat_back = [ rel.adjacency_matrix_backward \
for rel in fam.relation_types \
if rel.adjacency_matrix_backward is not None ]
weight = [ init_glorot(self.input_dim[fam.node_type_column],
self.output_dim[fam.node_type_row]) \
for _ in range(len(adj_mat)) ]
weight_back = [ init_glorot(self.input_dim[fam.node_type_column],
self.output_dim[fam.node_type_row]) \
for _ in range(len(adj_mat_back)) ]
adj_mat = torch.cat(adj_mat) \
if len(adj_mat) > 0 \
else None
adj_mat_back = torch.cat(adj_mat_back) \
if len(adj_mat_back) > 0 \
else None
self.adjacency_matrix.append(adj_mat)
self.adjacency_matrix_backward.append(adj_mat_back)
self.weight.append(weight)
self.weight_back.append(weight_back)
def forward(self, prev_layer_repr):
for i, fam in enumerate(self.data.relation_families):
repr_row = prev_layer_repr[fam.node_type_row]
repr_column = prev_layer_repr[fam.node_type_column]
adj_mat = self.adjacency_matrix[i]
adj_mat_back = self.adjacency_matrix_backward[i]
if adj_mat is not None:
x = dropout(repr_column, keep_prob=self.keep_prob)
x = torch.sparse.mm(x, self.weight[i]) \
if x.is_sparse \
else torch.mm(x, self.weight[i])
x = torch.sparse.mm(adj_mat, repr_row) \
if adj_mat.is_sparse \
else torch.mm(adj_mat, repr_row)
x = self.rel_activation(x)
x = x.view(len(fam.relation_types), len(repr_row), -1)
if adj_mat_back is not None:
x = torch.sparse.mm(adj_mat_back, repr_row) \
if adj_mat_back.is_sparse \
else torch.mm(adj_mat_back, repr_row)
@staticmethod
def _check_params(input_dim, output_dim, data, keep_prob,
rel_activation, layer_activation):
if not isinstance(input_dim, list):
raise ValueError('input_dim must be a list')
if not output_dim:
raise ValueError('output_dim must be specified')
if not isinstance(output_dim, list):
output_dim = [output_dim] * len(data.node_types)
if not isinstance(data, Data) and not isinstance(data, PreparedData):
raise ValueError('data must be of type Data or PreparedData')

Loading…
Cancel
Save