<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Rajanie Prabha on Medium]]></title>
        <description><![CDATA[Stories by Rajanie Prabha on Medium]]></description>
        <link>https://medium.com/@rajanieprabha?source=rss-9d9f7143632f------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*Er0e5eXl8hbt6bnq.</url>
            <title>Stories by Rajanie Prabha on Medium</title>
            <link>https://medium.com/@rajanieprabha?source=rss-9d9f7143632f------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 25 Jun 2026 06:24:14 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@rajanieprabha/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Graph Analysis Made Easy with PyG Explainability]]></title>
            <link>https://medium.com/stanford-cs224w/graph-analysis-made-easy-with-pyg-explainability-e3d3e3357dcc?source=rss-9d9f7143632f------2</link>
            <guid isPermaLink="false">https://medium.com/p/e3d3e3357dcc</guid>
            <category><![CDATA[explainable-ai]]></category>
            <category><![CDATA[graph-machine-learning]]></category>
            <dc:creator><![CDATA[Rajanie Prabha]]></dc:creator>
            <pubDate>Sun, 14 May 2023 05:03:50 GMT</pubDate>
            <atom:updated>2023-05-14T05:03:50.769Z</atom:updated>
            <content:encoded><![CDATA[<p>By: Anh Hoang Nguyen, Rajanie Prabha, Kevin Su as part of the Stanford CS224W course project.</p><p>Greetings, fellow graph enthusiasts! Do you want to understand why your GNN is doing what it’s doing, without having to resort to mind-reading or witchcraft? Probably staring at your model for a really long time works. In case that doesn’t give you the ‘why’ of things, you can resort to the Pytorch Geometric Explainability module. Please refer to the <a href="https://colab.research.google.com/drive/160vqAARqWkhU86zk2-RcupVmPL_ygA3_?authuser=0#scrollTo=CkTE6C9wmeTL">Colab</a> for the full code!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/988/0*lPL37UadJc2-zR2N" /></figure><p>Quick outline of the blog:</p><ul><li>First, we train a GNN model on the node property prediction task using the <a href="https://ogb.stanford.edu/docs/nodeprop/#ogbn-arxiv">ogbn-arxiv</a> dataset</li><li>Then, we’ll use PyG’s explainability module to apply the <a href="https://pytorch-geometric.readthedocs.io/en/latest/generated/torch_geometric.explain.algorithm.GNNExplainer.html#torch_geometric.explain.algorithm.GNNExplainer">GNNExplainer</a> algorithm (<a href="https://arxiv.org/pdf/1903.03894.pdf">Ying et al. 2019)</a> on explaining this model’s predictions as well as how to visualize the explanation result</li><li>Talk about Explanation evaluation metrics</li><li>Take a closer look at PyG’s implementation of the GNNExplainer algorithm</li></ul><h4>Why AI Explainability Matters: Trust, Ethics, and Accountability</h4><p>Explainability in Machine Learning is an ongoing effort in the research community. In traditional machine learning pipelines, neural networks are often viewed as black boxes that learn arbitrary non-linear functions that optimize certain objective functions. Many issues can arise, however, because there are no guarantees that neural networks actually perform the task that it was optimized to do. Unwanted behavior can creep into neural networks from bad data, or from artifacts of the inductive bias of the network. The field of machine learning explainability aims to build trust and transparency in models by providing important context for the reasons why a machine learning model made predictions.</p><p>The <a href="https://www.pyg.org/">PyG</a> community has been actively working on an explainability framework along with many benchmark datasets, evaluation methods, etc., to start exploring the world of interpretability in Graph Machine Learning.</p><h3><strong>What PyG’s Explainability Module Can Do:</strong></h3><p>PyG’s explainability module provides several tools for gaining insights into the decision-making processes of GNNs. The PyTorch Geometric <a href="https://pytorch-geometric.readthedocs.io/en/latest/tutorial/explain.html">explainability module</a> provides a powerful set of tools for understanding how our models are making decisions based on graphs. By providing detailed visualizations and explanations of the decision-making process, we can gain a deeper understanding of the inner workings of our models and make more informed decisions about how to improve them.</p><h4>The Explainability Toolset</h4><p>The PyG Explainability module has four main parts:</p><ol><li><a href="https://pytorch-geometric.readthedocs.io/en/latest/modules/explain.html"><strong>Explainer</strong></a><strong>: </strong>Class for instance-level explanations of GNNs. Explainer is the centerpiece of the Explainability module. On a high level, it takes in:</li></ol><ul><li>a model to explain,</li><li>explanation configurations, and</li><li>an explainability algorithm (represented by <a href="https://pytorch-geometric.readthedocs.io/en/latest/generated/torch_geometric.explain.algorithm.ExplainerAlgorithm.html#torch_geometric.explain.algorithm.ExplainerAlgorithm">ExplainerAlgorithm</a> class). The output of this class is an explanation wrapped in the <a href="https://pytorch-geometric.readthedocs.io/en/latest/modules/explain.html#explanations">Explanation</a> class.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/786/0*GgU_vQI4gP_gbbKT" /><figcaption>High-level overview of the PyG Explainability framework [Credits: <a href="https://medium.com/@pytorch_geometric/graph-machine-learning-explainability-with-pyg-ff13cffc23c2">https://medium.com/@pytorch_geometric/graph-machine-learning-explainability-with-pyg-ff13cffc23c2</a>]</figcaption></figure><p><strong>2. Explanations</strong>: The <a href="https://pytorch-geometric.readthedocs.io/en/latest/modules/explain.html#explanations">Explanation</a> class is a type of Data or HeteroData object that holds masks for different components of the graph data such as nodes, edges, and features, along with their attributes. With the help of the Explanation class, one can extract the induced explanation subgraph, which consists of non-zero explanation attributions, and the complement to the explanation subgraph. The class also provides methods for thresholding and visualizing the explanation.</p><p><strong>3. Algorithms: </strong>An abstract base class for implementing explainer algorithms. We plan to use GNNExplainer to explain the reasons for model recommendations trained on the ogbn-arxiv dataset. Given a trained model and a prediction, GNNExplainer identifies a subgraph structure and a subset of node features that are most influential for the prediction.</p><p><strong>4. Explanation Metrics:</strong> Metrics to judge the quality of explanations [Explained later in detail].</p><h3><strong>Okay, but how do these interpretations work?</strong></h3><p>In the context of GNNs, an “explanation” refers to a subset of the original graph that is represented as a mask or subgraph. This subset consists of weighted nodes, edges, and possibly node features, and the weights assigned to these entities reflect their relative significance in explaining the model’s results.</p><p>More formally, we can define our problem as follows.</p><p>Let <strong><em>G = (V, E)</em></strong> represent a graph with <strong>|𝑉 |</strong><em> </em>nodes and <strong>|𝐸| </strong>edges. Each node can have d-dimensional features. Also, we can treat our GNN model as a function <strong><em>f: V → Y</em></strong> where in the context of node classification, <strong><em>Y</em></strong> is the finite set of possible labels.</p><p>Our explanation for the prediction class <strong><em>𝑦ₜ</em></strong> of a target node <strong><em>𝑣ₜ</em></strong> will consist of an edge mask <strong>M_E(𝐸, 𝑓, 𝑣ₜ, 𝑦ₜ) ∊ℝ|𝑉|×|𝑉|</strong> and for a complex model<em>, </em>the node feature mask <strong>M_NF(V, 𝑓, 𝑣ₜ, 𝑦ₜ) ∊ℝ|𝑉|×d</strong> where each element is an importance score of that edge or node feature to the prediction. The importance score (sometimes also referred to as the weight) lies in the range [0,1] for soft masking, and {0,1} for hard masking.</p><p>(See <a href="https://arxiv.org/pdf/2206.09677.pdf">Amara et al. (2022)</a> for more details)</p><h3>Dataset <em>ogbn-arxi</em>v: Scholarly Network Exploration</h3><p>Let’s unlock the secrets of scholarly communication networks. The <a href="https://ogb.stanford.edu/docs/nodeprop/#ogbn-arxiv">ogbn-arxiv</a> dataset, an Open Graph Benchmark (OBG) dataset, provides a wealth of graph data that can be used to gain valuable insight into the world of research papers and their references. With millions of nodes and edges, this dataset offers a unique opportunity to understand the relationships and patterns of scholarly work.</p><p>Each paper is represented as a node, and each edge between nodes represents a citation relationship, where one paper cites another. The dataset also includes a 128-dimensional feature vector for each paper, which is created by averaging the embeddings of words in the paper’s title and abstract. The word embeddings are generated using the skip-gram model applied over the <a href="https://direct.mit.edu/qss/article/1/1/396/15572/Microsoft-Academic-Graph-When-experts-are-not">MAG</a> corpus. The dataset contains over 1.6 million papers and over 19 million citation relationships.</p><p><strong><em>Prediction task</em></strong>: a 40-class classification problem that aims to predict the primary categories of arXiv papers where categories are subject areas of the arXiv CS papers, such as cs.AI, cs.LG, and cs.OS.</p><p><strong><em>Data split</em></strong>: the idea is to train models on past papers and subsequently use them to predict the topic areas of newly released papers. Specifically, papers published before 2017 are used for training, those published in 2018 for validation, and those released after 2019 for testing.</p><p>Let’s put on our coding caps and explore this resource.</p><h3>Model: Graph Convolution Networks</h3><p>Let’s use Graph Convolution Network (GCN) to build our GNN model (<a href="https://arxiv.org/pdf/1609.02907.pdf">Kipf et al. 2017</a>). The PyG’s built-in <a href="https://pytorch-geometric.readthedocs.io/en/latest/generated/torch_geometric.nn.conv.GCNConv.html#torch_geometric.nn.conv.GCNConv">GCNConv</a> layer will come in handy for our implementation. BN is the Batch Normalization layer, followed by ReLU activation and a Dropout layer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/0*fxjbdgTnQ64X_206" /></figure><p>The below snippet shows how you can define various layers for your network:</p><pre>self.convs = torch.nn.ModuleList(<br>        [GCNConv(in_channels=input_dim,out_channels=hidden_dim)] + <br>        [GCNConv(in_channels=hidden_dim,out_channels=hidden_dim) <br>        for i in range(num_layers - 2)] +<br>        [GCNConv(in_channels=hidden_dim, out_channels=output_dim)]<br>        )<br>​​self.bns = torch.nn.ModuleList(<br>        [torch.nn.BatchNorm1d(num_features=hidden_dim)<br>        for i in range(num_layers - 1)]<br>        )<br>self.softmax = torch.nn.LogSoftmax()</pre><p>And, this is how you can proceed with the <strong>forward</strong> function:</p><pre>out = None<br>for i in range(len(self.bns)):<br>    x = self.convs[i](x, adj_t)<br>    x = self.bns[i](x)<br>    x = torch.nn.functional.relu(x)<br>    x = torch.nn.functional.dropout(x, p=self.dropout, training=self.training)<br><br>x = self.convs[-1](x, adj_t)<br>if not self.return_embeds:<br>    x = self.softmax(x)<br>out = x</pre><p>Here, <strong><em>adj_t</em></strong> is the Graph connectivity in COO format with shape [2, num_edges].</p><p>And, this is how you can train your model. We are using <a href="https://pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html">NLL</a> (Negative Log Likelihood Loss for this) and use accuracy as the evaluation metric.</p><pre>def train(model, data, train_idx, optimizer, loss_fn):<br>  model.train()<br>  loss = 0<br>  optimizer.zero_grad()<br>  o = model(data.x, data.edge_index)<br>  o = o[train_idx]<br>  y = torch.flatten(data.y[train_idx])<br>  loss = loss_fn(o, y)<br>  loss.backward()<br>  optimizer.step()<br>return loss.item()<br><br>​​def _eval_acc(self, y_true, y_pred):<br>  acc_list = []<br>  for i in range(y_true.shape[1]:<br>    is_labeled = y_true[:,i] == y_true[:,i]<br>    correct = y_true[is_labeled,i] == y_pred[is_labeled,i] <br>    acc_list.append(float(np.sum(correct))/len(correct))<br>return {&#39;acc&#39;: sum(acc_list)/len(acc_list)}<br><br><br>### Training Params:<br>args = {<br>  &#39;device&#39;: device,<br>  &#39;num_layers&#39;: 3,<br>  &#39;hidden_dim&#39;: 64,<br>  &#39;dropout&#39;: 0.5,<br>  &#39;lr&#39;: 0.01,<br>  &#39;epochs&#39;: 100 <br>  }</pre><p>What do we get?</p><pre>Train Accuracy: 70.73%, Valid Accuracy: 70.17% Test Accuracy: 69.36%</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/386/0*bhBu2M-KRPkmva9n" /></figure><p>Now, you are wondering, What? Why? How? What does it mean? We can answer some of these burning questions via the PyG explainability framework!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/315/0*ZAY6SXjNz-5GGGBb" /></figure><p><em>Let’s open this black box:</em></p><h3><em>IT IS GAME TIME!</em></h3><p>Below is the code snippet that initializes the Explainer class. Specifically, it focuses on explaining the behavior of a single node in the graph by identifying the top 40 contributing features. The Explainer object is instantiated with various configuration parameters, including the model being explained, the algorithm used for generating explanations (GNNExplainer in this case), and the explanation_type, which is set to &#39;model&#39; indicating that the goal is to explain the model&#39;s behavior rather than individual predictions.</p><p>The node_mask_type and edge_mask_type parameters indicate that the explanation will be focused on node attributes and object-level edges. Additionally, the model_config dictionary specifies the task being performed by the model (multiclass_classification) and the level at which the explanation is generated (node). The threshold_config the dictionary specifies the method used to threshold the contributions and is set to the top 40 features.</p><pre># Explanability for a single node<br>from torch_geometric.explain import Explainer, GNNExplainer<br>from torch_geometric.explain.metric import unfaithfulness, fidelity<br><br># Threshold contributions by the top 40 features.<br>topk = 40<br>node_index=10<br><br>explainer_individual = Explainer(<br>    model=model,<br>    algorithm=GNNExplainer(epochs=200),<br>    explanation_type=&#39;model&#39;,<br>    node_mask_type=&#39;attributes&#39;,<br>    edge_mask_type=&#39;object&#39;,<br>    model_config=dict(<br>        mode=&#39;multiclass_classification&#39;,<br>        task_level=&#39;node&#39;,<br>        return_type=&#39;log_probs&#39;,<br>    ),<br>    threshold_config=dict(threshold_type  = &#39;topk&#39;, value=topk)<br>)<br><br># Get explanation for node indexed 10<br>explanation_individual = explainer_individual(data.x, data.edge_index, index=node_index)</pre><p>In order to interpret the prediction for node indexed 10, the GNNExplainer provides the below feature importance bar plot for the top 10 features.</p><p>We can visualize feature importance and path graph by:</p><pre>path_features = &quot;feature_importance.png&quot;<br>explanation_individual.visualize_feature_importance(path_features, top_k=10)<br><br>path_graph = &quot;graph_importance.png&quot;<br>explanation_individual.visualize_graph(path_graph)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/0*3XOA9oK2oLZ2q69o" /><figcaption>Feature importance for node 10 in obgn-arxiv dataset</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*zhU-YCmTGMchDfhD" /><figcaption>Graph Visualization for node 10, top 40 nodes</figcaption></figure><p>How do we know if this makes sense?</p><h3>Metrics are all you need!</h3><ul><li><strong>unfaithfulness</strong></li></ul><p>This metric evaluates how faithful an <a href="https://pytorch-geometric.readthedocs.io/en/latest/modules/explain.html#torch_geometric.explain.Explanation">Explanation</a> is to an underlying GNN predictor, as described in the paper (<a href="https://arxiv.org/pdf/2208.09339.pdf">Agarwal and Queen 2023</a>). GEF (graph explanation unfaithfulness) can be expressed as:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/256/0*dK-bjWAjh_EYz_Bb" /></figure><p>where <em>y</em> refers to the prediction probability vector obtained from the original graph, and <em>y_hat</em> refers to the prediction probability vector obtained from the masked subgraph. Finally, the <a href="https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence">Kullback-Leibler (KL) divergence</a> score quantifies the distance between the two probability distributions.</p><ul><li><strong>fidelity</strong></li></ul><p>Fidelity evaluates the contribution of the produced explanatory subgraph to the initial prediction, either by giving only the subgraph to the model (fidelity-) or by removing it from the entire graph (fidelity+). The fidelity scores capture how well an explainable model reproduces the natural phenomenon or the GNN model logic. It evaluates the fidelity of an Explainer given an Explanation, as described in the paper (<a href="https://arxiv.org/pdf/2206.09677.pdf">Amara et. al. 2022</a>).</p><p>For <strong>phenomenon</strong> explanations, the fidelity scores are given by:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/762/1*qn_xS_8-xiR_UxpLIUTEZg.png" /></figure><p>For <strong>model</strong> explanations, the fidelity scores are given by:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/762/1*u3P7JjBxa_xea4Y5CCwGww.png" /></figure><p>For metrics:</p><pre>explanation_metrics = explainer_metrics(data.x, data.edge_index)<br>print(f&#39;Generated explanations in {explanation_metrics.available_explanations}&#39;)<br><br>fid_pm = fidelity(explainer_metrics, explanation_metrics)<br>print(&quot;Fidelity:&quot;, fid_pm)<br><br>char_score = characterization_score(fid_pm[0], fid_pm[1])<br>print(&quot;Characterization score:&quot;, char_score)</pre><blockquote>The Fidelity values achieved are (0.9929, 0.4951)</blockquote><blockquote>Characterization score: 0.7426</blockquote><h3>But what exactly does the above result mean for our explanation?</h3><p>Before going into what this score means, we need some background on what types of explanations are considered good.</p><p>Given a GNN model, there can be many possible explanations that can be put into 2 categories as proposed in <a href="https://arxiv.org/pdf/2206.09677.pdf">Amara et al. (2022)</a>!</p><ul><li><strong><em>Sufficient Explanation</em></strong>: An explanation is considered sufficient if it can independently lead to the model’s initial prediction. The same prediction may have multiple sufficient explanations due to the graph’s different configurations. The fidelity scores <em>fid–</em> of a sufficient explanation is close to 0.</li><li><strong><em>Necessary Explanation: </em></strong>An explanation is considered necessary if the model’s prediction changes when it’s removed from the original graph. Necessary explanations have a fidelity score <em>fid+</em> close to 1.</li></ul><blockquote>An explanation is a characterization of the prediction if it is both necessary and sufficient.</blockquote><p>The <a href="https://pytorch-geometric.readthedocs.io/en/latest/generated/torch_geometric.explain.metric.characterization_score.html#torch_geometric.explain.metric.characterization_score">characterization_score</a> is recommended as a global evaluation metric. The reason being since it is a weighted harmonic mean of <em>fid+</em> and <em>1-fid–</em>, it can balance the sufficiency and necessity requirements for an explanation. Ring any bells? We can’t read your mind but we bet you are also thinking about the <a href="https://en.wikipedia.org/wiki/F-score">F1-score</a> that combines precision and recall.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zUGp92XfkwIgEwtvnWKHRw.png" /><figcaption>Characterization score</figcaption></figure><p>The characterization score with equal weights on <em>fid+</em> and <em>1-fid–</em> is low as soon as one of the two terms is low.</p><blockquote>Our explanation has a characterization score of <strong>0.7</strong> which means it is pretty good!</blockquote><h3>Implementing Your Own Explainer Algorithm</h3><p>To implement your own custom explainability function, you can extend the <em>ExplainerAlgorithm</em> abstract base class. All you need to implement are the following two abstract methods:</p><ul><li><em>forward(model, x, edge_index, target, index): </em>The function that computes the explanations. <em>model</em> is the model used for explanations, <em>x</em> is the input node features, <em>edge_index</em> is the input edge features, <em>target</em> is the target of the model that is being explained (used in phenomena explanations), and <em>index</em> is the index of the model output to explain.</li><li><em>supports(self) -&gt; bool</em>: Returns whether or not the algorithm supports the current <em>explainer_config</em> and <em>model_config</em> parameters</li></ul><p>The <em>ExplainerAlgorithm</em> abstract base class also contains a list of helpful utility functions that can be used when implementing your explainer algorithm. See the <a href="https://pytorch-geometric.readthedocs.io/en/latest/_modules/torch_geometric/explain/algorithm/base.html#ExplainerAlgorithm.forward">source</a> for more details.</p><h3>Finally, A Closer Look at GNNExplainer</h3><p>In case you are still lost, let’s take a closer look at the <em>GNNExplainer</em> algorithm under the hood so that we can examine how this explainability algorithm works.</p><p>In the <em>GNNExplainer</em> problem setup, we perform multi-label node classification. We let <strong><em>G</em></strong> be a graph on edges <strong><em>E </em></strong>and nodes <strong><em>V</em></strong> with <strong><em>d-</em></strong>dimensional node features <strong><em>𝞦={𝑥₁…𝑥ₙ}</em></strong>. Additionally, let <strong><em>f</em></strong> be a label function on nodes <strong><em>f: V → {1,….C}</em></strong> that maps nodes to one of the <strong><em>C</em></strong> classes. The GNN model <strong><em>ɸ</em></strong> seeks to approximate <strong><em>f</em></strong>.</p><p>Recall that at layer 1, the update of a GNN model <strong><em>ɸ</em></strong> involves three key computations.</p><ol><li>First, the model computes a message for every pair of nodes. This message function is</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/156/0*4fgvdFwSr_INXs5h" /></figure><p>where <strong><em>h</em></strong> terms are corresponding representations for noded <strong><em>𝑣ᵢ </em></strong>and <strong><em>𝑣ⱼ </em></strong>in layer <strong><em>l-1 </em></strong>and <strong><em>rᵢⱼ</em></strong> is the relation between nodes.</p><p>2. Second, for each node <strong><em>𝑣ᵢ</em></strong> the GNN aggregates messages from <strong><em>𝑣ᵢ</em></strong><em>’</em>s neighborhood <strong><em>Nᵥᵢ</em></strong>, and aggregates the messages via an aggregation function</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/183/0*xsggqO4q9UfGCUMt" /></figure><p>3. Finally, the GNN takes the aggregated message <strong><em>M(l)ᵢ</em></strong> and <strong><em>𝑣ᵢ</em></strong><em>’</em>s previous representation <strong><em>h(l-1)ᵢ</em></strong>, and non-linearly transforms them to obtain <strong><em>𝑣ᵢ</em></strong><em>’</em>s representation</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/184/0*el1RrUnQH8mwd0vO" /></figure><p>The key insight of GNNExplainer is that the computation graph of a node <strong><em>𝑣</em></strong>, which is defined by the aggregation procedure, fully determines all of the information the GNN uses to make a prediction. The mathematical details of the specific optimization that GNNExplainer utilizes are out of scope for this tutorial, mostly because there is a different objective function for single-instance explanations vs. joint learning of graph structural and node feature information. For greater detail, see (<a href="https://arxiv.org/pdf/1903.03894.pdf">Ying et al., 2020</a>).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/852/1*TO3ZwOHWLXLCDaxsIJrrMw.png" /><figcaption>A figure demonstrating how aggregation determines node + node feature importance, from <a href="https://arxiv.org/pdf/1903.03894.pdf">Ying et al., 2019</a>.</figcaption></figure><h3>Conclusion</h3><p>In this blog post, we have trained a GCN on the <a href="https://ogb.stanford.edu/docs/nodeprop/#ogbn-arxiv">ogbn-arxiv</a> dataset (an Open Graph Benchmark (OBG) dataset) and showed how we can use PyG&#39;s built-in explainability module in order to produce explanations for both node features and graph structure. Then, we have examined ways to evaluate the quality of the explanations, and also how the algorithm GNNExplainer works under the hood. Hopefully, this tutorial has given you a greater understanding of the capabilities of the Explanability module in PyG and now life has started to make sense again!</p><h3>References:</h3><ol><li><a href="https://pytorch-geometric.readthedocs.io/en/latest/modules/explain.html">Pytorch Geometric Docs</a>.</li><li><a href="https://arxiv.org/pdf/1903.03894.pdf">Ying et. al., GNNExplainer: Generating Explanations for Graph Neural Networks, 2019</a>.</li><li><a href="https://arxiv.org/pdf/2206.09677.pdf">Amara et. al., GraphFramEx: Towards Systematic Evaluation of Explainability Methods for Graph Neural Networks, 2022</a>.</li><li><a href="https://arxiv.org/pdf/2208.09339.pdf">Agarwal and Queen et. al., Evaluating explainability for graph neural networks, 2023</a>.</li><li><a href="https://medium.com/@pytorch_geometric/graph-machine-learning-explainability-with-pyg-ff13cffc23c2">Blaž Stojanovič, Graph Machine Learning Explainability with PyG, 2013, Medium blog post</a>.</li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e3d3e3357dcc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stanford-cs224w/graph-analysis-made-easy-with-pyg-explainability-e3d3e3357dcc">Graph Analysis Made Easy with PyG Explainability</a> was originally published in <a href="https://medium.com/stanford-cs224w">Stanford CS224W: Machine Learning with Graphs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Prag Saga]]></title>
            <link>https://medium.com/@rajanieprabha/hey-yall-f80bf24c5690?source=rss-9d9f7143632f------2</link>
            <guid isPermaLink="false">https://medium.com/p/f80bf24c5690</guid>
            <category><![CDATA[europe]]></category>
            <category><![CDATA[praha]]></category>
            <category><![CDATA[travel]]></category>
            <category><![CDATA[prague]]></category>
            <category><![CDATA[trip]]></category>
            <dc:creator><![CDATA[Rajanie Prabha]]></dc:creator>
            <pubDate>Mon, 21 Feb 2022 09:18:00 GMT</pubDate>
            <atom:updated>2022-02-22T22:19:31.496Z</atom:updated>
            <content:encoded><![CDATA[<p>Hey y’all,</p><p>It’s 12:53 am and owing to my bad habits, I am high on caffeine.</p><p>This post was long due (had been sitting in my drive for 2 years now in the draft mode) so I had to change the opening to reflect my present life. Although, it’s pretty much the same, trying to find that work-life balance.</p><p>December 2017</p><p>With a two-week Christmas break and being a proud owner of a Schengen visa, this seemed like the perfect opportunity to visit someplace in Europe. How to decide where? The answer to that was pretty simple because Prague is known to be one of the cheapest party places across Europe. Forgive me, I’m a student, and I’m not earning yet. I tried making plans with some of my friends, but nothing seemed to work out, because people either had budget issues or they had folks visiting them. Me being myself, I had to go, even if I had to go alone.</p><p>I booked a hostel in the city center and a BlaBlaCar for 29th December morning. The interesting part was that I talked to one of my friends the night before, and he wanted to go too. I was so excited to have some company because yes, I was a little scared of a solo trip. So, he, his roommate, and I packed our bags and had an amazing car ride to Prague.</p><p>Prague is a beautiful city, a city with a typical touristy vibe. We roamed around the city, Charles Bridge, Petrin Tower, Castle, Museums, Christmas market, old square town, etc. We kept walking, observing, and feeling the excitement of the city. I would suggest <strong>Popocafepetl</strong> for their cheap alcohol and lively atmosphere. We went to a lot of chocolate factories tasting chocolates for free (YASS), had amazing Indian food (my friends were really into Indian food, well we don’t have to guess why) and some tasteless (we can agree to disagree) Czech food, went for a stupid (weird?) haunted underground tour but, all in all, had a lot of fun. We also explored <strong>Zizkov</strong> in Praha 3, which had a typical hippie vibe, ending the night with really good Mexican food (would highly recommend <strong>Las Adelitas</strong>), and happy lively bars. Freaking go to <strong>Bukowski</strong>. Period.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4A7HObLwDVe7hdpwQ0R5YQ.png" /></figure><p>The guys had to leave on the 31st, so I was on my own for the next two days. I didn’t visit a lot of touristy places after that, but I did walk around and explore the city with the two new Australian friends I just made at the hostel I was staying at. Ickle and Bickle (had to anonymize the names LOL) are two amazing crazy humans who I will never forget. I met a lot of other people in the hostel itself, Canadians, Germans, Mexicans, Indians, Australians, Americans, etc. Nobody had any plans for the evening, and we were all just hanging out in the common area of the hostel, drinking and chilling. I was literally the only sober person in the entire city that night (new year’s Eve), and trust me, I had as much fun as the other guys and maybe even more. Intoxication is not always proportional to having fun. Also, I didn’t want to get drunk, because it was my first solo experience and I didn’t want to take any risks. At around 10 PM, we got out on the road and just walked towards the Charles Bridge to watch the fireworks. Oh, man! The fireworks were so insane, I was shaking for the next few hours. The bridge got so crowded, that I felt squished, I was shouting (literally) and holding onto Ickle and Bickle. I thought I was going to die that night and I thought that was it. But somehow, we got pushed away from the crowd and I could eventually breathe. I can safely say that it was something I can never forget. The craziness, the drunk atmosphere, the fireworks, the crowd, it was all so thrilling. We watched the fireworks and just took a lot of pictures, hugged each other at midnight. A part of me missed my people who were not there with me to look at the fireworks, to hug, and to wish. We sang we danced, we got back to the hostel, we played pool till 5 in the morning, we talked about life and death and all the weird things in the world. Exhausted, I went to bed at 6 in the morning with a little ache in my heart for I will never see any of these guys again. It was one hell of a trip. I met so many people, learned about so many cultures, traditions, languages, festivals, and drinking habits!</p><p>That night was one of the most amazing nights of my life. It was absolutely what I wanted it to be like. Fun and insane. Prague is a beautiful place. I fell in love with the city.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*faxKdNBFm8-6UpVnvC1ZBg.jpeg" /></figure><p>Solo trips are subjective. You might just want to chill alone or you might just want to explore the world or you might just want to meet new people and hang around. Mine had all these things. Being an extrovert, I love meeting people, so that was the highlight of my trip (also chocolate factories) but yes, I would say that everyone should take a solo trip because it will remove the baggage of always finding someone to go on a trip with you, and it will make you realize that having fun on your own is something cool. Not just the city, explore your pure interests. Cheers!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bVyYkrMQSPcBBTR9D9nx3g.jpeg" /></figure><p>Thank you, Prague :)</p><p>Also, thanks to <a href="https://medium.com/u/7c9b097dd840">Ronn Jacob</a> for helping me with the editing!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f80bf24c5690" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tacotron-2 : Implementation and Experiments]]></title>
            <link>https://medium.com/@rajanieprabha/tacotron-2-implementation-and-experiments-832695b1c86e?source=rss-9d9f7143632f------2</link>
            <guid isPermaLink="false">https://medium.com/p/832695b1c86e</guid>
            <category><![CDATA[tacotron2]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[text-to-speech]]></category>
            <dc:creator><![CDATA[Rajanie Prabha]]></dc:creator>
            <pubDate>Fri, 03 Aug 2018 13:11:04 GMT</pubDate>
            <atom:updated>2019-10-09T11:48:07.381Z</atom:updated>
            <content:encoded><![CDATA[<p><strong><em>Why do we want to do Text-to-Speech?</em></strong></p><p>Not one but many reasons where TTS can be used such as accessibility features for people with little to no vision, communication-ware for mute people, voice assistants such as siri, screen readers, automated telephony systems, audio books, easier language learning etc.</p><p>In December 2016, Google released it’s new research called ‘Tacotron-2’, a neural network implementation for Text-to-Speech synthesis. Before moving forward, I would like you to checkout the results they posted on their blog <a href="https://google.github.io/tacotron/publications/tacotron2/">https://google.github.io/tacotron/publications/tacotron2/</a> and get excited about the mechanism.</p><p>Aren’t the results awesome and so human-like? Yes, that’s what motivated me to figure out how they did it and try to implement it eventually. I worked on Tacotron-2’s implementation and experimentation as a part of my Grad school course for three months with a Munich based AI startup called Luminovo.AI . I wanted to develop such a synthesizer on Angela Merkel’s speech.</p><p><strong>SEQ2SEQ MODEL WITH ATTENTION</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*fOfgv91uW0osDqddnJjdww.jpeg" /></figure><p>The working of the system was described by Jonathan Shen and Ruoming Pang, Software Engineers, Google Brain and Machine Perception Teams,</p><blockquote>‘’In a nutshell it works like this: We use a sequence-to-sequence model optimized for TTS to map a sequence of letters to a sequence of features that encode the audio. These features, an 80-dimensional audio spectrogram with frames computed every 12.5 milliseconds, capture not only pronunciation of words, but also various subtleties of human speech, including volume, speed and intonation. Finally these features are converted to a 24 kHz waveform using a WaveNet-like architecture.</blockquote><p>First part of the model i.e. Seq2Seq architecture which is responsible for converting texts into mel-spectrograms and these spectrograms are fed in a wave-net model to produce audio waveforms. One interesting thing is these two parts of the Tacotron architecture (Seq2Seq and Wavenet vocoder) can be trained independently. I worked on the Seq2Seq model.</p><p>The model is an encoder-attention-decoder setup where they use ‘Location sensitive attention’. The first part is an Encoder which converts the character sequence into word embedding vector. This representation is later consumed by the Decoder to predict spectrograms. Since I was using a German dataset, I made sure that my character space had german alphabets.</p><ul><li>The Encoder is composed of 3 convolutional layers each containing 512 filters of shape 5 x 1, followed by batch normalization and ReLU activations.</li><li>The next part is the attention network which takes the encoder output as input and tries the summarize the full encoded sequence as a fixed length context vector for each decoder output step.</li><li>The output of the final convolutional layer is passed into a single bi-directional LSTM layer containing 512 units (256 in each direction) to generate the encoded features.</li></ul><p><a href="https://arxiv.org/pdf/1506.07503.pdf"><strong>ATTENTION-BASED MODELS FOR SPEECH RECOGNITION</strong></a><strong>:</strong></p><p>Attention mechanism used here takes into account both the location of the focus in the previous step and the features of input sequence.</p><p>Let say we have data <strong>x </strong>= {x1,x2,x3….xN}. We pass this data to the encoder which produces an encoded output sequence <strong>h </strong>= {h1,h2,h3….hN}.</p><p>A(i) = Attention( s(i-1), A(i-1), <strong>h</strong> ) where s(i-1) is the previous decoding state and A(i-1) is the previous alignment.</p><p>s(i-1) is 0 for the first iteration of first step.</p><p>Attention function is usually implemented by scoring each element in <strong>h </strong>separately and then normalizing the score.</p><p>G(i) = A(i,0) <strong>h</strong>(0) + A(i,1) <strong>h</strong>(1) + ……. + A(i,N) <strong>h</strong>(N)</p><p>Y(i) ~ Generate ( s(i-1), G(i) )</p><p>where s is the decoding output, A(i) is a vector of attention weights called alignment.</p><p>Finally, s(i) = Recurrency ( s(i-1), G(i), Y(i) )</p><p>Recurrency is usually LSTM.</p><p><strong>DECODER</strong> :</p><p>The decoder is an autoregressive recurrent neural network which predicts a mel spectrogram from the encoded input sequence one frame at a time. The prediction from the previous time step is first passed through a small pre-net containing 2 fully connected layers of 256 hidden ReLU units. The pre- net output and attention context vector are concatenated and passed through a stack of 2 uni-directional LSTM layers with 1024 units. Finally, the predicted mel spectrogram is passed through a 5-layer convolutional post-net which predicts a residual to add to the prediction to improve the overall reconstruction. Each post-net layer is comprised of 512 filters with shape 5 × 1 with batch normalization, followed by tanh activations on all but the final layer.</p><p><strong>LOSS FUNCTION:</strong></p><p>Summed mean squared error (MSE)</p><p>In parallel to spectrogram frame prediction, the concatenation of decoder LSTM output and the attention context is projected down to a scalar and passed through a sigmoid activation to predict the probability that the output sequence has completed. This “stop token” prediction is used during inference to allow the model to dynamically determine when to terminate generation instead of always generating for a fixed duration.</p><p>I decided to go with <strong>pytorch</strong> for my implementation, tracked the training with <strong>tensorboard</strong>, used gcloud Tesla K80 GPU, connected to server ports by ‘ssh -NfL’, and heavily used <strong>jupyter lab</strong> during development. [life saver kit]</p><p>I referenced various github repositories [<a href="https://github.com/Rayhane-mamah/Tacotron-2">1</a>, <a href="https://github.com/NVIDIA/tacotron2">2</a>] to understand the paper, implementation, correcting bugs in my own code. Due to the natural complexity of the problem statement, I could not get astonishing human-like speech results but I learned a lot of things about Text-to-speech and that was the major goal when I started doing the project.</p><p><strong>Some results for reference:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wOP80AVpOM8txXdfmjDj6Q.png" /><figcaption>Predicted mel-spectrogram : As you can compare the upper regions, it has a lot of gaps and still needs a lot of training. The right side (solid green) is just padding in one batch.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5FgSv8vSaWHxi9xzQWYpXA.png" /><figcaption>Target mel-spectrogram</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*NQznWi0pWUhDFNIp0rH7OA.png" /><figcaption>Attention (As you can see in the lower left side, it looks like it is learning to align but it still needs around one week of training to get that perfect diagonal for attention)</figcaption></figure><p>All the images produced above are after 50K iterations (1 iteration = 1 batch) i.e. 3 days of training. This model needs around 300K iterations to get any close to human-like. You can see that, the predicted mel-spectrograms look pretty nice even when the attention is not learned properly. Save yourself from the trap and care about the attention!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/955/1*gDH1TCBZO1ZPdARsCzWqOg.jpeg" /><figcaption>Training loss from tensorboard</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/959/1*He8WxapeU0s9GyvoxMMv9A.jpeg" /><figcaption>Validation loss from Tensorboard</figcaption></figure><h3><strong>EXPERIMENTS and CONCLUSIONS:</strong></h3><p>Implementing the model and training it was not as trivial as I thought initially. I came across numerous issues which I want you guys to know beforehand and save hours on your GPU.</p><ol><li><strong>Study your data. </strong>This is the most important part of the project. Listen to your data samples, check the length of text samples, duration of audio samples etc. You can save a lot of time during training, if you know your data well. <a href="http://www.m-ailabs.bayern/en/the-mailabs-speech-dataset/">M-AILABS</a> announced their huge speech dataset earlier this year. They have humongous speech dataset in many different languages. I used the Angela Merkel data from the German female section, which has 12 hours of speech from her public speeches and interviews. This dataset was lesser as compared to <a href="https://keithito.com/LJ-Speech-Dataset/">LJSpeech</a> (most popular english dataset, 24 hours of speech). I figured this out only when I started training and spent days observing the results. So, heads up!</li><li>TTS is highly <strong>computationally expensive</strong>. Being a student, I just had access to one GPU (Nvidia Tesla K80) on Google cloud. Given the structure of the dataset I was using, my GPU only allowed batch-size of 8 while training. Google says, they train it with a batch-size of 64. I first tried with a batch-size of 2 (because of limited GPU memory) and when the model failed to show any convergence after 2–3 days of training, I sorted my data as per length of the text and as per duration of the audio, and started training with batch-size 8. Although, I couldn’t optimize more with the dataset and the GPU I had. So, plan accordingly.</li><li><strong>Teacher-forcing ratio. </strong>In teacher-forced training, the model is assisted by true labels i.e. it uses the current frame of the Ground Truth to predict the next decoding step. It is not clear in the paper regarding what ratio to use. Even if the attention is not learned, the model will predict good frames for training data in teacher-forced mode but in the evaluation mode it will not work because we don’t have ground truth (Thought the model was working since the predicted mels looked nice regardless of poor alignments). I did training with 1.0, 0.75 and 0.5 to make the model learn alignments. During eval mode, teacher-forcing should be turned off.</li><li>It takes <strong>days to train</strong> and get alignments. It is a real cumbersome process to train a TTS system. It might take around 7–10 days to train the model provided that you have limited GPU support (We are no google). And then, debugging the code with such a model, is another story.</li><li><strong>Hyperparameter tuning </strong>is very important part of Tacotron-2 system. The batch-size, learning-rate, teacher-forcing ratio, batch length are some of the parameters you should pay extra importance too. Things vary with datasets, so it is very sensitive!</li></ol><h3>CONCLUSION</h3><p>Text-to-speech is still a really complex research problem and it was exciting to work on this. My overall experience was amazing and I learnt a lot of things about TTS systems, audio waveforms, recurrent networks, mel-spectrograms, attention mechanisms and I hope that this post can help you in any way in your journey with TTS systems. In future, I would like to see an optimized version of Tacotron-2 model, something which is more robust across languages, easier to train and less computationally heavy.</p><p>So, I would just say, preprocess your data well, tune your hyperparameters, log everything on tensorboard and get going! All the best!</p><p><em>Special thanks to Luminovo.AI for their support!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=832695b1c86e" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>