Skip to content

Commit

Permalink
do_forward -> train_step and test_step;fix some typos
Browse files Browse the repository at this point in the history
  • Loading branch information
EdisonLeeeee committed Aug 20, 2020
1 parent 7b74d97 commit 5bf82a5
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 59 deletions.
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,25 +109,32 @@ Otherwise you can also use `model.show('model')` or `model.show('train')` to sho
NOTE: you should install texttable first.

## Visualization
NOTE: you must install [SciencePlots](https://github.com/garrettj403/SciencePlots) package for a better preview.
+ Accuracy
```python
import matplotlib.pyplot as plt
plt.plot(his.history['acc'])
plt.plot(his.history['val_acc'])
plt.legend(['Accuracy', 'Val Accuracy'])
plt.xlabel('Epochs')
plt.show()
with plt.style.context(['science', 'no-latex']):
plt.plot(his.history['acc'])
plt.plot(his.history['val_acc'])
plt.legend(['Train Accuracy', 'Val Accuracy'])
plt.ylabel('Accuracy')
plt.xlabel('Epochs')
plt.autoscale(tight=True)
plt.show()
```
![visualization](https://github.com/EdisonLeeeee/GraphGallery/blob/master/imgs/visualization_acc.png)

+ Loss
```python
import matplotlib.pyplot as plt
plt.plot(his.history['loss'])
plt.plot(his.history['val_loss'])
plt.legend(['Loss', 'Val Loss'])
plt.xlabel('Epochs')
plt.show()
with plt.style.context(['science', 'no-latex']):
plt.plot(his.history['loss'])
plt.plot(his.history['val_loss'])
plt.legend(['Train Loss', 'Val Loss'])
plt.ylabel('Loss')
plt.xlabel('Epochs')
plt.autoscale(tight=True)
plt.show()
```
![visualization](https://github.com/EdisonLeeeee/GraphGallery/blob/master/imgs/visualization_loss.png)

Expand Down
2 changes: 1 addition & 1 deletion graphgallery/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
from graphgallery import data


__version__ = '0.1.9'
__version__ = '0.1.10'

__all__ = ['graphgallery', 'nn', 'utils', 'sequence', 'data', '__version__']
23 changes: 13 additions & 10 deletions graphgallery/nn/models/basemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
import random
import logging

import os.path as osp
import numpy as np
import tensorflow as tf
import scipy.sparse as sp

from graphgallery import config, check_and_convert, asintarr, Bunch
from graphgallery.utils.type_check import is_list_like
from graphgallery.utils.misc import print_table
from graphgallery.data.utils import makedirs



class BaseModel:
Expand Down Expand Up @@ -97,8 +100,8 @@ def __init__(self, adj, x, labels=None, device="CPU:0", seed=None, name=None, **
self.__sparse = is_adj_sparse

# log path
self.weight_dir = "/tmp/weight"
self.weight_path = f"{self.weight_dir}/{name}_weights"
self.weight_dir = osp.expanduser(osp.normpath("/tmp/weight"))
self.weight_path = osp.join(self.weight_dir, f"{name}_weights")

# data types, default: `float32` and `int64`
self.floatx = config.floatx()
Expand Down Expand Up @@ -170,20 +173,19 @@ def _check_inputs(self, adj, x):
raise RuntimeError(f"The adjacency matrix should be N by N square matrix.")
return adj, x

@property
def model(self):
return self.__model

################### TODO: This may cause ERROR #############
def __getattr__(self, attr):
################### TODO: This may cause ERROR #############
try:
return self.__dict__[attr]
except KeyError:
if hasattr(self.model, attr):
return getattr(self.model, attr)
raise AttributeError(f"'{self.name}' and '{self.name}.model' objects have no attribute '{attr}'")


@property
def model(self):
return self.__model

@model.setter
def model(self, m):
# Back up
Expand All @@ -194,8 +196,8 @@ def model(self, m):


def save(self, path=None, as_model=False):
if not os.path.exists(self.weight_dir):
os.makedirs(self.weight_dir)
if not osp.exists(self.weight_dir):
makedirs(self.weight_dir)
logging.log(logging.WARNING, f"Make Directory in {self.weight_dir}")

if path is None:
Expand All @@ -216,6 +218,7 @@ def save(self, path=None, as_model=False):
def load(self, path=None, as_model=False):
if not path:
path = self.weight_path

if not path.endswith('.h5'):
path += '.h5'
if as_model:
Expand Down
19 changes: 2 additions & 17 deletions graphgallery/nn/models/semisupervised/sbvat.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,6 @@ def build(self, hiddens=[16], activations=['relu'], dropouts=[0.5],
self.epsilon = epsilon # Norm length for (virtual) adversarial training
self.n_power_iterations = n_power_iterations # Number of power iterations

# def propagation(self, x, adj, training=True):
# h = x
# for layer in self.GCN_layers:
# h = self.dropout_layer(h, training=training)
# h = layer([h, adj])
# return h

def propagation(self, x, adj, training=True):
h = x
for dropout_layer, GCN_layer in zip(self.dropout_layers, self.GCN_layers[:-1]):
Expand All @@ -145,7 +138,7 @@ def propagation(self, x, adj, training=True):
return h

@tf.function
def do_train_forward(self, sequence):
def train_step(self, sequence):

with tf.device(self.device):
self.train_metric.reset_states()
Expand All @@ -171,7 +164,7 @@ def do_train_forward(self, sequence):
return loss, self.train_metric.result()

@tf.function
def do_test_forward(self, sequence):
def test_step(self, sequence):

with tf.device(self.device):
self.test_metric.reset_states()
Expand All @@ -186,14 +179,6 @@ def do_test_forward(self, sequence):

return loss, self.test_metric.result()

def do_forward(self, sequence, training=True):
if training:
loss, accuracy = self.do_train_forward(sequence)
else:
loss, accuracy = self.do_test_forward(sequence)

return loss.numpy(), accuracy.numpy()

def virtual_adversarial_loss(self, x, adj, logit, adv_mask):
d = tf.random.normal(shape=tf.shape(x), dtype=self.floatx)

Expand Down
64 changes: 45 additions & 19 deletions graphgallery/nn/models/semisupervised/semi_supervised_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def train_v1(self, idx_train, idx_val=None,
if self.do_before_train:
self.do_before_train()

loss, accuracy = self.do_forward(train_data)
loss, accuracy = self.train_step(train_data)
train_data.on_epoch_end()

history.add_results(loss, 'loss')
Expand All @@ -230,7 +230,7 @@ def train_v1(self, idx_train, idx_val=None,
if self.do_before_validation:
self.do_before_validation()

val_loss, val_accuracy = self.do_forward(val_data, training=False)
val_loss, val_accuracy = self.test_step(val_data)

history.add_results(val_loss, 'val_loss')
history.add_results(val_accuracy, 'val_acc')
Expand Down Expand Up @@ -409,7 +409,7 @@ def train(self, idx_train, idx_val=None,
self.do_before_train()

callbacks.on_train_batch_begin(0)
loss, accuracy = self.do_forward(train_data)
loss, accuracy = self.train_step(train_data)
train_data.on_epoch_end()

training_logs = {'loss': loss, 'acc': accuracy}
Expand All @@ -419,7 +419,7 @@ def train(self, idx_train, idx_val=None,
if self.do_before_validation:
self.do_before_validation()

val_loss, val_accuracy = self.do_forward(val_data, training=False)
val_loss, val_accuracy = self.test_step(val_data)
training_logs.update({'val_loss': val_loss, 'val_acc': val_accuracy})

callbacks.on_epoch_end(epoch, training_logs)
Expand Down Expand Up @@ -584,7 +584,7 @@ def train_v2(self, idx_train, idx_val=None,
self.do_before_train()

callbacks.on_train_batch_begin(0)
loss, accuracy = self.do_forward(train_data)
loss, accuracy = self.train_step(train_data)
train_data.on_epoch_end()

training_logs = {'loss': loss, 'acc': accuracy}
Expand All @@ -594,7 +594,7 @@ def train_v2(self, idx_train, idx_val=None,
if self.do_before_validation:
self.do_before_validation()

val_loss, val_accuracy = self.do_forward(val_data, training=False)
val_loss, val_accuracy = self.test_step(val_data)
training_logs.update({'val_loss': val_loss, 'val_acc': val_accuracy})

callbacks.on_epoch_end(epoch, training_logs)
Expand Down Expand Up @@ -650,16 +650,15 @@ def test(self, index, **kwargs):
if self.do_before_test:
self.do_before_test(**kwargs)

loss, accuracy = self.do_forward(test_data, training=False)
loss, accuracy = self.test_step(test_data)

return loss, accuracy

def do_forward(self, sequence, training=True):
def train_step(self, sequence):
"""
Forward propagation for the input `sequence`. This method will be called
in `train` and `test`, you can rewrite it for you customized training/testing
process. If you want to specify your customized data during traing/testing/predicting,
you can implement a sub-class of `graphgallery.NodeSequence`, wich is iterable
in `train`. If you want to specify your customized data during traing/testing/predicting,
you can implement a subclass of `graphgallery.NodeSequence`, wich is iterable
and yields `inputs` and `labels` in each iteration.
Expand All @@ -672,8 +671,6 @@ def do_forward(self, sequence, training=True):
----------
sequence: `graphgallery.NodeSequence`
The input `sequence`.
trainng (Boolean, optional):
Indicating training or test procedure. (default: :obj:`True`)
Return:
----------
Expand All @@ -684,20 +681,49 @@ def do_forward(self, sequence, training=True):
"""
model = self.model
model.reset_metrics()

if training:
forward_fn = model.train_on_batch
else:
forward_fn = model.test_on_batch
with tf.device(self.device):
for inputs, labels in sequence:
loss, accuracy = model.train_on_batch(x=inputs, y=labels, reset_metrics=False)

return loss, accuracy

def test_step(self, sequence):
"""
Forward propagation for the input `sequence`. This method will be called
in `test`. If you want to specify your customized data during traing/testing/predicting,
you can implement a subclass of `graphgallery.NodeSequence`, wich is iterable
and yields `inputs` and `labels` in each iteration.
Note:
----------
You must compile your model before training/testing/predicting.
Use `model.build()`.
Arguments:
----------
sequence: `graphgallery.NodeSequence`
The input `sequence`.
Return:
----------
loss: Float scalar
Output loss of forward propagation.
accuracy: Float scalar
Output accuracy of prediction.
"""
model = self.model
model.reset_metrics()

with tf.device(self.device):
for inputs, labels in sequence:
loss, accuracy = forward_fn(x=inputs, y=labels, reset_metrics=False)
loss, accuracy = model.test_on_batch(x=inputs, y=labels, reset_metrics=False)

return loss, accuracy

def predict(self, index, **kwargs):
"""
Predict the output probability for the `index` of nodes.
Expand Down
13 changes: 11 additions & 2 deletions graphgallery/nn/models/semisupervised/sgc.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,19 @@ def preprocess(self, adj, x):
if self.norm_x:
x = normalize_x(x, norm=self.norm_x)

# InvalidArgumentError: Cannot use GPU when output.shape[1] * nnz(a) > 2^31 [Op:SparseTensorDenseMatMul]
with tf.device(self.device):

# To avoid this tensorflow error in large dataset:
# InvalidArgumentError: Cannot use GPU when output.shape[1] * nnz(a) > 2^31 [Op:SparseTensorDenseMatMul]
if self.n_features*adj.nnz>2**31:
device = "CPU"
else:
device = self.device

with tf.device(device):
x, adj = astensors([x, adj])
x = SGConvolution(order=self.order)([x, adj])

with tf.device(self.device):
self.x_norm, self.adj_norm = x, adj

def build(self, lr=0.2, l2_norms=[5e-5], use_bias=True):
Expand Down
Binary file modified imgs/visualization_acc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified imgs/visualization_loss.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5bf82a5

Please sign in to comment.