├── environment.yml
├── LICENSE
├── .gitignore
├── README.md
└── notebooks
├── 06-graph-neural-networks-1-gnn-model.ipynb
└── 08-applications-of-graph-neural-networks.ipynb
/environment.yml:
--------------------------------------------------------------------------------
1 | # This is Conda environment file
2 | # Usage: `conda env update -f environment.yml`
3 |
4 | name:
5 | cs224w
6 |
7 | channels:
8 | - pyg
9 | - pytorch
10 | - conda-forge
11 |
12 | dependencies:
13 | - grakel==0.1.8
14 | - ipywidgets
15 | - karateclub==1.2.1
16 | - notebook
17 | - ogb
18 | - pip
19 | - pyg
20 | - python==3.7.12
21 | - pytorch>=1.8.0
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Mario Namtao Shianti Larcher
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CS224W: Machine Learning with Graphs - Slides to Code (Unofficial)
2 |
3 | This repository is an attempt to convert the slides from Stanford's "CS224W: Machine Learning with Graphs" course into code. The notebooks presented here include code to implement techniques hinted at in the lectures but not shown in the official labs.
4 |
5 | My initial plan was to cover all the lessons but already by the eighth the computation becomes challenging for Colab and I think these first eight are already a great introduction to the subject, I'll stop here.
6 |
7 | > **Disclaimer**: I am not a Stanford student and this material has not been reviewed by the course instructors, it is possible that it contains errors, if you find any please open an issue.
8 |
9 | A few useful links:
10 | * [CS224W | Home](http://web.stanford.edu/class/cs224w/index.html#schedule)
11 | * [CS224W | YouTube](https://youtu.be/JAB_plj2rbA)
12 |
13 | # Notebooks
14 | 1. [Introduction; Machine Learning for Graphs](https://github.com/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/01-introduction-machine-learning-for-graphs.ipynb) [](https://colab.research.google.com/github/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/01-introduction-machine-learning-for-graphs.ipynb)
15 | 2. [Traditional Methods for ML on Graphs](https://github.com/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/02-traditional-methods-for-ml-on-graphs.ipynb) [](https://colab.research.google.com/github/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/02-traditional-methods-for-ml-on-graphs.ipynb)
16 | 3. [Node Embeddings](https://github.com/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/03-node-embeddings.ipynb) [](https://colab.research.google.com/github/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/03-node-embeddings.ipynb)
17 | 4. [Link Analysis: PageRank](https://github.com/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/04-link-analysis-pagerank.ipynb) [](https://colab.research.google.com/github/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/04-link-analysis-pagerank.ipynb)
18 | 5. [Label Propagation for Node Classification](https://github.com/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/05-label-propagation-for-node-classification.ipynb) [](https://colab.research.google.com/github/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/05-label-propagation-for-node-classification.ipynb)
19 | 6. [Graph Neural Networks 1: GNN Model](https://github.com/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/06-graph-neural-networks-1-gnn-model.ipynb) [](https://colab.research.google.com/github/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/06-graph-neural-networks-1-gnn-model.ipynb) [](https://blog.devgenius.io/how-to-train-a-graph-convolutional-network-on-the-cora-dataset-with-pytorch-geometric-847ed5fab9cb)
20 | 7. [Graph Neural Networks 2: Design Space](https://github.com/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/07-graph-neural-networks-2-design-space.ipynb) [](https://colab.research.google.com/github/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/07-graph-neural-networks-2-design-space.ipynb)
21 | 8. [Applications of Graph Neural Networks](https://github.com/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/08-applications-of-graph-neural-networks.ipynb) [](https://colab.research.google.com/github/mnslarcher/cs224w-slides-to-code/blob/main/notebooks/08-applications-of-graph-neural-networks.ipynb)
22 |
23 | # Changelog
24 |
25 | ## 2022-02-13
26 |
27 | - Add the link to the Medium article related to the 6th lesson "Graph Neural Networks 1: GNN Model"
28 |
29 | ## 2021-12-12
30 |
31 | - Complete the notebook related to the 8th lesson "Applications of Graph Neural Networks"
32 |
33 | ## 2021-12-08
34 |
35 | - Complete the notebook related to the 7th lesson "Graph Neural Networks 2: Design Space"
36 |
37 | ## 2021-12-04
38 |
39 | - Complete the notebook related to the 6th lesson "Graph Neural Networks 1: GNN Model"
40 | - Add Anaconda env. file
41 |
42 | ## 2021-11-28
43 |
44 | - Complete the notebook related to the 5th lesson "Label Propagation for Node Classification"
45 |
46 | ## 2021-11-14
47 |
48 | - Complete the notebook related to the 4th lesson "Link Analysis: PageRank"
49 |
50 | ## 2021-11-13
51 |
52 | - Complete the notebook related to the 3rd lesson "Node Embeddings"
53 |
54 | ## 2021-11-06
55 |
56 | - Complete the notebook related to the 2nd lesson "Traditional Methods for ML on Graphs"
57 |
58 | ## 2021-11-04
59 |
60 | - Complete the notebook related to the 1st lesson "Introduction; Machine Learning for Graphs"
61 |
--------------------------------------------------------------------------------
/notebooks/06-graph-neural-networks-1-gnn-model.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "colab_type": "text",
7 | "id": "view-in-github"
8 | },
9 | "source": [
10 | "
"
11 | ]
12 | },
13 | {
14 | "cell_type": "code",
15 | "execution_count": 1,
16 | "metadata": {
17 | "id": "PJSONe-045tN"
18 | },
19 | "outputs": [],
20 | "source": [
21 | "try:\n",
22 | " # Check if PyTorch Geometric is installed:\n",
23 | " import torch_geometric\n",
24 | "except ImportError:\n",
25 | " # If PyTorch Geometric is not installed, install it.\n",
26 | " %pip install -q torch-scatter -f https://pytorch-geometric.com/whl/torch-1.7.0+cu101.html\n",
27 | " %pip install -q torch-sparse -f https://pytorch-geometric.com/whl/torch-1.7.0+cu101.html\n",
28 | " %pip install -q torch-geometric"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {
34 | "id": "oV56fjpNYjCR"
35 | },
36 | "source": [
37 | "# Graph Neural Networks 1: GNN Model"
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "execution_count": 2,
43 | "metadata": {
44 | "colab": {
45 | "base_uri": "https://localhost:8080/"
46 | },
47 | "id": "2OtSkdGl48E0",
48 | "outputId": "7efa478a-75df-4efb-991a-a3ac877f6469"
49 | },
50 | "outputs": [],
51 | "source": [
52 | "from typing import Callable, List, Optional, Tuple\n",
53 | "\n",
54 | "import matplotlib.pyplot as plt\n",
55 | "import numpy as np\n",
56 | "import torch\n",
57 | "import torch.nn.functional as F\n",
58 | "import torch_geometric.transforms as T\n",
59 | "from torch import Tensor\n",
60 | "from torch.optim import Optimizer\n",
61 | "from torch_geometric.data import Data\n",
62 | "from torch_geometric.datasets import Planetoid\n",
63 | "from torch_geometric.nn import GCNConv\n",
64 | "from torch_geometric.utils import accuracy\n",
65 | "from typing_extensions import Literal, TypedDict"
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "metadata": {
71 | "id": "KYGSasdA5ziu"
72 | },
73 | "source": [
74 | "## Cora Dataset"
75 | ]
76 | },
77 | {
78 | "cell_type": "markdown",
79 | "metadata": {
80 | "id": "_iseKiaT5GZ7"
81 | },
82 | "source": [
83 | "> From The [Papers With Code page of the Cora Dataset](https://paperswithcode.com/dataset/cora): \"The Cora dataset consists of 2708 scientific publications classified into one of seven classes. The citation network consists of 5429 links. Each publication in the dataset is described by a 0/1-valued word vector indicating the absence/presence of the corresponding word from the dictionary. The dictionary consists of 1433 unique words.\""
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {
89 | "id": "z518Aul25JZv"
90 | },
91 | "source": [
92 | "> From [Kipf & Welling (ICLR 2017)](https://arxiv.org/abs/1609.02907): \"[...] evaluate prediction accuracy on a test set of 1,000 labeled examples. [...] validation set of 500 labeled examples for hyperparameter optimization (dropout rate for all layers, L2 regularization factor for the first GCN layer and number of hidden units). We do not use the validation set labels for training.\""
93 | ]
94 | },
95 | {
96 | "cell_type": "code",
97 | "execution_count": 3,
98 | "metadata": {
99 | "colab": {
100 | "base_uri": "https://localhost:8080/"
101 | },
102 | "id": "6Gg7oGlS5NRX",
103 | "outputId": "b8d10e40-275d-4b51-9907-b66d23465c6b"
104 | },
105 | "outputs": [
106 | {
107 | "name": "stdout",
108 | "output_type": "stream",
109 | "text": [
110 | "Dataset: Cora\n",
111 | "Num. nodes: 2708 (train=140, val=500, test=1000, other=1068)\n",
112 | "Num. edges: 5278\n",
113 | "Num. node features: 1433\n",
114 | "Num. classes: 7\n",
115 | "Dataset len.: 1\n"
116 | ]
117 | }
118 | ],
119 | "source": [
120 | "dataset = Planetoid(\"/tmp/Cora\", name=\"Cora\")\n",
121 | "num_nodes = dataset.data.num_nodes\n",
122 | "# For num. edges see:\n",
123 | "# - https://github.com/pyg-team/pytorch_geometric/issues/343\n",
124 | "# - https://github.com/pyg-team/pytorch_geometric/issues/852\n",
125 | "num_edges = dataset.data.num_edges // 2\n",
126 | "train_len = dataset[0].train_mask.sum()\n",
127 | "val_len = dataset[0].val_mask.sum()\n",
128 | "test_len = dataset[0].test_mask.sum()\n",
129 | "other_len = num_nodes - train_len - val_len - test_len\n",
130 | "print(f\"Dataset: {dataset.name}\")\n",
131 | "print(f\"Num. nodes: {num_nodes} (train={train_len}, val={val_len}, test={test_len}, other={other_len})\")\n",
132 | "print(f\"Num. edges: {num_edges}\")\n",
133 | "print(f\"Num. node features: {dataset.num_node_features}\")\n",
134 | "print(f\"Num. classes: {dataset.num_classes}\")\n",
135 | "print(f\"Dataset len.: {dataset.len()}\")"
136 | ]
137 | },
138 | {
139 | "cell_type": "markdown",
140 | "metadata": {
141 | "id": "hBzvCryI5Uba"
142 | },
143 | "source": [
144 | "> From [Kipf & Welling (ICLR 2017)](https://arxiv.org/abs/1609.02907): \"We initialize weights using the initialization described in Glorot & Bengio (2010) and accordingly (row-)normalize input feature vectors.\""
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "execution_count": 4,
150 | "metadata": {
151 | "colab": {
152 | "base_uri": "https://localhost:8080/"
153 | },
154 | "id": "nljKuAA85XDE",
155 | "outputId": "48bc3cd5-4d3b-4c1f-90ff-e435c28962da"
156 | },
157 | "outputs": [
158 | {
159 | "name": "stdout",
160 | "output_type": "stream",
161 | "text": [
162 | "Sum of row values without normalization: tensor([ 9., 23., 19., ..., 18., 14., 13.])\n",
163 | "Sum of row values with normalization: tensor([1.0000, 1.0000, 1.0000, ..., 1.0000, 1.0000, 1.0000])\n"
164 | ]
165 | }
166 | ],
167 | "source": [
168 | "dataset = Planetoid(\"/tmp/Cora\", name=\"Cora\")\n",
169 | "print(f\"Sum of row values without normalization: {dataset[0].x.sum(dim=-1)}\")\n",
170 | "\n",
171 | "dataset = Planetoid(\"/tmp/Cora\", name=\"Cora\", transform=T.NormalizeFeatures())\n",
172 | "print(f\"Sum of row values with normalization: {dataset[0].x.sum(dim=-1)}\")"
173 | ]
174 | },
175 | {
176 | "cell_type": "markdown",
177 | "metadata": {
178 | "id": "c0Jw_TT35AiO"
179 | },
180 | "source": [
181 | "## Graph Convolutional Networks"
182 | ]
183 | },
184 | {
185 | "cell_type": "markdown",
186 | "metadata": {
187 | "id": "b19trEwa5Y-W"
188 | },
189 | "source": [
190 | "> From [Kipf & Welling (ICLR 2017)](https://arxiv.org/abs/1609.02907): \"We used the following sets of hyperparameters for Citeseer, Cora and Pubmed: 0.5 (dropout rate), $5\\cdot10^{-4}$ (L2 regularization) and 16 (number of hidden units);\""
191 | ]
192 | },
193 | {
194 | "cell_type": "code",
195 | "execution_count": 5,
196 | "metadata": {
197 | "id": "-m_i0aCa5eM4"
198 | },
199 | "outputs": [],
200 | "source": [
201 | "class GCN(torch.nn.Module):\n",
202 | " def __init__(\n",
203 | " self,\n",
204 | " num_node_features: int,\n",
205 | " num_classes: int,\n",
206 | " hidden_dim: int = 16,\n",
207 | " dropout_rate: float = 0.5,\n",
208 | " ) -> None:\n",
209 | " super().__init__()\n",
210 | " self.dropout1 = torch.nn.Dropout(dropout_rate)\n",
211 | " self.conv1 = GCNConv(num_node_features, hidden_dim)\n",
212 | " self.relu = torch.nn.ReLU(inplace=True)\n",
213 | " self.dropout2 = torch.nn.Dropout(dropout_rate)\n",
214 | " self.conv2 = GCNConv(hidden_dim, num_classes)\n",
215 | "\n",
216 | " def forward(self, x: Tensor, edge_index: Tensor) -> torch.Tensor:\n",
217 | " x = self.dropout1(x)\n",
218 | " x = self.conv1(x, edge_index)\n",
219 | " x = self.relu(x)\n",
220 | " x = self.dropout2(x)\n",
221 | " x = self.conv2(x, edge_index)\n",
222 | " return x"
223 | ]
224 | },
225 | {
226 | "cell_type": "code",
227 | "execution_count": 6,
228 | "metadata": {
229 | "colab": {
230 | "base_uri": "https://localhost:8080/"
231 | },
232 | "id": "jKQH-HKS5hVt",
233 | "outputId": "e98433b7-97c9-4469-e409-6aa8b07dea4e"
234 | },
235 | "outputs": [
236 | {
237 | "name": "stdout",
238 | "output_type": "stream",
239 | "text": [
240 | "Graph Convolutional Network (GCN):\n"
241 | ]
242 | },
243 | {
244 | "data": {
245 | "text/plain": [
246 | "GCN(\n",
247 | " (dropout1): Dropout(p=0.5, inplace=False)\n",
248 | " (conv1): GCNConv(1433, 16)\n",
249 | " (relu): ReLU(inplace=True)\n",
250 | " (dropout2): Dropout(p=0.5, inplace=False)\n",
251 | " (conv2): GCNConv(16, 7)\n",
252 | ")"
253 | ]
254 | },
255 | "execution_count": 6,
256 | "metadata": {},
257 | "output_type": "execute_result"
258 | }
259 | ],
260 | "source": [
261 | "print(\"Graph Convolutional Network (GCN):\")\n",
262 | "GCN(dataset.num_node_features, dataset.num_classes)"
263 | ]
264 | },
265 | {
266 | "cell_type": "markdown",
267 | "metadata": {
268 | "id": "mN5NPwag6GPT"
269 | },
270 | "source": [
271 | "## Training and Evaluation"
272 | ]
273 | },
274 | {
275 | "cell_type": "code",
276 | "execution_count": 7,
277 | "metadata": {},
278 | "outputs": [],
279 | "source": [
280 | "LossFn = Callable[[Tensor, Tensor], Tensor]\n",
281 | "Stage = Literal[\"train\", \"val\", \"test\"]\n",
282 | "\n",
283 | "\n",
284 | "def train_step(\n",
285 | " model: torch.nn.Module, data: Data, optimizer: torch.optim.Optimizer, loss_fn: LossFn\n",
286 | ") -> Tuple[float, float]:\n",
287 | " model.train()\n",
288 | " optimizer.zero_grad()\n",
289 | " mask = data.train_mask\n",
290 | " logits = model(data.x, data.edge_index)[mask]\n",
291 | " preds = logits.argmax(dim=1)\n",
292 | " y = data.y[mask]\n",
293 | " loss = loss_fn(logits, y)\n",
294 | " # + L2 regularization to the first layer only\n",
295 | " # for name, params in model.state_dict().items():\n",
296 | " # if name.startswith(\"conv1\"):\n",
297 | " # loss += 5e-4 * params.square().sum() / 2.0\n",
298 | "\n",
299 | " acc = accuracy(preds, y)\n",
300 | " loss.backward()\n",
301 | " optimizer.step()\n",
302 | " return loss.item(), acc\n",
303 | "\n",
304 | "\n",
305 | "@torch.no_grad()\n",
306 | "def eval_step(model: torch.nn.Module, data: Data, loss_fn: LossFn, stage: Stage) -> Tuple[float, float]:\n",
307 | " model.eval()\n",
308 | " mask = getattr(data, f\"{stage}_mask\")\n",
309 | " logits = model(data.x, data.edge_index)[mask]\n",
310 | " preds = logits.argmax(dim=1)\n",
311 | " y = data.y[mask]\n",
312 | " loss = loss_fn(logits, y)\n",
313 | " # + L2 regularization to the first layer only\n",
314 | " # for name, params in model.state_dict().items():\n",
315 | " # if name.startswith(\"conv1\"):\n",
316 | " # loss += 5e-4 * params.square().sum() / 2.0\n",
317 | "\n",
318 | " acc = accuracy(preds, y)\n",
319 | " return loss.item(), acc"
320 | ]
321 | },
322 | {
323 | "cell_type": "markdown",
324 | "metadata": {
325 | "id": "oMqTMjZD5mTy"
326 | },
327 | "source": [
328 | "> From [Kipf & Welling (ICLR 2017)](https://arxiv.org/abs/1609.02907): \"We train all models for a maximum of 200 epochs (training iterations) using Adam (Kingma & Ba, 2015) with a learning rate of 0.01 and early stopping with a window size of 10, i.e. we stop training if the validation loss does not decrease for 10 consecutive epochs.\""
329 | ]
330 | },
331 | {
332 | "cell_type": "code",
333 | "execution_count": 8,
334 | "metadata": {},
335 | "outputs": [],
336 | "source": [
337 | "class HistoryDict(TypedDict):\n",
338 | " loss: List[float]\n",
339 | " acc: List[float]\n",
340 | " val_loss: List[float]\n",
341 | " val_acc: List[float]\n",
342 | "\n",
343 | "\n",
344 | "def train(\n",
345 | " model: torch.nn.Module,\n",
346 | " data: Data,\n",
347 | " optimizer: torch.optim.Optimizer,\n",
348 | " loss_fn: LossFn = torch.nn.CrossEntropyLoss(),\n",
349 | " max_epochs: int = 200,\n",
350 | " early_stopping: int = 10,\n",
351 | " print_interval: int = 20,\n",
352 | " verbose: bool = True,\n",
353 | ") -> HistoryDict:\n",
354 | " history = {\"loss\": [], \"val_loss\": [], \"acc\": [], \"val_acc\": []}\n",
355 | " for epoch in range(max_epochs):\n",
356 | " loss, acc = train_step(model, data, optimizer, loss_fn)\n",
357 | " val_loss, val_acc = eval_step(model, data, loss_fn, \"val\")\n",
358 | " history[\"loss\"].append(loss)\n",
359 | " history[\"acc\"].append(acc)\n",
360 | " history[\"val_loss\"].append(val_loss)\n",
361 | " history[\"val_acc\"].append(val_acc)\n",
362 | " # The official implementation in TensorFlow is a little different from what is described in the paper...\n",
363 | " if epoch > early_stopping and val_loss > np.mean(history[\"val_loss\"][-(early_stopping + 1) : -1]):\n",
364 | " if verbose:\n",
365 | " print(\"\\nEarly stopping...\")\n",
366 | "\n",
367 | " break\n",
368 | "\n",
369 | " if verbose and epoch % print_interval == 0:\n",
370 | " print(f\"\\nEpoch: {epoch}\\n----------\")\n",
371 | " print(f\"Train loss: {loss:.4f} | Train acc: {acc:.4f}\")\n",
372 | " print(f\" Val loss: {val_loss:.4f} | Val acc: {val_acc:.4f}\")\n",
373 | "\n",
374 | " test_loss, test_acc = eval_step(model, data, loss_fn, \"test\")\n",
375 | " if verbose:\n",
376 | " print(f\"\\nEpoch: {epoch}\\n----------\")\n",
377 | " print(f\"Train loss: {loss:.4f} | Train acc: {acc:.4f}\")\n",
378 | " print(f\" Val loss: {val_loss:.4f} | Val acc: {val_acc:.4f}\")\n",
379 | " print(f\" Test loss: {test_loss:.4f} | Test acc: {test_acc:.4f}\")\n",
380 | "\n",
381 | " return history"
382 | ]
383 | },
384 | {
385 | "cell_type": "code",
386 | "execution_count": 9,
387 | "metadata": {},
388 | "outputs": [],
389 | "source": [
390 | "def plot_history(history: HistoryDict, title: str, font_size: Optional[int] = 14) -> None:\n",
391 | " plt.suptitle(title, fontsize=font_size)\n",
392 | " ax1 = plt.subplot(121)\n",
393 | " ax1.set_title(\"Loss\")\n",
394 | " ax1.plot(history[\"loss\"], label=\"train\")\n",
395 | " ax1.plot(history[\"val_loss\"], label=\"val\")\n",
396 | " plt.xlabel(\"Epoch\")\n",
397 | " ax1.legend()\n",
398 | "\n",
399 | " ax2 = plt.subplot(122)\n",
400 | " ax2.set_title(\"Accuracy\")\n",
401 | " ax2.plot(history[\"acc\"], label=\"train\")\n",
402 | " ax2.plot(history[\"val_acc\"], label=\"val\")\n",
403 | " plt.xlabel(\"Epoch\")\n",
404 | " ax2.legend()"
405 | ]
406 | },
407 | {
408 | "cell_type": "code",
409 | "execution_count": 10,
410 | "metadata": {},
411 | "outputs": [
412 | {
413 | "name": "stdout",
414 | "output_type": "stream",
415 | "text": [
416 | "\n",
417 | "Epoch: 0\n",
418 | "----------\n",
419 | "Train loss: 1.9460 | Train acc: 0.1500\n",
420 | " Val loss: 1.9480 | Val acc: 0.0820\n",
421 | "\n",
422 | "Epoch: 20\n",
423 | "----------\n",
424 | "Train loss: 1.7267 | Train acc: 0.6500\n",
425 | " Val loss: 1.8245 | Val acc: 0.4860\n",
426 | "\n",
427 | "Epoch: 40\n",
428 | "----------\n",
429 | "Train loss: 1.4002 | Train acc: 0.7857\n",
430 | " Val loss: 1.6003 | Val acc: 0.6980\n",
431 | "\n",
432 | "Epoch: 60\n",
433 | "----------\n",
434 | "Train loss: 0.9969 | Train acc: 0.8714\n",
435 | " Val loss: 1.3578 | Val acc: 0.7540\n",
436 | "\n",
437 | "Epoch: 80\n",
438 | "----------\n",
439 | "Train loss: 0.7222 | Train acc: 0.9286\n",
440 | " Val loss: 1.1672 | Val acc: 0.7720\n",
441 | "\n",
442 | "Epoch: 100\n",
443 | "----------\n",
444 | "Train loss: 0.6089 | Train acc: 0.9214\n",
445 | " Val loss: 1.0402 | Val acc: 0.7800\n",
446 | "\n",
447 | "Epoch: 120\n",
448 | "----------\n",
449 | "Train loss: 0.5035 | Train acc: 0.9071\n",
450 | " Val loss: 0.9487 | Val acc: 0.7860\n",
451 | "\n",
452 | "Early stopping...\n",
453 | "\n",
454 | "Epoch: 127\n",
455 | "----------\n",
456 | "Train loss: 0.5273 | Train acc: 0.9500\n",
457 | " Val loss: 0.9461 | Val acc: 0.7760\n",
458 | " Test loss: 0.9202 | Test acc: 0.8080\n"
459 | ]
460 | },
461 | {
462 | "data": {
463 | "image/png": "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\n",
464 | "text/plain": [
465 | ""
466 | ]
467 | },
468 | "metadata": {
469 | "needs_background": "light"
470 | },
471 | "output_type": "display_data"
472 | }
473 | ],
474 | "source": [
475 | "SEED = 42\n",
476 | "MAX_EPOCHS = 200\n",
477 | "LEARNING_RATE = 0.01\n",
478 | "WEIGHT_DECAY = 5e-4\n",
479 | "EARLY_STOPPING = 10\n",
480 | "\n",
481 | "\n",
482 | "torch.manual_seed(SEED)\n",
483 | "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
484 | "\n",
485 | "model = GCN(dataset.num_node_features, dataset.num_classes).to(device)\n",
486 | "data = dataset[0].to(device)\n",
487 | "optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE, weight_decay=WEIGHT_DECAY)\n",
488 | "history = train(model, data, optimizer, max_epochs=MAX_EPOCHS, early_stopping=EARLY_STOPPING)\n",
489 | "\n",
490 | "plt.figure(figsize=(12, 4))\n",
491 | "plot_history(history, \"GCN\")"
492 | ]
493 | }
494 | ],
495 | "metadata": {
496 | "colab": {
497 | "authorship_tag": "ABX9TyM4BJ9SfFG7mXOuMcdhOFtF",
498 | "include_colab_link": true,
499 | "name": "06-graph-neural-networks-1-gnn-model.ipynb",
500 | "provenance": []
501 | },
502 | "kernelspec": {
503 | "display_name": "Python 3",
504 | "language": "python",
505 | "name": "python3"
506 | },
507 | "language_info": {
508 | "codemirror_mode": {
509 | "name": "ipython",
510 | "version": 3
511 | },
512 | "file_extension": ".py",
513 | "mimetype": "text/x-python",
514 | "name": "python",
515 | "nbconvert_exporter": "python",
516 | "pygments_lexer": "ipython3",
517 | "version": "3.7.12"
518 | }
519 | },
520 | "nbformat": 4,
521 | "nbformat_minor": 1
522 | }
523 |
--------------------------------------------------------------------------------
/notebooks/08-applications-of-graph-neural-networks.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "id": "e578f14e",
6 | "metadata": {},
7 | "source": [
8 | "
"
9 | ]
10 | },
11 | {
12 | "cell_type": "markdown",
13 | "id": "8b54d1d9",
14 | "metadata": {},
15 | "source": [
16 | "> **Warning**: this notebook takes forever on the CPU and goes OOM on the standard Colab GPU, if possible use a more powerful GPU"
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "execution_count": 1,
22 | "id": "c2d8a203",
23 | "metadata": {},
24 | "outputs": [],
25 | "source": [
26 | "try:\n",
27 | " # Check if PyTorch Geometric is installed:\n",
28 | " import torch_geometric\n",
29 | "except ImportError:\n",
30 | " # If PyTorch Geometric is not installed, install it.\n",
31 | " %pip install -q torch-scatter -f https://pytorch-geometric.com/whl/torch-1.7.0+cu101.html\n",
32 | " %pip install -q torch-sparse -f https://pytorch-geometric.com/whl/torch-1.7.0+cu101.html\n",
33 | " %pip install -q torch-geometric"
34 | ]
35 | },
36 | {
37 | "cell_type": "markdown",
38 | "id": "bc6e944c",
39 | "metadata": {},
40 | "source": [
41 | "# Applications of Graph Neural Networks"
42 | ]
43 | },
44 | {
45 | "cell_type": "code",
46 | "execution_count": 2,
47 | "id": "76f2ecef",
48 | "metadata": {},
49 | "outputs": [],
50 | "source": [
51 | "import os\n",
52 | "from copy import deepcopy\n",
53 | "from typing import List, Optional, Tuple\n",
54 | "\n",
55 | "import matplotlib.pyplot as plt\n",
56 | "import networkx as nx\n",
57 | "import numpy as np\n",
58 | "import torch\n",
59 | "import torch.nn.functional as F\n",
60 | "import torch_geometric.transforms as T\n",
61 | "from sklearn.metrics import roc_auc_score\n",
62 | "from torch_geometric.data import Data\n",
63 | "from torch_geometric.loader.neighbor_sampler import EdgeIndex\n",
64 | "from torch_geometric.utils import to_networkx\n",
65 | "from tqdm import tqdm"
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "id": "bc71bb37",
71 | "metadata": {},
72 | "source": [
73 | "# Feature Augmentation on Graphs"
74 | ]
75 | },
76 | {
77 | "cell_type": "code",
78 | "execution_count": 3,
79 | "id": "7d4c1589",
80 | "metadata": {},
81 | "outputs": [],
82 | "source": [
83 | "def draw_graph_from_data(data: Data, node_size: Optional[int] = 1500, seed: Optional[int] = None) -> None:\n",
84 | " G = to_networkx(data, to_undirected=data.is_undirected())\n",
85 | " labels = {node_id: f\"ID: {node_id}\\n$x_{node_id}$: {node_x.tolist()}\" for node_id, node_x in enumerate(data.x)}\n",
86 | " pos = nx.spring_layout(G, seed=seed)\n",
87 | " nx.draw(G, pos=pos, labels=labels, node_size=node_size)"
88 | ]
89 | },
90 | {
91 | "cell_type": "markdown",
92 | "id": "5f1c355a",
93 | "metadata": {},
94 | "source": [
95 | "## Asign constant values to nodes"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": 4,
101 | "id": "dd3c9d6e",
102 | "metadata": {},
103 | "outputs": [
104 | {
105 | "name": "stdout",
106 | "output_type": "stream",
107 | "text": [
108 | "Num. nodes: 6\n",
109 | "Num. node features: 1\n",
110 | "Num. edges: 14\n",
111 | "Is undirected? True\n"
112 | ]
113 | },
114 | {
115 | "data": {
116 | "image/png": "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\n",
117 | "text/plain": [
118 | ""
119 | ]
120 | },
121 | "metadata": {},
122 | "output_type": "display_data"
123 | }
124 | ],
125 | "source": [
126 | "x = torch.ones((6, 1))\n",
127 | "edge_index = torch.tensor(\n",
128 | " [[0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 4, 4, 5, 5], [1, 2, 3, 0, 2, 0, 1, 4, 5, 0, 2, 5, 2, 4]], dtype=torch.long\n",
129 | ")\n",
130 | "data = Data(x=x, edge_index=edge_index)\n",
131 | "print(f\"Num. nodes: {data.num_nodes}\")\n",
132 | "print(f\"Num. node features: {data.num_node_features}\")\n",
133 | "print(f\"Num. edges: {data.num_edges}\")\n",
134 | "print(f\"Is undirected? {data.is_undirected()}\")\n",
135 | "\n",
136 | "draw_graph_from_data(data, seed=42)"
137 | ]
138 | },
139 | {
140 | "cell_type": "markdown",
141 | "id": "844252c4",
142 | "metadata": {},
143 | "source": [
144 | "## Asign unique IDs to nodes"
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "execution_count": 5,
150 | "id": "3ca0acae",
151 | "metadata": {},
152 | "outputs": [
153 | {
154 | "name": "stdout",
155 | "output_type": "stream",
156 | "text": [
157 | "Num. nodes: 6\n",
158 | "Num. node features: 6\n",
159 | "Num. edges: 14\n",
160 | "Is undirected? True\n"
161 | ]
162 | },
163 | {
164 | "data": {
165 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAb4AAAEuCAYAAADx63eqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAABT3UlEQVR4nO3de1xUdf4/8NfcZxguAnJVvKUImoGXFFILDU0gLUkLtlRqtzTa/LmZmasPe7hiumtqll90V2vNWxheVhO8Jwkm6qpcxFEoTBB0ELnMMMwwt/P7w3UKGZgZBmYG5v18PPxjDp/P+bzPEXjzOedzYTEMw4AQQghxEmx7B0AIIYTYEiU+QgghToUSHyGEEKdCiY8QQohTocRHCCHEqVDiI4QQ4lQo8RFCCHEqlPgIIYQ4FUp8hBBCnAolPkIIIU6FEh8hhBCnwrV3AITYm1SmguSuDAq1DhqtHjwuG2I+B0MC3OHrLrR3eISQDkaJjzidWoUa6ZfLcUoiheSeHGqtHnwuGwzDgGEAFgtgsViG46H+bogO9cPMkUHwFPPtHT4hxEos2p2BOIu88jpszS7FKYkULBag0ujNrivkscEwQHSoH94ePwDhQT06L1BCSKeixEe6vbpGNZYcKERW8X00aXXQW/Edz2YBAi4HUcE+WB0/DD1cqAdISFdDiY90ayevS7EwPQ8qjR5qnfk9PFP4HDaEPDbWvxqO6FC/DjsvIaTzUeIj3RLDMPDy7w23SX8GO+gpNBScwoOjX4DFfdhDY7t4QNhnGDwiZ4Ln1cusc2rrpKjY8keweL8NePF+Zib+36KPsTQ2FCwWq1OuhRDSsWhwC+l2GIbBxwcK0dCkBV+nh+h/xwW9QuD/xj/A6HXQ1ldBdvEg7m5fAP9Za8H36Wf2+YP+shcsNsfwefeFMshVWqyJH0bJj5AugObxkW4nJVOCw/mVaO1ZBovNAc8zAN4vJEMY9CTqc/ZY1Z5So8Ph/EqsypRYdR5CiG1Q4iPdysnrUuy5UAalRmdWeZfgSKjKrxs+V371ZyiKstqsU5H6Ju783xxUZ3wOXWM9gIfJb/eFMpySSNsdOyHENijxkW6jrlGNhel5Zic9AOC4eUOvkhs+B/5xE8RDo4yWZbu4w3/OBvRK/jcCkj4Ho25E9fefGb6u1OiwMD0PdY3qdl8DIaTzUeIj3caSA4UWzc0DAK38AdhCN7PKsvkiCAIGgcXmgCP2hNekd6G6dRX6pkZDGaVajyUHCy2KgRBiW5T4SLeQV16HrOL7Fk9ZUBafhzBoSPsafTSO5XcvE9U6PbJu3kd+eV37zkkI6XSU+Ei3sDW7FE1a8x5xMnodNHX3UHNiC1RlhfAY+wez6jVV3oTmwR0wjB46pQw1J/8FQZ9hYAvFzctpddiaXWrxNRBCbIOmM5Aur1ahximJ1OSKLE0VN1C2bgYABmyRO4R9hiFgzgbwegYZylRuS4Z75Ey4Dp3Qor627h5qf9wBfWMd2HwXCPuFw2faRy3K6RngpESKWoWa1vYkxAHRBHbS5f3r7C9Yf6rY4vd7nUnIY2PhpMF4e/wAe4dCCHkMPeokXd4pidShkh7wcAFsmtpAiGOixEe6PMk9uelCdiC5K7N3CIQQIyjxkS5NKlNBrXWs3t4jKq0eVTKVvcMghDyGEh/p0iR3ZeBzHfPbWMBlO2xvlBBn5pi/MQgxk0Ktg6OOz2IYBoomrb3DIIQ8hhIf6dI0Wn2ri1HbG8PAYR/DEuLMKPE5KRaLBbFYjKVLl9o7FKvwuGw46k5ALBYc9jGsvUycOBFCoRDjxo2zdyjEidFPpRPLz8/HqlWrDJ9ramowffp0iMVi9O3bF3v2tL1dj6Xl21v392WDgoKwYsUKfPPNN1iyZAnW//1TNMgb2mxLp5Sjan8Kyta9gjupb7a5+4IlZU3VrS/MgljQ+hoR9rh/lrYDAJs2bcKoUaMgEAiQlJRkVVw//PADtmzZYlH7hHS0LrNyi1SmguSuDAq1DhqtHjwuG2I+B0MC3OHrLjR9AmLSe++9Bz6fD6lUiry8PMTFxSEsLAxDhw7tkPLm1tXpdCgrK8ONGzdw8+ZNbNq0CTKZDGKxGA8ePMDf/vY3xMTEICIiAn+IHYk1RSK0NY2v5sRmsDg89H5/F9TSUlTtWwGeb3/wffpaVdZU3cp9K8D66FUAPja9fx3ZDgAEBgZi2bJlOH78OJRKZYfFRYi9OOzKLbUKNdIvl+OURArJPTnUWj34XDYYhgHDPHyMxGKxDMdD/d0QHeqHmSODuuUyUR999BFKSkpw8OBBAMCiRYtw5coVHDt2DDwez+LzsVgslJSUYODAgQAAhUIBT09PXLt2DcHBwQCAWbNmoVevXlizZk2L+paWN1b3woULYBgGN27cwJo1a6DRaMDn81FSUgJvb2+EhITgiSeewLZt2/DVV18hOjoagYGBmD17drN2hq04DrnK+CASvVqF8s8TEPin/wPPqxcAoPr7deC4ecMzKqndZc1ppz5zPebGPN1p98+cuta087hly5bhzp072L59u1Vxbd++Hdu2bUNOTo5F7RPSURyux5dXXoet2aU4JZGCxUKzFTmaWhko0KTV4+KvtSioqMe6k8WIDvXD2+MHIDyoh42i7nyLFy/GE088gby8POTm5uLYsWPIyclpM+klJycDAFJTU02ev7i4GBwOx/ALCwDCwsLw448/WlWeYRhUVlbixo0bhh7cxYsXodVqMXbsWAwcOBAhISHw8/PDgwcPsG3bNgQHB8PV1RUAcPXqVXzzzTeYM2dOq+2E+rvh4q+1RuPU1lSAxWYbkhEA8Hz7o6ms5dZBlpQ1p26fQUNQVFRktLyl97u9da1px1K2bIsQazhM4qtrVGPJgUJkFd9Hk1ZncsFhYx4lyaPX7uKHG1WICvbB6vhh6OHS9XuA3t7eWLBgAWbPno36+nrk5OTAw8MDv/76K55++mnDo6T09HT4+Dx8tGZOwnukoaEBHh4ezY55eHhALjc+D+3x8iqVCg0NDSgtLUVKSgpu3rxpSHQuLi4YPHgwQkJCEBISgqCgIPzyyy+4d+8eOBwOAGDr1q3YvXs3RowYYXFc0aF+KKioN7psmV6jBEvg0uwYW+ACvbrlIztLypqqK+SxETYgAGUXjSdNS+93e+ta046lbNkWIdZwiMR38roUC9PzoNLoLd5PzRg983A37NM3qvDs2jNY/2o4okP9OiBS+xo+fDhWrFiB3bt3Iyjotx0FnnvuOezbt8+qc7u6ukIma77Elkwmg5vbb5u0MgyD6upq3LhxAydOnMCDBw/w4osv4saNG7hz5w7c3d3BZrPR0NCA559/Hu+99x4GDx4MT0/PZue9evUqPvnkE0PSM9aWJXHNHBmEdSeLjV4XmycC09Q8cTFNjWDzRVaVNVWXYYBBnhzUGrkmwLzrao0lda1px1K2bIsQa9h1VCfDMEjJuI75aVchU2k7JOn9nlqnh0ylxfvfXkVKxnWHnehsjsLCQrz77ruYM2cOvv7662ZfO3fuHMaPH4+//vWv7b7G4OBgaLValJSUQKvVori4GEeOHEFDQwPeeustjB07Fj179kRwcDAWL16MX3/9FQzDIC4uDhkZGZDL5ZgyZQqSkpKwZs0aJCUlISIiokXSe7ytR/Lz840OgDCnrKeYj+hQP7CNTGvgevV6uP9eTYXhmLrqFnhGBqtYUratumwWMCnUDyWSolYHdVhyD6ypa007lrJlW4RYw26Jj2EYfHygECten4CakssAgIaCU7j992koWzcDZetm4M7mP6I64/Nmv4gsUZezB7fXvIiaksvYfaEMHx8o7JLJr6KiAlOnTsWWLVuQmpqKwsJCZGVlAQACAgLw888/4+zZs6iqqsKBAwfMPq9MJsOFCxfwzTffICUlBb6+vhg1ahTEYjEmTJiAnJwcBAUFISIiAqtXr4ZEIkFNTQ1++ukn7Ny5EzNmzMDZs2fRu3dvXLx4EYcOHcKsWbMAAElJSa0OfReLxYiPj8fy5cuhUChw7ty5ZnUtLZuUlITyg59BwOW0qM/mC+EyOBJ12buhV6ugunMdjT9fgNjIfnvmlK0+sgHVRza0WZen12CUsKrVazLnumx9/9qapqDVaqFSqaDT6aDT6aBSqaDVthxMZElchNiT3RJfSqYEh/MrW6y6IegVgj4L9yHoL3vhl5ACFpePu9sXQH3/V4vOr6m9i8ab58Bx9QLw8NHn4fxKrMqUdNAV2IZMJkNsbCw++OADTJs2DS4uLli0aJFh4rlAIIBYLAaLxUJ8fDzy8/MNdefNm4e5c+fi119/xbFjx/D5559j3rx5iIqKAgCMHz8e7733Hk6ePAmxWIyVK1di5MiR4HK54HA4+Oabb7Bjxw688847ePbZZzFnzhysXr3acP7U1FQolUr4+voiMTERmzdvNvx1X15ejrFjx7Z6XW3VjYmJwaeffmpW2UdtTZ08AVHBPuBzWn5Le01OBqNV486Xr6P68Fp4T042TE+QfvcJ6n/6zqyyAKCT34egd6jRa/KanAyWTo3SzxOxfME7LeK05LqsuX+Pt2XO/WurrZSUFIhEIqxZswa7du2CSCRCSkqKxddEiKOwy3SGk9elmJ92FUqNDndS34J37HyI+oWjoeAUGgpOwP+NfzQrX5W+AiwuDz7T/2p2G9LvPoH7yBfx4Phmw/kBQMTj4MvE4d3inR/wMDG6u7tDoVDg/fffh0AggK+vr2EU5e+nBjz6N3jwYLz44osQCASYP38+Vq5c2aExqdVqhIWFoaCgoF1TLdrblkLD4Nm1ZyBrZWqDtRidBpVfv4/AtzaBxTH+etxDxMXZRRPhIWr/ddvr/nV2WwAwadIk5ObmYvTo0Th9+nSnt0eIMTYf3FLXqMbC9DwoNTqz67gER6L2xx2Gz5Vf/RkeETMgHhpltLziRg5YbC5ETzwNYHOzryk1OixMz8OPH07ocqM9H00NeDRi8saNG8jOzkZRURG0Wi08PDzw/PPPw8fHBy+99BI++ugjBAcHGx1coFJ13nY5fD4fEolteta/b6sHD1g3M9zwR1VHY3F46PV266uOiHgcrJsZblXSA+x3/2zh5MmTNmuLkNbYPPEtOVBo8W7ZHDdv6FW/DYkO/OOmVsvq1UrU/fgNfF9rvRejVOux5GAhNr8+0qI4bKWpqQklJSXNEtyjqQEikahZ723KlCkICQlB3759m42SdFaThvjh9TF9sPtCWackv9aIeBy8PqZPt3mSQEh3ZtPEl1deh6zi+xaP3tTKH4AtNG9IdF32boiHTgSvh3+rZdQ6PbJu3kd+eR3C7DTJ/dHUgMeT26OpAf369TMkt+effx7JyckYPHgwvLy87BJvV7I0NhRylRaH8yttkvxEPA6mhQdiaazxd3+EEMdi08S3NbsUTVrLfxEpi89DGDTErLKq2/nQyR9AfjUDAKBvlKH6P2vgHjEDHhEzDOWatDpszS7Fpj+MaO1UHUKr1aK0tNTQY/t9gtPr9c16b+PHj0dISAgGDBhgk/ct3RWLxcKa+GFwE3I7vef3qKe3NDYULEfdJoIQ0ozNEl+tQo1TEqnZK7Iweh20svuQX/wPVGWF8J/1mVn1/BJXAbrfftHd/eYv8Hz+TxANaP5YU88AJyVS1CrUHbK2Z11dXbPVSh4lt9LSUgQGBhqS25gxYzBnzhyEhITAx8eHfll2EhaLhWVxQzCmv3eHLo7wCJ/DhojPxrqZ3WNxBEKcic0SX/rlcrP2TWuquIGydTMAMGCL3CHsMwwBczaA1/O3lUoqtyXDPXImXI3MxeKI3JsfYLHBFroaXX2DxQL2XbmDt8cPMOsa9Hq9YdeAxxOcXC5vtixXYmIiQkJCMHDgQIhEplf+IJ1j0hA/nF00werl8B5hswABl4OowT5YPb17LIdHiLOx2XSGV//5U6sLCdvTmP5e2PtOZLNjCoUCxcXFLRJccXExvL29myW4R/969epFvTcHl/+/BdBPGlkA3RSWTgO+QIBJ/1sA3V7vhgkh1rNZ4mtr6xh7cuECfw643SzBVVVVYdCgQS0SXGtTA0jXUqtQY9+VOw+3vLorg0qrh8DIlldNWj2EXDYG+7ribNomZO9Yh+C+gfYOnxBiJZskPqlMhWfXnml1WyG70mvxXN0phA3ub0hwNDXAuVTJVJDck0PRpDXs7ygWcBHq72bY5DghIQETJkzA3Llz7RwtIcRaNnnHJ7krA5/LdsjE5+YixFt/XI7ngo3vkk26P193oSHBtWbmzJnYvHkzJT5CugGbrNWpUOscdnFohmGgaHK8R7DEscTExODSpUu4f/++vUMhhFjJJolPo9W3WIzaUTAMoHbAnihxLC4uLpgyZQoOHjxo71AIIVaySeLjcdlmTWWwBxYL4HPtui2hw5k4cSKEQiHGjRtn71AcysyZM5Genm7vMAghVmrzN35NTQ2mT58OsViMvn37Ys+ePe0qK+ZzTA711ynlqNqfgrJ1r+BO6ptQFGV1SFlTdesLsyAWtP6q05J78LhNmzZh1KhREAgEbe53Zm07ltY3VfaHH37Ali2tL8bsrGJjY3Hx4kVUV1fbOxRCiBXaHNzy3nvvgc/nQyqVIi8vD3FxcQgLCzO6v1ZbZUMD3E0+Tqw5sRksDg+9398FtbQUVftWgOfbv9leaO0pa6pu5b4VYH30KgDjg1ssuQePCwwMxLJly3D8+HEolco2y1rTjqX1rW3LWbm4uOCFF17AwYMH8fbbb9s7HEJIO7XZ49u/fz9WrlwJV1dXjBs3DtOmTcPOnTtblFMoFG2W9XMXtvk4Ua9WofHmT+jx7Btg80UQBg2Fy8AxUBSdsaqsOXXdB0cg8+B3Rsubui5T4uPj8fLLL8Pb27vNcta2Y0l9a9tydvS4k5Cur83Ex+FwEBwcbPgcFhaGoqKiFuWKi4tNlg31b33it7amAiw2GzyvXoZjPN/+0Ny/bVVZc+p6+vXG5cuXjZY357o6grXtWFLfVtfUXcXGxuLChQv0uJOQLqzNxOfh4dHis1wub1GuoaHBZNnoUD8Iecab02uUYAlcmgcmcIFe3fLxoCVlTdXlsRhwVbXIyspCeHg4li5dip9++gm6/y1ybc51dQRr27Gkvq2uqbsSi8WYPHky/vOf/9g7FEJIO7WZ+GQyWYvPxpbscnV1NVl25sigVqc0sHkiME3NExfT1Gh0YWlLypqqy+ZwMCtmLF544QVs2rQJer0e8+bNg5+fH9544w3k5OSYfQ+sYc7966j61rZF6HEnIV1dm4lPq9WipKTE8Dk/P9/oAIjg4GCTZT3FfESH+oFtZHAn16sXGL0OmpoKwzF11S3wjAxWsaRsW3XZLGBSqB9KJEV48sknMW7cOKxevRoFBQW4cuUKxo0bh+zsbCiVSowcOdLwtdbugTXMuX8dVd/atggQFxeH3NxcPHjwwN6hEELaoc3EFx8fj+XLl0OhUODcuXM4dOgQZs2a1aKcWCw2WTYpKQnlBz+DgNtyDUw2XwiXwZGoy94NvVoF1Z3raPz5AsRGth0yp2z1kQ2oPrKhzbo8vQajhFVGr6lPnz6YN28eMjMzMWPGDLi5ueH27duYMmUKdu3ahdLSUnz//fd444032pymoNVqoVKpoNPpoNPpoFKpoNW2XCXG3PvXWlvm1G9PWWKcWCzGpEmT6HEnIV1Um4kvNTUVSqUSvr6+SExMxObNmw09g5iYGHz66admlQWA8vJyTJ08AVHBPuBzWjbrNTkZjFaNO1++jurDa+E9OdkwPUH63Seo/+k7s8oCgE5+H4LeoUavyWtyMlg6NUo/T8TyBe+0iPPx6/rnP/+JHj16YOfOneByufj73/+O0aNHY8OGDUhLS8OlS5fw5ZdforS0tEVbKSkpEIlEWLNmDXbt2gWRSISUlBSjbZlz/8aOHWv0mkzVt/T/iphGjzsJ6bpssjuDWq1GWFgYCgoKoNAweHbtGcg6aYsiRqdB5dfvI/CtTWBxjE9T9BBxcXbRRHiIeO1uR61WY9iwYVixYgWOHz+OzMxMeHl5IS4uDnFxcRg7diz4/I7ZpPT394/Ha3/M5po0aRJyc3MxevRonD59utPb64oaGhrQq1cv3Lp1C15eXvYOhxBiAZvtx/d7J69LMT/tKpQana2bhojHwZeJwxEd6teh59Xr9bh8+TIyMjKQmZmJ4uJiREdHIy4uDjExMfD39+/Q9oj9vfLKK4iLi8Nbb71l71AIIRawS+IDgJSM69h9ocymyU/E4+D1MX2wLG5Ip7cllUpx9OhRZGRk4OTJkxg0aBDi4uIQGxuLUaNGgc2m9UG7urS0NHzzzTc4evSovUMhhFjAbomPYRh8fKAQh/MrbZL8RDwOpoUHYs30YSbXDe1oGo0GOTk5ht7ggwcPEBMTg7i4OEyePLnFvDrSNdDjTkK6JrslPuBh8luVKen0nt+jnt7S2FCbJz1jSktLkZmZiYyMDOTk5GDUqFGG3mBoqGPESMwTHx+PqVOn4s0337R3KIQQM9k18T1y8roUC9PzoNLoodZ13N54fA4bIj4b62aGd/g7vY6iUCjwww8/ICMjAxkZGeByuYYBMlFRURCJTE/MJ/bz7bffYufOncjMzLR3KIQQMzlE4gOAukY1lhwoRFbxfTRpddBbERWbBQi4HEQN9sHq6cPQw6VjRld2NoZhcO3aNUMSzM/Px3PPPWfoDfbp08feIZLHyOVy9OrVC7dv34anp6e9wyGEmMFhEt8j+eV12JpdipMSKVgsQKUxvwco5LHBMA9XZHl7/ACEBfXovEBtoKamxjBV4tixY/D39zf0BiMjI8HltrmrFLGR6dOn46WXXjK55yIhxDE4XOJ7pFahxr4rd3BKIoXkrgwqrR4CLhsMw4BhHu6czmKx0KTVQ8hlIzTAHdGhfpgxojc8xV2jh2cJnU6HixcvGnqDZWVlmDx5MuLi4jBlyhT07NnT3iE6rT179mD37t3IyMiwdyiEEDM4bOJ7XJVMBck9ORRNWqi1evC5bIgFXIT6u8HXXWjv8GyuoqICmZmZyMzMxA8//IAhQ4YYeoPh4eE0QMaGHj3uLCsrQ48ePewdDiHEhC6T+EjrmpqacPbsWUNvsLGxEbGxsYiNjUV0dDTtvGADL7/8MqZPn445c+bYOxRCiAmU+Lqh4uJiw5zB3NxcREREGHqDgwYNsnd43dLu3bvx7bff4siRI/YOhRBiAiW+bk4ul+PUqVOGROjq6moYJfrss89CIBDYO8RuQSaToXfv3vS4k5AugBKfE2EYBlevXjUkwevXr2PixImGRBgYGGjvELu0l156Ca+88gpmz55t71AIIW2gxOfE7t+/j2PHjiEjIwMnTpxAv379DElw9OjR4HBa7p1IWrdr1y7s3bsX33//vb1DIYS0gRIfAfBw09yffvrJ0Bu8d+8epkyZgri4OLzwwgs0OdsM9fX1CAoKQnl5Oa2/SogDo8RHjLp9+7ZhPdGzZ88iPDzc0Bt88sknabpEK6ZNm4aZM2fSjvaEODBKfMQkpVKJM2fOGBKhXq9HbGws4uLiMHHiRLi4uNg7RIexc+dOpKen4/Dhw/YOhRDSCkp8xCIMw0AikRjmDF6+fBnjx4839Ab79+9v7xDtih53EuL4KPERq9TV1eHEiRPIzMzE0aNH4e3tbZgzOHbsWPB4PHuHaHNTp07Fa6+9hjfeeMPeoRBCjKDERzqMXq/Hf//7X0Nv8JdffsGkSZMQGxuLmJgY+Pk55tZQHW3Hjh3Yv38/Dh06ZO9QCCFGUOIjnebu3bs4evQoMjMzcerUKQQHBxt6gyNGjACbzbZ3iJ2irq4Offr0wZ07d+Du7g4AkMpUkNyVQaHWQaPVg8dlQ8znYEiAu1OuNUuIPVHiIzahVquRk5Nj6A3W1dUZ1hOdPHmyIUF0F1NeegX9JiSiRhQIyT25YWH1x3cXeXQ81N8N0aF+mDkyqFvuLkKII6HER+zil19+MYwSPXfuHJ5++mlDb3Dw4MFddrpE3v/2kzx+rRI6nRYM2/x3nI/2k4z+336S4V18P0lCHBUlPmJ3CoUCp0+fNvQGBQKBYZRoVFQUhELHfxRY16jGkgOFyCq+jyatDnorfqrYLEDA5SAq2Aer44ehhwv1AAnpSJT4iENhGAYFBQWG3mBBQQGioqIMiTAoKMjeIbZw8roUC9PzoNLoodbpO+y8fA4bQh4b618NR3SocwwMIsQWKPERh/bgwQMcP34cGRkZOHbsGHr37m1IghEREeByuXaLjWEYrMqUYPeFMig1uk5rR8Tj4PUxfbA0NrTLPgImxJFQ4iNdhk6nQ25urqE3WF5ejhdeeAFxcXGYMmUKvL29bRYLwzD4+EAh1v9xErxi5kPULxwNBafw4OgXYHEfPppku3hA2GcYPCJngufVy6zzNlXcQF32Lqjv/Qyw2BD2GQbPSXPh5umDaWGBWBM/jJIfIVaixEe6rDt37hiS4JkzZzBs2DBDbzAsLKxTE8TKjOvYc6EMJRvnwDv2t8TXUHAC/m/8A4xeB219FWQXD0JRdAb+s9aC79PP5HmVv/wXeo0Kov4jADYbNSe2QNdQA7/X/mbo+S2LG9Jp10WIM+ieE6mIU+jduzfeeecdHDp0CFVVVfjkk08glUoxY8YMBAUFGb7W0NDQoe2evC7FHhOPN1lsDnieAfB+IRnCoCdRn7PHrHOLnhgFccg4sAUuYPOEcBv5IpoqJAAApUaH3RfKcEoi7ZDrIMRZUeIj3YJQKMTkyZOxceNGlJSU4PTp0wgJCcEXX3yBgIAAvPDCC/jiiy/w888/W9VOXaMaC9PzLHqn5xIcCVX5dcPnyq/+DEVRlll1m8qLwOvZx/BZqdFhYXoe6hrVZrdPCGmOEh/pdlgsFgYPHowPPvgAp0+fRkVFBebOnYv8/HyMHz++2dfUassSyJIDhVBpLBu5yXHzhl4lN3wO/OMmiIdGmaynrrqF+nPfwnPCm82OK9V6LDlYaFEMhJDfUOIj3Z67uzvi4+Px1VdfoaKiAnv27EGPHj3w17/+FT4+Poav3b17t83z5JXXIav4vsVTFrTyB2AL3Syqo6mtRNV3n8Az+h0Ig55s9jW1To+sm/eRX15n0TkJIQ9R4iNOhc1mY+TIkVi+fDkuXLiAkpISvPzyyzhx4gSGDBnS7Gt6ffMEtzW7FE1ay6ctKIvPQxhk/oAUbX0VpN8ug8fYBLg+OdFomSatDluzSy2OhRBCiY84OV9fX8yePRt79+5FVVUV1q9fD5VKhbfeegv+/v6Gr/169z5OSaRmr8jC6HXQ1N1DzYktUJUVwmPsH8yqp5VXQ/rtX+E2Mg5uw2NbLadngJMSKWoV9K6PEEvRdAZCWvHrr78apktckrtDHPEaGE7ztTfvpL7VbDrDb/P4GLBF7g/n8UXMBK/nbyvOVG5LhnvkTLgOndCizbqcPajP2QMWr/kybX0W7mtRVshjY+GkwXh7/ICOuWBCnAQlPkLM8MrmHFwuq7d3GC2M6e+Fve9E2jsMQroUetRJiBmKqxT2DsEoyV2ZvUMgpMuhxEeICVKZCmptxy0+3ZFUWj2qZCp7h0FIl0KJjxATJHdl4HMd80dFwGVDck9uuiAhxMAxf5oJcSAKtQ6O+iqcYRgomrT2DoOQLoUSHyEmaLR6OGjeA8PAYR/DEuKoKPGRTsNisSAWi7F06VJ7h2IVHpcNR90JiMWCwz6GtZeJEydCKBRi3Lhx9g6FOCj6iSGdKj8/H6tWrTJ8rqmpwfTp0yEWi9G3b1/s2dP2rgWWlm9v3bbKivkck1scyS5/j7vbF+D22pdRfWRDm2V1Sjmq9qegbN0ruJP6ptkLVhurW1+YBbGg9c14HeH+2bqtH374AVu2bLGofeJc7Ld9NXFK7733Hvh8PqRSKfLy8hAXF4ewsDAMHTq0Q8q3t25bZUMD3E0+TuS6esPjmdegvHUFjKbt1VRqTmwGi8ND7/d3QS0tRdW+FeD59gffp6/Ja3q8buW+Faia8xyYQVOMJmdHuH/msGVbhNAEdmLw0UcfoaSkBAcPHgQALFq0CFeuXMGxY8fA4/FM1G6JxWKhpKQEAwcOBAAoFAp4enri2rVrCA4OBgDMmjULvXr1wpo1a1rUt7R8e+uaU3bYiuOQq0wPIqk9uxM6WTV6vvgXo1/Xq1Uo/zwBgX/6P8Ou7NXfrwPHzRueUUltnttY3QeH/wH9r/+Fh4cHIiMjERERgYiICIwaNQp6vd5h7p+t29q+fTu2bduGnJwck+0T50OPOonB4sWLcebMGeTl5WHLli04duwYDhw40GbSS05ORnJyslnnLy4uBofDMfzCAoCwsDAUFRV1SPn21jWnbKi/ZbsrtEZbUwEWm21IXADA8+0Pzf3b7ao7IPQpTJw4EefOncOMGTNQXl6OhQsXomfPnnj66aeh1+tx6dIl/PLLL2AYxm73z1HaIgSgR53kd7y9vbFgwQLMnj0b9fX1yMnJgYeHB86fP48PPvgAfD4fgYGB2LFjhyEZpqammn3+hoYGeHh4NDvm4eEBudz4PDRLy7e3rjllo0P9UFBRb/FefI/Ta5RgCVyaHWMLXKBXKy2uK+SxETYgAGUXC9G/f3/0798fiYmJAAClUol///vf+Pjjj/Gf//wHixcvhlqtRkBAAORyOc6cOYOnn34arq6uRtvq6PvXFlu2RQhAPT7ymOHDh6OwsBCrV69GUNDDhZX79u2LH374AT/++CMGDBiAQ4cOtevcrq6ukMmaL7Elk8ng5ma8N2Vp+fbWNafszJFBHTKlgc0TgWlqnuSYpkaw+SKL6zIMMMiTY/SaRCIRIiMjodVqkZ6ejjt37uDKlSsIDw8Hi8XCsmXL4Ofnh7CwMMybNw/bt2/HzZs3DVsxdfT9a4st2yIEoMRHfqewsBDvvvsu5syZg6+//tpwPDAwECLRw1/MXC4XbHb7vm2Cg4Oh1WpRUlJiOJafn9/qoARLy7e3rjllPcV8RIf6gW3ltAauV6+HWxbVVBiOqatugWfGwJbf12WzgEmhfiiRFJl9/3r37g2GYTBz5kycO3cOtbW12Lp1K4YMGYLjx49jypQp6NmzJ2JiYrB//35oNBpcvnzZcD5r7l9bOvr/ihBTKPERAEBFRQWmTp2KLVu2IDU1FYWFhcjKympW5tatWzh69ChefPHFdrUhFosRHx+P5cuXQ6FQ4Ny5czh06BBmzZrVrvJJSUlISkqyui1zyiYlJaH84GcQcDlG22P0OjBaNaDXAYwejFYNRt9y01o2XwiXwZGoy94NvVoF1Z3raPz5AsS/26Ko+sgGo1Mifl+Xp9dglLDKqvv3zjvvIDU1FfPnz8e3336LW7du4fr165g7dy60Wi08PT0RERGB0NBQvPjii0hPT0dERAR0Op1F7Ty6f7b6vyLEJIY4vfr6euapp55iNm7caDi2du1a5plnnmlWZvz48cyNGzea1Z07dy4zd+5co+cFwJSUlDQ79uDBA+all15iXFxcmKCgIGb37t3Nvj5lyhRm1apVZpWfOHEi869//avV62qrriXt/L6teTv/ywxamsn0/fhIs38eYxMZAM3+eYxNZPp+fIQRDhjJ9Hh2tqFs7//3LSMaFMGweAKG4+7D9Jz6YbNzCfs+xXhN+XOLNh7VFQdHMFyB0Cb3b9q0aYxQKGQ8PT2ZcePGMYMGDWLc3d2Z559/nnniiSeY2bNnM9XV1WbfP1v8XzEMw/z73/9mxo4d22p7xLnRdAZiklarxUsvvYSFCxdi4sSJZtcTCoUQCASYP38+Vq5c2aExqdVqhIWFoaCgoF1TLdrblkLD4Nm1ZyAzY2pDezA6DSq/fh+Bb20Ci2N87JmHiIuziybCQ9T+67bm/lVXV+PChQvIzc3F+fPncenSJfj5+SEiIsIwpWLYsGHgcrlWt9UekyZNQm5uLkaPHo3Tp093enuk66HER0zauXMn/vKXv+DJJ58EALz77rt47bXX7ByV/Zy8LsX8tKtQalo+yuxsIh4HXyYOR3Son83bbo1Op4NEIsH58+cNybC8vBwjR45slgz9/BwnZuLcKPER0g4pGdex+0KZTZOfiMfB62P6YFncEJu12V51dXW4ePGiIRleuHChxST78PBw8Pl8e4dKnBAlPkLagWEYfHygEIfzK22S/EQ8DqaFB2LN9GEm1w11RHq9HsXFxcjNzTX0Cn/++WeEh4c3S4a9e/e2d6jECVDiI6SdGIbBqkxJp/f8HvX0lsaGdsmk1xq5XI5Lly41S4ZCodCQBCMjIzFixAgIhUJ7h0q6GUp8hFjp5HUpFqbnQaXRQ63ruL3xeGzARcDFupnhDvVOr7MwDIPS0lJDEszNzYVEIsHQoUOb9Qr79evXrf4AILZHiY+QDlDXqMaSA4XIKr6PJq0Oeit+qtgsgA09BA9+Rs76ZHiKBR0XaBfT2NiIy5cvG5Lh+fPnwTBMs0Ezo0aNglgstneopAuhxEdIB8ovr8PW7FKclEjBYsGitT2FPDYY5uGKLG8+0wez457DqlWr8PLLL3dewF0MwzAoLy839Ahzc3NRUFCAwYMHN3tEOnDgQOoVklZR4iOkE9Qq1Nh35Q5OSaSQ3JVBpdVDwGWDYRgwzMOd01ksFpq0egi5bIQGuCM61A8zRvSGp/jhSMdTp05h7ty5KCoqovdcbWhqasLVq1ebPSJVKBQYM2aMoVc4evRouLu72ztU4iAo8RFiA1UyFST35FA0aaHW6sHnsiEWcBHq7wZf99aT2ssvv4wxY8ZgyZIlNoy266usrGw2aObq1avo379/s0ekISEh7V53lgBSmQqSuzIo1DpotHrwuGyI+RwMCXBv83vaEVDiI8SB/fLLLxg9ejQKCwsRGBho73C6LI1Gg4KCgmaPSB88eIDRo0cbkuHo0aPh5eVl71AdVq1CjfTL5Q+fYtyTG/6Ae/wpxqPjof5uiA71w8yRQYanGI6CEh8hDm7JkiWoqKjAjh077B1Kt1JVVYULFy4YkuGlS5fQq1evZiNIn3zySXA4xhcmdxZ5/3tvfcqK99bRoX54e/wAhAf16LxALUCJjxAHJ5fLERISgv379yMiIsLe4XRbWq0WRUVFzR6RVlZWYtSoUYZe4ZgxY+Dr62vvUG2io0cqC7gcRAX7YHX8MPRwsW8PkBIfIV3Ajh07sGnTJuTm5tJ7KRuqqakxLMj9aOk1b29vQ68wMjISTz31lE0W37alzpqbyuewIeSxsf5V+85NpcRHSBeg1+sRGRmJ5ORkzJkzx97hOC29Xo8bN240G0F669YtDB8+vNkj0q76PpZhGHj594bbpD+DHfQUGgpO4cHRL8DiPuyhsV08IOwzDB6RM8Hz6mXeOXUaVB9ei6a7P0Mnq4Jf4qfwHDjcrqsRUeIjpIu4cOECpk+fjps3b8LNzc3e4ZD/qa+vNyy99igZurq6NhtBOnz4cAgEjr0QwaP1Z9f/cRK8YuZD1C8cDQWn0FBwAv5v/AOMXgdtfRVkFw9CUXQG/rPWgu/Tz/R5dRrIr2SC7z8Q1f9Zg57TFkHY96mH68+GBWJNvO3XnzW+4RchxOGMGTMGkyZNwqpVq7BmzRp7h0P+x8PDA9HR0YiOjgbwMIH8/PPPhiS4Y8cO3Lx5E0899VSzSfZBQUEONck+JVOCw/mVaK0rxGJzwPMMgPcLydDJ7qM+Zw98pv/V5HlZHB7cn37p4YffPaZXanQ4nF8JNyHX5juOUOIjpAtZs2YNhg0bhj/96U8YOHCgvcMhRrBYLAwaNAiDBg3C7NmzAQAKhQL//e9/kZubi2+//Rbz588Hh8Np9nh05MiRcHFxsUvMJ69LsceCxdZdgiNR++Nvo4wrv/ozPCJmQDw0yqJ2lRoddl8oQ8QAb5u+86PER0gXEhAQgA8//BALFy7EoUOH7B0OMZNYLMZzzz2H5557DsDDXuGvv/5qGDSzcOFCFBUVITQ0tNkj0gEDBnR6r7CuUY2F6XkW7TDCcfOGXiU3fA7846Z2t6/U6LAwPQ8/fjjBZqM9aXgYIV3MggULcO3aNZw4ccLeoZB2YrFY6N+/PxITE7Fx40ZcvHgR1dXV+OKLL9C/f3/85z//wXPPPQc/Pz9MmzYNn376Kc6cOYOGhoYOj2XJgUKL5uYBgFb+AGxhx71nVqr1WHKwsMPOZwr1+AjpYoRCIdavX48FCxYgPz+/2w2ld1YikQjPPPMMnnnmGcOxO3fuGAbNLFu2DHl5eRg4cGCzR6TBwcHtnuKSV16HrOL7Fk9ZUBafhzCo497LqXV6ZN28j/zyOoTZYJI79fgI6YKmTZuGXr16YfPmzfYOhXSi3r17Y8aMGVi3bh3OnTuH2tpabN26FUOGDMGJEycQExODnj17IiYmBitWrMCJEydQV1dn9vm3ZpeiSWveI05Gr4Om7h5qTmyBqqwQHmP/YHY7jFYDRqv+33m0YLRqPD6hoEmrw9bsUrPPaQ2azkBIF1VUVISoqChcv34dPj4+9g6H2Mm9e/cM7wpzc3Nx+fJlBAUFNZtkHxoa2mLptVqFGhFrTqNJ27y3dyf1LXjH/jad4bd5fAzYIveH8/giZoLXM8hQp3JbMtwjZ8J16ASjMd5JfQs6WVWzY73mfQVuj+YDWgRcNnI/fr7T1/akxEdIFzZ//nxoNBrq+REDrVaLwsLCZvMKpVIpnn76aUMyHDNmDA5cr8f6U8UWv9/rTEIeGwsnDcbb4wd0ajuU+AjpwmpraxESEoITJ04gLCzM3uEQB1VdXW1Yeu38+fO4dOkSvGb+DYyP402JGdPfC3vfiezUNijxEdLFbd68GXv37sWZM2ccakI0cVw6nQ5PrTgOhcbxfv27C7ko+OSFTm2DBrcQ0sW98847qK2txf79++0dCukiqhUaaBnH/CNJpdWjSqbq1DYo8RHSxXE4HHz++ef48MMPoVQq7R0O6QIkd2Xgcx3z17+Ay4bkntx0QSs45pUTQiwyYcIEjBo1Cp999pm9QyFdgEKtazGdwFEwDANFk7ZT26DER0g38dlnn+Hzzz9HeXm5vUMhDk6j1be6GLW9MQyg1nbuSFNKfIR0E/369UNycjIWL15s71C6LRaLBbFYjKVLl9o7FKvwuGw46jgoFgud/hiWEh8h3cjHH3+M7Oxs5OTk2DuUbis/Px+rVq0yfK6pqcH06dMhFovRt29f7Nmzp836lpb/vU2bNmHUqFEQCARISkpqdztiPsfkCGCdUo6q/SkoW/cK7qS+CUVRVoeUNVW3vjALYkHrq2lac/8eobU6CelGxGIx/v73v2P+/Pm4dOlSi9U6SMd77733wOfzIZVKkZeXh7i4OISFhWHo0KEdUv73AgMDsWzZMhw/ftzkQKa22gkNcDf5OLHmxGawODz0fn8X1NJSVO1bAZ5vf/B9+lpV1lTdyn0rwProVQDGVyOy5v49Qj0+QrqZxMREuLi44N///re9Q7G7jz76CNOnTzd8XrRoEZ5//nloNJoOOb9CocD+/fuxcuVKuLq6Yty4cZg2bRp27tzZIeUfFx8fj5dffhne3t5WxeXnLmzzcaJerULjzZ/Q49k3wOaLIAwaCpeBY6AoOmNVWXPqug+OQObB79p1XeaixEdIN8NisbBx40YsW7YM9fX19g7HrhYvXowzZ84gLy8PW7ZswbFjx3DgwIE2d7RITk5GcnKyWecvLi4Gh8NBcHCw4VhYWBiKioo6pHx7tdWOXq/HuXPnwFNUtVpfW1MBFpsNnlcvwzGeb39o7t+2qqw5dfsMGtLp948SHyHd0MiRI/Hiiy/ib3/7m71DsStvb28sWLAAs2fPxurVq5GZmQkPDw/U19dj9OjRcHV1xbVr15rVSU1NRWpqqlnnb2hogIeHR7NjHh4ekMuNz0OztHx7Pd4OwzCoq6tDfn4++vfvj3feeQcDhY0QcIy/59NrlGAJmu8Gzxa4QK9u+XjVkrKm6gp5bIQNCOj0+0eJj5BuatWqVfjmm29w8+ZNe4diV8OHD0dhYSFWr16NoKCHOwq4uLggIyMDM2bMsOrcrq6ukMlkzY7JZDK4uRnfpNXS8tbGJZFI8MknnyAkJASbN2+GQCDAkSNHUFRUhH8ufhOtDe1k80RgmponLqapEWy+yKqypuoyDDDIk9Pp948SHyHdlJ+fHz7++GN88MEH9g7FbgoLC/Huu+9izpw5+Prrrw3HeTxeh2zlFBwcDK1Wi5KSEsOx/Pz8VgdaWFq+PW7duoXvv/8eKpUKUVFRkMvl2LVrF+Li4vDKK69g2LBhAABPMR/RoX5gG8l9XK9eD/ffq6kwHFNX3QLPyGAVS8q2VZfNAiaF+qFEUtTp948SHyHd2Pz581FSUoLMzEx7h2JzFRUVmDp1KrZs2YLU1FQUFhYiKyurQ9sQi8WIj4/H8uXLoVAocO7cORw6dAizZs1qV/mkpKQ2pylotVqoVCrodDrodDqoVCpotVpUVlZi48aNiIyMxOjRo3H37l1ERUVhwoQJWLlyJdRqdYu4kpKSUH7wMwi4LUf+svlCuAyORF32bujVKqjuXEfjzxcgNrLfnjllq49sQPWRDW3W5ek1GCWs6tT7Z2jXZAlCSJfF5/OxYcMG/OUvf4FarbZ3ODYjk8kQGxuLDz74ANOmTYOLiwsWLVpk1sTzefPmYd68eWa3lZqaCqVSCV9fXyQmJmLz5s3NeiAxMTH49NNPzSpfXl6OsWPHttpWSkoKRCIR1qxZg127dkEkEmHQoEEYOnQo1q5di8GDB6OyshKbN2/Gvn37oFKpWo2rvLwcUydPQFSwD/iclqnAa3IyGK0ad758HdWH18J7crJheoL0u09Q/9N3ZpUFAJ38PgS9Q41ek9fkZLB0apR+nojlC97p1Pv3CG1LRIgTiI2NxfPPP4+FCxfaOxSHkpSUhA8//BBPPvmkWeWFQiEEAgHmz5+PlStXdmgsarUaYWFhKCgoaHXUqUwmw6FDh5CWloacnBxMmTIFCQkJiImJgVAobFdbCg2DZ9eegUzVOetjMjoNKr9+H4FvbQKLY3zquIeIi7OLJsJD1PpoW1PMuX+PUOIjxAncuHED48aNQ1FREfz8/OwdjkOIjY1FXl4e+vbti7lz55r1iMwelEolMjIykJaWhpMnT+K5555DQkICpk2bBldX1w5p4+R1KeanXYVSo+uQ81lCxOPgy8ThiA613fclJT5CnMTChQtRX1+Pbdu22TsUYoJarcbJkyeRlpaGI0eOYNSoUUhISEB8fDw8PT07pc2UjOvYfaHMpslPxOPg9TF9sCxuiM3aBCjxEeI06urqEBISgoyMDIwcOdLe4ZDH6HQ6/Pjjj0hLS8OBAwcQEhKChIQEzJw50ya9dIZh8PGBQhzOr7RJ8hPxOJgWHog104eZXDe0o1HiI8SJbNu2Ddu3b0d2drbNf9mQlhiGQW5uLtLS0vDdd98hMDAQCQkJePXVV9G3r+npAJ0Rz6pMSaf3/B719JbGhtrl+5ASHyFORKfT4emnn8aiRYuQmJho73CcEsMwyM/PR1paGtLS0iASiZCYmIjXXnsNgwcPtnd4AB6+81uYngeVRg+1ruP2xuNz2BDx2Vg3M9ym7/QeR4mPECeTnZ2NP/zhD7hx4wbEYrG9w3EaN2/eNCQ7lUqFhIQEJCQk4KmnnnLI3nddoxpLDhQiq/g+mrQ66K3IFGwWIOByEDXYB6unD0MPF37HBdoOlPgIcUKJiYkYNGiQ06/l2dlu376NvXv3Ii0tDffu3cOrr76KhIQEjBkzxiGTnTH55XXYml2KkxIpWCxApTG/ByjkscEwD1dkeXv8AIQF9ei8QC1AiY8QJ1ReXo7w8HBcvnwZ/fr1s3c43cq9e/eQnp6OtLQ03Lx5E6+88goSEhLw7LPPdun9EWsVauy7cgenJFJI7sqg0uoh4LLBMAwY5uGynywWC01aPYRcNkID3BEd6ocZI3rDU2zfHt7jKPER4qT+9re/obCwEOnp6fYOpcurqanBgQMHkJaWhsuXL2Pq1KlISEhAdHQ0+HzH+qXfUapkKkjuyaFo0kKt1YPPZUMs4CLU3w2+7uZPprcHSnyEOKnGxkYMGTIE27dvR1RUlL3D6XLkcjkOHz6MtLQ0nD17FpMnT0ZCQgJiY2MhEpnemYDYDyU+QpxYeno6UlJScPnyZXC5xpeTIr9RKpU4evQo0tLScPz4cYwfPx4JCQl46aWXOnxrIdJ5KPER4sQYhsGECROQkJBg0cLMzkSj0eDUqVNIS0vD4cOHMWLECMMqKt7e3vYOj7QDJT5CnFxeXh5eeOEF3Lhxo9OWw+pqdDodsrOzkZaWhv3792PQoEGGVVQCAgLsHR6xEiU+QgjmzZsHgUCAjRs3tlpGKlNBclcGhVoHjVYPHpcNMZ+DIQHuDj+YwRwMw+DixYuGVVR8fX2RkJCA1157jUa+djOU+AghuH//PoYMGYKsrCzD3ma1CjXSL5c/HL5+T24Yuff48PVHx0P93RAd6oeZI4Mcbvh6axiGQWFhoWFiOY/HM6yiEhpqfP840vVR4iOEAAA2btyIjIwM/H3bXmzLuYVTVkxYjv7fhOVwB5mw/LiSkhKkpaXh22+/hUKhMKyiEh4e3mUmlpP2o8RHCAEA3K9vRMT7G8EOGgYdw+qYJaqCfbA63v5LVAEPJ+3v3bsX3377LSoqKgyrqERERIDNbrkDOem+KPERQgyLEjc2aaHtwN8IfA4bQh4b61+1z6LEUqkU+/btQ1paGq5fv474+HgkJCQgKiqqS6+iQqxDiY8QJ9Ydt6Gpra3FwYMHkZaWhosXL+LFF19EQkICJk+e3G1XUSGWocRHiJN6tPHo+j9OglfMfIj6haOh4BQeHP0CLO7DBMF28YCwzzB4RM4Ez6uX2edW/pqHmhNboJPdBz8wGD3j/gK3ngGYFhaINfEdv/FoQ0MDvv/+e6SlpSErKwvR0dFISEhAXFwcXFxcOrQt0vXRUg2EOKmUTAkO51fi8T99Bb1C4P/GP8DoddDWV0F28SDubl8A/1lrwffpZ/K8usZ63D/4Kbxj5sNl4GjUnd2F+4f+Du7sdTicXwk3IRfL4oZYHb9KpcKxY8eQlpaGo0ePYuzYsUhISMCOHTvg4eFh9flJ90VvdAlxQievS7HHxONNFpsDnmcAvF9IhjDoSdTn7DHr3I3F58Hv2QfikHFgcfnwGPcHaKpuQfOgHEqNDrsvlOGURNquuDUaDY4fP44333wTgYGB2LhxIyZMmIBffvkFmZmZmD17NiU9YhIlPkKcTF2jGgvT8yx6p+cSHAlV+XXD58qv/gxFUZbRspr7t8Hz7W/4zOYLwe3hD/X9MgCAUqPDwvQ81DWqzWpbr9fj7NmzSE5ORq9evfDJJ58gLCwMhYWFOHPmDObOnYuePXuafS2E0KNOQpzMkgOFFs3NAwCOmzf0Krnhc+AfN7VaVq9RgePSvNfFFojBqJWGz0q1HksOFmLz6yONnoNhGPz3v/9FWloa9u7dC29vbyQkJCA3NxcDBgywKHZCHkeJjxAnkldeh6zi+1DrLEt8WvkDsIXm7T7A5gmhb2psdkyvbgSL/9tWPWqdHlk37yO/vK7ZrtzXrl0zrKLCYrGQmJiIEydOYMgQ698JEvIIJT5CnMjW7FI0aS2ftqAsPg9hkHnJh+fTF4rC04bPerUK2tp74Pv0aVauSavD1uxSLBjtjr179yItLQ11dXVISEjA3r17MWLECFpFhXQKesdHiJOoVahxSiI1e0UWRq+Dpu4eak5sgaqsEB5j/2BWPZfgSKirb0Nx4xwYrRr1574Fz7cfeN5BzcrpGeBIXhnGTpyMu3fvYvPmzbh9+zbWrl2LkSNHUtIjnYZ6fIQ4ifTL5TAnlzRV3EDZuhkAGLBF7hD2GYaAORvA6/lb4qrclgz3yJlwHTqhRX2Oiwd8pv8VNSe24MGRdeAHBMNn2kdG2+LxeFiy4wTmRg1s72URYjGawE6Ik3j1nz/h4q+19g6jhTH9vbD3nUh7h0GcCD3qJMRJSO7JTReyA8ldmb1DIE6GEh8hTkAqU0GttWwkp62otHpUyVT2DoM4EUp8hDgByV0Z+FzH/HEXcNkO2xsl3ZNj/iQQQjqUQq2Do77OZxgGiiatvcMgToQSHyFOQKPVt1iM2lEwDBz2MSzpnijxEdIGFosFsViMpUuX2jsUq/C4bLOmMtgDiwWHfQxrLxMnToRQKMS4cePsHUq3RN9thJiQn5+PVatWGT5v2rQJo0aNgkAgQFJSksn6NTU1mD59OsRiMfr27Ys9e8zb5cDSum2VFfM5JieE65RyVO1PQdm6V3An9c1WF6G2tKypuvWFWRALWp9S7Aj3z9Zt/fDDD9iyZYtF7RPz0QR2QiwUGBiIZcuW4fjx41AqlSbLv/fee+Dz+ZBKpcjLy0NcXBzCwsIwdOjQDq3bVtnQAHeTjxNrTmwGi8ND7/d3QS0tRdW+FeD59gffp69VZU3Vrdy3AqyPXgXgY/U9sKauNe3Yui1iHerxkW7lo48+wvTp0w2fFy1ahOeffx4ajabD2oiPj8fLL78Mb29vk2UVCgX279+PlStXwtXVFePGjcO0adOwc+fODq1rqqyfu7DNx4l6tQqNN39Cj2ffAJsvgjBoKFwGjoGi6IxVZc2p6z44ApkHv7P6HlhT15p2bN0WsR4lPtKtLF68GGfOnEFeXh62bNmCY8eO4cCBA+DxeK3WSU5ORnJycqfEU1xcDA6Hg+DgYMOxsLAwFBUVdWhdc8qG+re+u4K2pgIsNhs8r16GYzzf/tDcv21VWXPq9hk0pNX74Uj3z1HaItajR52kW/H29saCBQswe/Zs1NfXIycnx7Aj99KlS3H27Fn4+flhx44dcHFxAQCkpqZ2WjwNDQ0tdgT38PCAXG563poldc0pGx3qh4KKeqN78ek1SrAELs2OsQUu0KtbPsq1pKypukIeG2EDAlB2sdBoeUe6f47SFrEe9fhItzN8+HAUFhZi9erVCAp6uLDytWvX8MsvvyA7OxvR0dH4+uuvbRKLq6srZLLmS3LJZDK4uZne286SuuaUnTkyqNUpDWyeCExT88TFNDWC/bs99NpT1lRdhgEGeXJavR+OdP8cpS1iPUp8pFspLCzEu+++izlz5jRLbtnZ2YiJiQEAxMTEICcnxybxBAcHQ6vVoqSkxHAsPz/frEEMltQ1p6ynmI/oUD+wjQzu5Hr1ergNUU2F4Zi66hZ4RgarWFK2rbpsFjAp1A8lkqJW74cj3T9HaYtYjxIf6TYqKiowdepUbNmyBampqSgsLERWVhYAoLa21vB4ycPDAzU1Ne1uR6vVQqVSQafTQafTQaVSQas1vvKIWCxGfHw8li9fDoVCgXPnzuHQoUOYNWsWACApKanVKRGm6lpaNikpCeUHP4OAy2lRn80XwmVwJOqyd0OvVkF15zoaf74AsZFth8wpW31kA6qPbGizLk+vwShhVavX5Ij3z1Ztkc5FiY90CzKZDLGxsfjggw8wbdo0uLi4YNGiRYaJ556enqivrwcA1NfXw8vLy1B33rx5mDdvntltpaSkQCQSYc2aNdi1axdEIhFSUlIMX4+JicGnn35q+JyamgqlUglfX18kJiZi8+bNhr/uy8vLMXbs2FbbaquuJe08amvq5AmICvYBn9PyR99rcjIYrRp3vnwd1YfXwntysmF6gvS7T1D/03dmlQUAnfw+BL1DjV6T1+RksHRqlH6eiOUL3mkRp63u3+NtmXP/bPV/RToX7cdHnMKjd3579uzBv/71LzQ1NeH99983WU8oFEIgEGD+/PlYuXJlh8akVqsRFhaGgoKCNkeddnRbCg2DZ9eegUzVOetjMjoNKr9+H4FvbQKLY3z8nIeIi7OLJsJD1P7rttf96+y2AGDSpEnIzc3F6NGjcfr06U5vz9lQ4iNOY8mSJcjJyYGvry927NgBsVhs75Ds5uR1KeanXYVSo7N52yIeB18mDkd0qJ/N2yYEoMRHiNNKybiO3RfKbJr8RDwOXh/TB8vihtisTUIeR+/4CHFSS2NDMS0sECJey8EunUHE42BaeCCWxhp/90eIrVCPjxAnxjAMVmVKOr3n96intzQ21ORi2YR0Nkp8hBCcvC7FwvQ8qDR6qHUdtzcen8OGiM/Gupnh9E6POAxKfIQQAEBdoxpLDhQiq/g+mrQ66K34zcBmAQIuB1GDfbB6+jD0cOF3XKCEWIkSHyGkmfzyOmzNLsVJiRQsFoyu7dkaIY8Nhnm4Isvb4wcgLKhH5wVKSDtR4iOEGFWrUGPflTvYdvQCahgXsLh8CLhsMAwDhnm4czqLxUKTVg8hl43QAHdEh/phxoje8BRTD484Lkp8hJA2TZ48GfPnz8foZ6MhuSeHokkLtVYPPpcNsYCLUH83+LoL7R0mIWajxEcIaZVer4eXlxdKSkrg42N8h3RCuhqax0cIaZVEIoGPjw8lPdKtUOIjhLTq/PnziIiIsHcYhHQoSnyEkFadP38ekZGR9g6DkA5FiY8Q0qrc3Fzq8ZFuhwa3EEKMqqurQ+/evVFXVwcu1/j2QoR0RdTjI4QYdfHiRYwcOZKSHul2KPERQoyi93uku6LERwgxit7vke6K3vERQlrQ6/Xw9vaGRCKBv7+/vcMhpENRj48Q0kJxcTF69OhBSY90S5T4CCEt0Ps90p1R4iOEtJCbm0uJj3RblPgIIS3QUmWkO6PBLYSQZuRyOQICAlBTUwM+n/bVI90P9fgIIc1cvHgR4eHhlPRIt0WJjxDSDL3fI90dJT5CSDP0fo90d/SOjxBiwDAMfHx8UFBQgMDAQHuHQ0inoB4fIcTg559/houLCyU90q1R4iOEGNDEdeIMKPERQgxoYWriDCjxEUIMqMdHnAENbiGEAAAUCgV8fX1RU1MDgUBg73AI6TTU4yOEAAAuXbqEp556ipIe6fYo8RFCAND7PeI8KPERQgDQ+z3iPOgdHyEEDMPA398fly5dQp8+fewdDiGdinp8hBDcunULXC4XQUFB9g6FkE5HiY8QYni/x2Kx7B0KIZ2OEh8hhN7vEadCiY8QQiM6iVOhwS2EODmlUomePXuiuroaIpHI3uEQ0umox0eIk7t8+TKGDh1KSY84DUp8hDg52niWOBtKfIQ4udzcXBrYQpwKJT5CnBjDMNTjI06Ha+8ACCGdTypTQXJXBoVaB41WDx6XDTGfA3e9HHq9Hv369bN3iITYDI3qJKQbqlWokX65HKckUkjuyaHW6sHnssEwDBgGYLEAFosFZZMGeq0ao57wR3SoH2aODIKnmG/v8AnpVJT4COlG8srrsDW7FKckUrBYgEqjN7uukMcGwwDRoX54e/wAhAf16LxACbEjSnyEdAN1jWosOVCIrOL7aNLqoLfip5rNAgRcDqKCfbA6fhh6uFAPkHQvlPgI6eJOXpdiYXoeVBo91Drze3im8DlsCHlsrH81HNGhfh12XkLsjRIfIV0UwzDw8u8Nt0l/BjvoKTQUnMKDo1+AxX3YQ2O7eEDYZxg8ImeC59XLrHOqq8vw4Mh6aGvvAgD4/gMREPMu3npxPJbGhtIi1qRboFGdhHRBDMPg4wOFaGjSgq/T49GaK4JeIfB/4x9g9Dpo66sgu3gQd7cvgP+steD79DN5Xq6rF3xeXgKOhy/A6CG/koE7+9dgt09fyFVarIkfRsmPdHk0j4+QLiglU4LD+ZVo7XkNi80BzzMA3i8kQxj0JOpz9ph1XrbQFdwefobkxmKxoa29C6VGh8P5lViVKemoSyDEbqjHR0gXc/K6FHsulEGp0ZlV3iU4ErU/7jB8rvzqz/CImAHx0KhW65RteA2MWgkwDDzGvw4AUGp02H2hDBEDvOmdH+nSKPER0oXUNaqxMD3P7KQHABw3b+hVcsPnwD9uMlmnz1/2Qq9WQXHtNDjuvobjSo0OC9Pz8OOHE2i0J+my6FEnIV3IkgOFFs3NAwCt/AHYQjeL22LzhXAdHoMHR9ZDp6gzHFeq9VhysNDi8xHiKCjxEdJF5JXXIav4vsVTFpTF5yEMGtK+RhkGjLYJOvkDwyG1To+sm/eRX17XvnMSYmeU+AjpIrZml6JJa94jTkavg6buHmpObIGqrBAeY/9gVj3lratQ3/sFjF4HfVMjak9vA1voCl7PoGblmrQ6bM0utfgaCHEE9I6PkC6gVqHGKYnU5IosTRU3ULZuBgAGbJE7hH2GIWDOhmaJq3JbMtwjZ8J16IQW9fVNCtSc/Cd08mqwuHzwAwbB99UVhrmBhnIMcFIiRa1CTWt7ki6HJrAT0gX86+wvWH+q2OL3e51JyGNj4aTBeHv8AHuHQohF6FEnIV3AKYnUoZIe8HAB7FMSqb3DIMRilPgI6QIk9+SmC9mB5K7M3iEQYjFKfIQ4OKlMBbXWsXp7j6i0elTJVPYOgxCLUOIjxMFJ7srA5zrmj6qAy3bY3ighrXHMnyZCiIFCrYOjjkFjGAaKJq29wyDEIpT4CHFwGq2+1cWo7Y1h4LCPYQlpDSU+0m2xWCyIxWIsXbrU3qFYhcdlw1F3AmKx4LCPYe1l4sSJEAqFGDdunL1DIa2g71jSreXn52PVqlWGzzU1NZg+fTrEYjH69u2LPXva3q7H0vLtrdtWWTGfY3IPPJ1Sjqr9KShb9wrupL4JRVFWh5R9nOzy97i7fQFur30Z1Uc2PPzjQtD6OhiOcP9s3dYPP/yALVu2WNQ+sS1auYU4lffeew98Ph9SqRR5eXmIi4tDWFgYhg4d2iHl21u3rbKhAe4mHyfWnNgMFoeH3u/vglpaiqp9K8Dz7Q++T1+ryj6O6+oNj2deg/LWFTAaNZq0eoT6t74AtiPcP3PYsi1if7RyC3EYH330EUpKSnDw4EEAwKJFi3DlyhUcO3YMPB7P4vOxWCyUlJRg4MCBAACFQgFPT09cu3YNwcHBAIBZs2ahV69eWLNmTYv6lpZvb11zyg5bcRxylfFBJHq1CuWfJyDwT/8HnlcvAED19+vAcfOGZ1RSu8u2pfbsTuhk1RgwYxEKPnnB6ntgTV1r2umstrZv345t27YhJyfHZPvE9uhRJ3EYixcvxpkzZ5CXl4ctW7bg2LFjOHDgQJtJLzk5GcnJyWadv7i4GBwOx/ALCwDCwsJQVFTUIeXbW9ecsm31qrQ1FWCx2YZEBgA83/7Q3L9tVVlzhAa4t/o1R7p/jtIWcQz0qJM4DG9vbyxYsACzZ89GfX09cnJy4OHhAalUiunTp4PH44HD4WD37t0ICAgAAKSmppp9/oaGBnh4eDQ75uHhAbnc+Dw0S8u3t645ZaND/VBQUW902TK9RgmWwKXZMbbABXq10qqypnDYrDZ3Ynek++cobRHHQD0+4lCGDx+OwsJCrF69GkFBD3cU6NmzJ3JycvDjjz9i9uzZ+Oqrr9p1bldXV8hkzZfYkslkcHMz3puytHx765pTdubIoFanNLB5IjBNzRMX09QINl9kVVlzzBjRu9WvOdL9c5S2iGOgxEccRmFhId59913MmTMHX3/9teE4h8MBm/3wW1Uul7d7EEFwcDC0Wi1KSkoMx/Lz81s9n6Xl21vXnLKeYj6iQ/3ANjK4k+vV6+H+ezUVhmPqqlvgGRmsYknZtrAABHoI29ySyJHun6O0RRwDJT7iECoqKjB16lRs2bIFqampKCwsRFZWluHreXl5GDNmDDZt2oQRI0a0qw2xWIz4+HgsX74cCoUC586dw6FDhzBr1qx2lU9KSkJSUpLVbZlTNikpCeUHP4OAy2lRn80XwmVwJOqyd0OvVkF15zoaf74AsZH99swpW31kA6qPbDB6XYxeB0arBgcMnujpApVKBa3W+KAbR7t/tmqLOD5KfMTuZDIZYmNj8cEHH2DatGlwcXHBokWLmk08Dw8Px4ULF7By5UqsXr3acHzevHmYN2+e2W2lpqZCqVTC19cXiYmJ2Lx5c7O/1mNiYvDpp5+aVb68vBxjx45tV1uWtPOoramTJyAq2Ad8TssfW6/JyWC0atz58nVUH14L78nJhukJ0u8+Qf1P35lVFgB08vsQ9A41ek3159JQ9lk8an76DhkHv4NIJEJKSorN79/jbZlz/2z1f0UcH01nIA6vqakJAoEAAHD8+HEcP34c69evN1lPKBRCIBBg/vz5WLlyZYfGpFarERYWhoKCgnZNtWhvWwoNg2fXnoGslakN1mJ0GlR+/T4C39oEFsf42DcPERdnF02Eh6j9122v+9fZbQHApEmTkJubi9GjR+P06dOd3h6xHCU+4vDOnz+PxYsXg8PhQCgU4uuvvzaM6nRGJ69LMT/tKpQanc3bFvE4+DJxeJujOQlxdJT4COmCUjKuY/eFMpsmPxGPg9fH9MGyuCE2a5OQzkDv+AjpgpbGhmJaWCBEvJaDXTqDiMfBtPBALI01/u6PkK6EenyEdFEMw2BVpqTTe36PenpLY0NNLpZNSFdAiY+QLu7kdSkWpudBpdFDreu4vfH4HDZEfDbWzQynd3qkW6HER0g3UNeoxpIDhcgqvo8mrQ56K36q2SxAwOUgarAPVk8fhh4urU9SJ6QrosRHSDeSX16HrdmlOCmRgsWC0bU9WyPkscEwwKRQP7w9fgDCgnp0XqCE2BElPkK6oVqFGvuu3MEpiRSSuzKotHoIuGwwDAOGebhzOovFQpNWDyGXjdAAd0SH+mHGiN5tLkNGSHdAiY8QJ1AlU0FyTw5FkxZqrR58LhtiAReh/m7wdRfaOzxCbIoSHyGEEKdC8/gIIYQ4FUp8hBBCnAolPkIIIU6FEh8hhBCnQomPEEKIU6HERwghxKlQ4iOEEOJUKPERQghxKpT4CCGEOBVKfIQQQpzK/wf0XHfImx6FngAAAABJRU5ErkJggg==\n",
166 | "text/plain": [
167 | ""
168 | ]
169 | },
170 | "metadata": {},
171 | "output_type": "display_data"
172 | }
173 | ],
174 | "source": [
175 | "x = torch.eye(6)\n",
176 | "edge_index = torch.tensor(\n",
177 | " [[0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 4, 4, 5, 5], [1, 2, 3, 0, 2, 0, 1, 4, 5, 0, 2, 5, 2, 4]], dtype=torch.long\n",
178 | ")\n",
179 | "data = Data(x=x, edge_index=edge_index)\n",
180 | "print(f\"Num. nodes: {data.num_nodes}\")\n",
181 | "print(f\"Num. node features: {data.num_node_features}\")\n",
182 | "print(f\"Num. edges: {data.num_edges}\")\n",
183 | "print(f\"Is undirected? {data.is_undirected()}\")\n",
184 | "\n",
185 | "draw_graph_from_data(data, seed=42)"
186 | ]
187 | },
188 | {
189 | "cell_type": "markdown",
190 | "id": "3611f325",
191 | "metadata": {},
192 | "source": [
193 | "# Add Virtual Nodes/Edges"
194 | ]
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "id": "e0d02317",
199 | "metadata": {},
200 | "source": [
201 | "## Add virtual edges"
202 | ]
203 | },
204 | {
205 | "cell_type": "code",
206 | "execution_count": 6,
207 | "id": "46ed6e1a",
208 | "metadata": {},
209 | "outputs": [],
210 | "source": [
211 | "from torch_geometric.utils import dense_to_sparse, to_dense_adj"
212 | ]
213 | },
214 | {
215 | "cell_type": "code",
216 | "execution_count": 7,
217 | "id": "c399a5f8",
218 | "metadata": {},
219 | "outputs": [],
220 | "source": [
221 | "def draw_bipartite(\n",
222 | " data: Data,\n",
223 | " node1_color: str = \"tab:orange\",\n",
224 | " node2_color: str = \"tab:blue\",\n",
225 | " node1_shape: str = \"o\",\n",
226 | " node2_shape: str = \"s\",\n",
227 | " set1_name: str = \"Authors\",\n",
228 | " set2_name: str = \"Papers\",\n",
229 | " text_size: int = 16,\n",
230 | " font_weight: str = \"bold\",\n",
231 | ") -> None:\n",
232 | " group0_len = (data.x == 0).sum().item()\n",
233 | " group1_len = (data.x == 1).sum().item()\n",
234 | " len_max = max(group0_len, group1_len)\n",
235 | " offset = (group0_len - group1_len) / 2\n",
236 | " bipartite = data.x.flatten().tolist()\n",
237 | " labels = {\n",
238 | " node_id: str(node_id - group0_len + 1) if node_group else chr(node_id + 65)\n",
239 | " for node_id, node_group in enumerate(bipartite)\n",
240 | " }\n",
241 | " pos = {\n",
242 | " node_id: (1 + node_group, group0_len - node_id + node_group * (offset + group0_len - 1))\n",
243 | " for node_id, node_group in enumerate(bipartite)\n",
244 | " }\n",
245 | " node_colors = [node1_color if gr else node2_color for gr in bipartite]\n",
246 | " node_shapes = [node1_shape if gr else node2_shape for gr in bipartite]\n",
247 | " G = to_networkx(data, to_undirected=data.is_undirected())\n",
248 | "\n",
249 | " nx.draw_networkx_nodes(range(group0_len), pos=pos, node_color=node1_color, node_shape=node1_shape)\n",
250 | " nx.draw_networkx_nodes(\n",
251 | " range(group0_len, group0_len + group1_len), pos=pos, node_color=node2_color, node_shape=node2_shape\n",
252 | " )\n",
253 | " nx.draw_networkx_labels(G, pos=pos, labels=labels)\n",
254 | " nx.draw_networkx_edges(G, pos=pos, width=2)\n",
255 | "\n",
256 | " plt.text(0.95, len_max + 0.75, set1_name, size=text_size, fontweight=font_weight)\n",
257 | " plt.text(1.95, len_max + 0.75, set2_name, size=text_size, fontweight=font_weight)\n",
258 | "\n",
259 | " plt.axis(\"off\")"
260 | ]
261 | },
262 | {
263 | "cell_type": "code",
264 | "execution_count": 8,
265 | "id": "3ab7a9b4",
266 | "metadata": {},
267 | "outputs": [],
268 | "source": [
269 | "def connect_two_hop_neighbors(data: Data) -> Data:\n",
270 | " data = deepcopy(data)\n",
271 | " A = to_dense_adj(data.edge_index)[0]\n",
272 | " idx = range(len(A))\n",
273 | " A2 = torch.matrix_power(A, 2)\n",
274 | " A2[idx, idx] = 0.0\n",
275 | " data.edge_index = dense_to_sparse(A + A2)[0]\n",
276 | " return data"
277 | ]
278 | },
279 | {
280 | "cell_type": "code",
281 | "execution_count": 9,
282 | "id": "e7224566",
283 | "metadata": {
284 | "scrolled": true
285 | },
286 | "outputs": [
287 | {
288 | "data": {
289 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfAAAAECCAYAAAAB9oX0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAABUSklEQVR4nO2dd5hdZbX/P2tSCZAJIYRAIFVEpCq9g/Tee7VAUGxX9Adcvd5Rr4Ioip2ACgkgRUGEIFUBRVHpTUAlBRLSSSZ1kszM+v2x3pOz58ze55yZ2aevz/Och2Gfs/d+Z3K+71r7LesrqorjOI7jOLVFU6Ub4DiO4zhOz/EA7jiO4zg1iAdwx3Ecx6lBPIA7juM4Tg3iAdxxHMdxahAP4I7jOI5Tg5QkgIvI0yKikdd2fbzeiSLSEl7Dct4bF7nPzX25j1O/hO+O5rw6RGShiNwvIvtXuo3ViGvZqTZcy1lSD+AiMhHYK+fweX287InA/4bXsD5ey3EyNAEjgGOBJ0TkpAq3p6pwLTs1RENquRRP4OfGHDtbRKQE96oIIjK40m1w+sTXVFWAZuD6cKwJuLZyTSqOMn/3XMtOtdPQWi5lAF8N3BF+HgusH9YQkQsjQx8X5jsuIgpcELn+jMhnxuXeXEROF5GXRWS1iLwuIhfEfGZ/EbkvDLmsE5F5InKHiOyU87mbI/faX0R+IyKtwOvh/fEiMlVE3haRNhFZKiKvhvNG9vxP55QTVV0GfDlyaLyIjAnfhTdEZEn4fiwSkYdF5LDo+TlDeSeIyOTwnVolIg+JyLY5n28SkUtF5BkRWRG+o6+IyBdFpH/kc12GkkXk4tCedcCZ4TMXicizIvKeiKwRkTki8mjc970PuJZdyzVBw2pZVVN7YcNtGl73AEdG/v/GyOcujBy/MN/xyP/HvcaFV+b/5yV8br/IPc4FOhI+1wYcFPnszZH3FkV+nhnefy1P23ZI82/rrz5/N1si/zYtkeMjcr8ref5NO4CDE665MObz84FR4bNNwL15rn0/IOGz0e/0opzPXQicluc6v0np7+Vadi1X5QvX8vpX2k/g0SG33wB/AJaG/z9VRAb19IJqwyNTIofGq6qE18ycj28OfAqbW/t25Ph5ACKyIfAj7B+gHTgJGApcEj43CJic0JRlwN7ABsDRIrIp8MHw3g+BDYHhwO7A/wCtPfk9nfIjIkOBb0QOTQfeAk4AtgIGY/+ux4X3m4DPJVxuCbA91oncHY6NBP5f+Pn0cF2Aq7DvylDgunDsWOz7mMumwNXhuiOBR4ADwnsrgG2x7+3YcI+HEn/hnuFadi3XDA2r5RSzogFkM5c2YGg4PpVsRnFKOHZh5NiFkWskHb85cnxczn3HRd57NnJ8h8jxh8KxwyPHfpdznRci770v5r5n53y+CfuHVuBfwP8B5+DZelW+6Jphx706gVOAgdhQ3ItBVLmfez3hmhdFjm8TOf5KOHZbgfsrcH3Md/oNQjYfuf4XIm2einVEhwPNKf2tXMuu5ap9uZazrzSfwI/EMguA54ExIrID8FLkM4VWsPYv8H4h3oz8vDLyc2axwGaRY2/nnDsr8nPcnNcL0f9R1U7s95mN/SN/GbgVeCXMhWzdg3Y7lUGB94DfA4eo6t3YE9j/ATtjGXsuGyRc6+2EnzOaKGYeddOYYy9pUHqEnwK/xkR/Hpb5PwzMF5ErirhPIVzLruVaoyG1nGYAjw657Q28El7fjRw/SkSGA2six6Ir8SYkXDv3l05iXYFzFkZ+HpPzXvT/F8Scu7pbo1SnhfO2BY4Hvo7NrewAfKWI9jqV4Wtqw7ZNqrqpqh6jqo+H984M/10D7IM9jQ4t4ppjEn5eFP4b/U7tq9mh4/UvbNgsl7jvXZuqno4N3e0HfAz4Ozb89i0RGV1Ee/PhWnYt1woNreVUAniYfzi+iI8OxH6xaIZ8TFjRtw3w8YTzFkd+3lmk19tY/oINlYF1QMeLyEYichHwoXD8TVX9TzEXE5EfAYdgwzMPYfMlmQ4tt1NxaoP28N9ObM53Q+A7RZx3mYh8IMynXhU5/mj477TIsR+KyM4iMlhEJojIySIyjex8WF5E5BQR+TQwGnsq/jXZp2PB5vx6hWvZtVxH1L+WU5qT+BjZcf47Yt6Pzlf9BRte+3fk2HLsj7wycuzCyPmn0n2OYWbMHMPNkXOix5+IHD+H3q1cHRfze7UnXEeBz1d6rshfXf6tWiL/Ni15PndjzL/lv3K/dzHXnBNzXu7K1Wl5vi+a+e4lfacj9/1Knmu8C2zQh7+Ta9m1XNUv13L2ldYQenTIbWrM+49hfxSwoYwx2GrAP2IZ7wrg+2RX+eVyN/BNbD6ioy8NVdXbgIOwf4DFmHDnA3cBe6jqEz243NXAU9iQSjuwCpsz/Czwg76006kY/4UVhFiABaFpwKFFnDcJm89ahAWPR4ADVHUerJ9nPQH4NDZEtgJ7wpuFPfF9GvvuFMMfgF8B/wnX6QDmYnu1D1TVbkN1PcC17FquF+pey5m9ao7j9BARacFKgoLtKX2icq1xHKe31KqW3Y3McRzHcWoQD+CO4ziOU4P4ELrjOI7j1CD+BO44juM4NYgHcMdxHMepQTyAO47jOE4N4gHccRzHcWoQD+CO4ziOU4N4AHccx3GcGsQDuOM4juPUIB7AHcdxHKcG8QDuOI7jODWIB3DHcRzHqUE8gDuO4zhODeIB3HEcx3FqEA/gjuM4jlODeAB3HMdxnBrEA7jjOI7j1CAewB3HcRynBvEA7jiO4zg1iAdwx3Ecx6lBPIA7juM4Tg3iAdxxHMdxapD+JbtyS/NI4AJgJ2AYsBR4GbiZltaFJbuv4zjp4lp2nKpEVDXdK7Y07w5cCRwFKLBB5N3VgAAPAlfR0vpMujd3HCc1XMuOU9WkG8Bbmi8BrgUGk394vhNoAy6jpfX69BrgOE4quJYdp+pJL4BnBT+kB2etwoXvONWFa9lxaoJ0ArgNtT1BjOAPunklL83vYN5lGzOov8SdvQo4kJbWZ/veEMdx+oRr2XFqhrRWoV+JDbV1YebSTv78dgcC3Pdme9K5g8P5juNUHtey49QIfQ/gtkL1qLhrTX1pHXtt1Y8LdxnIlJfW5WvD0bQ0b9bntjiO03tcy45TU6TxBH4BtkK1G1NfWss5Ow7gnB0H8PBb7cxf0Zl0DQ3XcRyncriWHaeGSCOA70TX7SUAPPV2O7NaldO378+uW/Zj4iZN/OqVxMx9g3Adx3Eqh2vZcWqINAL4sLiDU15cx+ET+zNiiN3i7B0H5Bt645UFHbuLyNkisqeIbCYisatkHMcpGcPiDvZUy8/P7dhXRD4lIkeKyPtFZGBJWus4DU4aldiW5h5YvU6565/r6OiEUd9dDsCaDmVpG7w0r4OdR/XrdpEX5nZ8ALgtcmi5iEwHoq+3wn9nqeraFNruOE6WpbkHeqPlVxd0TAB+EjmkIvIO3XWc+fk9Tb2ilOPUP2kE8Jexqkzrh97ufaOdfgKvXLoRAyP6Pv3Xq5n60jquzRH92g7tWNPOU8BCYAIwEWgGdg6vXDrzdAjT8Q7BcXpDn7Xc1q4dbe38BXgT0/EEYEzkdVDMfZdFkvXc4P62qiY/7jtOA9P3feC2cnUWka0nR966ku0368e1R3TdjXLXa+v47INtzP7CRvRvyo6Qr16njPvBiiULVurNwA2Y+DfBxJ8J6NGftyb/8H8rycHdOwTHiSMlLY+5bgWLVumfgMnA3Vi1tjF013HmvxvnaVUn8DbddfwWMF1Vl/Tpd3acGiatQi73ACfQizn1TlV99K321iNvWz0scvhJTPz3qOqa3HPCnFpuh5DpDCYCG+W5ZQfWIcQF97dUdWlPfwfHqRv6oGVV7fzb7I5Z+/xy1Uhgw3B4MXAzcIOq/iv3nLDWZTjxwX0ClqznWw+zlPgn9+nAO6qauGndcWqdkldiK4JVwIHytWUAk4CzKFL8cYQOYVPig/sEYCvydwhLSAjuwGzvEJy6Jh0t/ws4G9PzLpH3H8cS898Wu4ZFRAYBY0kejdsw+WzasRGFuHU001W1tdhfzHGqkaqrhS4iQ0lJ/HGEDmEc8R3CBIrrEOKy/emquqy37XKcqiE9LQuwO6blMyPXW0g2Mf9Pb5sZrr8ZycF9dIFLLCYhuGPJekdv2+Y45aBq3cgKiP8m4Ma+iD/PPUeSHNyL6RBi5+qAOd4hODVDym5kItIMnIPpObpP/A9YYv67tHeWiMhgLFlPGo3rtuc9wjpgJglraVR1eZptdZzeUAo/8N2weshHk+wh/HvMQ7go04Mg/nMx8e8Yeatk4k9oxwZkn97j5uy61ZCOsJauHULu0/uKUrXbcXpFabQswJ6Yls+IXHMB8EssMZ+eSvsLt2NzkoP7FgUusZDkbXHvqmpiqTrHSYv0A3gGq4d8AZZtD8MWm7wMTKGldWFvLhlEtxdwMRUUf562jSI5uI8qcIkFJK+c9w7BqRxBy1NfWvudYYOF47cdcAt91DKAiAwDzsOC+faRtx7BdqPcV6kdIyIyBBhP8mjcoDynrwVmEB/cZ6jqytK13GkkShfAS4yIbEL2qbyqxB+HiGxI9+G8zM/jyd8hrCG+Q8g8va8qWcMdJyAiCqCqqVZJDMnvPlhifjrZkax5ZBPzmWnesy+ISBP2hJ4U3DcvcIn5JK+cn+fJulMsNRvAM0TEPwkTfyYQVqX44wgdwpbED+VNwObl8zGP5JXz87yojZMGpQrgOfcYTvapfLtwWIGHscT8/mrfCSIiG5F9es9N2McB+UrLtmHJelxwn6Gqq0vWcKfmqPkAHiWI/3xM/B8IhzPinwxMq3bxxyEiG5M8nDceGJDn9NV07xAyncJM7xCcYilHAI/cS4D9MC2fSjYxnwv8Avi5qs4qdTvSRkT6kU3W40bjRhS4xLskr5yf78l6Y1FXATxDHvG/S1b8b1eoeakSOoTRxA/lTcT2xOfjXRK2xQELvENwMpQzgOfcd1NsPc3FwLbhsAIPYon572sxMY8jbKMdT3xwH0f+8terSA7uM1W1rWQNdypCXQbwKBHxTwLeHw7XpfjjCCv4czuETKcwlvwdwkrydwjdquRVG+OueGAZ+Ut1FsvymVcfMzSF69QslQrgkfsLcACm5VPIDkXPAX4O/EJV36lE28qBiPTHClElTbUNz3O6Yn+npJXzi6o9WXctd6fuA3iGIP4DyYo/M+w8m+xT+ewKNa8iRDqEpDKWm+Q5XbG/XdLK+aroEMZd8UBqbZh59TENbXFb6QCe05bMLpeLgW3C4U5sW9tk4MFGq7sQVvUnBfexQHfruCwrSA7uVeH+6FruTsME8Ch5xP8AJv6HGk38cYSV/kkdwhjydwjLSQ7uZesQXPTpUU0BPENIzA/GEvOTyCbm75B9Kp9ToeZVDSIyAKsrnzTV1pzn9E4sWU8qUlUW90fXcncaMoBnCKu/D8LF32NChzCG5DKW+YaoOrG/cdJWmiVpdQgu+vSoxgAeRURGAhdiifnEcLgDmIYl5o94Yt6dkARlkvW44F7I/XEZyVpOzf3Rtdydhg7gUVz86RFxmMrXIeQTUMYONi7jf6cnHUKS6Jc9dz8rX/0DaxfOZMPtDmTEMf9V8Fr1IvreUu0BPENIzD+CJeYnkl3nMYtsYj63Mq2rPRLcH6N2sMW6P8ZVoCzaDjZfAO+pnutFyx7Acygg/huBX7r4+0boEMaSXMaymA4hyR96afTDSaJf9eZfQYTVM55H29d6AC+CWgngUURkFPBR4CJsMSfYd+g+LDF/1Aun9J4E98foz8W6P8ZNt3Wxg80XwHuq53rRsgfwPCSIv52s+B9z8adL6BBGkL9DyMcSIp3A2MunXZH3w3+6hY7lizyAF0EtBvAMITE/FEvMTyC7fmMGlpjfpKrzKtS8uqWA++NE8jvedbGDHXv5tEmF7lesnutFy/m2EDU8QdBXici3gcMw8R8PnBxeM0Qk81Q+v3ItrR/C3PfC8Ppb7vsRh6mkMpabALuFl+MAEBLtR4BHRGQL4GNkE/NvAV8XkXuxxPyPnpinQ9hq+mZ4daGA++NErODNRLJTmk4OHsCLIIj5YeBhF39lCcUo3givLkQcpjIdwIeAwo/WTkMRpsC+KSJXA4djifmxWNGnU4G3QmJ+k6ouqFxL65uQrM8Pr6dz389xf/wgcE0521cLeADvIS7+6iHUnJ5A/Dz6OPLXnHYanLAo9UHgQREZTTYxnwhcDXxDRH6LJeaPV0Ndg3olTHFkKkrGjaxtVrnWVS8ewHtJjPg/DnwCF39q5Lg+xc2JFzJ5mU9hZyjHIWwX/YaIfAs4EkvMj8EMkk4H/i0iNwA3q+qiyrW0dgmOjEkJ93jyJ9xryO/Y2JB4AE+BIP6vi8g3cfH3iBzf5dwgXchmNeO7HLcifYaqrkxauaqdHdDZAdoB2om2r4WmfkhTvto0Tr0TEvMHgAdEZGuyifk2wHew0bd7sMT8SU/Ms4SEexTJu0sKJdMLSPZlmIvtHoilUfXsq9BLRI74R4fDa4GGEn+Ylx5F8kKVUQUusZDkPeHvFlpvkBTAlz51G61/ub3LseZ9z2LYfuckXqteVq72llpehd4XQsnho7EaEUeT3Rb1JmZxOkVVF1eoeWUlzEvnS7gHJ5/NWmAmyVapK/LdO982sp7quV607AG8xETEPwk4ijoUf1gZnmR3OgHYIM/p6zBRx5ZdVdXlfWmbV29Kj0YN4FFEZAyWlH8cWyUNNrz7Gywxf6qWE/OchaBxQXqLApdYRP6Eu9fFsFzL3fEh9BITChHcB9wnImPJin9b4FrgWyJS1eIPot6M5L3Zo5PPBmAxycUaZnuFO6dWCDbEXxWRr2OLVycBRwDnhNfrYbpsqqq+V7mWJlPEVsxCe7NnEl86dYaqLitVu53u+BN4BQhP5VHxZ7LB17FAfku5xR8KLuSrjrZhntO7FFyge7nE1tK1PBkROWzs5dMeSet69ZK19xZ/Ao9HRMZhq9c/RnZKqA34Nabnv5YzMS+iGNJo8ldHe49kI6LZlbBfFpENxl4+bVVa16sXLfsTeAUIArgXuFdExmNP5R8DtgOuA64WkVTFHyl5mFSfvFDJw6UkuxG9UwlR50NETgZuL/hBx+kjqjoT+LKItADHYYn54cB54fWaiEwGbu1J7e98JJQjjv5cqBxxNOHOnbZamkYb00JEhmKjmE4OHsArjKrOICv+4zHxH0ZW/K+GIblbCgkrYjqQNDRWyCEsI+pui0zS6njKgYhciHm8N1W4KU4DEUx27gHuEZEJZJ/Ktwd+CHxbRO7CEvO/5UvMizAE2or83+9Wkld098gQqJKIyAhsu65XVozBA3iVEAR1N3B3jvh3ICv+O7GnyvdI9ujOJ+rlmJDjnqRTs/2rJCLyOWwUA+BrqvoFEdk4hUv3aTGd01io6nTgShH5X6z2+iTgEOCC8HolFHz6E1bPIC5IF5NwJwXp1Cx5K0Wor/EIVoVtumrn5iJN+abyiqVutOxz4FVGmB/fGhPwNthQ3D4ULloCoGR9tuOepN+rdVEnEZ5Y/gf4Wjj0X6p6XeVaVH/4HHjPEZGMz/YEYHdMzx8EBhRx+gryJ9xrS9HmaiA8xDyG7W55DTiskAtkI34//Qm8AohIM8nVxcaSdUoqRDvwD+BO4CFgVjAPaChC8L4Wq3veCXxCVW+qbKucRiCScMct/MyY6xTLXGy4+FbgFWBxvSbc+RCRHbAn7y2w/u3oWt9qWyr8CbwEiEg/bI4qKUgPL3CJ2SRvu2oFTsKKShwcOedFbG7tV420lSP8rW/AphvWAWep6t2VbVV90ohPOLB+EVW+hDvfg9BKkkfEZoXzLwYuxBaZZs65HZisqs+m+9tUNyKyB5bEDAceB04othZEI34/SxfAW5pHYnM9OwHDsFXMLwM309K6sDQ3LR9hXjUp6x5H/iGyVXQN0FFxzwyOW8W04f00sPjD1rdbMROZ1cBJqvpwZVtVhwQt3/LS2muGDRaO23bArdSXlvuRNdKIC9KbJp8NwBySt10tKOYpOuzNPhnT84GRt57HEvPb+1rUqNoRkYOx1eYbAfcDpxfbF4bzPYD3mZbm3YErsapjStcqXKuxrUoPAlfR0vpMujdPjxh3nFxxF3LHmUvytqv5aQ6NRcQ/CTgg8lbdij8YI9yN7aNvBY5R1b9UtlV1Rp1oGbo51+UG6XHkT7hXkzwiNlNVV6fc1g9ggfwCsqN1K4DbgBtU9fk071cNiMhx2L75Qdjv+dGeLqr1AN5XWpovweYiB5N/NXQnVujgMlpar0+vAT0jBIHxxGfdxbjjJA2NzVTV1IoO9AQR2Y6s+DPzb3UlfhEZBkwD9sVqpR+uqi9Wsk11R+1puQkrbZq0hbLQItB5JK/onleJueiQmJ+KJeb7Rd56FkvM7yhUP7wWEJGzganY2p+fAZ8u5HGQcB0P4L0mK/h8ZfhyWUUJhR9xx0kaGivkjjOf5CA9rzdfsnJRr+IXkZHAw8Au2Ir7w1T1zYo2qt6oQi3Deue6pBGxQs51a+juXBedtlpZqnangYhsjyXm52NTkmDboW7FpsteqlDT+oSIfBL4CTaacxXw5d4mSx7Ae4sNtT1BRPDjrlvO/JVKP4EB/WCfrftz/TGD2bq5WzK/CjiQltZezdem4I4zg+SKRFUt6mKpF/EHh7fHgPcD/wYODbWpnbSorJYzznVJ5XwLOdctIKEQETC3mhPuYgn93WlYYr5P5K2/Y4n5XbXSb4nIFVjQBrhCVb/dx+t5AO8VLc33YMUK1it63HXL+fnxG3DohP60tSufeqCN91Yr957ZLanvBO6lpfWU2Abmd8eZQNYRKImMHWVckJ5TD6IulvAEkxH/3pG3ql78YcHeo1ixmpeAI1R1fmVbVYeUUMuwPgCNIz5Ij6ewc10m4Y4z0qi5EaW+ICI7Yon5eUBzONxKNjF/pVJty0fo068CLsfWVnxSVSencN2GC+B93wduK1SPIs882eD+wqkf7M/nH4rdotykqkefv/PAvW99eV2m6EFv3HGSPGYbZktVIcK8/BRgSo749wyv74tI1YlfRHbG9oWOBJ7GFqzVTGnXmiElLX/toEEf/NqTa5NqHRRKuDN2lHEruue4c12WoNHPiMjlwBlYYr4ncClwqYg8TTYxT3WhXW8JK/5/grW1HThfVd2zoJekUcjlAiyLSmTVOuXO19rZa6v4+iSr2xm8+Yby1zyXeI/kFd1uR9kLIuK/AjidKhW/iOwDPIAN/T+KbRWrylGCOiAVLa9Yy2t5LhG1o8wN0jMq5VxXy4TE/CbgppDsZhLzvcPrOhGZiiXm/6xUO0VkAPYAcRa28PE0VZ1WqfbUA2kE8J1IGPY68Y5V9G+CFWth5IbCw+fGP0gPGSDsObrfCuBvxA+NLU2hnU4MIRhGxT8JOJcqEL+IHIa5tg3BTCLObsRKc2UkFS1/eIumtdg+8bggXRE7ykYhrGe5VET+H3Ampufdgc8CnxWRp7DCR78pZ2Iepk5+DRyD7Yo5TlWfKNf965W+z4G3NN+PeVt3ITpv1tGp/O7Ndj5x32r+eelGjNoodoTuflpaj+9bY5w0CHtmz8Qy+d0jb5VN/CJyEnAHtpXvZuAi7/hLjGu5LhGRD2GB/ByyNqNLsKfhyar6RonvPxQr0HIgNpp6pKqmXjegEefA8+3vLJalhT7Qr0k4ebsB9GsSnno7cbS74HWc8qCqK1T156q6B7ArNpS+AtuONhWYIyLfDwUnUkdELgB+gwXvHwIf9+BdFpYW+oBrufZQ1RdU9RJs/cEkrMDTJsDngddF5EkROTtUNkyVYAf6Byx4zwUOKEXwblTSCOAvY5WKElFVfvfGOpasVrYb0f2W6zp03eJVnf9OoS1Oyqjq8+UUv4h8FnvibsKcxT7fSDsFKkyftbymXTv+Prt9WVhp7FQRqrpcVW9Q1V0xf+0bsdLLB2CFnuaIyHdFZNs07hfsQJ8M95oO7Keq+dZHOD0kjSH0kVhR/i77raN7R0VgbHMTV+43iHN26l6xcPU6Zex1K9oWrtKM2f3TjejCUyuIyG7Y8PrZQMafdzEWeG/sTWGV0OF/Bfh6OPQFVf1+31vrFE1KWh5z3QoWrdJXsemWW3wNS/UShrfPxpLzXSJvPYH1xb/tzbqTGDvQw1X13b62t8A9G24IvWT7wIulU1WfmNmx8JCpq6KlDl38NUBa4g/B+7vAF7C9xBep6i/Tbq9TBH3Qsqp2Pje389+737hyE7KlS1djdreTgb97Yl6dBA3uhmn5LLJbdxdhi1xvVNWiRklz7ECfAY7SMtiBNmIAT2MIHWxTftGuMV0aILL6I+P7H4PtEb0aq6a0Azb3+a6I3CQie/mQXPWhqstU9Xrgw9gWtF9i1bgOwhzRZovINSLyvqRrhH2hP8eC9zrgDA/eFaXXWhaRtt227Hcu5o99Ojb3uQHmlvc08KKIfEpEmpOv4lQCNZ5R1U9g02WXYlMqI4AvAf8SkT+IyOkikugREexAn8SC9xPAIeUI3o1K1dVCD1+OE7BM8JDIZ1/GsvjbfK9o9RI653Owf7+dIm/9ARtVuVdV14bPuh1oNZJiLfSQvF0EfJSsg98qbIfBZOAZfyqvTsJD056Yls8gu8VwAdmn8rcin8+1Az2jzFvVGu4JvKrdyERkG7LiHxEOr8Ke7m7AxV+1FCH+W7Fh8yOAZVh1tacq0FQnjvS1PAg4Efs+HBx560UskP/KqyZWL8EB8Fzs32+HyFuPYv9+HVhSNgj4FXCh9tAONIU2egDvMy3Nu2EewkeT7CH8e8xDuCjTgyD+k7CFU3Hiv03rzO+6ngjiPw8T//Y5by/DTEl8a0m1UQItw/q69hdjQ+ubhsMrsY7/BlXtlRmKU3pCYr43puXT6W4WdRtWHrXsO0c8gKdJS/NmWGnGnbAymEuxYfAptLQu7O1lC4h/sqo+1+s2OyUliP9obC/58Mhb87H58xtVdUYl2ubkIWh56ktrvzNssHD8tgNuIR0tDwZOxvR8YOSt57HE/HZPzKsXERkOXI8ZJGVQbAHbZGBaOZ/CPYDXEBHxT8L2MWZ4jqz4G8qdqNrJsQN9CxtGPx3YLnykYuJ3ClPKDjIUBboYS/ozyd0K7Ilusqq+kPY9nb6RYwc6GZv7PpWsL/tc4BfAz1V1Vhna4wG8FhGR7ciKf5Nw2MVfReTYgb6M7QudH57K98MSsYqJ3ylMOTrIkJifin0f9ou89QwWJO5wM5vKEmMH+qmwGwUR2RQ4H/v3yxSEUeBBbN3SA6WqqugBvMZx8VcnxdqBBvFfgCVjZRW/U5hyd5Aisj32XTgfm4YDWE7W7/qlcrTDySIiTZgd6CXYwrXzVfVXMZ8TbGR0EnAKVhYZYA7ZxPydlNvmAbxeSBD/MrLif7lCTWsocuxAH8O2iuWd2qiE+J3CVKqDDE5Wp2Hfh30ib/0dS8zvDJaaTgkJdqA3Y8Wb1mB2oPcXcd4IbM3SxcA24XAntgByMvCgpmAJ7QG8DhGRIWTFv3fkrb9hT3Uu/hKRYwf6W+CsnpZlFJHMYsheiX/cFQ8sAzbuceO7s3zm1ccMTeE6NUs1dJAisiNZv+tMQZhW4BYsMX+1Um2rZ0ISdRfmVtcrO9CQmB+E9cUnA5lavO9gxZx+oapzks53LXcnrUpsVYuqrlLVKaq6D7Yi/seY4PfCVj6/KyI/CuX/nJQIdqDTsOA9BTi9NzWVVXWhqn4XG1I/BOtEOrCO5H5ghoh8NRgnxJGG4NO8jtMHVPUVVf0MVi3sY9hTeDPwaeAVEfmLiFwQAo6TAiKyMZYwH4vZgX6kp8Eb1ld7e1xVzwS2wubQ38Iq930NeFtEficiR4cKjbm4lnOo+wAeJSL+0SSL/3wXf9/IsQP9EfCxvs5dB/H/UVXPoHfid+qIkJjfpKp7YXX4f4rNj++DDfO+KyI/EJEPVq6VtU9Yl/IH7Mk5NTtQVV2gqtdgO1IOw/qLTuB4bMrtLRH5iohs2dd71TMNFcAzqOrKHPH/jKz4p2C2ete5+HuOdLUD/TrwubSLOrj4nSiq+pKqXorV3/4Etmh1GPBZ4DUR+bOInBsWuTpFEvTzJ2B3YAYlsANV1U5VfUxVT8OS8f8O9xoLfANLzO8RkSPSvG+9UPdz4MUiIhsBZ2Lza7tH3noKm2v9jar2yuShEQjzW1E70MtU9XtlvP8orOTuRZiFIUDH2MunxT6Na/s6Fj/yU9pmvUhn2wr6D9uCTQ44nw0m7pZ4j5lXH9Mwi2PiqIY58GIRkQ9hc63nYPuTwYZ/p2DV3t6oVNtqAelqB/pP4DAtsR1o5N5NwKHYv98JQD+AsZdPi/18I2u5IZ/A41DVFar6c1XdA9gVC9orsO1ot2BP5d8LBSecCCF4fxcL3p3AJ8oZvAFUdZ6qXgW8DzgSWzSX/PnODvoPHcGos69m68/fybD9z2Xhfd+mvXV+WdrrlBZVfUFVL8Hmyi/GCjwNB/4LeF1EnhSRs0OZZidC2MHzFBa8n8WGzcsSvGH9U/kjqnoK9lT+FcynPv7zDaxlD+AxqOrzEfFPwko7uvhjCPPNN5K1Az1TVX9RqfYE8T+sqidj4o+laeBghu13Dv2bN0ekiSHv24P+zZuzZt5/ythap9So6nJVvVFVd8P8rm/ESi8fgBV6miMi3w2FhhoeEdkdGzbfArMFragdqKrOVdVvYnbTsTSylj2A5yGI/wZV3RUXfzfErF9vBz6OmVscr6q/rmyrsqjq3GI/27FyCevem8PAEWNK2SSngqjqc6p6MZaYfxIzQ9oUuAx4U0T+KCJnSB6/63pGRA4C/og9rEwDjtIqcYjryT7xRtKyB/AicfF3Jeyv/x22x34ZVhr1ocq2qndoRzuL7v8uG+1wCAM2TXxod+oEVV0WSn9+GNgDKw60CnM6vAOYLSLXiHmZNwQicizwELZe4HbgZC2jl3daNJqWPYD3kBzx74ntJW8o8YtIM/AwNte8CDhYa9TLW7WTRdOuhX79GX7YJZVujlNGwtbEZ1T1E1hifilWp38z4EvAv0XkMRE5rZ4TcxE5C1szMghzFztPa9BIqBG17AG8lwTx/0NVP04DiV9ERgKPY4v7ZgP7q+rzlW1VPGFxXSKqyuLf/5COVUvZ7MT/Rvr1L1fTnCpDVVtV9afYttK9sa2Qq8kWD3pHRK4Oq7PrBhG5BJsO7A98GzMm6XNZ03LTqFr2AJ4CRYr/qloXv5gd6J+ADwH/wfaFVt12HBEZISKXAXnb9t4jP2Hd4ncYecpXaRrQ8OsRHdYn5n9T1Y9iiflngFcxI57LsRoDj4jIKaE2eM0iIpdjNTAEuFJVr9Aq21csxkEicnu+zzWqln0feIkQkWFYveZJwPaRtx7BarDfV0vDVCKyDbYvNGMHeoSqzqtsq7KEp+39ydqSDoTkvaPtrQuYc/3HoN8ApCm7VXz4EZey0fYHx55TL3tHe0st7QNPk/Dd2hv7bp0OZArCzMOm0G5U1ZmVaV3PCb/Pt4ArMLe/S1X1Z5VtVVckxpnQtdwdD+AlJohlH+yLWJPiF5GdsMRjc8wE5miNsQOtBCIyHHOcuxjYLhxWbI5+8tjLp+XdD94T6kX0vaVRA3iU8H3LJOa537cbgPv7Wja4lEh3O9ALVPW2yrbKSErCsRKuvxh7+bSvpHWvetGyD6GXmDAk9xdVvQCrwf554HVgFFY2cLqIPCgiJ4pI1U3ciMje2H7QzbGayIdVOniHYbX9RGQq8C7wfawznYc9WUxU1aNU9d4KNtOpQ1T1PVX9ATaqltlOuhZb0HkPVvrzGyIytoLNjCUM+d+CBe81mLVvxYO3iAwXkc8Dr2F9zdmYU9lDwEnAGFX9n8q1sHrxAF5GCoj/t8AsEfm6iFTFBkYRORQbNh+G2YIeqwW8vEvcnk1CrfVXgD9jT0KDsNGBUzChf1lVZ1SqjU5jEBLzP6vquVhi/gXgTawAylcwl7wHROT4akjMQx34u7HguALb413Qy7uE7RER2Tck4XPIk4RX84hGpfEAXgFixH8ZJv4tgf8BZlZa/GJ2oA9gdqBTgdMqUQs+CH1vEbkZe9rOJEALgKsxoR+hqvfU0poCp35Q1cWqmglAB2H7qNcBR2O1EmaKSEtYBFp2JGsHehxWD/4QVX28Qm3ZREQ+gyXhT2FJ+GAsCT8VT8J7hAfwChPE/z2SxT8jiH+rcrVJRM4Hfk3WDvSj5c6CRaRZRC4FXgL+ii1oGYwN458ObK2qV6rq9HK2y3GSCIn5k6p6NpaYfwn4d/j5f7FAfr+IHCtlsryVrB3owdhc8oGq+o9y3DvShmgSPgf4IfFJ+N2ehPcMD+BVQo74tyIr/q0w8c8SkftE5JhSij9kx1MwB6BvUAI70Dz3FhHZU0R+iXU2PwZ2BBYC1wDbqOqhqvprVV1b5GWXp9S8tK7jNACqukhVv4utoP4IcCe2aOxY4H4sMf+qiIwuVRvE7ECfJGsHur+qvlqq+8XcPy4J34DeJ+Gu5Rx8FXoVE1ZlHoytsD4ZW9gB8A7wc+AXqjonxXt9GQvaAF9U1WvTuHYR9x6K2T5OAnaOvPU45gp3r6quKUdbnGR8FXrfCEWQLsT0nDHn6MDqjk8GHkmriIqIjMfWr0zA7EAPT6uvKHBfwRKGSZg985Dw1kLgJmzXTUlcRhrx++kBvEYopfiD6L6DzcUrcLGq/ryvbS7ivrthQj8L2DAcXowVwrlBVf9V6jY4xdOIHWQpCFu5Dsa++ydhVdDALDMziXnRRjwx1/8g8Ci2puZZbMHaoj41uvA9M0n4xVhBqwxlS8Ib8fvpAbzGCOL/CCb+E+mj+MNw/GTMUWwdcK6q3pVmm3PutzG2EvZirJ58hiexfbT3VGKxnFOYRuwgS42IbA58FNPD+HC4A7gP0+WjPZnCCknxQ5jR0pOYQ2DJHMWqKQlvxO9n6QJ4S/NIbM5jJ2wb0lKsgtfNtLQuLM1NGwsRGYWJ/yJ6IX6xGu23Yo5iq4FTVPXBErX1w5jQz8Ycj8BWxE7BhF51JVmdQNDyLS+tvWbYYOG4bQfcims5VUJifiimkROwNShgc9c3AjcVqnwoIgdi8+sbYztITtMSOIqFJPys0NaqScI9gKdBS/PuwJXAUdhw7AaRd1djdXcfBK6ipfWZdG/emPRG/GJ2oHdje9CXYXu8/5xyuzbC5sEmYX7qGZ7CEozf+NN2FeNarggisgXwMSwxzxSEacdqMUwG/pibmIvIMcBvsJ0adwDnp72iOyThF2ND5VWXhHsA7ystzZcA12Jfonwr3DuBNuAyWlqvT68BTjHixzL0aZij2CKsrnlqjmIisgsm9HPDvcBGYKZiQn8trXs5JcK1XHHC9NZhWAJ8HNnE/C2yifkCMTvQqdh02mSstnlai+FqJgn3AN4XsoIfUuijEVbhwi8JQfyHY8I7lq5P5YOwBS5zgEPTyJxFZEPgjHC/PSJv/RUT+q9LMZznlADXctURtptlEvNMQZh12FTGh7HRkGuAVBzFRGRnTMs1k4R7AO8tNtT2BDmC/9Ur6/je02t4Y1EnGw8SdhnVxJf3H8R+Y7oUF1sFHEhL67N9b4gTR0T8l2CBO8M0rITh470VvYjsiAn9PGBoONyK1Vy+QVVf6W27nQqQoGUoSs+u5RITEvMjySbmmWC1CPPzvrm3K85DEn56uPaekbdqIglvxACeViGXK8m6bAHwvafX8PmH2vjv/Qcx/4sb8/bnN+JTuw3kd290K+g1OJzvlIiw//MOLGMHm/PuxDqAPwBvisgXRWREMdcTkSEicoGI/BV7ArgUC95/xxKFLVX1Mx68a5JuWoai9exaLjFhaPz3mEe5YGsTlgAjsK2gc0TkdjEP7aICmYjsKCI/xkbkfokF71askNJOqrqvqk6t5uDdqPT9CdxWqM4iIvrWNmX095Zz0wkbcNr2RXnetwFjfEVraZAYO1BsEcrHgU9gpR7BjFXuwbLtJ3OfykVke7JP28PC4eVkn7ZfKukv4pSWGC1Dj/XsWi4hYcHqj4FPEuxAsSpvR2HaPJrsU/mb2KrwKaq6OOc6G5B92t478tbfMf3fqaqrSvebpI8/gfeOC7AscD1Pz+6grR1O2q5oHw4N13FSRkT2IsYOVFXfUdUWYBy2cv0BrNLbmVjxhddF5AsiMlpEzhORp7Cs/zNY8H4GC/5bqOqlHrzrgm5ahh7r2bVcIsTsQKdiwXu9Haiqtqvq/ap6LKbnb2DGP9tiaxneFZHbROQAEfmgiPwgvH8zFryXAz8FdlHVvVT1ploL3o1KGk5XO9F1ewmLVykjhgj9m4pOhDYI13FSRMwO9F6swMK9wFm5K0aDScl9wH1iNqafwJ7MM+KPllNdge0bv0FVXyh1+52y003L0GM9u5ZLgJgd6J3A8ZgOj9cYRzFVfRv4qoh8HZsiuxibMz87vKI8gz1t36GqK0vYfKdEpPEEPiz3wKZDhEWrlPbO4ofn/z67/eDgunWemE/sFsXO4TjdEZETsafqDSneDnQBNuyWVKt4NvAGNszq1B/D4g72VM9Pvd1+uIhcJyKfDc5b24UhW6cXSNYO9HiKtAMNifkbmJ7jKrGtCe+/gS0+dGqQNJ7Al+Ye2HurfgzuD/e+0c6pHyxqDpw3F3dmXLeirBaR6cB0bO/j9MhrRrXsP6w2ROQ8zDigH2YH+vkCFdm2xTL1C7ASjAArgV9hT+d7Y4vTPgBcB1wtIr/Gsve/prFtxakKlsYd7Kmepy/p3Bz4XO5xEXmX7lrO/LzAv0fdEZHhWLGcPTCHvsPzOYqJyCDgFGxu+4DIW89jpZZbMZ0fjq1lOQ94TUQmA7eq6pJS/B5OaUgjgL+MVWVan2E3Dxa+fvAgLv19G/2b4PCJ/RnQBI9Nb+fxmR1cc1jXRa4dnbpm44FyH2afOQEz65iABZPtw6sbIjKH7h1B5ueFjdghiMinsaANNhf2v3F/hyD0kzChHxR560UsMP8qUkN5moi0YMUkJtFV/K+KyA3ALaq6NOVfxykv3bQMPdNzR6e2bb6h3AW8Qlctj8O2MG6JFRDKZVVI1uOC+8xGdKMLRZkeAXbA6jccpqpvJXx2W2yP+IV0T8Inq+pzkY//SkQmhM9/DOtffwh8W0TuwvT/t0bsP2uNkqxCz3Dby+v4/t/W8PqiTjYeKOy6ZT++vP9A9tm6W94Qu3JVRJqxGt+ZTiDaIYwlfwKykvgn97eAWfXWIYTphv8G/i8cirUDFZFtMOF+FNt6AjaEdjsm3GcLCTdH/CPD4dWAi7+WyaNlKFrPSVruj3nb5+o48xqep2WKbXGKC+7TgUX19n0rxg60h0l40n0GYkPzk7ByzBleCde4VVVb+/K7lItGXIWeViGXe7CVzL2ZU+8E7qWl9ZSenBTpEOKC+wRgkzynKzafGxfcpwOLa6lDCMH7GuCLxNiBBpGeiIn0I5FTX8ZEeltvRFpP4ncCFdAygIgMIzm4jyVbSTCO5cTreDqWrK/taXsqSSE7UBF5Hzbl1eskPOG+7yOb3G8Wue4d4brPVHO/6AG8t+Sp3lQEJaneJCKb0LUTiHYKY8jfISyja4cQ7RTerqYOIVRmuh5bPd7FDlREJpIVZPRJ+U5MkH9PS5C1Ln4nUJ1aHoCVD83V8cTwGpp8Np3AOyRPtS2ppu9lkh1oJAm/GDgkckqfkvCENiQl/C9i+8pvK/RkXwk8gPeFGqqfHDqEMcQH92I6hLdJyPhV9b3StbwrQWi3YAUZVmOLVx7DnqByn4pfJftUvLSEbRpEVvwHR956kSoWvxOhtrQs2GhbnI4nYIE/32hCK8nB/Z20Hb3yEWcHij2FlyUJT2jT+8nOrWee9lcSnvZVtWrK5noA7yt14GAUOoThxA/lTcQ6hHxfkKXEdwiZp/dutWR72c4hmH3gUdiIwUXALti89ObhY21k56WfLveTRkT8H6XrwpqqE7+TQx1oGdYnuWOID+4TydpixtFBNlnvNv+eZiKcYwd6J1YR8ROYG1mGsiThCe0bBJyMJeYHRt56PrTpdlVdXs425eIBPA1amnfD6iEfTbKH8O8xD+Ga68BDhzCW+OA+gcIdwiwSFtcVOwQWFvfdD+yPBe/XgL3IJhavY6K6pZwjAknUgvidGOpfy4I9VSZNtW1F/mR9Ccnb4mYXm6zn2IG+gD11V0USHoeIfIDsU3lm8eEK4DasyFNq1sQ9bJcH8NRoad4M22+4E1YgYik2XzOlXuskRzqEpIV1WxW4xHskD+fNVtUOEdkM8/TeAXv6yTwdrcEy+MnAU9Ug9DiC+DN7zqtG/E4egpanvrT2O8MGC8dvO+AW6lzLsL762ViSp9ryTTG0Y8l67Mr5zDSSiHwS+AndE4WqSsLjCH+fzJ7z/SNvPUu2wtuKMrbHA7hTOsIXfhzJq23zdQjrsAA/gq4L8GZiYrkx17Cgmgl/i1OxYF5x8TuFacQOMomQrI8keapty+SzAdNyf7qut1mHWfz+APhTtSbhcYSV85nEfFg4vBwrvTy5HF4Jjfj99ABeJYQOYXO6B/cPAB8k/9A8mB9w0ra4OfkqsVWaahC/U5hG7CB7SygdO47uT+07Y+5/+dYVrMUS89i1NNWc2Ibf+zRMz/tG3sq4nN1Vqrrrjfj99ABehYStYVF7wKjYF2CruYeS7RTGk1B8I7AWq+QUF9xnVEuHEBH/JGCfyFslF79TmEbsINNARLYmaxI0OvKWYmtZXqBroB9V4JILSJ5qm1stybqI7IAF8vOB5nC4lWxi/krK92u476cH8CpCRLYi69GdmS9vx+a6B2J2oCfmBlwxj+BRJC+s25z8zCe5EEZFOoQg/oz3eMnF7xSmETvI3pInCV+ObRNbA5yuqvfFnLshlpTHTbWNBwblufUassl6bnCfoRWwCQ07ZjLe43tF3nqabGK+OoX7NNz30wN4hQlCPwL7ch9LVuhvYYvVzsHmxn8HnKm9MHAJHULSStvxWHKQRBvxHULm6b2kHUJfxT/uigeWYR1mX1k+8+pj8tUHqHsasYPsKSIymmwSvnU4vA6z8x2NjSytxAq0/LEX12/C5teTFtZtlnw2APNIXjk/r9Tz7iKyE6blc8nO/y/FVuFPVtV/Jp3rWu6OB/AKISJbYnu2L8L2qYI9bf8WC0wbY/tBM8VaPpbWHvKcdjRhHUvSwrpCHcJckmvOz0+zQxCRnbEhuaLFP+6KB1K7/8yrj2nowOUBPJ4CSfgNwK+BX2CFjZZgpVH/XqK2bEz26T03uI8D8tnJrcaS9SRDmT4/JUfauSFwBvY32yPy1lPY3+w3ufdzLXfHA3gZCcHycOxLexzZ1eQzsC/tTao6P8cO9MfA5yo1ryUiQ8nfIeQzlFlNcnCf2ZvRhNCmDYEzsb/j7pG3uonfRZ8eHsC7EknCP4FtNwNLwu/FkvA/YosyM3ag8zBHsUQ70FISEo1Msh631XXT5LMBeJdkQ5le28GKyC6Yls8h+4S9BJiCbS19HVzLcXgALwMiMors0/a4cLgDGxafDDyWCdAicikWtMGcxb5ardtJQoeQcZiK6xCGJ58NdHeYinYKRdnBisiHsKfyWPGPvXxa4pBcT6kX0fcWD+Drk/DDsIBzPF2T8BuxJHxe+GzUDnQmcKgm2IFWA6FA1ATip9uKdX+MC+5F2cGKyEbAWZied4u89SdMy7f28FdKpF607AG8RAShH4IJ/QSyX/5ZmNB/qapzI58XrOrVN8OhL6nqd8vX4vQJDlP57GDzGcqsIL/DVJcOISL+ScCumeNjL5+WeINF93+Xtlkv0bmujX4bbsLQPU9h452PSPx8vYi+tzRyAO9JEh4+H7UDfR178u5iB1pLBPfHjKFM3HRbMe6PSSvnu7k/isiHMS2fTdhC61ruTr6MyukFIrI5VmLwYuyLDSb0ezGhP6qqHTnnCPBt4EvYl32Sqt5YpiaXjFCv+YXw6kLoEMYQ3yFMxFae7xRe3S4tInEOUy8BR2LJQeapfMOk9g3d6zQ2PepzSP8BrFv8DvNuv5KBm09k0Kj39e4XduqKnibhkfOidqDPAUdqxA60Fgnrb2aE1x9y389xf4yzg906vA7MPRdYLiJxwf072ENNZmvph5La16ha9gCeAkHoB2NfshPJLhR5h6zQY7PvMAz9Myyzb8fsQO8sdZsrTegQMkLthogMJ78dbOZ1UMzpy8J1/4ANc8YycLOxkf8TBKF9ydy6F72THxEZiRnwXIR976Dr0/YjuUl45NyoHeifgOMawX1PVZdgycpzue/luD/GbXUdihW42Tnm0p1k7WATaVQtewDvA6Eu+YXY017mm9KJFWeYDDyUJPRw/kBsBfUZ2HatU1T196Vsc60Q6j+/h5VW7ULEYSpfh7BLeOVl8SM/ZeUrf0Db1zBw84lsMHG3Qqc4dUhIwg/CkvCT6EESHrlG1A7098Cpaa7crlXULFnfCq9Ho+/lcX+M2sGOJbtIMJFG1LIH8B4SvnAHYkI/mewe6tnAz4FfqOrsIq4zBNtecjRW3OFYVf1TSRpdZ6jqWuA/4dWF8O+zKdlO4Ff5rrXp4Z9i+KGTWPPuG7S9/QrSL98uG6fe6GsSHrlOrh3o+eF76uQhzH0vDq9nct8PToZjMC0/mO9ajajlfPV4nQgiMkJELgPeAB7HtjENAB7AhmnHq+rXigzeQ7Ev49FYDfODPXingxqLVPUfqnp7MedIUz8Gb7U9HcsXsfwFHwCpd8Q4SERuxxLva7DgPRtoAcaq6vGq+kCRwftMbI3LYGwb4zkevNNBVdeo6r9V9aFiPt9oWvYn8DyEp7n9saftU8k+bb+LFWb4uaq+3cNrjsDmyHbFtlEdltnn6FSYzk7al3Zbk+TUCSKyKWaYczGwbTisWBI+GXiwp8WSRORi4HrMDvQ7wOXVuu2zoWgQLfsTeAwiMlxEPg+8BjyJbWUYgD01n4Rl6F/tRfAejS1s2RWbD9rPg3dl6Fi5lJX/fJLOtavRzg5WT3+Ola8/yeCxcetonFolPG0fICK3YYn3tVjwfhf4BjBOVY9V1ft7Eby/hAV+Af4bD94VoZG17E/ggfC0vS+WnZ9O1jBgHtmn7Zl9uP77sAUc44BXgcPjtqA4ZUKE5S8+yOJHfgraSf+hI9nkIxcxZJu9Cp/rVD1hF8P5mJ63C4cVS8JvAKb1tjRx6Cv+DwvaAJeq6k/71mKn1zSwlhs+gIf9i+dhQt8+HFbgYUzo94dVlH25x45YRaZRmDXm0WGVtVMh+g1pZtTZV1e6GU6KhMC6DzbldRpZi91UkvBwjybgR8CnsK1lF6pqahXCnJ7TyFpuyAAehL4XJvQzyAp9PvBL4EZVnZHSvfbEsv5NsNrIJ+TagTqO03tCEn4upuftI289gg1x9zkJD/cZgPUP5wJrMTvQ3/X1uo7TWxoqgIdavxmh7xh56zFM6PeluXpURD4C3IdVA+u1HajjOF3JScJPBzYIby0gm4TnLf7Rw/tltocdj9X9PkFVu1Ukc5xyUvcBPAh9D0zoZ5IV+kLM8etGVe22nziF+56ACX4QcCtmB9rnpwDHaWTKnYSHe26MbRP7CCW2A3WcnlC3ATzstT4HE3p0OeIfMaHfW6q9miJyLnAzZtbxE+CzlbIDdZxaJyThu5NNwoeEt0qahId7D8eqqu2JzaUfrqqvlOJejtNT6i6Ah1rEkzBnqoyRxSIsoN6oqv8q8f0/hQVtMGex//GtJRVlOVmb0b5exykjkST8YrqWxX2cbBJe0KayD/eP2oHOwuxAS5IoOEXhWs6hLuxEwxDX2ZjQPxx560lM6PeUUuihDQJcAXwrHPp/qvqdUt7TccpJuexEE5LwxWSftkuahIc2jMOG5Sdi1RcPK6bKolM5GtHutqafwOM8YzEDjJsxob9RpnYIcDXw/6gjO1DHKRchCc/4uVckCY+0ZTusZsNo4HnMDnRhOe7tOD2h5gK4iGyEzYNNAqJ2M3/GhH53OVd6BzvQn2JP/w1jB+o4aRCS8Ix3ezQJnwLcUK4kPNKeXbEaEJtifcpxqtpazjY4TrGULoC3NI/E6g7vBAwDlgIvAzfT0trjbFZEdsGC9jlk50GWkhX6P/va5F60aQBmB3ombgfq1CtBy1NPHMywwQItzbfQNy3nS8JvAH5Tie2WInIAMA3rXx7E7EBXlbsdjlMs6c+BtzTvDlwJHIUNJ28QeXc1Vjf4QeAqWlq72cd1aZzIhlihlUnYVrAMf8GE/utK+e2KyAaYHegxuB2oU4+kqGVYn4RfjG0Dq4okPIOIHA3cjduB1iyNOAeebgBvab4EMwsYTH6jlE7sifUyWlqv79YokZ0woZ8HDA2HW7Gn3RtU9dX0Gt1zwurY+4EDsMU1R6jqc5Vsk+OkSnpaTkrC/4pNeVUsCc8gImdgtRr6AzcCnyzGRtSpLjyA94Ws4IcU+miEVQThi8gQrKLSJKzCUoa/YUK/qxqGs3LsQN/FVqdW7MnBcVKnj1qG9fX/J9E9Cb8FmFzpJDyDiFxE1lHsu9jukdrfmtOAeADvLTbU9gRB8OOuW878lUr/Jugn8MHN+nH+zgO4eNcBNEnXv22nattJd67+3X1vth+BzZUDLMMy4smq+nLfG5gOwQ70Uczd6C0seKdSM91xqoIcLUPxelbVVZ98oO2ayc+tOwLYO3LVqkrCM4jIFzEPb4AvA1d58K5dGjGAp7WI7UqyhiAA3H/WEA6d0J/WNuXJWe187qE2/j6ng5tO2KDLiaoMPn+nAWfc92Y7wD8wod+pqitTalsqiMhEbF/oONwO1KlfumkZitNzpzLksAn9WyY/tw6qNAmH9ds+v4EFbYBPq+pP8pziOFVJvrmt4rAVqkclXat5sHD8tgO489QhTHlxHa8u6Dq11K9JOH7b/h0nf6D/R1R1T1X9ZRUG7x2Ap7Dg/Q/gQA/eTt1RQMuQX8/9moRj399fdxnV9DlgS1W9tAqDd8YO9MuYHej5HrydWqXvAdy2ihUcdtpjdD+2Gir8eVb3tSED+snau88YsmsKbUmdYAf6J8zL+49YOUX38nbqkaK0DMl6HtRf2l6YtNHAakvCAUSkP7bi/VLMDvRUVb2lsq1ynN6TxhD6TnTdXpLIlhs38d7q2P5hg3CdqiLHDvQ+4Ay3A3XqmKK1DIl6rlYtDwbuAE7A7UCdOiGNAD6s2A/OWd7J8A3i1xc89Xb7EfuL/AhbHDY986rUopccO9DbgI+6HahT5wzryYeT9Pz4zPZjPyJyC1kdZzQ9rxKufKFwzO8wO9ClmB3o38rdDsdJmzQC+NJiPvTMnA7mLFP2G9Mv9v3pSzpHAp/OPS4i8+jaCUQ7hXmlWDWaYwf6U+AzbgfqNABLi/1gPj2/09q5CVasJZc2EZlBVy1nfp5Riv3gOXag87HFp1U1L+84vSWNAP4yVpUpduht2RrlT2HV6rk7DWDHzbsLvrNT20Zt1HRnuNYEzAFoAjAem3seBewTc/nVMR1CplOY2ZsOIccO9FvAV3xridMg5NUyFNZzp2rb+4Y33QQ8Q1ctTwA2w7Zgbhd3bRGZS3xwnw7M76kORWQUZge6I24H6tQhfd8HbitXZxHZehLdN9oU9o2eu+MALtltAP2aYofQ24AxuXWVg1HIlnTtBKI/jyjQuneJD+7TgQXRDiHGDvRyVb2mmD+B49QFMVqGHus5VsuwvoLheLrreAK2w2NAntatIl7H07FkvcvaFLcDbTwacR94WoVc7sEWh/RmVXsncC8traf09MTQIUQ7gWinMI78Iwwr6doh7Agciq3C/bSq/rSn7XGcmqdyWu4HbEV8cJ8IDM9zugJzyGp5GTaEPxwbVTjU7UDrHw/gvSWmelMPWAUcSEvrs31vSJawZSTTIeR2ChOBTfKcrsBskjP+RT6s7tQlVahlABEZhj29x43GjcXWqySxgngdvwXMctOS+sADeF9IoX5yORGRTYBtgO8B+2JFHV7GVuKOIX+HsJzk4O4dglPb1J6W+wNbYyMH38Lm8OcBc7EA35zndAXeIT64Twfe82S9NvAA3ldScjAqB/nsQIPP99bED+VNJGvOEEcn2Q4hrlNY4h2CU/XUkJYBROQo4B5i7EBDsp60jmYM+X+/ZSQH97d9a2n14AE8DVqad8PqKR9Nsofw7zEP4dSH2oqhL3agYbFbvg5ha/J3CK0kb4t7xzsEp2qoAS0DiMjpWK2GHtuBishALIgnTbVtnHw2ncDbJKycV9Ulvfl9nN7hATxNWpo3w0oz7oQNSy/FhqinxK1QLReltgMNHcJYkjuEjfKc3kH3DmF9p6CqS9Nqp+MUTdDy1JfWfmeY1UK/hSrQMoCIfAK4gRLYgYZkfVOStbxVuG8SS0neFveOqran0U7H8ABe51TaDjR0CCNI7hBGk79DWELytrjZ3iE4paTaOkgRuQwL2lABO1ARGYQl63FTbROwEsxJtGNb9mKn2lR1WelaXp9U2/ezHDRMAK8FO9BQrznz9B43RJ9vUVE7MJOExXXeITh9pVo6yJAIfx34SjhUdXagoY2bkRzcRxe4xGKS19HMKXaKoJGolu9nOWmIAB7sQB/FKrr9A6uFXFOOYqFDGElyh7BlgUssIr5DmI53CE4RVEMHGexAf4CVXe7APApqzlEsJOuZojZxe9/zmcqsI5us5wb3Gaq6vGQNr2Kq4ftZbuo+gIvIHtic9yaYHeiJ9fgFD6vqox1CbqcwOPls1hLfIWSe3leUrOElZtwVDywj/0KkYlk+8+pj8u0+qHsq3UGG7WK/BM7DvrNnqOq9lWhLKQnJ+iiSg/sWBS6xkOSV8+/Wqq+Da7k7adRCr1pE5GDMBnQj6twONNR9/2d4dSE8teTrEEYB7w+vbojIApJXzs+t8g4hDcGneR2nF4Qn1tuBE6lzO9Awjz83vP6S+76IDCG+JO3EcHyz8Noz5vJrRGQmyYYyVefjHsG1nEPdBnAROR64C7cDJQTYd8Prqdz3RWRDkmtUj8eG7kcCe8Vcfk0eQ5kZlbKDdeoHtwPtStDUa+HVhZCsb0HyOpqRwLbh1Q0RmU/yyvmK2ME6ydRlABeRc4ApuB1oUYSs+9Xw6kLoELYkuUPYDPhAeHUj2MEmrZwviR2sUz+4HWjPCP3cnPD6c+77IRlKKkk7Htg8vOLcH9tEJKkCZUnsYJ381F0AD3agP8a2Y7kdaB8JHcLs8PpT7vsisjHJHcI4snaw+8ZcfnVOhxDtFHplB+vUD24Hmj5hPcsr4dWFYCgzmuR1NCOAD4ZXN0TkXZIXyvbYDtYpTF0FcBG5ErcDLSthQeDL4dWFSIeQVLVuU2D78OqGiEQdpnI7hAVpdAjr3pvDu7/8NBtuuy8jjvtiXy/npITbgZafsBPl7fB6Ivd9EWkmeeX8OGykbktgv5jLr4ok67lD9DNVdU0av0Oj6bkuAnhYtXkVcDlW8vESVb2hsq1ycjqEx3PfDx1CUrY/Fgv+o4H9Yy6/MqFDyDy9F9UhvPfo9QzaYpue/WJOSRGR7bBtn6OB54Ej3Q608qhqK/BieHUhx/0xbqvrJsAO4dXt0pFkPW7+vWj3x0bTc80H8PCU9xNgElbM5DxVvaOyrXKKIXQIL4RXFyIOU0lV64ZhQ6s7xl1aRGYD08dePi3x/iv/+SRNgzZkwOgP0L6kqmr6NCwi8mHgYWy49s/AceF74lQxoQrkzPD6Y+77wVAmd6oto+UxWPDfCvOnyGWFiOTVMjSmnms6gAfXsCnAWZgj0qmq+kBlW+WkQegQZoRXt+1CoUNIyvbHYMF/66Trd65ZxdKnbmPzM7/JipcfSf8XcHqMiOwPTMPc/h7E9Oy7GOqAYOyyBBtR6UKC++PEyH+HYp4aiTSqnms2gMfYgR6nqk9WtlVOuQgdwnPhtZ5ICcu9gT2A/447f+mfb2GjnQ6n/9DNSt1Upwhy7EDvwkbS1la2VU45CNt7M8PmXQjBfUdsVfyPkq7RqHquyQAe7EDvAw7EagYfqaoVszN0ykskY096Am/Od/7a+dNpm/kSW3z0B6VuqlMEOXagP8fWsHhp3wYhYTQt8/MY8tszN7Seay6ABzvQB4HdKIEdqFMdiMgwkivHjcX2+CexkuwCmBNz32x7+xXal81n9s8+CoCubQPtZO7Nn2OLCxuvE6gkOXag1wJf8u1G9UXOepa4ID0sz+kKvINp+cC4DzSynmsqgAc70EewfYjTsX2hZbMDddIjLD6MLlLLFffwApeYTfIWs4WZIDDuige6BYONdjmCDbfLrpVZ9o97aG+dz/AjLu3jb+X0hBw70K8A3/LgXZvk7CiJS7jzxZqVJDuvzcrsKInTMjS2nmsmgIvIBGxf6HishOBh1WYH6nQlFHlJyrrHkf/7t4oEa1Rsm1iva9o3DRgMA7LeLjJwMNJ/IP2G5B15d1Iixg70M6r64wo2ySlASLgz28TigvSmBS5RspoOjaznmgjgwQ70EazG7z+Ao1V1cWVb5YQyq5nKTXFBekSBS8wlue5y2So3DdvvnHLcxiHWDvRjqjq1sq1yoEvCHTcqNg4YkOf01eRPuMtWVbGR9Fz1ATzYgT6IDak+jrkQ1Z0daLUSqZ2cZHQyMM/pbdg2sLha6DN9i1Bj0Sh2oNVKxNcgbuFnxtcgH7m+BrlGJz79UWaqOoDn2IHeD5xer3aglSLHvSguSG9e4BLzSbYadfciB4i1Az1RVR+raKPqkDzOghmr0XwJ9xq6J9xRb4JqthptSKo2gIvIcdg+74a3A+0rOf7BcQ5Eg5PPZi0m6rggPd1F7RQijOLcCxyC2YEerapPV7JNtUpIuEeRXKGwUMK9gOSSpXM94a4tqjKAi8jZwFRsq9DPgE/7FyuZsChoc5KHxrYocImFJC8wmVPjf/vlwMYpXcfpIcEO9AHMS97tQIsgFKlKMg2ZQP6Eex3xCfdbmOXnitK1vOS4lnOQapu2EJFPYrXNMwYlX/a5lfVDkONIXjC2QZ7T12E1iuMWmcxQ1WWlardTP4iIAqiqFPn5qB3o29i2z3+XroW1QUi4R5Ls0rdlgUssInnb1bteBKdxqKoncBG5AgvaAFeo6rcr2Z5yEikBmjQ0NrrAJd4jfh56OjDbRe2UExEZi237fB/wJrbt853Ktqp8iMggLOFOCtJD8pyeMQaJHRXzhNvJUBUBPMYO9JOqOrmyrUofERlI9ik6bmhsozyndwCziA/SM1R1aana7Tg9QUQ+gNmBboU5zR1Rb3agoc8aQXI539HYKGISS0he0T07mPk4Tl4qHsDDooyfAJdgmef5qnp7ZVvVO4Koh5OcdW9NflG3YkKOC9LvuKidaifHDvQp4NhatQMNCfdY4oP0BPLPx2YS7qRpqyWla7nTKJQugLc0jwQuwGzghmGrT18GbqaldSGsN6W4GTgb2zN8mqrmN32tMKHNY0gO0kPznN5JV1F3ycBd1E5VErQ89cTBDBss0NJ8Czlahm52oA8Bp1TzXv9Iwp1Uzndr8htpLKN7wp35+R3fNeOUmvQXsbU07w5cCRyFDYdHF1etxp5AH5y1tPN7436w4nLgWGAFZgf6RLqN6R1FeE3nE/VysiLOfZKe5aJ2aoYitQxcJV9btilmB5qx+T23GuxAIwl3UpDOV2+zk6yRRlyQXuILbJ1Kkm4Ab2m+BHMUGkyeIKeqnWs64PMPtTVNfm7de5gd6DPpNSQ/edxxMv8/LM/pUXecuCC92EXt1DxFahnobO/UdZ99sK3/z55d1w/4BTCpnIsmI851SXaU+ZzrVhCfcL8FvF0NSYjjJJFeAM8KPt/qyi6sWqf6xqLOb3x48or/TacRWXLccXLFXYw7TtKK7vXuOI5Tl/RCyyvXKpOfW/vYZY+sOTztBDYk3BkjjbggvUme05Vk57q38ITbqWHSCeA21PYEEcGPu24581cq/SJLti7cZQA/PrrbduVVwIG0tD7bk1vGuOPkirsYd5ykIL3QRe00JDFahuL0rKqrRKTHWgYQkaEkb6EslHCvInlF90xPuJ16Ja1FbFcSUx3o/rOGcOiEgrcYHM4/JfeN4I4znmQ7ymLccZKMNLymuuN0J1bLUFjPodhQkpb7kXWui5u6KuRcF7WjzNV1n+woHadW6XsAtxWqR5F/niwfTR2deuxuW/T77IvzOjOFTIp1x5lLcpAumx2l49QFKWi5U/XYfbfuf/7fZnfk7pEeR2HnuqTFYmW1o3ScWiGNJ/ALsHmmXrOmg4GHjO//gxfndVsvsobkrHtGNW9RcZwapM9abmtn4L5b95vyt9mxa9jmkRyk3Y7ScXpIGgF8JxLqcJ94xyr6R3L57xw2mIt27Z6EDxkgHDGx34xrn+ZWuorb3XEcp3wkahmK0/OQAcJHxvebc+3T3EP3aSt3rnOcFEkjgA9LeuPeM4uaAwfgsIkDXlVd9dUU2uM4Tu8Ylu/NYvV89DYDnldd9dm0GuU4Tjy9neuKsjSFa6R5HcdxesfSKruO4zh5SCOAv4yt+O4Lq8N1HMepHK5lx6kh0hhCnwJ8Pe6N425f1WXf6GET+/PbM2JrQ0i4juM4lSNRy1C0nl3LjlMm0irkcg9wAr17ou8E7qWltdveUcdxyoxr2XFqhjSG0MG8vHtbGKUtnO84TuVxLTtOjZBOAG9pfQa4DCtp2BNWAZf1pvSi4zglwLXsODVDRdzIsKG2Nkzw16fXAMdxUsG17DhVTyn8wHfD6iEfTbKH8O+Bqzxbd5wqxrXsOFVN+gE8Q0vzZlhpxp2wAhFLse0lU2hpXViamzqOkzquZcepSkoXwB3HcRzHKRlprUJ3HMdxHKeMeAB3HMdxnBrEA7jjOI7j1CAewB3HcRynBvEA7jiO4zg1iAdwx3Ecx6lBPIA7juM4Tg3iAdxxHMdxahAP4I7jOI5Tg3gAdxzHcZwaxAO44ziO49QgHsAdx3EcpwbxAO44juM4NYgHcMdxHMepQTyAO47jOE4N8v8BMTSx390nwXgAAAAASUVORK5CYII=\n",
290 | "text/plain": [
291 | ""
292 | ]
293 | },
294 | "metadata": {},
295 | "output_type": "display_data"
296 | }
297 | ],
298 | "source": [
299 | "x = torch.vstack([torch.zeros((5, 1)), torch.ones((4, 1))])\n",
300 | "edge_index = torch.tensor(\n",
301 | " [[0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8], [5, 6, 5, 7, 7, 6, 8, 5, 8, 0, 1, 4, 0, 3, 1, 2, 3, 4]],\n",
302 | " dtype=torch.long,\n",
303 | ")\n",
304 | "data = Data(x=x, edge_index=edge_index)\n",
305 | "data_with_virtual_edges = connect_two_hop_neighbors(data)\n",
306 | "\n",
307 | "plt.figure(figsize=(8, 4))\n",
308 | "\n",
309 | "plt.subplot(121)\n",
310 | "draw_bipartite(data)\n",
311 | "\n",
312 | "plt.subplot(122)\n",
313 | "draw_bipartite(data_with_virtual_edges)"
314 | ]
315 | },
316 | {
317 | "cell_type": "markdown",
318 | "id": "7e5ff688",
319 | "metadata": {},
320 | "source": [
321 | "## Add virtual nodes"
322 | ]
323 | },
324 | {
325 | "cell_type": "code",
326 | "execution_count": 10,
327 | "id": "a7d43d06",
328 | "metadata": {},
329 | "outputs": [],
330 | "source": [
331 | "def add_virtual_node(data: Data) -> Data:\n",
332 | " data = deepcopy(data)\n",
333 | " node_id = len(data.x)\n",
334 | " data.x = torch.vstack([data.x, torch.ones(1)])\n",
335 | " list1 = [node_id] * node_id\n",
336 | " list2 = list(range(node_id))\n",
337 | " data.edge_index = torch.hstack([data.edge_index, torch.tensor([list1 + list2, list2 + list1])])\n",
338 | " return data"
339 | ]
340 | },
341 | {
342 | "cell_type": "code",
343 | "execution_count": 11,
344 | "id": "d0a7a182",
345 | "metadata": {},
346 | "outputs": [],
347 | "source": [
348 | "def average_shortest_path_length(data: Data) -> float:\n",
349 | " G = to_networkx(data, to_undirected=data.is_undirected())\n",
350 | " return nx.average_shortest_path_length(G)"
351 | ]
352 | },
353 | {
354 | "cell_type": "code",
355 | "execution_count": 12,
356 | "id": "3bb20f1c",
357 | "metadata": {},
358 | "outputs": [
359 | {
360 | "data": {
361 | "image/png": "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\n",
362 | "text/plain": [
363 | ""
364 | ]
365 | },
366 | "metadata": {},
367 | "output_type": "display_data"
368 | }
369 | ],
370 | "source": [
371 | "x = torch.ones((6, 1))\n",
372 | "edge_index = torch.tensor(\n",
373 | " [[0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 4, 4, 5, 5], [1, 2, 3, 0, 2, 0, 1, 4, 5, 0, 2, 5, 2, 4]], dtype=torch.long\n",
374 | ")\n",
375 | "data = Data(x=x, edge_index=edge_index)\n",
376 | "data_with_virtual_node = add_virtual_node(data)\n",
377 | "\n",
378 | "plt.figure(figsize=(12, 4))\n",
379 | "\n",
380 | "ax1 = plt.subplot(121)\n",
381 | "ax1.set_title(f\"Average shortest path length: {average_shortest_path_length(data):.2f}\")\n",
382 | "draw_graph_from_data(data)\n",
383 | "\n",
384 | "ax2 = plt.subplot(122)\n",
385 | "ax2.set_title(f\"Average shortest path length: {average_shortest_path_length(data_with_virtual_node):.2f}\")\n",
386 | "draw_graph_from_data(data_with_virtual_node)"
387 | ]
388 | },
389 | {
390 | "cell_type": "markdown",
391 | "id": "4e0ef4c7",
392 | "metadata": {},
393 | "source": [
394 | "# Node Neighborhood Sampling"
395 | ]
396 | },
397 | {
398 | "cell_type": "markdown",
399 | "id": "35e2d8c6",
400 | "metadata": {},
401 | "source": [
402 | "> The following part is an adaptation of a [example](https://github.com/pyg-team/pytorch_geometric/blob/bee6ca2e78890e57c97f71b6110dc86cbdbf5efb/examples/reddit.py)."
403 | ]
404 | },
405 | {
406 | "cell_type": "code",
407 | "execution_count": 13,
408 | "id": "294405db",
409 | "metadata": {},
410 | "outputs": [],
411 | "source": [
412 | "from torch_geometric.datasets import Reddit\n",
413 | "from torch_geometric.loader import NeighborSampler\n",
414 | "from torch_geometric.nn import SAGEConv"
415 | ]
416 | },
417 | {
418 | "cell_type": "code",
419 | "execution_count": 14,
420 | "id": "75147c14",
421 | "metadata": {},
422 | "outputs": [],
423 | "source": [
424 | "class SAGE(torch.nn.Module):\n",
425 | " def __init__(self, in_channels: int, hidden_channels: int, out_channels: int) -> None:\n",
426 | " super().__init__()\n",
427 | "\n",
428 | " self.num_layers = 2\n",
429 | "\n",
430 | " self.convs = torch.nn.ModuleList()\n",
431 | " self.convs.append(SAGEConv(in_channels, hidden_channels))\n",
432 | " self.convs.append(SAGEConv(hidden_channels, out_channels))\n",
433 | "\n",
434 | " def forward(self, x: torch.Tensor, adjs: List[EdgeIndex]) -> torch.Tensor:\n",
435 | " # `train_loader` computes the k-hop neighborhood of a batch of nodes,\n",
436 | " # and returns, for each layer, a bipartite graph object, holding the\n",
437 | " # bipartite edges `edge_index`, the index `e_id` of the original edges,\n",
438 | " # and the size/shape `size` of the bipartite graph.\n",
439 | " # Target nodes are also included in the source nodes so that one can\n",
440 | " # easily apply skip-connections or add self-loops.\n",
441 | " for i, (edge_index, _, size) in enumerate(adjs):\n",
442 | " x_target = x[: size[1]] # Target nodes are always placed first.\n",
443 | " x = self.convs[i]((x, x_target), edge_index)\n",
444 | " if i != self.num_layers - 1:\n",
445 | " x = F.relu(x)\n",
446 | " x = F.dropout(x, p=0.5, training=self.training)\n",
447 | " return x.log_softmax(dim=-1)\n",
448 | "\n",
449 | " def inference(self, x_all: torch.Tensor, subgraph_loader: NeighborSampler) -> torch.Tensor:\n",
450 | " pbar = tqdm(total=x_all.size(0) * self.num_layers)\n",
451 | " pbar.set_description(\"Evaluating\")\n",
452 | "\n",
453 | " # Compute representations of nodes layer by layer, using *all*\n",
454 | " # available edges. This leads to faster computation in contrast to\n",
455 | " # immediately computing the final representations of each batch.\n",
456 | " for i in range(self.num_layers):\n",
457 | " xs = []\n",
458 | " for batch_size, n_id, adj in subgraph_loader:\n",
459 | " edge_index, _, size = adj.to(device)\n",
460 | " x = x_all[n_id].to(device)\n",
461 | " x_target = x[: size[1]]\n",
462 | " x = self.convs[i]((x, x_target), edge_index)\n",
463 | " if i != self.num_layers - 1:\n",
464 | " x = F.relu(x)\n",
465 | " xs.append(x.cpu())\n",
466 | "\n",
467 | " pbar.update(batch_size)\n",
468 | "\n",
469 | " x_all = torch.cat(xs, dim=0)\n",
470 | "\n",
471 | " pbar.close()\n",
472 | "\n",
473 | " return x_all"
474 | ]
475 | },
476 | {
477 | "cell_type": "code",
478 | "execution_count": 15,
479 | "id": "905b6b3a",
480 | "metadata": {},
481 | "outputs": [],
482 | "source": [
483 | "class Trainer:\n",
484 | " def __init__(\n",
485 | " self,\n",
486 | " model: torch.nn.Module,\n",
487 | " x: torch.Tensor,\n",
488 | " y: torch.Tensor,\n",
489 | " train_mask: torch.Tensor,\n",
490 | " val_mask: torch.Tensor,\n",
491 | " test_mask: torch.Tensor,\n",
492 | " optimizer: torch.optim.Optimizer,\n",
493 | " sizes: List[int] = [25, 10],\n",
494 | " batch_size: int = 512,\n",
495 | " num_workers: int = 2,\n",
496 | " ) -> None:\n",
497 | " self.model = model\n",
498 | " self.data = data\n",
499 | " self.x = x\n",
500 | " self.y = y\n",
501 | " self.train_mask = train_mask\n",
502 | " self.val_mask = val_mask\n",
503 | " self.test_mask = test_mask\n",
504 | " self.optimizer = optimizer\n",
505 | " self.train_loader = NeighborSampler(\n",
506 | " data.edge_index,\n",
507 | " node_idx=data.train_mask,\n",
508 | " sizes=sizes,\n",
509 | " batch_size=batch_size,\n",
510 | " shuffle=True,\n",
511 | " num_workers=num_workers,\n",
512 | " )\n",
513 | " self.subgraph_loader = NeighborSampler(\n",
514 | " data.edge_index, node_idx=None, sizes=[-1], batch_size=batch_size, shuffle=False, num_workers=num_workers\n",
515 | " )\n",
516 | "\n",
517 | " def training_epoch(self, epoch: int) -> float:\n",
518 | " self.model.train()\n",
519 | " pbar = tqdm(total=int(self.train_mask.sum()))\n",
520 | " pbar.set_description(f\"Epoch {epoch:02d}\")\n",
521 | " total_loss = 0\n",
522 | " for batch_size, n_id, adjs in self.train_loader:\n",
523 | " # `adjs` holds a list of `(edge_index, e_id, size)` tuples.\n",
524 | " adjs = [adj.to(device) for adj in adjs]\n",
525 | " self.optimizer.zero_grad()\n",
526 | " out = self.model(self.x[n_id], adjs)\n",
527 | " loss = F.nll_loss(out, self.y[n_id[:batch_size]])\n",
528 | " loss.backward()\n",
529 | " self.optimizer.step()\n",
530 | " total_loss += float(loss)\n",
531 | " pbar.update(batch_size)\n",
532 | "\n",
533 | " pbar.close()\n",
534 | " loss = total_loss / len(self.train_loader)\n",
535 | " return loss\n",
536 | "\n",
537 | " @torch.no_grad()\n",
538 | " def evaluate(self) -> List[float]:\n",
539 | " self.model.eval()\n",
540 | "\n",
541 | " out = self.model.inference(self.x, self.subgraph_loader)\n",
542 | " y_true = self.y.cpu().unsqueeze(-1)\n",
543 | " y_pred = out.argmax(dim=-1, keepdim=True)\n",
544 | "\n",
545 | " results = []\n",
546 | " for mask in [self.train_mask, self.val_mask, self.test_mask]:\n",
547 | " results += [int(y_pred[mask].eq(y_true[mask]).sum()) / int(mask.sum())]\n",
548 | "\n",
549 | " return results\n",
550 | "\n",
551 | " def fit(self, num_epochs: int = 10) -> None:\n",
552 | " for epoch in range(1, num_epochs + 1):\n",
553 | " loss = self.training_epoch(epoch)\n",
554 | " print(f\"Epoch {epoch:02d}, Loss: {loss:.4f}\")\n",
555 | " train_acc, val_acc, test_acc = self.evaluate()\n",
556 | " print(f\"Train: {train_acc:.4f}, Val: {val_acc:.4f}, Test: {test_acc:.4f}\")"
557 | ]
558 | },
559 | {
560 | "cell_type": "code",
561 | "execution_count": 16,
562 | "id": "cfdd899a",
563 | "metadata": {
564 | "scrolled": true
565 | },
566 | "outputs": [
567 | {
568 | "name": "stderr",
569 | "output_type": "stream",
570 | "text": [
571 | "Epoch 01: 100%|██████████| 153431/153431 [00:06<00:00, 23528.50it/s]\n"
572 | ]
573 | },
574 | {
575 | "name": "stdout",
576 | "output_type": "stream",
577 | "text": [
578 | "Epoch 01, Loss: 0.6978\n"
579 | ]
580 | },
581 | {
582 | "name": "stderr",
583 | "output_type": "stream",
584 | "text": [
585 | "Evaluating: 100%|██████████| 465930/465930 [00:21<00:00, 21265.90it/s]\n"
586 | ]
587 | },
588 | {
589 | "name": "stdout",
590 | "output_type": "stream",
591 | "text": [
592 | "Train: 0.9416, Val: 0.9423, Test: 0.9385\n"
593 | ]
594 | },
595 | {
596 | "name": "stderr",
597 | "output_type": "stream",
598 | "text": [
599 | "Epoch 02: 100%|██████████| 153431/153431 [00:06<00:00, 24566.45it/s]\n"
600 | ]
601 | },
602 | {
603 | "name": "stdout",
604 | "output_type": "stream",
605 | "text": [
606 | "Epoch 02, Loss: 0.8775\n"
607 | ]
608 | },
609 | {
610 | "name": "stderr",
611 | "output_type": "stream",
612 | "text": [
613 | "Evaluating: 100%|██████████| 465930/465930 [00:21<00:00, 21307.97it/s]\n"
614 | ]
615 | },
616 | {
617 | "name": "stdout",
618 | "output_type": "stream",
619 | "text": [
620 | "Train: 0.9482, Val: 0.9441, Test: 0.9448\n"
621 | ]
622 | },
623 | {
624 | "name": "stderr",
625 | "output_type": "stream",
626 | "text": [
627 | "Epoch 03: 100%|██████████| 153431/153431 [00:06<00:00, 24169.32it/s]\n"
628 | ]
629 | },
630 | {
631 | "name": "stdout",
632 | "output_type": "stream",
633 | "text": [
634 | "Epoch 03, Loss: 0.9626\n"
635 | ]
636 | },
637 | {
638 | "name": "stderr",
639 | "output_type": "stream",
640 | "text": [
641 | "Evaluating: 100%|██████████| 465930/465930 [00:21<00:00, 21296.08it/s]\n"
642 | ]
643 | },
644 | {
645 | "name": "stdout",
646 | "output_type": "stream",
647 | "text": [
648 | "Train: 0.9485, Val: 0.9454, Test: 0.9434\n"
649 | ]
650 | },
651 | {
652 | "name": "stderr",
653 | "output_type": "stream",
654 | "text": [
655 | "Epoch 04: 100%|██████████| 153431/153431 [00:06<00:00, 23724.96it/s]\n"
656 | ]
657 | },
658 | {
659 | "name": "stdout",
660 | "output_type": "stream",
661 | "text": [
662 | "Epoch 04, Loss: 0.9915\n"
663 | ]
664 | },
665 | {
666 | "name": "stderr",
667 | "output_type": "stream",
668 | "text": [
669 | "Evaluating: 100%|██████████| 465930/465930 [00:22<00:00, 21157.18it/s]\n"
670 | ]
671 | },
672 | {
673 | "name": "stdout",
674 | "output_type": "stream",
675 | "text": [
676 | "Train: 0.9507, Val: 0.9464, Test: 0.9452\n"
677 | ]
678 | },
679 | {
680 | "name": "stderr",
681 | "output_type": "stream",
682 | "text": [
683 | "Epoch 05: 100%|██████████| 153431/153431 [00:06<00:00, 23812.61it/s]\n"
684 | ]
685 | },
686 | {
687 | "name": "stdout",
688 | "output_type": "stream",
689 | "text": [
690 | "Epoch 05, Loss: 0.9560\n"
691 | ]
692 | },
693 | {
694 | "name": "stderr",
695 | "output_type": "stream",
696 | "text": [
697 | "Evaluating: 100%|██████████| 465930/465930 [00:22<00:00, 21124.83it/s]\n"
698 | ]
699 | },
700 | {
701 | "name": "stdout",
702 | "output_type": "stream",
703 | "text": [
704 | "Train: 0.9538, Val: 0.9472, Test: 0.9475\n"
705 | ]
706 | }
707 | ],
708 | "source": [
709 | "path = os.path.join(\"..\", \"tmp\", \"data\", \"Reddit\")\n",
710 | "dataset = Reddit(path)\n",
711 | "data = dataset[0]\n",
712 | "\n",
713 | "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
714 | "model = SAGE(dataset.num_features, 256, dataset.num_classes)\n",
715 | "optimizer = torch.optim.Adam(model.parameters(), lr=0.01)\n",
716 | "\n",
717 | "trainer = Trainer(\n",
718 | " model=model.to(device),\n",
719 | " x=data.x.to(device),\n",
720 | " y=data.y.squeeze().to(device),\n",
721 | " train_mask=data.train_mask,\n",
722 | " val_mask=data.val_mask,\n",
723 | " test_mask=data.test_mask,\n",
724 | " optimizer=optimizer,\n",
725 | ")\n",
726 | "trainer.fit(num_epochs=5)\n",
727 | "\n",
728 | "torch.cuda.empty_cache()"
729 | ]
730 | },
731 | {
732 | "cell_type": "markdown",
733 | "id": "575bf948",
734 | "metadata": {},
735 | "source": [
736 | "# Prediction Heads: Node-level"
737 | ]
738 | },
739 | {
740 | "cell_type": "markdown",
741 | "id": "6cc46b18",
742 | "metadata": {},
743 | "source": [
744 | "> See previous example."
745 | ]
746 | },
747 | {
748 | "cell_type": "markdown",
749 | "id": "a8a36ed8",
750 | "metadata": {},
751 | "source": [
752 | "# Prediction Heads: Edge-level"
753 | ]
754 | },
755 | {
756 | "cell_type": "markdown",
757 | "id": "e4d3422f",
758 | "metadata": {},
759 | "source": [
760 | "> The following part is an adaptation of a PyTorch Geometric [example](https://github.com/pyg-team/pytorch_geometric/blob/master/examples/link_pred.py)."
761 | ]
762 | },
763 | {
764 | "cell_type": "code",
765 | "execution_count": 17,
766 | "id": "490f4a4b",
767 | "metadata": {},
768 | "outputs": [],
769 | "source": [
770 | "from torch_geometric.datasets import Planetoid\n",
771 | "from torch_geometric.nn import GCNConv\n",
772 | "from torch_geometric.utils import negative_sampling"
773 | ]
774 | },
775 | {
776 | "cell_type": "code",
777 | "execution_count": 18,
778 | "id": "4302ba04",
779 | "metadata": {},
780 | "outputs": [],
781 | "source": [
782 | "class GCN(torch.nn.Module):\n",
783 | " def __init__(self, in_channels: int, hidden_channels: int, out_channels: int, use_dot: bool = True) -> None:\n",
784 | " super().__init__()\n",
785 | " self.conv1 = GCNConv(in_channels, hidden_channels)\n",
786 | " self.conv2 = GCNConv(hidden_channels, out_channels)\n",
787 | " self.use_dot = use_dot\n",
788 | " if not use_dot:\n",
789 | " self.linear = torch.nn.Linear(out_channels * 2, 1)\n",
790 | "\n",
791 | " def encode(self, x: torch.Tensor, edge_index) -> torch.Tensor:\n",
792 | " x = self.conv1(x, edge_index).relu()\n",
793 | " return self.conv2(x, edge_index)\n",
794 | "\n",
795 | " def decode(self, z: torch.Tensor, edge_label_index) -> torch.Tensor:\n",
796 | " if self.use_dot:\n",
797 | " return (z[edge_label_index[0]] * z[edge_label_index[1]]).sum(dim=-1)\n",
798 | " else:\n",
799 | " z = torch.hstack([z[edge_label_index[0]], z[edge_label_index[1]]])\n",
800 | " return self.linear(z)"
801 | ]
802 | },
803 | {
804 | "cell_type": "code",
805 | "execution_count": 19,
806 | "id": "527bdd2d",
807 | "metadata": {},
808 | "outputs": [],
809 | "source": [
810 | "class Trainer:\n",
811 | " def __init__(\n",
812 | " self,\n",
813 | " model: torch.nn.Module,\n",
814 | " train_data: Data,\n",
815 | " val_data: Data,\n",
816 | " test_data: Data,\n",
817 | " optimizer: torch.optim.Optimizer,\n",
818 | " ) -> None:\n",
819 | " self.model = model\n",
820 | " self.train_data = train_data\n",
821 | " self.val_data = val_data\n",
822 | " self.test_data = test_data\n",
823 | " self.optimizer = optimizer\n",
824 | "\n",
825 | " def training_epoch(self) -> torch.Tensor:\n",
826 | " self.model.train()\n",
827 | " self.optimizer.zero_grad()\n",
828 | " z = model.encode(self.train_data.x, self.train_data.edge_index)\n",
829 | "\n",
830 | " # We perform a new round of negative sampling for every training epoch:\n",
831 | " neg_edge_index = negative_sampling(\n",
832 | " edge_index=self.train_data.edge_index,\n",
833 | " num_nodes=self.train_data.num_nodes,\n",
834 | " num_neg_samples=self.train_data.edge_label_index.size(1),\n",
835 | " method=\"sparse\",\n",
836 | " )\n",
837 | "\n",
838 | " edge_label_index = torch.cat(\n",
839 | " [train_data.edge_label_index, neg_edge_index],\n",
840 | " dim=-1,\n",
841 | " )\n",
842 | " edge_label = torch.cat([train_data.edge_label, train_data.edge_label.new_zeros(neg_edge_index.size(1))], dim=0)\n",
843 | "\n",
844 | " out = model.decode(z, edge_label_index).view(-1)\n",
845 | " loss = F.binary_cross_entropy_with_logits(out, edge_label)\n",
846 | " loss.backward()\n",
847 | " optimizer.step()\n",
848 | " return loss\n",
849 | "\n",
850 | " @torch.no_grad()\n",
851 | " def evaluate(self) -> List[float]:\n",
852 | " model.eval()\n",
853 | " results = []\n",
854 | " for data in [self.val_data, self.test_data]:\n",
855 | " z = model.encode(data.x, data.edge_index)\n",
856 | " out = model.decode(z, data.edge_label_index).view(-1).sigmoid()\n",
857 | " auc = roc_auc_score(data.edge_label.cpu().numpy(), out.cpu().numpy())\n",
858 | " results.append(auc)\n",
859 | "\n",
860 | " return results\n",
861 | "\n",
862 | " def fit(self, num_epochs: int = 100, print_interval: int = 1) -> None:\n",
863 | " for epoch in range(1, num_epochs + 1):\n",
864 | " loss = self.training_epoch()\n",
865 | " val_auc, test_auc = self.evaluate()\n",
866 | " if epoch % print_interval == 0:\n",
867 | " print(f\"Epoch {epoch:02d}, Loss: {loss:.4f}\")\n",
868 | " print(f\"Val: {val_auc:.4f}, Test: {test_auc:.4f}\")"
869 | ]
870 | },
871 | {
872 | "cell_type": "markdown",
873 | "id": "84995c9b",
874 | "metadata": {},
875 | "source": [
876 | "## (1) Concatenation + Linear"
877 | ]
878 | },
879 | {
880 | "cell_type": "code",
881 | "execution_count": 20,
882 | "id": "1abeaa84",
883 | "metadata": {},
884 | "outputs": [
885 | {
886 | "name": "stdout",
887 | "output_type": "stream",
888 | "text": [
889 | "Epoch 20, Loss: 0.5618\n",
890 | "Val: 0.6947, Test: 0.7304\n",
891 | "Epoch 40, Loss: 0.5206\n",
892 | "Val: 0.7169, Test: 0.7433\n",
893 | "Epoch 60, Loss: 0.4923\n",
894 | "Val: 0.7146, Test: 0.7367\n",
895 | "Epoch 80, Loss: 0.5081\n",
896 | "Val: 0.7067, Test: 0.7336\n",
897 | "Epoch 100, Loss: 0.5037\n",
898 | "Val: 0.7050, Test: 0.7331\n"
899 | ]
900 | }
901 | ],
902 | "source": [
903 | "USE_DOT = False\n",
904 | "\n",
905 | "\n",
906 | "device = torch.device(\"cpu\")\n",
907 | "# See https://github.com/pyg-team/pytorch_geometric/issues/3641\n",
908 | "\n",
909 | "transform = T.Compose(\n",
910 | " [\n",
911 | " T.NormalizeFeatures(),\n",
912 | " T.ToDevice(device),\n",
913 | " T.RandomLinkSplit(num_val=0.05, num_test=0.1, is_undirected=True, add_negative_train_samples=False),\n",
914 | " ]\n",
915 | ")\n",
916 | "\n",
917 | "path = os.path.join(\"..\", \"tmp\", \"data\", \"Planetoid\")\n",
918 | "dataset = Planetoid(path, name=\"Cora\", transform=transform)\n",
919 | "# After applying the `RandomLinkSplit` transform, the data is transformed from\n",
920 | "# a data object to a list of tuples (train_data, val_data, test_data), with\n",
921 | "# each element representing the corresponding split.\n",
922 | "train_data, val_data, test_data = dataset[0]\n",
923 | "\n",
924 | "model = GCN(dataset.num_features, 128, 64, use_dot=USE_DOT).to(device)\n",
925 | "optimizer = torch.optim.Adam(model.parameters(), lr=0.01)\n",
926 | "\n",
927 | "trainer = Trainer(\n",
928 | " model=model.to(device),\n",
929 | " train_data=train_data,\n",
930 | " val_data=val_data,\n",
931 | " test_data=test_data,\n",
932 | " optimizer=optimizer,\n",
933 | ")\n",
934 | "trainer.fit(print_interval=20)"
935 | ]
936 | },
937 | {
938 | "cell_type": "markdown",
939 | "id": "bdbaebc2",
940 | "metadata": {},
941 | "source": [
942 | "## (2) Dot product"
943 | ]
944 | },
945 | {
946 | "cell_type": "code",
947 | "execution_count": 21,
948 | "id": "3114da30",
949 | "metadata": {
950 | "scrolled": false
951 | },
952 | "outputs": [
953 | {
954 | "name": "stdout",
955 | "output_type": "stream",
956 | "text": [
957 | "Epoch 20, Loss: 0.6341\n",
958 | "Val: 0.7855, Test: 0.7926\n",
959 | "Epoch 40, Loss: 0.5270\n",
960 | "Val: 0.8369, Test: 0.8390\n",
961 | "Epoch 60, Loss: 0.4692\n",
962 | "Val: 0.8991, Test: 0.8986\n",
963 | "Epoch 80, Loss: 0.4549\n",
964 | "Val: 0.9197, Test: 0.9046\n",
965 | "Epoch 100, Loss: 0.4411\n",
966 | "Val: 0.9274, Test: 0.9039\n"
967 | ]
968 | }
969 | ],
970 | "source": [
971 | "USE_DOT = True\n",
972 | "\n",
973 | "\n",
974 | "device = torch.device(\"cpu\")\n",
975 | "# See https://github.com/pyg-team/pytorch_geometric/issues/3641\n",
976 | "\n",
977 | "transform = T.Compose(\n",
978 | " [\n",
979 | " T.NormalizeFeatures(),\n",
980 | " T.ToDevice(device),\n",
981 | " T.RandomLinkSplit(num_val=0.05, num_test=0.1, is_undirected=True, add_negative_train_samples=False),\n",
982 | " ]\n",
983 | ")\n",
984 | "\n",
985 | "path = os.path.join(\"..\", \"tmp\", \"data\", \"Planetoid\")\n",
986 | "dataset = Planetoid(path, name=\"Cora\", transform=transform)\n",
987 | "# After applying the `RandomLinkSplit` transform, the data is transformed from\n",
988 | "# a data object to a list of tuples (train_data, val_data, test_data), with\n",
989 | "# each element representing the corresponding split.\n",
990 | "train_data, val_data, test_data = dataset[0]\n",
991 | "\n",
992 | "model = GCN(dataset.num_features, 128, 64, use_dot=USE_DOT).to(device)\n",
993 | "optimizer = torch.optim.Adam(model.parameters(), lr=0.01)\n",
994 | "\n",
995 | "trainer = Trainer(\n",
996 | " model=model.to(device),\n",
997 | " train_data=train_data,\n",
998 | " val_data=val_data,\n",
999 | " test_data=test_data,\n",
1000 | " optimizer=optimizer,\n",
1001 | ")\n",
1002 | "trainer.fit(print_interval=20)"
1003 | ]
1004 | },
1005 | {
1006 | "cell_type": "markdown",
1007 | "id": "d011895b",
1008 | "metadata": {},
1009 | "source": [
1010 | "# Prediction Heads: Graph-level"
1011 | ]
1012 | },
1013 | {
1014 | "cell_type": "markdown",
1015 | "id": "ba875e25",
1016 | "metadata": {},
1017 | "source": [
1018 | "## (1) Global mean pooling"
1019 | ]
1020 | },
1021 | {
1022 | "cell_type": "markdown",
1023 | "id": "6659379b",
1024 | "metadata": {},
1025 | "source": [
1026 | "TODO, see [global_mean_pool](https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html?highlight=global%20pooling#torch_geometric.nn.glob.global_mean_pool)"
1027 | ]
1028 | },
1029 | {
1030 | "cell_type": "markdown",
1031 | "id": "5bc7769b",
1032 | "metadata": {},
1033 | "source": [
1034 | "## (2) Global max pooling"
1035 | ]
1036 | },
1037 | {
1038 | "cell_type": "markdown",
1039 | "id": "2e7c2dbe",
1040 | "metadata": {},
1041 | "source": [
1042 | "TODO, see [global_max_pool](https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html?highlight=global%20pooling#torch_geometric.nn.glob.global_max_pool)"
1043 | ]
1044 | },
1045 | {
1046 | "cell_type": "markdown",
1047 | "id": "87b09c4e",
1048 | "metadata": {},
1049 | "source": [
1050 | "## (3) Global sum pooling"
1051 | ]
1052 | },
1053 | {
1054 | "cell_type": "markdown",
1055 | "id": "3e677b16",
1056 | "metadata": {},
1057 | "source": [
1058 | "TODO, see [global_add_pool](https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html?highlight=global%20pooling#torch_geometric.nn.glob.global_add_pool)"
1059 | ]
1060 | },
1061 | {
1062 | "cell_type": "markdown",
1063 | "id": "fe4f9d37",
1064 | "metadata": {},
1065 | "source": [
1066 | "# Hierarchical Global Pooling"
1067 | ]
1068 | },
1069 | {
1070 | "cell_type": "markdown",
1071 | "id": "086d0ec4",
1072 | "metadata": {},
1073 | "source": [
1074 | "TODO, see [pooling-layers](https://pytorch-geometric.readthedocs.io/en/latest/modules/nn.html#pooling-layers)"
1075 | ]
1076 | }
1077 | ],
1078 | "metadata": {
1079 | "kernelspec": {
1080 | "display_name": "Python 3",
1081 | "language": "python",
1082 | "name": "python3"
1083 | },
1084 | "language_info": {
1085 | "codemirror_mode": {
1086 | "name": "ipython",
1087 | "version": 3
1088 | },
1089 | "file_extension": ".py",
1090 | "mimetype": "text/x-python",
1091 | "name": "python",
1092 | "nbconvert_exporter": "python",
1093 | "pygments_lexer": "ipython3",
1094 | "version": "3.7.12"
1095 | }
1096 | },
1097 | "nbformat": 4,
1098 | "nbformat_minor": 5
1099 | }
1100 |
--------------------------------------------------------------------------------