Skip to content

Correct and Smooth on Cora

Author: K3-Node Team
Backend: Multi-Backend
Dataset: Cora (Planetoid)
Description: Classify papers in the Cora citation network by topic in two stages (Huang et al., 2020).

View in Colab   GitHub source


Correct and Smooth on Cora

Classify papers in the Cora citation network by topic in two stages (Huang et al., 2020). First, a plain MLP predicts each paper's topic from its own features only. Then Correct and Smooth uses the graph without any training: it spreads the MLP's errors on the labeled papers to their neighbors ("correct"), and then smooths the predictions over the graph ("smooth").

Same model as PyG's examples/correct_and_smooth.py; on Cora instead of ogbn-products to keep the dataset small, trained for 200 epochs instead of 300.

Install K3-Node, then choose a backend: "tensorflow", "torch" or "jax"

!pip install k3-node[examples]
import os
os.environ["KERAS_BACKEND"] = "tensorflow"

Load the data

data holds one graph: node features x, edges edge_index, labels y, and masks marking the training, validation and test nodes.

import keras
from keras import ops
from k3_node.datasets import Planetoid
from k3_node.loader import FullGraphDataset

dataset = Planetoid("data/Planetoid", name="Cora")
data = dataset[0]
print(data)

Train a plain MLP

The MLP ignores the graph and looks only at each paper's words.

from k3_node.models import MLP, CorrectAndSmooth


class MLPClassifier(keras.Model):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.mlp = MLP([in_channels, 200, 200, out_channels], dropout=0.5, norm="batch_norm", act_first=True)

    def call(self, data, training=False):
        return self.mlp(data.x, training=training)


model = MLPClassifier(dataset.num_features, dataset.num_classes)
model.compile(
    optimizer=keras.optimizers.Adam(learning_rate=0.01),
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    weighted_metrics=["accuracy"],
)
model.fit(FullGraphDataset(data, mask="train_mask"), epochs=200, verbose=0)
y_soft = ops.softmax(model.predict(FullGraphDataset(data), verbose=0))
print(f"MLP test accuracy: {data.accuracy(y_soft, mask='test_mask'):.4f}")

Correct and smooth

No training here: both steps propagate information along the citation links.

post = CorrectAndSmooth(num_correction_layers=50, correction_alpha=1.0,
                        num_smoothing_layers=50, smoothing_alpha=0.8, autoscale=False, scale=20.0)
y_soft = post.correct(y_soft, data.y, data.train_mask, data.edge_index)
y_soft = post.smooth(y_soft, data.y, data.train_mask, data.edge_index)
print(f"Test accuracy after Correct and Smooth: {data.accuracy(y_soft, mask='test_mask'):.4f}")