Created
February 19, 2021 05:48
-
-
Save fgolemo/b762ddc59c83ca19cd15f3767e2c3780 to your computer and use it in GitHub Desktop.
autobot_toy.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"nbformat": 4, | |
"nbformat_minor": 0, | |
"metadata": { | |
"accelerator": "GPU", | |
"colab": { | |
"name": "autobot_toy.ipynb", | |
"provenance": [], | |
"collapsed_sections": [], | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"display_name": "Python 3", | |
"name": "python3" | |
} | |
}, | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/fgolemo/b762ddc59c83ca19cd15f3767e2c3780/autobot_toy.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "EB9MwlqV98w-" | |
}, | |
"source": [ | |
"# AutoBot Toy Dataset Modelling" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"collapsed": true, | |
"id": "6lMLqmTN9i8G" | |
}, | |
"source": [ | |
"## Generate Toy Dataset\n", | |
"In this section, we generate our tiny toy dataset that showcases AutoBot's ability to model multimodal trajectories. We generate these trajectories by adopting a simple bicycle model that turns with a constant steering angle at a constant speed. This toy dataset not only demonstrates the multimodal trajectories AutoBot generates, but also shows the importance of the entropy regularization term." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 596 | |
}, | |
"id": "cBIkHktQ9i8K", | |
"outputId": "13cebbfc-0bd7-434f-e929-22b7948eec08" | |
}, | |
"source": [ | |
"import numpy as np\n", | |
"import matplotlib.pyplot as plt\n", | |
"%matplotlib inline\n", | |
"\n", | |
"\n", | |
"l = 2 # length of bycicle\n", | |
"dt = 0.5\n", | |
"start_pos = np.array([-0.0, -10.0])\n", | |
"data = []\n", | |
"\n", | |
"# we'll generate a total of 6 trajectories\n", | |
"\n", | |
"# we will have 2 trajectories go left, 2 go straight, 2 go right\n", | |
"phis = [-0.2, 0.0, 0.2]\n", | |
"\n", | |
"# the trjeactories will go left/straight/right at one of 2 possible speeds\n", | |
"speeds = [1.5, 3.0]\n", | |
"\n", | |
"configs = np.array(np.meshgrid(phis, speeds)).T.reshape(-1, 2)\n", | |
"\n", | |
"fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(15, 10))\n", | |
"row = 0\n", | |
"for i, config in enumerate(configs):\n", | |
" wheel_pos = []\n", | |
" speed = 3.0\n", | |
" heading = np.pi / 2\n", | |
" phi = 0.0\n", | |
" positions = {\n", | |
" \"rear\": np.array([0.0, 0.0]) + start_pos,\n", | |
" \"front\": np.array([l * np.cos(heading), l * np.sin(heading)]) + start_pos\n", | |
" }\n", | |
"\n", | |
" # we are generating trajectories of total length 18, \n", | |
" # 6 of which will be used as input trajectory and\n", | |
" # the remaining 12 as output trajectory\n", | |
" for t in range(18):\n", | |
" \n", | |
" # the first 6 steps are fixed to be straight upwards-facing at the given velocity\n", | |
" if t > 6:\n", | |
" phi, speed = config\n", | |
"\n", | |
" # for the remaining 12 steps, we apply different headings and velocities\n", | |
" x_v = speed*np.cos(heading)\n", | |
" y_v = speed*np.sin(heading)\n", | |
" omega = speed*np.tan(phi)/l\n", | |
" heading += omega * dt\n", | |
" positions[\"rear\"] += np.array([x_v * dt, y_v * dt])\n", | |
" positions[\"front\"] = positions[\"rear\"] + np.array([l * np.cos(heading), l * np.sin(heading)])\n", | |
" wheel_pos.append([positions[\"rear\"][0], positions[\"rear\"][1], positions[\"front\"][0], positions[\"front\"][1]])\n", | |
" data.append(np.array(wheel_pos))\n", | |
" \n", | |
" # plotting the data\n", | |
" col = i % 3\n", | |
" if i > 0 and i % 3 == 0:\n", | |
" row += 1\n", | |
" ax[row, col].scatter(np.array(wheel_pos)[:6, 0], np.array(wheel_pos)[:6, 1], color='#94D0FF', label='past', s=40)\n", | |
" ax[row, col].scatter(np.array(wheel_pos)[6:, 0], np.array(wheel_pos)[6:, 1], color='#FF6AD5', label='future', s=40)\n", | |
" ax[row, col].axis(xmin=-15, xmax=15, ymin=-15, ymax=20)\n", | |
"\n", | |
"ax[1, 2].legend()\n", | |
"plt.show()\n", | |
"data = np.array(data)[:, :, :2]" | |
], | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA3UAAAJDCAYAAACsWj0kAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nOzde5BlV30f+u/q7pnpK4IFwpOZsR6R7OIhWSYyGYgUZMoPHD/KFmAFBQq7SF3HY4KpJNyUCxJXXfvm4iqZ2KbKZWMslylxrwMOsYKhbJeNRXDwWKSCJOtiPYwRIJuZ6GWGUQB5Ht297h+7e6andXr6nD7n7L3P9OdT1ZzufbrPXupqvrN/+6z1W6XWGgAAAGbTXNcDAAAAYPsUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM2zsoq6Ucnkp5eOllAdLKQ+UUv7V6vFLSil/VEr57Orjc8cfLsDw5BPQR7IJmLQy7j51pZQDSQ7UWu8tpTw7yT1JXp3knyU5Vmu9tZTy9iTPrbW+bdwBAwxLPgF9JJuASRv7nbpa66O11ntXP/9KkoeSXJrkVUnet/pt70sTVgCtkU9AH8kmYNLGfqfunBcr5cokn0hybZK/rrU+Z/V4SfLlta8B2iafgD6STcAkLEzqhUopfyfJHUn+da31fzVZ1Ki11lLKwOqxlHIoyaEkedaznvUPXvSiF01qSEBP3HPPPX9Ta93b1fnlEzCIbAL6aDvZNJGirpSyK00o/cda639ZPfx4KeVArfXR1bnjTwz62VrrbUluS5KDBw/Wu+++exJDAnqklPJXHZ5bPgEDySagj7aTTZPoflmS/EaSh2qtv7juqY8keePq529M8uFxzwUwCvkE9JFsAiZtEu/UvTzJjyT581LKfavH/l2SW5N8sJTyo0n+KsktEzgXwCjkE9BHsgmYqLGLulrr4SRlk6e/a9zXB9gu+QT0kWwCJm3s6ZcAAAB0R1EHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwyZS1JVS3ltKeaKUcv+6Yz9TSjlaSrlv9eP7J3EugGHJJqCv5BMwSZN6p+72JN874Pi7aq3XrX78/oTOBTCs2yObgH66PfIJmJCJFHW11k8kOTaJ1wKYFNkE9JV8AiZp2mvq3lJK+fTqFIPnTvlcAMOSTUBfySdgZNMs6n41yTcluS7Jo0l+YdA3lVIOlVLuLqXc/eSTT05xOABJhsymRD4BrXPtBGzL1Iq6WuvjtdblWutKkl9P8rJNvu+2WuvBWuvBvXv3Tms4AEmGz6bV75VPQGtcOwHbNbWirpRyYN2Xr0ly/2bfC9AW2QT0lXwCtmthEi9SSvlAkm9P8vWllCNJfjrJt5dSrktSkzyS5McncS6AYckmoK/kEzBJEynqaq2vH3D4Nybx2gDbJZuAvpJPwCRNu/slAAAAU6SoAwAAmGGKOgAAgBmmqAMAAJhhijoAAIAZpqgDAACYYYo6AACAGaaoAwAAmGGKOgAAgBmmqAMAAJhhijoAAIAZpqgDAACYYYo6AACAGaaoAwAAmGGKOgAAgBmmqAMAAJhhijoAAIAZpqgDAACYYYo6AACAGaaoAwDO78RK8vjJ5nGaPwPAtix0PQAAoKeWa3LHY8ldx5O5kqzU5B89J7l5fzJfJvczAIxFUQcADLZWnJ2uSWpz7K7jzeMtByb3MwCMxfRLANhphpkaeWJlXXG2zunaHB/0s9v5GQDG5p06ANgpRpka+dTp5ntSn/k6c6V5fnHP+D8DwNgUdQCwU4wyNfLiXU3RN8hKbZ7faDs/A8DYTL8EgAvBVlMqR50auTjXvIu3a8M7eLtKc3xxwCXEdn4GgLF5pw4AZtmwUyq3MzXy5v3N46DX3sx2fgaAsUykqCulvDfJDyR5otZ67eqxS5L8pyRXJnkkyS211i9P4nwAw5BN7AjDTqncztTI+dK8xk37mqLv4l1bv9u2nZ/ZgeQTMEmTStnbk3zvhmNvT/KxWuvzk3xs9WuANt0e2cSFbJQpleNMjVycS/btGa04287P7Cy3Rz4BEzKRpK21fiLJsQ2HX5Xkfaufvy/JqydxLoBhySYueGemVA6wNqVyvZv3ny3s9sydLehMjWydfAImaZpr6vbVWh9d/fyxJPumeC6AYckmZseJlfNPYRx1SqWpkX0nn4BtaaVRSq21llIG/qtTSjmU5FCSXHHFFW0MByDJ+bMpkU90aNjmJ2tTKjdOwdxqSuXinP3ies61EzCKad6ee7yUciBJVh+fGPRNtdbbaq0Ha60H9+7dO8XhACQZMpsS+USH1jc/Oblydo3cHY8983tNqbyQuHYCtmWaRd1Hkrxx9fM3JvnwFM8FMCzZRL+Nup/c2pTKW1+YvO2q5vGWA+e+o8eskE/AtkykqCulfCDJJ5O8sJRypJTyo0luTfLdpZTPJnnl6tcArZFNzKRRm5+s0W1ypsgnYJImsqau1vr6TZ76rkm8PsB2yCZm0nb2k2PmyCdgktzOA4A+GWc/OeDCdGIlefzkM6dfw6pWul8CAOtstVXBWpOTQd0vgZ1j2E647HiKOgBoy7AXaPaTA5JzO+FmdVr2Xcebx1sOdDYs+se/EADQllG2Kkg0P4GdbNROuOxo/pUAgDa4QANGsd1OuOxIijouTBYUA33jAg0YhU64jMCaOi4sFhQDfeUCDRjF4lxyw3OSw19O1t+jnktz3LRs1vHXwIVl1PUqAG2xVQEwsnqmP8r6Q888yE7nXxAuHNarAH138/6zhd2eubMFna0KgI1OrCSffGpwUffJp1zXcA7TL7kwnFhJPv+11fUqA+5era1XWdzT+tCAHWizfehsVQAM68w6XNc1bE1Rx2xbv4auJDllvQrQoWHX9S7OuRgDzs86XEbg9iCzbf0aus0KOutVgLZY1wtMylqjlI2XLxqlMIC/BmbXZmvo1livArTJul5g4jRKYTimXzKbtlpDt7sk//zS5Buf5U4W0A7rX4BJ2qpRyqv2u8bhDEUds2XYNXQ1CjqgXda/AJPkRhEjcMXLbLGGDugr+9ABk+RGESPwLwyzwxo6oO/sQwdMihtFjMD0S2bH+aYhWEMHtG3QXnT2oQMm6dX7ks9+Lfmfp84e27urOQ7rKOqYDSdWklMrzZq6QayhA9oyzF509qEDJuF3Hk+ePH3usSdPN8dvOdDNmOglRR39tvHiabk2k4bXdwY3DQFo0/q1vWszB+463jy6yAImZattUm7a59qHM/wl0G8bN/Jdu4aai/UqQPvsRQe05cyykwHWul/CKu/U0V+bXTzVJPNJ3nplsne3u1RAe7QYB9qi+yUjcDVMfz15qtmLbpD5uaY5ioIOaJOLLKAti3PJDc955tX6XJrjroFYxzt19M/aOro//XKytMn3uHgCurDWYnzjLAJre4GpqM+cGFDP/A+c4V8f+mdtHd1mBZ2LJ6BL9qID2nBiJfnkU4OLuk8+ZQ0v5/BOHf2y1QbjLp6ArtmLDmiDNbyMYOpFXSnlkSRfSbKcZKnWenDa52SGnS/AdpXk31yZXP6/tT0qLkCyibHZi44pkU8ksYaXkbT1Tt131Fr/pqVzMcsW5zffYDxJ9rqAYqJkE1s7seIdObogn3a6tUYph7987v68GqUwgOmX9MP6TcYH3ZWyjg5o2/pcmitNNq1N/57frDUvwCRplMJw2rhCrkk+Wkq5p5RyqIXzMYvWbzK+/m7UfKyjY1pkE+e3PpdOrpzdYPyOx7oeGRc++YRGKYykjXfqbqy1Hi2l/N0kf1RK+Yta6yfWnlwNq0NJcsUVV7QwHHrnfM1RSpL/6/nJxd5UZuLOm02JfNrRNsultcLupn1mDjBNrp3QKIWRTP1fpFrr0dXHJ5J8KMnLNjx/W631YK314N69e6c9HProTGgNMD+XnFhudzzsCFtl0+pz8mmnOl8urV1MwZS4diKJRimMZKpFXSnlWaWUZ699nuQfJ7l/mudkBl28a/PmKEKLKZBNbMnFFB2RT5yx1ihl49W6RikMMO05bfuSfKiUsnau99da/2DK52SWLNfkI48PLuo0R2F6ZBPntzjX5M/GKZhyiemTT6yjUQrDmWpRV2v9fJK/P81zMOPWGhFszKa5aI7C1MgmhrKWP4O6X8KUyCfO2KpRyqv2u8HEGbpP0J3zNUiZS9OIQNtwoCvzJbnlQJNF9qkD2qZRCiNQ1NGd84XV/JywAvphcU4WAe2ztpcRuOVIdzRIAfrqxEry+En7QAHdWVvbu2vDrCVrexnAO3V0Q4MUoI+W69m1vhvX0ZkODrTt1fuSz34t+Z+nzh7bu6s5Duu4aqYbGqQAfbSWTadrcnLl7GbjdzzW9ciAneh3Hk+e3LAv5pOnm+OwjqKO9mmQAvTRZtm0VtiZigm0SSYxAkUd7TvTIGWAtQYpAG07XzatdZoDaItMYgSKOtqnmxPQR7IJ6BOZxAgUdbRvV2kW+Q46rkEK0BWd5oA+WZxLbnjOM6/W59Icl0mso/sl7bvjseSJU888vneXBilAt9YyaFD3S4DW1Wc2latn/gfOUNTRrrVFv0sDnnvydLP4V5MUoCvzJbnlQNOw6anTzfQmd8OBLpxYST751OCi7pNPJa/aL584w18C7bLoF5gFi3PJvj0umIDuuGZiBP61ol0W/QJ9dmIlefykVuFA91wzMQLTL2nXWpOU/3nqmcc1IgC6slzPbjy+cS2dKeFAF9YapRz+crL+PpNGKQygqKNdmqQAfbRW0J2uObOA5a7jzeMtBzobFrDTaZTCcJT4tGeYJikAbVvLpo0ZdLo2x03FBLqwVaMU2cQ6ijraY8Ev0EeyCegj2cQIFHW0x4JfoI9kE9BHsokRKOpoz+Jc03hg14a7TpqkAF2STUAfySZG4K+B9izXpNZkad1dp7UOTpqkAF26ef/Zi6c9c2cvmmQT0KVX72uaya23d1dzHNbR/ZL23PHYMxf8ziUp0TIc6NZ8abpc3rSvWady8S53wYHu/c7jTTO59Z483RzXmZd1/ItFOzbrLrcU3eWA/licS/btUdAB3dOZlxH4V4t26OAEADA8106MQFFHO3RwAmbBiZXk8ZPugAPdc+3ECKypox2Lc01DlMNfTtZfK601SjHVCejScm3W/d51vLkDvlLPNkqx5hfogmsnRqCoo0X13CYpq4eeeRCgZWsF3emaM5l01/HmUTMCoDOunRjO1Ev8Usr3llI+U0p5uJTy9mmfj546sfLMzpdJ8/UnnzLVidbJJs7QjICekU8kce3ESKZa1JVS5pP8SpLvS3JNkteXUq6Z5jnpKYt96RHZxDnkEz0inzhDNjGCab9T97IkD9daP19rPZXkt5K8asrnpI8s9qVfZBNnySf6RT7RkE2MYNpF3aVJvrju6yOrx9hpFueapgO7Ntxx2lWa4xb70i7ZxFnyiX6RTzRkEyPo/K+hlHKolHJ3KeXuJ598suvhME037z8bTnvmzobSzfu7HhkMJJ92EPnEDJFNO4hsYkjT7n55NMnl676+bPXYGbXW25LcliQHDx7UyudCNl+aLnI37WvmgV+8y10murJlNiXyaUeRT/SHayfOkk0Madp/FZ9K8vxSylWllN1JXpfkI1M+J323OJfs2yOU6JJsYjD5RPfkE88km9jCVN+pq7UulVLekuQPk8wneW+t9YFpnpP+O7WcPL2UXLSQ7J7vejTsRLKJzcgnuiafGEQ2sZWpbz5ea/39JL8/7fPQfys1OXw0efBY04l3pSbXXJLceOnmHXthWmQT68kn+kQ+sUY2MaypF3Ww5vDR5KFjyXJtPpLm6yR5xWXdjQtAPgF9JJsYlom5tOLUcnOXaWnDcu6l2hw/tdzNuADkE9BHsolRKOpoxdNLm08TmCvN8wBdkE9AH8kmRqGooxUXLTTzwAdZqc3zAF2QT0AfySZGoaijFbvnm4W9CxvuOC2U5rhOTkBX5BPQR7KJUajxac2NlzaP6zs4XX3J2eMAXZFPQB/JJoalqKM1c6Xp1HT9AXutAP0in4A+kk0MS1FH63bPCySgn+QT0Eeyia1YUwcAADDDFHW07tRycvyk/VWA/pFPQB/JJrZi+iWtWanJ4aPnLva9ZnWx72b7sAC0QT4BfSSbGJaijtYcPpo8dCxZrs1H0nydNIuAAboin4A+kk0My/RLWnFqubnLtLRhE82l2hw3nQDoinwC+kg2MQpFHa14emnzaQJzpXkeoAvyCegj2cQoFHW04qKFZh74ICu1eR6gC/IJ6CPZxCgUdbRi93yzsHdhwx2nhdIct/cK0BX5BPSRbGIUanxac+OlzeP6Dk5XX3L2OEBX5BPQR7KJYSnqaM1caTo1XX+gmQd+0YK7TEA/yCegj2QTw1LU0brd8wIJ6Cf5BPSRbGIr1tQBAADMMEUdrTu1nBw/aX8VoH/kE9BHsomtmH5Ja1ZqcvjouYt9r1ld7LvZPiwAbZBPQB/JJoalqKM1h48mDx1LlmvzkTRfJ80iYICuyCegj2QTwzL9klacWm7uMi1t2ERzqTbHTScAuiKfgD6STYxCUUcrnl7afJrAXGmeB+iCfAL6SDYxCkUdrbhooZkHPshKbZ4H6IJ8AvpINjEKRR2t2D3fLOxd2HDHaaE0x+29AnRFPgF9JJsYxdSKulLKz5RSjpZS7lv9+P5pnYvZcOOlydWXJPMl2TXXPF692sEJ2iKbGEQ+0QfyiY1kE8Oa9hu376q1/vyUz8GMmCtNp6brDzTzwC9acJeJzsgmziGf6BH5xBmyiWGZjUvrds8LJKCf5BPQR7KJrUx7Td1bSimfLqW8t5Ty3Cmfixlxajk5flIrXjolmxhIPtED8olnkE1sZax36kopdybZP+Cpn0ryq0n+7yR19fEXkvzvA17jUJJDSXLFFVeMMxx6bqU2m2g+eKyZTrBSm4W+N166ecte2I5JZNPq68inHUI+0RbXToxCNjGsUusmvVIneZJSrkzyu7XWa8/3fQcPHqx333331MdDNz5xJHlowyaaC6sLfl9xWXfjYvpKKffUWg92PY6Nhs2mRD5d6OTTztTXbEpcO9GQTTvTdrJpmt0vD6z78jVJ7p/Wuei/U8vNXaalDfcQlmpz3HQC2iKb2Eg+0RfyifVkE6OYZqOUd5ZSrkszheCRJD8+xXPRc08vNdMElge8MTxXmuctAKYlsolzyCd6RD5xhmxiFFMr6mqtPzKt12b2XLTQzAMfZKU2z0MbZBMbySf6Qj6xnmxiFNPufglJmjtJ11zSzANfb6E0x91pAroin4A+kk2MQo1Pa268tHlc38Hp6kvOHgfoinwC+kg2MSxFHa2ZK02npusPNPPAL1pwlwnoB/kE9JFsYliKOlq3e14gAf0kn4A+kk1sxZo6AACAGaaoo3WnlpPjJ+2vAvSPfAL6SDaxFdMvac1KTQ4fPXex7zWri33nytY/DzAt8gnoI9nEsBR1tObw0eShY80mmmsbaT50rHl8xWXdjQtAPgF9JJsYlumXtOLUcnOXaWnDJppLtTluOgHQFfkE9JFsYhSKOlrx9NLm0wTmSvM8QBfkE9BHsolRKOpoxUULzTzwQVZq8zxAF+QT0EeyiVEo6mjF7vlmYe/ChjtOC6U5bu8VoCvyCegj2cQo1Pi05sZLm8f1HZyuvuTscYCuyCegj2QTw1LU0Zq50nRquv5AMw/8ogV3mYB+kE9AH8kmhqWoo3W75wUS0E/yCegj2cRWrKmjdaeWk+MnteIF+kc+AX0km9iKd+pozUptNtFcPy/8mtV54Zu17AVog3wC+kg2MSxFHa05fDR56FiyXJuPpPk6aeaLA3RFPgF9JJsYlumXtOLUcnOXaWnDfitLtTluOgHQFfkE9JFsYhSKOlrx9NLm0wTmSvM8QBfkE9BHsolRKOpoxUULzTzwQVZq8zxAF+QT0EeyiVEo6mjF7vlmYe/ChjtOC6U5rk0v0BX5BPSRbGIUanxac+OlzeP6Dk5XX3L2OEBX5BPQR7KJYSnqaM1caTo1XX+gmQd+0YK7TEA/yCegj2QTw1LU0brd8wIJ6Cf5BPSRbGIr1tQBAADMsLGKulLKa0spD5RSVkopBzc8929LKQ+XUj5TSvme8YYJMBr5BPSRbAKmYdzpl/cn+aEkv7b+YCnlmiSvS/LNSb4hyZ2llBfUWm2TCLRFPgF9JJuAiRvrnbpa60O11s8MeOpVSX6r1nqy1vqFJA8nedk45wIYhXwC+kg2AdMwrTV1lyb54rqvj6weA+iafAL6SDYB27bl9MtSyp1J9g946qdqrR8edwCllENJDiXJFVdcMe7LATuIfAL6SDYBbduyqKu1vnIbr3s0yeXrvr5s9dig178tyW1JcvDgwbqNcwE7lHwC+kg2AW2b1vTLjyR5XSllTynlqiTPT/I/pnQugFHIJ6CPZBOwbeNuafCaUsqRJDck+b1Syh8mSa31gSQfTPJgkj9I8hO6NwFtkk9AH8kmYBrG2tKg1vqhJB/a5LmfTfKz47w+wHbJJ6CPZBMwDdOafgkAAEALFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzbKyirpTy2lLKA6WUlVLKwXXHryyl/G0p5b7Vj/eMP1SA4cknoI9kEzANC2P+/P1JfijJrw147nO11uvGfH2A7ZJPQB/JJmDixirqaq0PJUkpZTKjAZgQ+QT0kWwCpmGaa+quKqX8WSnlv5VSvm2K5wEYlXwC+kg2Aduy5Tt1pZQ7k+wf8NRP1Vo/vMmPPZrkilrrl0op/yDJ75RSvrnW+r8GvP6hJIdWvzxZSrl/yLF35euT/E3Xg9iCMU6GMU7OC6fxovLpGWbh78EYJ8MYJ0M2tWMW/haMcTKMcTJGzqYti7pa6ytHfdFa68kkJ1c/v6eU8rkkL0hy94DvvS3JbUlSSrm71npw4/f0iTFOhjFOxiyMMWnGOY3XlU/nMsbJMMbJmJUxTuN1ZdO5jHEyjHEyZmWMo/7MVKZfllL2llLmVz//xiTPT/L5aZwLYBTyCegj2QSMY9wtDV5TSjmS5IYkv1dK+cPVp16R5NOllPuS/HaSN9Vaj403VIDhySegj2QTMA3jdr/8UJIPDTh+R5I7tvGSt40znpYY42QY42TMwhiTDsYpn3rLGCfDGCdDNrXDGCfDGCfjghxjqbVOYyAAAAC0YJpbGgAAADBlvSjqSimvLaU8UEpZKaUcXHf8ylLK35ZS7lv9eE/fxrj63L8tpTxcSvlMKeV7uhrjeqWUnymlHF33u/v+rse0ppTyvau/q4dLKW/vejyDlFIeKaX8+ervbird0UZVSnlvKeWJ9a2rSymXlFL+qJTy2dXH5/ZwjL39W9yKbJqOvv5NyKbtk0/tk0+T1+e/B/m0PTspm3pR1CW5P8kPJfnEgOc+V2u9bvXjTS2Pa72BYyylXJPkdUm+Ocn3Jnl3We1e1QPvWve7+/2uB5Mkq7+bX0nyfUmuSfL61d9hH33H6u+uL21vb0/zN7be25N8rNb6/CQfW/26S7fnmWNMevi3OCTZND29+puQTWO7PfKpbfJpOnr39yCfxnJ7dkg29aKoq7U+VGv9TNfjOJ/zjPFVSX6r1nqy1vqFJA8neVm7o5spL0vycK3187XWU0l+K83vkC3UWj+RZGMntFcled/q5+9L8upWB7XBJmOcWbJpR5FNY5BP7ZNPO4p82qadlE29KOq2cFUp5c9KKf+tlPJtXQ9mgEuTfHHd10dWj/XBW0opn159W7fTt5bX6fPva72a5KOllHtKKYe6Hsx57Ku1Prr6+WNJ9nU5mPPo49/iuGTTePr2N9H339eaWcmmRD51ST5tXx//Hvr8+1pvVvLpgsym1oq6UsqdpZT7B3yc707Do0muqLV+a5L/I8n7Sylf17MxdmaL8f5qkm9Kcl2a3+MvdDrY2XNjrfUlaaY6/EQp5RVdD2grtWll28d2tr3+W5RN0yGfpmbmsimRT9slnyZPNk3VzOXThZRNY+1TN4pa6yu38TMnk5xc/fyeUsrnkrwgyVQWX25njEmOJrl83deXrR6bumHHW0r59SS/O+XhDKuz39coaq1HVx+fKKV8KM3Uh0HrFrr2eCnlQK310VLKgSRPdD2gjWqtj6993rO/xSSyaVpmMJ9k0+TJpzHJp8mbwWxK5NOkXZDZ1Ovpl6WUvWV14Wwp5RuTPD/J57sd1TN8JMnrSil7SilXpRnj/+h4TFn9I13zmjSLlfvgU0meX0q5qpSyO81C6Y90PKZzlFKeVUp59trnSf5x+vP72+gjSd64+vkbk3y4w7EM1OO/xW2TTePp6d+EbJo8+dQB+bR9Pf57kE+TdWFmU62184/VwR5Jc2fp8SR/uHr85iQPJLkvyb1JfrBvY1x97qeSfC7JZ5J8X9e/z9Ux/b9J/jzJp9P88R7oekzrxvb9Sf5y9Xf2U12PZ8D4vjHJ/7f68UBfxpjkA2negj+9+rf4o0mel6Zz02eT3Jnkkh6Osbd/i0P898im6Yy5l38Tsmmsscmn9v975NPkx9vbvwf5tO1x7ZhsKqsvBgAAwAzq9fRLAAAAzk9RBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTGF3Ih0AACAASURBVFEHAAAwwxR1AAAAM0xRBwAAMMMUdQAAADNMUQcAADDDFHUAAAAzTFEHAAAww8Yu6kopl5dSPl5KebCU8kAp5V+tHr+klPJHpZTPrj4+d/zhAgxPPgF9JJuASSu11vFeoJQDSQ7UWu8tpTw7yT1JXp3knyU5Vmu9tZTy9iTPrbW+bdwBAwxLPgF9JJuASRv7nbpa66O11ntXP/9KkoeSXJrkVUnet/pt70sTVgCtkU9AH8kmYNLGfqfunBcr5cokn0hybZK/rrU+Z/V4SfLlta8B2iafgD6STcAkLEzqhUopfyfJHUn+da31fzVZ1Ki11lLKwOqxlHIoyaEkedaznvUPXvSiF01qSEBP3HPPPX9Ta93b1fnlEzCIbAL6aDvZNJGirpSyK00o/cda639ZPfx4KeVArfXR1bnjTwz62VrrbUluS5KDBw/Wu+++exJDAnqklPJXHZ5bPgEDySagj7aTTZPoflmS/EaSh2qtv7juqY8keePq529M8uFxzwUwCvkE9JFsAiZtEu/UvTzJjyT581LKfavH/l2SW5N8sJTyo0n+KsktEzgXwCjkE9BHsgmYqLGLulrr4SRlk6e/a9zXB9gu+QT0kWwCJm1ijVIAAACGcfr06Rw5ciQnTpzoeiidWVxczGWXXZZdu3aN/VqKOgAAoFVHjhzJs5/97Fx55ZVZ3/l1p6i15ktf+lKOHDmSq666auzXG7tRCgAAwChOnDiR5z3veTuyoEuSUkqe97znTeydSkUdAADQup1a0K2Z5H+/og4AAGAb/viP/zh33XVX18NQ1AEAAP13ajk5frJ57AtFHQAAwBZWavKJI8l7H0g++JfN4yeONMfH8cgjj+RFL3pR3vCGN+Tqq6/OP/kn/yRPP/10/v2///d56UtfmmuvvTaHDh1Krc2JfumXfinXXHNNXvziF+d1r3tdHnnkkbznPe/Ju971rlx33XX5kz/5kwn8126Pog4AAOitw0eTh44lyzU5vdI8PnSsOT6uz3zmM3nzm9+chx56KF/3dV+Xd7/73XnLW96ST33qU7n//vvzt3/7t/nd3/3dJMmtt96aP/uzP8unP/3pvOc978mVV16ZN73pTXnrW9+a++67L9/2bd82/oC2SVEHAAD00qnl5MFjydKGd+WWanN83KmYl19+eV7+8pcnSX74h384hw8fzsc//vH8w3/4D/Mt3/It+a//9b/mgQceSJK8+MUvzhve8Ib85m/+ZhYW+rUznKIOAADopaeXkrlNmkTOleb5cWzsQFlKyZvf/Ob89m//dv78z/88P/ZjP3Zm24Hf+73fy0/8xE/k3nvvzUtf+tIsLY158glS1AEAAL100cLma+dWavP8OP76r/86n/zkJ5Mk73//+3PjjTcmSb7+678+X/3qV/Pbv/3bzblWVvLFL34x3/Ed35Gf+7mfy1NPPZWvfvWrefazn52vfOUr4w1iAhR1AABAL+2eT665JFnY8G7dQmmO754f7/Vf+MIX5ld+5Vdy9dVX58tf/nL+xb/4F/mxH/uxXHvttfme7/mevPSlL02SLC8v54d/+IfzLd/yLfnWb/3W/Mt/+S/znOc8Jz/4gz+YD33oQ503SunXZFB2hhMryVOnk4t3JYvuKwAAsLkbL20eHzzWTLlcqcnVl5w9Po6FhYX85m/+5jnH3vGOd+Qd73jHM7738OHDzzj2ghe8IJ/+9KfHH8iYFHW0Z7kmdzyW3HX87P8j/9Fzkpv3J/ObTJYGAGBHmyvJKy5Lrj/QrKG7aGH8d+guNIo62rNW0J2uSVYnR991vHm85UBnwwIAoP92z0+2mLvyyitz//33T+4FO2TuG+04sbKuoFvndG2On1jpZlwAADDjFHW046nT5+9H+9TpdscDAAAXCEUd7bh41/n70V68q93xAADABUJRRzsW55qmKLs2vFu3qzTHdcEEAIBtcSVNe27ef7aw2zN3tqC7eX/XIwMAYIf5pV/6pVx99dV5wxveMPD548eP593vfnfLo9oe3S9pz3xpulzetM8+dQAAjGbCex2/+93vzp133pnLLrts4PNrRd2b3/zmkV53eXk58/Pt7rngipr2Lc4l+/Yo6AAA2NpyTT74aPL2zyQ/94Xm8YOPNse36U1velM+//nP5/u+7/ty8cUX5+d//ufPPHfttdfmkUceydvf/vZ87nOfy3XXXZef/MmfzB//8R/nB37gB85831ve8pbcfvvtSZrtEd72trflJS95Sf7zf/7P+ehHP5obbrghL3nJS/La1742X/3qV7c91mG4qqZ9J1aSx0/axgAAgK2t3+v45MrZLbHueGzbL/me97wn3/AN35CPf/zjeetb3zrwe2699dZ80zd9U+677778h//wH7Z8zec973m5995788pXvjLveMc7cuedd+bee+/NwYMH84u/+IvbHuswTL+kPcv17P8p50rT9XJtTd38JtsdAACwc2211/FN+3oz++uf/tN/miT57//9v+fBBx/My1/+8iTJqVOncsMNN0z13Io62rP+LktW/4951/Hm8ZYDnQ0LAICeOrPX8YCplmt7HS/uGesUCwsLWVk5O4PsxIkT2/q+Zz3rWUmSWmu++7u/Ox/4wAfGGtco+lHWcuHb6i6LqZgAAGzUwl7HV155Ze69994kyb333psvfOELSZJnP/vZ+cpXvnLm+/7e3/t7efDBB3Py5MkcP348H/vYxwa+3vXXX58//dM/zcMPP5wk+drXvpa//Mu/HHuc5zORoq6U8t5SyhOllPvXHfuZUsrRUsp9qx/fP4lzMaPO3GUZYO0uC0yYbAL6Sj7BkFrY6/jmm2/OsWPH8s3f/M355V/+5bzgBS9I0qyRe/nLX55rr702P/mTP5nLL788t9xyS6699trccsst+dZv/daBr7d3797cfvvtef3rX58Xv/jFueGGG/IXf/EXY4/zfCY1/fL2JL+c5P/ZcPxdtdaff+a3s+O0cJcFBrg9sgnop9sjn2A4a3saD+rLMIZHHnnkzOcf/ehHB37P+9///nO+fuc735l3vvOd532tJPnO7/zOfOpTnxprfKOYSFFXa/1EKeXKSbwWF6i1uywbp2BO8C4LbCSbgL6STzACex1vadq/jbeUUj69OsXguVM+F3138/6zb5/vmTtb0I15lwW2QTYBfSWfYDP2Ot7UNH8jv5rkm5Jcl+TRJL8w6JtKKYdKKXeXUu5+8sknpzgcOrd2l+XWFyZvu6p5vOWA7Qxo21DZlMgnoHWunYBtmVpRV2t9vNa6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\n", | |
"text/plain": [ | |
"<Figure size 1080x720 with 6 Axes>" | |
] | |
}, | |
"metadata": { | |
"tags": [], | |
"needs_background": "light" | |
} | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "9JaFXTes9i8M" | |
}, | |
"source": [ | |
"## Creating a pytorch dataloader" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "P0eRpxAs9i8M" | |
}, | |
"source": [ | |
"from torch.utils.data import Dataset\n", | |
"\n", | |
"\n", | |
"class NPYFakeDataset(Dataset):\n", | |
" def __init__(self):\n", | |
" self.ego_dataset = data\n", | |
"\n", | |
" def get_input_output_seqs(self, ego_data):\n", | |
" # 6 input timesteps, (cyan-colored in the plot above), \n", | |
" # which are identical across all 6 examples.\n", | |
" ego_in = ego_data[:6] \n", | |
"\n", | |
" # 12 output (to be predicted by the model) timesteps,\n", | |
" # (pink in the plot above)\n", | |
" ego_out = ego_data[6:]\n", | |
" \n", | |
" return ego_in, ego_out\n", | |
"\n", | |
" def __getitem__(self, idx: int):\n", | |
" ego_data = self.ego_dataset[idx]\n", | |
" in_ego, out_ego = self.get_input_output_seqs(ego_data)\n", | |
" return in_ego, out_ego\n", | |
"\n", | |
" def __len__(self):\n", | |
" return len(self.ego_dataset)\n" | |
], | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "7sg9ohVJ9i8N" | |
}, | |
"source": [ | |
"## Model Code" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "9On9HNKh9i8N" | |
}, | |
"source": [ | |
"import math\n", | |
"import numpy as np\n", | |
"import torch\n", | |
"import torch.nn as nn\n", | |
"import torch.nn.functional as F\n", | |
"\n", | |
"\n", | |
"def init(module, weight_init, bias_init, gain=1):\n", | |
" weight_init(module.weight.data, gain=gain)\n", | |
" bias_init(module.bias.data)\n", | |
" return module\n", | |
"\n", | |
"\n", | |
"class PositionalEncoding(nn.Module):\n", | |
" '''\n", | |
" Sine/cosine positional encoding (standard procedure for transformer sequential inputs)\n", | |
" '''\n", | |
"\n", | |
" def __init__(self, d_model, dropout=0.1, max_len=20):\n", | |
" super(PositionalEncoding, self).__init__()\n", | |
" self.dropout = nn.Dropout(p=dropout)\n", | |
" pe = torch.zeros(max_len, d_model)\n", | |
" position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)\n", | |
" div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))\n", | |
" pe[:, 0::2] = torch.sin(position * div_term)\n", | |
" pe[:, 1::2] = torch.cos(position * div_term)\n", | |
" pe = pe.unsqueeze(0).transpose(0, 1)\n", | |
" self.register_buffer('pe', pe)\n", | |
"\n", | |
" def forward(self, x):\n", | |
" '''\n", | |
" :param x: must be (T, B, H)\n", | |
" :return:\n", | |
" '''\n", | |
" x = x + self.pe[:x.size(0), :]\n", | |
" return self.dropout(x)\n", | |
"\n", | |
"\n", | |
"class AutoBot(nn.Module):\n", | |
" '''\n", | |
" Nested Set Transformer model specialized for car environment with opponents.\n", | |
" '''\n", | |
" def __init__(self, hidden_size=64, num_modes=3):\n", | |
" super(AutoBot, self).__init__()\n", | |
"\n", | |
" init_ = lambda m: init(m, nn.init.orthogonal_, lambda x: nn.init.constant_(x, 0), np.sqrt(2))\n", | |
"\n", | |
" self.hidden_size = hidden_size\n", | |
" self.num_modes = num_modes\n", | |
" self.num_heads = 8\n", | |
"\n", | |
" self.output_model = OutputModelBVG(hidden_size=hidden_size)\n", | |
"\n", | |
" tx_encoder_layer = nn.TransformerEncoderLayer(d_model=hidden_size, nhead=self.num_heads)\n", | |
" self.tx_encoder = nn.TransformerEncoder(tx_encoder_layer, num_layers=2)\n", | |
"\n", | |
" self.emb_pos = init_(nn.Linear(2, hidden_size))\n", | |
" \n", | |
" tx_decoder_layer = nn.TransformerDecoderLayer(d_model=hidden_size, nhead=self.num_heads)\n", | |
" self.tx_decoder = nn.TransformerDecoder(tx_decoder_layer, num_layers=2)\n", | |
"\n", | |
" self.pos_encoder = PositionalEncoding(hidden_size, dropout=0.0)\n", | |
"\n", | |
" self.emb_intention = nn.Sequential(\n", | |
" init_(nn.Linear(num_modes, hidden_size))\n", | |
" )\n", | |
" self.emb_posint = nn.Sequential(\n", | |
" init_(nn.Linear(2*hidden_size, hidden_size)), nn.ReLU(),\n", | |
" init_(nn.Linear(hidden_size, hidden_size))\n", | |
" )\n", | |
"\n", | |
" self.mode_parameters = nn.Parameter(torch.Tensor(1, num_modes, hidden_size))\n", | |
" nn.init.xavier_uniform_(self.mode_parameters)\n", | |
" self.prob_decoder = nn.TransformerDecoderLayer(d_model=hidden_size, nhead=8)\n", | |
" self.prob_predictor = init_(nn.Linear(hidden_size, 1))\n", | |
"\n", | |
" self.train()\n", | |
"\n", | |
" def generate_decoder_mask(self, seq_len, device):\n", | |
" ''' For masking out the subsequent info. '''\n", | |
" subsequent_mask = (torch.triu(torch.ones((seq_len, seq_len), device=device), diagonal=1)).bool()\n", | |
" return subsequent_mask\n", | |
"\n", | |
" def forward(self, ego_input_positions, ego_output_positions):\n", | |
" B = ego_input_positions.size(0)\n", | |
" horizon = ego_output_positions.size(1)\n", | |
" \n", | |
" # Encode all observations\n", | |
" encoded_obs = self.emb_pos(ego_input_positions).transpose(0, 1)\n", | |
"\n", | |
" # Add positional encoding\n", | |
" encoded_obs = self.pos_encoder(encoded_obs)\n", | |
"\n", | |
" # TX on input seqs\n", | |
" in_memory = self.tx_encoder(encoded_obs)\n", | |
" mode_probs = self.prob_decoder(self.mode_parameters.repeat(B, 1, 1).transpose(0, 1), in_memory).transpose(0,1)\n", | |
" mode_probs = F.softmax(self.prob_predictor(mode_probs).squeeze(-1), dim=1)\n", | |
"\n", | |
" intentions = torch.eye(self.num_modes).to(device=ego_input_positions.device).unsqueeze(0).repeat(B, 1, 1)\n", | |
" enc_intentions = self.emb_intention(intentions).view(B*self.num_modes, self.hidden_size).unsqueeze(0)\n", | |
" in_memory = in_memory.unsqueeze(2).repeat(1, 1, self.num_modes, 1).view(-1, B * self.num_modes, self.hidden_size)\n", | |
"\n", | |
" pred_obs = [ego_input_positions[:, -1].unsqueeze(1).repeat(1, self.num_modes, 1).view(B * self.num_modes, -1)]\n", | |
" dec_start_emb = self.emb_pos(torch.stack(pred_obs, dim=0))\n", | |
" dec_input_emb = dec_start_emb\n", | |
" for ts in range(horizon): # autoregressive rollout\n", | |
" T = len(dec_input_emb)\n", | |
" curr_intentions = enc_intentions.repeat(T, 1, 1)\n", | |
" out_emb = torch.cat((curr_intentions, dec_input_emb), dim=-1)\n", | |
" out_emb = self.emb_posint(out_emb)\n", | |
"\n", | |
" out_emb = self.pos_encoder(out_emb)\n", | |
" time_masks = self.generate_decoder_mask(seq_len=T, device=ego_input_positions.device)\n", | |
" out_seq = self.tx_decoder(out_emb, in_memory, tgt_mask=time_masks)\n", | |
" dec_input_emb = torch.cat((dec_start_emb, out_seq), dim=0)\n", | |
"\n", | |
" out_dists = self.output_model(out_seq).view(horizon, B, self.num_modes, -1).permute(2, 0, 1, 3)\n", | |
" return out_dists, mode_probs\n", | |
"\n", | |
"\n", | |
"class OutputModelBVG(nn.Module):\n", | |
" def __init__(self, hidden_size=64):\n", | |
" super(OutputModelBVG, self).__init__()\n", | |
" self.hidden_size = hidden_size\n", | |
" init_ = lambda m: init(m, nn.init.orthogonal_, lambda x: nn.init.constant_(x, 0), np.sqrt(2))\n", | |
" self.observation_model = nn.Sequential(\n", | |
" init_(nn.Linear(hidden_size, hidden_size)), nn.ReLU(),\n", | |
" init_(nn.Linear(hidden_size, hidden_size)), nn.ReLU(),\n", | |
" init_(nn.Linear(hidden_size, 5))\n", | |
" )\n", | |
" self.min_stdev = 0.1\n", | |
"\n", | |
" def forward(self, agent_latent_state):\n", | |
" '''\n", | |
" :param agent_latent_state: the social state of the ego-agent (B, H).\n", | |
" :return: reward for current latent state\n", | |
" '''\n", | |
" pred_obs = self.observation_model(agent_latent_state)\n", | |
" x_mean = pred_obs[:, :, 0]\n", | |
" y_mean = pred_obs[:, :, 1]\n", | |
" x_sigma = F.softplus(pred_obs[:, :, 2]) + self.min_stdev\n", | |
" y_sigma = F.softplus(pred_obs[:, :, 3]) + self.min_stdev\n", | |
" rho = torch.tanh(pred_obs[:, :, 4]) * 0.9 # for stability\n", | |
" return torch.stack([x_mean, y_mean, x_sigma, y_sigma, rho], dim=2)\n", | |
"\n" | |
], | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "hvQG71Au9i8Q" | |
}, | |
"source": [ | |
"## Utility Functions\n", | |
"We define some utility functions for plotting circles for the output distributions (mean and variance at each timestep) and for calculating the multimodal loss.\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "Iwz5gzTE9i8S" | |
}, | |
"source": [ | |
"import numpy as np\n", | |
"import torch\n", | |
"from scipy import special\n", | |
"import torch.distributions as D\n", | |
"from torch.distributions import MultivariateNormal\n", | |
"from matplotlib.patches import Ellipse\n", | |
"\n", | |
"\n", | |
"def _plot_gaussian(dist, ax, color, zorder=0):\n", | |
" \"\"\"Plots the mean and 2-std ellipse of a given Gaussian\"\"\"\n", | |
" cov_val = dist[4] * dist[2] * dist[3]\n", | |
" mean = [dist[0], dist[1]]\n", | |
" covariance = np.array([[dist[2] ** 2, cov_val], [cov_val, dist[3] ** 2]])\n", | |
"\n", | |
" if covariance.ndim == 1:\n", | |
" covariance = np.diag(covariance)\n", | |
"\n", | |
" radius = np.sqrt(5.991) # for 95% confidence interval.\n", | |
" eigvals, eigvecs = np.linalg.eig(covariance)\n", | |
" axis = np.sqrt(eigvals) * radius\n", | |
" slope = eigvecs[1][0] / eigvecs[1][1]\n", | |
" angle = 180.0 * np.arctan(slope) / np.pi\n", | |
"\n", | |
" e = Ellipse(mean, 2 * axis[0], 2 * axis[1], angle=angle, fill=False, color=color, linewidth=1, zorder=zorder, alpha=1.0)\n", | |
" ax.add_artist(e)\n", | |
" e.set_clip_box(ax.bbox)\n", | |
" return ax\n", | |
"\n", | |
"\n", | |
"def get_BVG_distributions(pred):\n", | |
" '''\n", | |
" Transform the prediction tensor of dim (B, T, 5) to torch Multivariate Gaussians distributions.\n", | |
" '''\n", | |
" B = pred.size(0)\n", | |
" T = pred.size(1)\n", | |
" mu_x = pred[:, :, 0].unsqueeze(2)\n", | |
" mu_y = pred[:, :, 1].unsqueeze(2)\n", | |
" sigma_x = pred[:, :, 2]\n", | |
" sigma_y = pred[:, :, 3]\n", | |
" rho = pred[:, :, 4]\n", | |
"\n", | |
" cov = torch.zeros((B, T, 2, 2)).to(pred.device)\n", | |
" cov[:, :, 0, 0] = sigma_x ** 2\n", | |
" cov[:, :, 1, 1] = sigma_y ** 2\n", | |
" cov_val = rho * sigma_x * sigma_y\n", | |
" cov[:, :, 0, 1] = cov_val\n", | |
" cov[:, :, 1, 0] = cov_val\n", | |
"\n", | |
" biv_gauss_dist = MultivariateNormal(loc=torch.cat((mu_x, mu_y), dim=-1), covariance_matrix=cov)\n", | |
" return biv_gauss_dist\n", | |
"\n", | |
"\n", | |
"def nll_pytorch_dist(pred, data):\n", | |
" '''\n", | |
" Args:\n", | |
" pred: [B, T, 5]\n", | |
" data: [B, T, 2]\n", | |
" This function computes the negative log-likelihood of the data given the predicted distributions.\n", | |
" Returns the nll vector for all elements in the batch.\n", | |
" '''\n", | |
" biv_gauss_dist = get_BVG_distributions(pred)\n", | |
" loss = -biv_gauss_dist.log_prob(data).sum(1) # sum over all timesteps\n", | |
" return loss # [B]\n", | |
"\n", | |
"\n", | |
"def nll_loss_multimodes(pred, data, modes_pred, entropy_weight=1.0, val_nll=False, kl_weight=1.0):\n", | |
" \"\"\"NLL loss multimodes for training. MFP Loss function\n", | |
" Args:\n", | |
" pred: [K, T, B, 5]\n", | |
" data: [B, T, 2]\n", | |
" modes_pred: [B, K], prior prob over modes\n", | |
" \"\"\"\n", | |
" K = len(pred)\n", | |
" T, B, dim = pred[0].shape\n", | |
"\n", | |
" # Here, we compute the log-likelihood of the data given the predicted distributions, p(y|z,x). \n", | |
" # This part is used in combination with the predicted prior distribution p(z|x) to compute the posterior p(z|y,x).\n", | |
" log_lik = np.zeros((B, K))\n", | |
" with torch.no_grad():\n", | |
" for kk in range(K):\n", | |
" nll = nll_pytorch_dist(pred[kk].transpose(0, 1), data)\n", | |
" log_lik[:, kk] = -nll.cpu().numpy()\n", | |
"\n", | |
" # The following is an application of Bayes Rule.\n", | |
" priors = modes_pred.detach().cpu().numpy()\n", | |
" log_post_unnorm = log_lik + np.log(priors)\n", | |
" log_post = log_post_unnorm - special.logsumexp(log_post_unnorm, axis=1).reshape((B, 1))\n", | |
" post_prob = np.exp(log_post)\n", | |
" post_prob = torch.tensor(post_prob).float().to(data.device)\n", | |
"\n", | |
" # Using the computed posterior, we now can compute the data negative loglikelihood exactly.\n", | |
" loss = 0.0\n", | |
" for kk in range(K):\n", | |
" nll_k = nll_pytorch_dist(pred[kk].transpose(0, 1), data) * post_prob[:, kk]\n", | |
" loss += nll_k.sum() / float(B)\n", | |
"\n", | |
" # Compute the KL divergence between p(z|x) and p(z|x,y).\n", | |
" kl_loss = torch.nn.KLDivLoss(reduction='batchmean')\n", | |
" loss += kl_weight*kl_loss(torch.log(modes_pred), post_prob)\n", | |
"\n", | |
" # The entropy regularization term.\n", | |
" if not val_nll:\n", | |
" entropy_vals = []\n", | |
" for kk in range(K):\n", | |
" entropy_vals.append(get_BVG_distributions(pred[kk]).entropy())\n", | |
" entropy_loss = torch.mean(torch.stack(entropy_vals).permute(2, 0, 1).sum(2).max(1)[0])\n", | |
" loss += entropy_weight*entropy_loss\n", | |
"\n", | |
" return loss\n" | |
], | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "aXJMdKqU9i8U" | |
}, | |
"source": [ | |
"## Training Loop\n", | |
"The training loop takes about 10 minutes on a single-GPU machine." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "6mxWEJKd9i8V", | |
"outputId": "700362c2-e517-4d47-e169-6c7700cf8aed" | |
}, | |
"source": [ | |
"import torch\n", | |
"from torch import optim\n", | |
"import torch.distributions as D\n", | |
"\n", | |
"\n", | |
"num_modes = 10\n", | |
"hidden_size = 64\n", | |
"learning_rate = 0.000075\n", | |
"entropy_weight = 10.0 # turn this up/down to see the effect on the variance.\n", | |
"seed = 0\n", | |
"np.random.seed(seed)\n", | |
"\n", | |
"if torch.cuda.is_available():\n", | |
" device = torch.device(\"cuda\")\n", | |
" torch.cuda.manual_seed(seed)\n", | |
"else:\n", | |
" device = torch.device(\"cpu\")\n", | |
"\n", | |
"# Initialize model\n", | |
"autobot_model = AutoBot(hidden_size=hidden_size, num_modes=num_modes).to(device)\n", | |
"optimiser = optim.Adam(autobot_model.parameters(), lr=learning_rate, eps=1e-4)\n", | |
"\n", | |
"# Initialize dataloader\n", | |
"train_nuscenes = NPYFakeDataset()\n", | |
"train_loader = torch.utils.data.DataLoader(train_nuscenes, batch_size=6, shuffle=True, num_workers=3, drop_last=True, pin_memory=True)\n", | |
"\n", | |
"total_steps = 0\n", | |
"losses = []\n", | |
"for train_iter in range(0, 3000):\n", | |
" for i, data in enumerate(train_loader):\n", | |
" ego_in, ego_out = data\n", | |
" ego_in = ego_in.float().to(device)\n", | |
" ego_out = ego_out.float().to(device)\n", | |
"\n", | |
" # encode observations\n", | |
" pred_obs, modes_pred = autobot_model(ego_in, ego_out)\n", | |
"\n", | |
" # Compute the loss.\n", | |
" loss = nll_loss_multimodes(pred_obs, ego_out[:, :, :2], modes_pred, entropy_weight=entropy_weight)\n", | |
"\n", | |
" # A measure of the entropy of the output distributions.\n", | |
" sigmas = pred_obs[:, :, :, 2:4]\n", | |
" sigma_magnitude = torch.mean(torch.norm(sigmas, dim=-1))\n", | |
"\n", | |
" optimiser.zero_grad()\n", | |
" loss.backward()\n", | |
" torch.nn.utils.clip_grad_norm_(autobot_model.parameters(), 0.5)\n", | |
" optimiser.step()\n", | |
"\n", | |
" # Store (0) observation loss (1) reward loss (2) KL loss\n", | |
" losses.append(loss.item())\n", | |
"\n", | |
" if train_iter % 50 == 0:\n", | |
" print(train_iter, \"Obs_Loss\", losses[-1], \"Prior Entropy\", torch.mean(D.Categorical(modes_pred).entropy()).item(), \"Sigma Magnitude\", sigma_magnitude.item())\n" | |
], | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"text": [ | |
"0 Obs_Loss 11723.958984375 Prior Entropy 1.857177734375 Sigma Magnitude 1.3646622896194458\n", | |
"50 Obs_Loss 306.9662170410156 Prior Entropy 2.06771183013916 Sigma Magnitude 0.9929002523422241\n", | |
"100 Obs_Loss 234.70278930664062 Prior Entropy 2.0464229583740234 Sigma Magnitude 0.8464294075965881\n", | |
"150 Obs_Loss 219.2841339111328 Prior Entropy 1.9615720510482788 Sigma Magnitude 0.7770584225654602\n", | |
"200 Obs_Loss 198.8031463623047 Prior Entropy 2.008603811264038 Sigma Magnitude 0.673245906829834\n", | |
"250 Obs_Loss 138.7711639404297 Prior Entropy 2.072270393371582 Sigma Magnitude 0.6537865400314331\n", | |
"300 Obs_Loss 123.04424285888672 Prior Entropy 2.0243639945983887 Sigma Magnitude 0.6342011094093323\n", | |
"350 Obs_Loss 96.79385375976562 Prior Entropy 2.082216501235962 Sigma Magnitude 0.6264477968215942\n", | |
"400 Obs_Loss 81.11720275878906 Prior Entropy 2.120720863342285 Sigma Magnitude 0.619354784488678\n", | |
"450 Obs_Loss 67.96978759765625 Prior Entropy 2.129866123199463 Sigma Magnitude 0.5915012359619141\n", | |
"500 Obs_Loss 98.8485336303711 Prior Entropy 2.142521858215332 Sigma Magnitude 0.5233737826347351\n", | |
"550 Obs_Loss 142.97808837890625 Prior Entropy 2.0970046520233154 Sigma Magnitude 0.6683558225631714\n", | |
"600 Obs_Loss 68.43778228759766 Prior Entropy 2.091160297393799 Sigma Magnitude 0.6223364472389221\n", | |
"650 Obs_Loss 29.45511245727539 Prior Entropy 2.0658717155456543 Sigma Magnitude 0.5888274908065796\n", | |
"700 Obs_Loss 17.957138061523438 Prior Entropy 2.093405246734619 Sigma Magnitude 0.6362965106964111\n", | |
"750 Obs_Loss 31.798233032226562 Prior Entropy 2.0856008529663086 Sigma Magnitude 0.5461905002593994\n", | |
"800 Obs_Loss 10.051948547363281 Prior Entropy 2.090461254119873 Sigma Magnitude 0.6038259267807007\n", | |
"850 Obs_Loss 59.378623962402344 Prior Entropy 2.0865261554718018 Sigma Magnitude 0.5151104927062988\n", | |
"900 Obs_Loss -6.811798095703125 Prior Entropy 2.1136908531188965 Sigma Magnitude 0.5225884914398193\n", | |
"950 Obs_Loss -10.759872436523438 Prior Entropy 2.118497371673584 Sigma Magnitude 0.6135889291763306\n", | |
"1000 Obs_Loss -33.444671630859375 Prior Entropy 2.0734384059906006 Sigma Magnitude 0.5419284105300903\n", | |
"1050 Obs_Loss -35.84764862060547 Prior Entropy 2.1095805168151855 Sigma Magnitude 0.5613827109336853\n", | |
"1100 Obs_Loss -29.234100341796875 Prior Entropy 2.1014890670776367 Sigma Magnitude 0.5027151703834534\n", | |
"1150 Obs_Loss -34.968345642089844 Prior Entropy 2.1073012351989746 Sigma Magnitude 0.5491200685501099\n", | |
"1200 Obs_Loss -39.077980041503906 Prior Entropy 2.100574016571045 Sigma Magnitude 0.4987635016441345\n", | |
"1250 Obs_Loss -48.33007049560547 Prior Entropy 2.1208224296569824 Sigma Magnitude 0.510762631893158\n", | |
"1300 Obs_Loss -58.208953857421875 Prior Entropy 2.0919651985168457 Sigma Magnitude 0.4930139482021332\n", | |
"1350 Obs_Loss -87.03924560546875 Prior Entropy 2.118295669555664 Sigma Magnitude 0.4436866343021393\n", | |
"1400 Obs_Loss -47.048927307128906 Prior Entropy 2.097531795501709 Sigma Magnitude 0.44906753301620483\n", | |
"1450 Obs_Loss -72.15503692626953 Prior Entropy 2.092167854309082 Sigma Magnitude 0.4120866358280182\n", | |
"1500 Obs_Loss -80.47696685791016 Prior Entropy 2.103466749191284 Sigma Magnitude 0.4134567379951477\n", | |
"1550 Obs_Loss -94.25555419921875 Prior Entropy 2.080009698867798 Sigma Magnitude 0.36127781867980957\n", | |
"1600 Obs_Loss -88.59275817871094 Prior Entropy 2.0875422954559326 Sigma Magnitude 0.3591216206550598\n", | |
"1650 Obs_Loss -124.26649475097656 Prior Entropy 2.093277931213379 Sigma Magnitude 0.34293627738952637\n", | |
"1700 Obs_Loss -108.07246398925781 Prior Entropy 2.0913078784942627 Sigma Magnitude 0.29710695147514343\n", | |
"1750 Obs_Loss -133.356689453125 Prior Entropy 2.0764667987823486 Sigma Magnitude 0.2864120900630951\n", | |
"1800 Obs_Loss -150.91000366210938 Prior Entropy 2.1066884994506836 Sigma Magnitude 0.27043548226356506\n", | |
"1850 Obs_Loss -144.8616943359375 Prior Entropy 2.0808260440826416 Sigma Magnitude 0.2537614107131958\n", | |
"1900 Obs_Loss -142.93882751464844 Prior Entropy 2.0847625732421875 Sigma Magnitude 0.2622417211532593\n", | |
"1950 Obs_Loss -174.2861328125 Prior Entropy 2.078876495361328 Sigma Magnitude 0.23730503022670746\n", | |
"2000 Obs_Loss -148.6193389892578 Prior Entropy 2.062580108642578 Sigma Magnitude 0.24768507480621338\n", | |
"2050 Obs_Loss -131.22848510742188 Prior Entropy 2.0892975330352783 Sigma Magnitude 0.21530592441558838\n", | |
"2100 Obs_Loss -183.94528198242188 Prior Entropy 2.0834622383117676 Sigma Magnitude 0.2223784178495407\n", | |
"2150 Obs_Loss -139.89260864257812 Prior Entropy 2.076235055923462 Sigma Magnitude 0.19737689197063446\n", | |
"2200 Obs_Loss -177.97433471679688 Prior Entropy 2.0840203762054443 Sigma Magnitude 0.20732863247394562\n", | |
"2250 Obs_Loss -194.98463439941406 Prior Entropy 2.1062493324279785 Sigma Magnitude 0.20598143339157104\n", | |
"2300 Obs_Loss -177.98443603515625 Prior Entropy 2.083662748336792 Sigma Magnitude 0.19716553390026093\n", | |
"2350 Obs_Loss -183.91876220703125 Prior Entropy 2.076279640197754 Sigma Magnitude 0.19121479988098145\n", | |
"2400 Obs_Loss -201.8154296875 Prior Entropy 2.092423677444458 Sigma Magnitude 0.19742748141288757\n", | |
"2450 Obs_Loss -189.528076171875 Prior Entropy 2.092670440673828 Sigma Magnitude 0.1925940066576004\n", | |
"2500 Obs_Loss -194.66998291015625 Prior Entropy 2.0779054164886475 Sigma Magnitude 0.17988410592079163\n", | |
"2550 Obs_Loss -200.75863647460938 Prior Entropy 2.0983500480651855 Sigma Magnitude 0.18578983843326569\n", | |
"2600 Obs_Loss -199.38670349121094 Prior Entropy 2.093242645263672 Sigma Magnitude 0.18134918808937073\n", | |
"2650 Obs_Loss -192.5203857421875 Prior Entropy 2.089531421661377 Sigma Magnitude 0.18082661926746368\n", | |
"2700 Obs_Loss -187.53192138671875 Prior Entropy 2.0818114280700684 Sigma Magnitude 0.17122453451156616\n", | |
"2750 Obs_Loss -207.5955352783203 Prior Entropy 2.062140941619873 Sigma Magnitude 0.17080239951610565\n", | |
"2800 Obs_Loss -189.11380004882812 Prior Entropy 2.0947937965393066 Sigma Magnitude 0.17124949395656586\n", | |
"2850 Obs_Loss -198.44921875 Prior Entropy 2.0777957439422607 Sigma Magnitude 0.16536590456962585\n", | |
"2900 Obs_Loss -217.40306091308594 Prior Entropy 2.0797410011291504 Sigma Magnitude 0.16628232598304749\n", | |
"2950 Obs_Loss -228.67001342773438 Prior Entropy 2.0792946815490723 Sigma Magnitude 0.1648883819580078\n" | |
], | |
"name": "stdout" | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "Tw0HaOtk9i8W" | |
}, | |
"source": [ | |
"## Testing Mode Learning on Toy Dataset\n", | |
"\n", | |
"This consistutes the results shown in Figure 5 (bottom row) of the paper. To get the results corresponding to the middle row, reduce the `entropy_weight` in the training block above and repeat training.\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 596 | |
}, | |
"id": "9o6cRo6y9i8W", | |
"outputId": "021a3675-9863-4103-b5a8-e41e0534b706" | |
}, | |
"source": [ | |
"autobot_model.eval()\n", | |
"with torch.no_grad():\n", | |
" for i, data in enumerate(train_loader):\n", | |
" ego_in, ego_out = data\n", | |
" ego_in = ego_in.float().to(device)\n", | |
" ego_out = ego_out.float().to(device)\n", | |
"\n", | |
" pred_obs, mode_preds = autobot_model(ego_in, ego_out)\n", | |
" pred_positions = pred_obs[:, :, 0, :2].squeeze().cpu().numpy()\n", | |
" mode_probs_np = mode_preds[0].squeeze().cpu().numpy()\n", | |
" pred_distributions = pred_obs[:, :, 0].squeeze().cpu().numpy()\n", | |
"\n", | |
" top_6_modes = mode_probs_np.argsort()[-6:][::-1]\n", | |
" fig, ax = plt.subplots(nrows=2, ncols=5, figsize=(15, 10))\n", | |
" row = 0\n", | |
" for k_idx in range(num_modes):\n", | |
" col = k_idx % 5\n", | |
" if k_idx > 0 and k_idx % 5 == 0:\n", | |
" row += 1\n", | |
" k = k_idx\n", | |
" ax[row, col].scatter(pred_positions[k, :, 0], pred_positions[k, :, 1], s=10, color='k')\n", | |
"\n", | |
" for t in range(12):\n", | |
" ax[row, col] = _plot_gaussian(pred_distributions[k, t], ax[row, col], color='#966BFF')\n", | |
" ax[row, col].axis(xmin=-15, xmax=15, ymin=-15, ymax=20)\n", | |
"\n", | |
" plt.show()\n" | |
], | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/png": "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\n", | |
"text/plain": [ | |
"<Figure size 1080x720 with 10 Axes>" | |
] | |
}, | |
"metadata": { | |
"tags": [], | |
"needs_background": "light" | |
} | |
} | |
] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment