{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/teddy/miniconda3/envs/gsnn-lib/lib/python3.12/site-packages/torch_geometric/typing.py:124: UserWarning: An issue occurred while importing 'torch-sparse'. Disabling its usage. Stacktrace: /home/teddy/miniconda3/envs/gsnn-lib/lib/python3.12/site-packages/torch_sparse/_version_cuda.so: undefined symbol: _ZN5torch3jit17parseSchemaOrNameERKSs\n", " warnings.warn(f\"An issue occurred while importing 'torch-sparse'. \"\n" ] } ], "source": [ "from matplotlib import pyplot as plt\n", "import seaborn as sbn\n", "import numpy as np\n", "import torch\n", "import pandas as pd\n", "\n", "from gsnn.models.GSNN import GSNN\n", "from gsnn.simulate.nx2pyg import nx2pyg\n", "from gsnn.simulate.datasets import simulate_3_in_3_out\n", "import time\n", "\n", "# for reproducibility \n", "torch.manual_seed(0)\n", "np.random.seed(0)\n", "\n", "%load_ext autoreload\n", "%autoreload 2\n", "\n", "import torch" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Gradient checkpointing and compiling" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "G, pos, x_train, x_test, y_train, y_test, \\\n", " input_nodes, function_nodes, output_nodes = simulate_3_in_3_out(n_train=10, \n", " n_test=1, \n", " noise_scale=0.1)\n", "\n", "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", "data = nx2pyg(G, input_nodes, function_nodes, output_nodes) \n", "\n", "kwargs = {'channels': 10, \n", " 'bias': True, \n", " 'add_function_self_edges': True, \n", " 'norm': 'none', \n", " 'residual': True, \n", " 'dropout': 0.}" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def memory_usage(model, x_train): \n", " torch.cuda.reset_peak_memory_stats()\n", " model(x_train.to(device))\n", " return torch.cuda.max_memory_allocated() / 1e6 \n", "\n", "def time_usage(model, x_train, n=50): \n", " times = []\n", " for i in range(n): \n", " start = time.time()\n", " model(x_train.to(device))\n", " times.append(time.time() - start)\n", " return np.mean(times)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## checkpointing with `share_layers=False`" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "progress: 5.00%\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ "progress: 100.00%\r" ] }, { "data": { "image/png": "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dJ4/f67vKhARqYyxy/gxaaJK+frrr+Hr6ws7Ozu4uLjg/fffR3Z2NgBACIEmTZpg1apVco+5fPkyzMzMcOPGDQBAXl4ePvzwQzg5OcHe3h7du3fH77//Liu/ePFivPHGG9i+fTsaNWoEa2trCCHw/fffo1WrVqhWrRpq166Nnj174vHjx7o7eSIyWoxdpA4mTVQphYWF+PTTT/H777/j4MGDSE1NxZgxYwAAEokEY8eOxY4dO+Qes337dvj7+6Nx48YQQqBfv37IysrC4cOHER8fj7Zt26JHjx548OCB7DF//PEHvv32W+zbtw+JiYnIysrCiBEjMHbsWCQlJSEqKgqDBg0C158mImUwdpFaBJGKunbtKqZPn65w39mzZwUA8fDhQyGEEHfu3BHm5ubizJkzQgghCgsLRd26dcXOnTuFEEL8+uuvwt7eXjx79kzuOI0bNxabNm0SQgixaNEiYWlpKbKzs2X74+PjBQCRlpam6dMjIhPF2EWVxZYmqpSEhAQMGDAAHh4esLOzQ0BAAAAgPT0dAODq6op+/fph+/btAICffvoJz549w5AhQwAA8fHxePToEWrXro0aNWrIbqmpqbImcADw8PBA3bp1Zfe9vb3Ro0cPtGrVCkOGDMGWLVuQm5uro7MmImPH2EXqYNJEanv8+DECAwNRo0YNfP311zh37hwOHDgAQNr0XWr8+PEICwvD06dPsWPHDgwbNgy2trYAgJKSEri6uiIxMVHulpKSgo8//lh2jOrVq8s9t7m5OSIjI/HLL7+gefPm+O9//4umTZsiNTVVB2dORMaMsYvUZaHvCpDxSk5ORk5ODpYtWwZ3d3cAwPnz58uU69u3L6pXr44NGzbgl19+wW+//Sbb17ZtW2RlZcHCwgINGzZU6fklEgk6deqETp064ZNPPoGHhwcOHDiA4ODgSp0XEZk2xi5SF1uaSG0NGjSAlZUV/vvf/+LmzZs4dOgQPv300zLlzM3NMWbMGISEhKBJkybw8/OT7evZsyf8/PwwcOBAHD16FGlpaYiNjcWCBQsUBrFSZ86cweeff47z588jPT0d+/fvx71799CsWTOtnCsRmQ7GLlIXkyZSW926dbFz50589913aN68OZYtW1ZmiG6pcePGobCwEGPHjpXbLpFIcPjwYXTp0gVjx47F66+/juHDhyMtLQ3Ozs7lPre9vT1+++039O3bF6+//joWLFiAL774An369NHoORKR6WHsInVJhOA4R9K+U6dOISAgALdu3aowoBARGRLGLnoRkybSqoKCAmRkZODDDz+Eq6srvvnmG31XiYjolRi7SBFeniOt2rt3L5o2bYq8vDysWLFC39UhIlIKYxcpwpYmIiIiIiWwpYmIiIhICUyaiIiIiJTApImIiIhICUyaiIiIiJTApImIiIhICUyaiIiIiJTApImIiIhICUyaiIiIiJTApImIiIhICf8P5vBj0KEpu4kAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "with `share_layers=False`:\n", "\tusing checkpointing on average has a -54.80% decrease in memory usage\n", "\tusing checkpointing on average has a 36.12% increase in runtime\n" ] } ], "source": [ "\n", "res = {'layers':[], 'mem_no_ckpt':[], 'time_no_ckpt':[], 'mem_ckpt':[], 'time_ckpt':[]}\n", "\n", "for layers in np.linspace(5,100,10):\n", " print(f'progress: {layers:.2f}%', end='\\r') \n", " layers = int(layers)\n", "\n", " model_no_ckpt = GSNN(data.edge_index_dict,\n", " data.node_names_dict, \n", " share_layers=False,\n", " checkpoint=False, \n", " layers=layers, \n", " **kwargs).to(device)\n", "\n", " model_ckpt = GSNN(data.edge_index_dict,\n", " data.node_names_dict, \n", " share_layers=False,\n", " checkpoint=True, \n", " layers=layers, \n", " **kwargs).to(device)\n", "\n", " res['layers'].append(layers)\n", " res['mem_no_ckpt'].append(memory_usage(model_no_ckpt, x_train))\n", " res['time_no_ckpt'].append(time_usage(model_no_ckpt, x_train))\n", " res['mem_ckpt'].append(memory_usage(model_ckpt, x_train))\n", " res['time_ckpt'].append(time_usage(model_ckpt, x_train))\n", "\n", "res = pd.DataFrame(res)\n", "\n", "f,axes = plt.subplots(1,2, figsize=(6,3))\n", "sbn.scatterplot(data=res, x='layers', y='mem_no_ckpt', color='red', label='no checkpointing', ax=axes[0])\n", "sbn.scatterplot(data=res, x='layers', y='mem_ckpt', color='blue', label='checkpointing', ax=axes[0])\n", "\n", "sbn.scatterplot(data=res, x='layers', y='time_no_ckpt', color='red', label='no checkpointing', ax=axes[1])\n", "sbn.scatterplot(data=res, x='layers', y='time_ckpt', color='blue', label='checkpointing', ax=axes[1])\n", "\n", "axes[0].set_ylabel('memory usage (MB)')\n", "axes[1].set_ylabel('time (s)')\n", "axes[0].set_xlabel('layers')\n", "axes[1].set_xlabel('layers')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "mem_percent_change = ((res.mem_ckpt - res.mem_no_ckpt)/res.mem_no_ckpt*100).mean()\n", "\n", "time_percent_change = ((res.time_ckpt - res.time_no_ckpt)/res.time_no_ckpt*100).mean()\n", "\n", "print('with `share_layers=False`:')\n", "print(f'\\tusing checkpointing on average has a {mem_percent_change:.2f}% decrease in memory usage')\n", "print(f'\\tusing checkpointing on average has a {time_percent_change:.2f}% increase in runtime')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Checkpointing with `share_layers=True`" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "progress: 100.00%\r" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "with `share_layers=True`:\n", "\tusing checkpointing on average has a -77.51% decrease in memory usage\n", "\tusing checkpointing on average has a 36.19% increase in runtime\n" ] } ], "source": [ "\n", "res = {'layers':[], 'mem_no_ckpt':[], 'time_no_ckpt':[], 'mem_ckpt':[], 'time_ckpt':[]}\n", "\n", "for layers in np.linspace(5,100,10):\n", " print(f'progress: {layers:.2f}%', end='\\r') \n", " layers = int(layers)\n", "\n", " model_no_ckpt = GSNN(data.edge_index_dict,\n", " data.node_names_dict, \n", " share_layers=True,\n", " checkpoint=False, \n", " layers=layers, \n", " **kwargs).to(device)\n", "\n", " model_ckpt = GSNN(data.edge_index_dict,\n", " data.node_names_dict, \n", " share_layers=True,\n", " checkpoint=True, \n", " layers=layers, \n", " **kwargs).to(device)\n", "\n", " res['layers'].append(layers)\n", " res['mem_no_ckpt'].append(memory_usage(model_no_ckpt, x_train))\n", " res['time_no_ckpt'].append(time_usage(model_no_ckpt, x_train))\n", " res['mem_ckpt'].append(memory_usage(model_ckpt, x_train))\n", " res['time_ckpt'].append(time_usage(model_ckpt, x_train))\n", "\n", "res = pd.DataFrame(res)\n", "\n", "f,axes = plt.subplots(1,2, figsize=(6,3))\n", "sbn.scatterplot(data=res, x='layers', y='mem_no_ckpt', color='red', label='no checkpointing', ax=axes[0])\n", "sbn.scatterplot(data=res, x='layers', y='mem_ckpt', color='blue', label='checkpointing', ax=axes[0])\n", "\n", "sbn.scatterplot(data=res, x='layers', y='time_no_ckpt', color='red', label='no checkpointing', ax=axes[1])\n", "sbn.scatterplot(data=res, x='layers', y='time_ckpt', color='blue', label='checkpointing', ax=axes[1])\n", "\n", "axes[0].set_ylabel('memory usage (MB)')\n", "axes[1].set_ylabel('time (s)')\n", "axes[0].set_xlabel('layers')\n", "axes[1].set_xlabel('layers')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "mem_percent_change = ((res.mem_ckpt - res.mem_no_ckpt)/res.mem_no_ckpt*100).mean()\n", "\n", "time_percent_change = ((res.time_ckpt - res.time_no_ckpt)/res.time_no_ckpt*100).mean()\n", "\n", "print('with `share_layers=True`:')\n", "print(f'\\tusing checkpointing on average has a {mem_percent_change:.2f}% decrease in memory usage')\n", "print(f'\\tusing checkpointing on average has a {time_percent_change:.2f}% increase in runtime')\n" ] } ], "metadata": { "kernelspec": { "display_name": "gsnn-lib", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.8" } }, "nbformat": 4, "nbformat_minor": 2 }