mirror of
https://github.com/ROCm/jax.git
synced 2025-04-14 19:06:07 +00:00
1099 lines
107 KiB
Plaintext
1099 lines
107 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "LQHmwePqryRU"
|
||
},
|
||
"source": [
|
||
"# How to think in JAX\n",
|
||
"\n",
|
||
"<!--* freshness: { reviewed: '2024-04-08' } *-->\n",
|
||
"\n",
|
||
"[](https://colab.research.google.com/github/jax-ml/jax/blob/main/docs/notebooks/thinking_in_jax.ipynb) [](https://kaggle.com/kernels/welcome?src=https://github.com/jax-ml/jax/blob/main/docs/notebooks/thinking_in_jax.ipynb)\n",
|
||
"\n",
|
||
"JAX provides a simple and powerful API for writing accelerated numerical code, but working effectively in JAX sometimes requires extra consideration. This document is meant to help build a ground-up understanding of how JAX operates, so that you can use it more effectively."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "nayIExVUtsVD"
|
||
},
|
||
"source": [
|
||
"## JAX vs. NumPy\n",
|
||
"\n",
|
||
"**Key concepts:**\n",
|
||
"\n",
|
||
"- JAX provides a NumPy-inspired interface for convenience.\n",
|
||
"- Through duck-typing, JAX arrays can often be used as drop-in replacements of NumPy arrays.\n",
|
||
"- Unlike NumPy arrays, JAX arrays are always immutable.\n",
|
||
"\n",
|
||
"NumPy provides a well-known, powerful API for working with numerical data. For convenience, JAX provides `jax.numpy` which closely mirrors the numpy API and provides easy entry into JAX. Almost anything that can be done with `numpy` can be done with `jax.numpy`:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {
|
||
"id": "kZaOXL7-uvUP",
|
||
"outputId": "7fd4dd8e-4194-4983-ac6b-28059f8feb90"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"image/png": "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\n",
|
||
"text/plain": [
|
||
"<Figure size 640x480 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"x_np = np.linspace(0, 10, 1000)\n",
|
||
"y_np = 2 * np.sin(x_np) * np.cos(x_np)\n",
|
||
"plt.plot(x_np, y_np);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {
|
||
"id": "18XbGpRLuZlr",
|
||
"outputId": "3d073b3c-913f-410b-ee33-b3a0eb878436"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAAGdCAYAAAAfTAk2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABz9UlEQVR4nO3deXyU1b0/8M/sS5bJnknIxiZhB0FSkFZ7zSWotdJaK71YKrX4u1TaKr5cuFex1SrVtrZXy0/qrr9qtb23WrW9KEXRqggIRgEhbNkgmezJJDOZ9Xl+f8ycZyaQPfPMs33fr9e8WibPzJyJT875nnO+5xwdz/M8CCGEEEJURC91AQghhBBCEo0CHEIIIYSoDgU4hBBCCFEdCnAIIYQQojoU4BBCCCFEdSjAIYQQQojqUIBDCCGEENWhAIcQQgghqmOUugBS4DgOTU1NSEtLg06nk7o4hBBCCBkFnufR29uLwsJC6PXDj9FoMsBpampCcXGx1MUghBBCyDg0NjaiqKho2Gs0GeCkpaUBiPyC0tPTJS4NIYQQQkbD7XajuLhYaMeHo8kAh01LpaenU4BDCCGEKMxo0ksoyZgQQgghqkMBDiGEEEJUhwIcQgghhKgOBTiEEEIIUR0KcAghhBCiOhTgEEIIIUR1KMAhhBBCiOpQgEMIIYQQ1aEAhxBCCCGqI2qA8/777+Oqq65CYWEhdDodXnvttRFfs3v3blx44YWwWCyYNm0annvuufOu2bZtG8rKymC1WlFRUYF9+/YlvvCEEEIIUSxRAxyPx4P58+dj27Zto7q+trYWV155Jb761a+iuroat9xyC37wgx/grbfeEq555ZVXsGnTJtx77704ePAg5s+fj6qqKrS2tor1NQghhBCiMDqe5/mkfJBOh1dffRWrVq0a8po777wTf/vb33D48GHhudWrV6O7uxs7duwAAFRUVOCiiy7C7373OwAAx3EoLi7Gj370I9x1112jKovb7YbD4UBPTw+dRUUIIYQoxFjab1kdtrlnzx5UVlYOeK6qqgq33HILACAQCODAgQPYvHmz8HO9Xo/Kykrs2bNnyPf1+/3w+/3Cv91ud2ILLjM8z2N/XRc+PNkOnuexqCwLX56WA71+5MPJiHb5gmHsOOzCMVcvMuwmrJiVjym5qVIXi8jc2e5+/O+hZrT1+TE1NxVXzC1AqkVWTQvRKFndhS6XC/n5+QOey8/Ph9vtRn9/P7q6uhAOhwe95tixY0O+79atW/Gzn/1MlDLLTZcngFv/VI3dNW0Dnl9YkoFHVy9EcZZdopIROdt7ugM/ebkaLrdPeO6hHcfw/Ysn467Ly2Ey0HoEMhDH8XjsnZN47J0TCHGxiYCtfz+Kh781H/86K3+YVxMiPk3UWps3b0ZPT4/waGxslLpIouj0BHDN9o+wu6YNZoMeqxYU4luLipBqMeLThm58a/tHqGv3SF1MIjO7a1qx5qm9cLl9KHRY8d0vleKSC3LB88DTH9TiRy99ilCYk7qYREZ4nsd/vnYIv/nHcYQ4HksmZ+F7S0sxOScFXd4gbvp/n+C1T89KXUyicbIawXE6nWhpaRnwXEtLC9LT02Gz2WAwGGAwGAa9xul0Dvm+FosFFotFlDLLBcfx2PCHAzjd5kGhw4pn1y3BDGcaAODWf70A657dh+MtfVj/wid47eaLkUJDyATAydY+bPjDQYQ4HitnO/Gb6xbAZjYAAHYcduHHf/wUO4648Mu3a7D58pkSl5bIxbMf1uGP+xqh1wG/+OY8fPuiYgBAIMThntcO45VPGnH7f3+G0mw7FpZkSlxaolWyGsFZunQpdu3aNeC5nTt3YunSpQAAs9mMRYsWDbiG4zjs2rVLuEarnvmwFntrO2E3G/DCjbHgBgAmZdjwhxsrkJdmwYnWPvzq7RoJS0rkIszxuOWVT9EfDGPplGw8+p2FQnADACvnOPHIdfMBAL9/7zT213VKVVQiI8dbevGLHZGUgHu+NksIbgDAbNRj6zfn4vI5TgTDPG55pRq+YFiqohKNEzXA6evrQ3V1NaqrqwFEloFXV1ejoaEBQGTqaO3atcL1//7v/47Tp0/jjjvuwLFjx/B//+//xZ/+9CfceuutwjWbNm3Ck08+ieeffx5Hjx7Fhg0b4PF4sG7dOjG/iqyd6fLil29Fgpa7r5yFaXlp512Tl27Fr78daaye/6gOh8/2JLWMRH5e3t+Aw2fdcNhM+K/VC2A2nl8dfG1eIa5bHGnA7nntME1VaRzP8/jPVw8hEOLw1Rm5uGFZ2XnX6PU6PPStechPt6C+w4sn3z+d/IISApEDnE8++QQLFy7EwoULAUSCk4ULF2LLli0AgObmZiHYAYDJkyfjb3/7G3bu3In58+fj17/+NZ566ilUVVUJ11x33XX41a9+hS1btmDBggWorq7Gjh07zks81pL/+scJ+EMcvjQlC99ZUjzkdV+enouvzSsAxwP3vflFEktI5KanP4hfv30cAHBr5XTkpVuHvPbOy8uRYTfhmKsXf9yvzvw1Mjq7jrZif10XrCY9tn5zHnS6wVdmpltN+M8rZwEAtu0+ieae/mQWkxAASdwHR07UtA/OydY+rPjNe+B44NUfLhtxvru5px+XPLwbgTCHV276EiqmZCeppEROHtt1Ar/eeRxTc1Ow45avjLhK6vmP6nDv60cwKcOG3bdfSquqNIjjeKz8r/dxvKUPGy6dijtXlg97Pc/zuHb7HnxS34XvXzwZW66alaSSEjUbS/tNtZTCbX/vFDgeqJyZP6pkvgKHDd9aXAQA+N27J8UuHpEhXzCM5z6qAwD8+LLpowpWrruoGLlpFpzt7sertDpGk96tacXxlj6kWY3490umjni9TqfDjy6bDgD4474GdHoCYheRkAEowFGwjj4/Xv+sCQCw4dKRKxxmwyVTYdDr8M8T7TjmUvemh+R8/3PwDDo8AUzKsOGKuQWjeo3VZMD6L08GADzx/mlocOBX8579sA4A8J0lJXDYTKN6zVem52DOpHT0B8P4f3vqRSwdIeejAEfBXt7fiECIw7wiBy4syRj164qz7KiaHclZemlvwwhXEzXheV5oaL6/fPKYppq+s6QENpMBJ1v7sL+uS6wiEhmqcfXig5Pt0OuAtUtLR/06nU6H9V+eAgB4ZX8DwhwFxiR5KMBRKI7jheDke0vLhkz2G8p3lpQAAF49eBbeQCjh5SPy9PmZHhxz9cJi1ONbi4rG9No0qwlfn18IAHh5HwXGWvLy/sh/7xWznCjKHNtu6FWznciwm9DU48P7x9tGfgEhCUIBjkLtre3E2e5+pFmMuHLe6KYZ4l08NQclWXb0+kN48/NmEUpI5OhPn0RWQa2c4xz1NEO871REAuO/HWpGjzeY0LIReQqGObxeHZkK//ZFYwuKgcj05jcXRl73RwqMSRJRgKNQbBv0K+YWwGoyjHD1+fR6Hb4dTTZ+I5rHQ9TNFwwLOVtsb5uxml/kQLkzDf4Qhx1HKDDWgvePt6HDE0BOqhlfmZ47rvdYHd2+4p1jrej2UrIxSQ4KcBTIFwzj74cijcs3Lpw07ve5Kjrd8OHJdrT3+Ue4mijdByfa0esLocBhxZfGuT2ATqcT7hsa+dOGvxyMdKauXjAJxnFuD3BBfhrKnWkIcTzeOuJKZPGIDPmCYVmkPlCAo0DvHW9Drz+EQocVS8qyxv0+pdkpmF/kAMcD/3uYKh21Y/+Nq2Y7odePLWcr3teiU6IUGKufLxjGuzWtAICrFxRO6L0oMNaOHYddWHjfTvzsjSOSloMCHAXa+UXksNGqORNrqIDIVvwA8CZNU6laIMRh5xeRAOfyOUMfTDsapdkpmDuJAmMt+PBkO7yBMAocVsyd5JjQe10Z3ZLgo1Md6KDAWNV2ftECf4iD3Tz29IlEogBHYcIcj3eORXpU/zpr4sdTrIw2dp/Ud9HcuIrtOd0Bty+EnFQzFk9g1I9h++ewYJuoE5tOWjErf8wrNc9VlpOC2YXpCHM8dkXrMKI+/lAYu2tYGzWxztREUYCjMAfqu9DpCcBhM01oeoopzrJjRn4awhyP92gJp2rtOByZFqia7YRhgqN+AFA5Mw8A8PHpDlnMtZPEC3M8/nE00lCtmJ2YhuqymZFO2bsU4KjWnlMd8ATCyEuzYN4ER/0migIchWHTDP9SnjfuhL9zfbU80li9Q5WOKnEcj51fRP7brpzg9BQzLS8VRZk2BEIcPjzZkZD3JPLCOlPpViOWTJ54ZwqI1FsA8M8T7QjSyfSqxEZ1K2flTziFYqIowFEQnueFmycR01PMZdHe+O6aNoSo0lGdoy432vv8sJkMCWuodDqd0FhRYKxOrDN12cz8hB2uOm+SAzmpZvT5Q9hf15mQ9yTywfNxKRQzE9dGjRcFOArS0OlFXYcXJoMOX7lgfPtRDGZhcQYy7Cb09AdxsKE7Ye9L5OGfJ9oBAEunZsNiTFzSHxv5e/dYK51NpULsvrl0RuLqGr1eh0suiN03RF1OtfWhuccHs1E/7q0oEokCHAX54GSkwrmwJBOpFmPC3tdo0OOSaMC06xgljaoN2x7/K9NzEvq+S6dkw2rSw+X24YtmOrRVTdp6/Tjm6gUAXDwtsffNV8sjdQ2N/KkPC4ovKsuETeIVVAAFOIryYTTASXSFA8R6aR9RPoWqeAMhfBI9GDORo35AZAv+i6dG7sUPohUbUQdW18wqSEdOqiWh7/3l6bkw6HU41ebBmS5vQt+bSIvVA8unJbauGS8KcBQizPH46FQk+BAjwFkWbagON/XQGUMq8vHpDgTCHCZl2DA5JyXh7790amQYmt2bRB3YaPGXEzzqBwAOmwnziiKraz4+TXk4ahEMc/j4dKQeEOO+GQ8KcBTiiyY3ur1BpFqMmF+U+KV3+elWTMlNAc8De2upsVKL949HGqqvXJA74X1MBsMCnP11nbQqRiV4no/1xEVqqJZG8zP2UGCsGp82dMMTCCMrxYxZBelSFwcABTiKwXpUX5qSnbDl4edaRr1x1WE9quUijPoBwExnOjLsJngDYXx+pkeUzyDJdaqtDy53JFH0ogTstTUYFhh/fLqDEtRV4oMTkVy/ZVOzJV8ezlCAoxBsTnz5NPEy09k0FWsUibJ1ewOoaYkkiiZqefi59HodvjQ51lgR5WMdnIvKMmE1iZMourg0CyaDDme7+9HY2S/KZ5DkYtONYnWmxoMCHAUIhjl8Uh+5eZZOFe/mYcv6jrl66RBFFfikrgs8D0zJTUFuWmITReMtm0bTDWqyP5qUXjFZvM6UzWzAguIMAMCe05SgrnT+UBjVZ7oBiNeZGg8KcBTgSJMbviAHh82E6Xmpon1OVooZ5c40ANQbV4N90Y3UKkSucFg+xf66TvhDYVE/i4iL53nsr43cN4vLMkX9LMrDUY9DZ3oQCHHISTWLsphhvCjAUYBPog3V4tJM0ec22SgOW1pMlGtvtKESu0c1LS8VOalm+EMcDlEejqKd6eqHy+2DyaDDwmJxAxxW19BKKuXbJ7RRWaIsZhgvCnAUgG1pnohToEeyqDRSqR2opwBHyfr8IRw+Gwk2log41QBEjm1g983BBrpvlIzVNXMmOUTfqG1hSSYMeh1cbh+auikPR8nYqN9FMpqeAijAkT2e54XRlItEHjIGYgHOF81uOiVawQ7WdyHM8SjKtGFShk30z6PAWB32C3WN+A2VzWwQlhPTfaNcYY7HJ9H/fkuScN+MBQU4Mlfb7kGHJwCzUY+5Iux/c67CDBsKHFaEOR6fNdJ0g1Kxac1kVTixAKeblv0qGBvBSUaAA1BgrAY1rl70+kJIMRswsyBN6uIMQAGOzLHRm/lFjoQelDicC4VKh+bGlerTxm4AwMKSjKR83uxCB8wGPdr7/LTsV6E6PQGcbO0DEMn3S4YLaWpT8dgK3wtLM0Xbo2285FUach528yQj/4ZZTL0qReN5Hp9FA5wFIieKMlaTAbMnRacbGigwVqLqxsjf+9TcFGSmmJPymRdGA/AvmtzoD9AKPCWqbugGEDkEWm4owJE5Nk2UzJsnljDaDY6j6QalqW33wO0LwWLUozyJQ8aLovcorcBTJlbXJCsoBoBJGTbkp1sQ4nh8Ht1HhSjLZ9H/bguSNFo8FhTgyJjHH8KJ1shOtGKcPzWUmQXpsJr06OkP4lRbX9I+lyRGdXT0Zs4kB0xJHDKmfAplYw3V/OLk1TXxK/AO0DSV4rh9QZxq8wAA5hdlSFuYQVCAI2OHz/aA4wFnuhV56dakfa7JoMe8SRkAgM9oXxPFqRampzKS+rksn+J4Sy88flqBpyTx05rJbqjY6PTB+u6kfi6ZOLbvVUmWHVlJmtYci6QEONu2bUNZWRmsVisqKiqwb9++Ia+99NJLodPpzntceeWVwjU33HDDeT9fuXJlMr5KUrHDC+clcfSGYSu2DtGwseKwAGd+kgOc/HQr8tMt4PjINgNEORo7+9HlDcJsSO60JhC7Tw+d7U7q55KJY3WNFG3UaIge4LzyyivYtGkT7r33Xhw8eBDz589HVVUVWltbB73+L3/5C5qbm4XH4cOHYTAYcO211w64buXKlQOu++Mf/yj2V0m6amHIOCPpn81u2M/P0giOkviCYRyNBhcLJbhv5kZH/uhkcWVh01MzC9KStlqTmVWQDr0OaHH70er2JfWzycR8JtFo8WiJHuA88sgjWL9+PdatW4dZs2Zh+/btsNvteOaZZwa9PisrC06nU3js3LkTdrv9vADHYrEMuC4zU34Z3BPFku6kmNucOykS4HzR5EYwzCX988n4HGlyIxjmkZ1iRlGm+Bv8nYsFxocpMFaUzyQa9QOAFIsRU3MjZ+wdovtGUT6TsBM+GqIGOIFAAAcOHEBlZWXsA/V6VFZWYs+ePaN6j6effhqrV69GSsrAA7x2796NvLw8zJgxAxs2bEBHx9AHtvn9frjd7gEPueuI208kGRv8nassOwVpFiP8IQ4nWijRWCnie1RSnAnD7lVaEaMsn0nYmQLi7xsKcJTC1eNDi9sPg16H2YXpUhdnUKIGOO3t7QiHw8jPzx/wfH5+Plwu14iv37dvHw4fPowf/OAHA55fuXIlXnjhBezatQsPPfQQ3nvvPVx++eUIhwffR2Hr1q1wOBzCo7i4ePxfKknY1NCUnBQ4bKakf75er8Oc6CgOzY0rh1QJxgwb+Tvd7kGvLyhJGcjYhMKcMHIiVU983iQa+VMaVtdckJ8Gu9kobWGGIOtVVE8//TTmzp2LJUuWDHh+9erV+PrXv465c+di1apVePPNN7F//37s3r170PfZvHkzenp6hEdjY2MSSj8xnzdKl2DMzKNeleKwBkKKUT8AyEm1oNBhBc9HpsuI/J1o7YMvyCHNYsSUnJSRXyCCuXE5f3TUhzII+98kcVuBsRI1wMnJyYHBYEBLS8uA51taWuB0Ood9rcfjwcsvv4wbb7xxxM+ZMmUKcnJycPLkyUF/brFYkJ6ePuAhd+zmmSfh3gLCSirqVSmCxx9CbUdkT4rZhdJVOrEVeHTfKAGb1pxb5IBen/xpTQCYVeCAXge09frR4vZLUgYyNp/LoI0aiagBjtlsxqJFi7Br1y7hOY7jsGvXLixdunTY1/75z3+G3+/H9ddfP+LnnDlzBh0dHSgoKJhwmeWCjZokc9Otc7G9cI42u+EP0Tbqcne02Q2eB/LTLchNs0hWDlbh0Qo8ZWAjbWxKWgo2swEX5EeWp1OHSv54nscX7L6RsDM1EtGnqDZt2oQnn3wSzz//PI4ePYoNGzbA4/Fg3bp1AIC1a9di8+bN573u6aefxqpVq5CdnT3g+b6+Ptx+++34+OOPUVdXh127duHqq6/GtGnTUFVVJfbXSYrWXh/a+/zQ6SK7CkulOMuGDLsJwTCP4y5KNJY71lBJOXoDxPJwaA8lZWB7FkmdKEr3jXI09/jQ5Q3CqNdhen6q1MUZkuiZQddddx3a2tqwZcsWuFwuLFiwADt27BASjxsaGqDXD4yzampq8MEHH+Dtt98+7/0MBgM+//xzPP/88+ju7kZhYSFWrFiB+++/HxaLdL3WRGKR8eScFEmTt3Q6HeZOcuCfJ9rx2ZluyfI6yOgcaYr0fOXSUNV1eNHTH5QkSZ6MTpjjhX2TJL9vihz484EzNPKnAKyNmpaXCqspufsmjUVSWs+NGzdi48aNg/5ssMTgGTNmDJloZrPZ8NZbbyWyeLJztDly/tQsCUdvmDnRAId2ppU/ufTEM6N78Jzp6seRph4sm5ojaXnI0Oo7PPAGwrCa9JicI21PfG7cSiqe5yXZ5oCMDhstlkMbNRxZr6LSKtZQzZLB3gJsiuwoBTiyFgxzwjSi1FNUQKziY8E6kSdW18xwpsMgUYIxU+6M7Gjc3hdAWy8lGsvZF82RUTY5tFHDoQBHhr6ITjXIITqeFT2XpsbVC46j5ZtydaKlD4Ewh3SrUZIdjM9FgbEyfCGjnrjNbEBZdJn6URcFxnImp074cCjAkRlvIITT7ZGlvnK4ecqyU2Ax6uENhFHf6ZW6OGQILP9mVmG6LIb2Z0YD42MuCnDkTC7TmgwFxvLX0x8UdtmXQ2A8HApwZKbG1Quej2yYlpdmlbo4MBr0mOGMNFZU6ciXXFZQMayhOt7ShxCdZSZbQi6FTAKcWRTgyB77bzMpw4YMu1ni0gyPAhyZkePQ30wnVTpy90WTvHrixZl2pJgNCIQ4YUSSyEtrrw9tvZHtKMqjnRipsXIco9wt2fpCZkHxcCjAkRk5zYkzbLqBAhx54nk+bqpBHiM4er0O5dQblzWWAC71dhTx2MjfqbY+2lxUpo7IrDM1HApwZOaoHEdwaEWMrJ3t7kefPwSzQY8pudKcJTSYWGBM940cybEzVeCwwmEzIcTxONlKm4vKkTDLIKP7ZigU4MhImONxzMX2wJHHkDEQWb4JRBrSnn46IVpuaqL3zJTcFJgM8vmTLqepTVmT26gfENlctNxJgbFcBUIcTrZG/rtIucv+aMmnNiRo6PTKZtOteA67CZMyIkuPj1FjJTs1LZEKZ4ZM8igYWhEjbzXRFW5yyb9h6L6Rr7oOD4JhHqkWeWxHMRIKcGSE9cSn56VJvunWuSgPR77YfSO3AKfcmQadDmjt9aOjjzZuk5NAiMPptkjyt9zuGzb1QVsMyA+ray7IT5XFdhQjoQBHRo63sJtHXhUOQHk4ciYEODK7b1IsRpRm2QFAmHol8lDb7kGI45FmMaLAIf12FPHK43K3hjqyh0hDzm3UYCjAkZGallh0LDczqVclS8FwrCcux0qHphvkiTVU02XYE78gPw16HdDpCaCVjmyQldgIjvzqmsFQgCMjJ1iAI7MhYyAWdJ1o7aNelYzUtXsQCHNIMRtkOSfOKkLWoBJ5OC7TvC0AsJoMmBw9sqGGRv5kRc73zWAowJGJ+DlxOUbHpdkpMBl08AbCONvdL3VxSFRNXFAst544EB/g0JJfOZF7T5wCY/nxBWPH9cj1vjkXBTgyUdcRmRNPtRhRKLM5cQAwGfSYEl3ZdYIaK9k4LtP8G4aN/J2kkT9ZkXsuxfS82H1D5CHyNwxkpZiRkyrvIxoYCnBkQlhBJcM5cWZ6tLGiXpV8HJN5T7w0OwVGvQ59/hCae3xSF4dAGT3x6TSCIzuxVb7ybaPORQGOTLD8G7n2xIHI8nWAphvkhDUActvLhDEb9UI+BTVW8qCEnjgLvE600MifXCgt/wagAEc2amQ+ZAzEJxpTQyUH/YG4nriMK534xopITwl7mZTl2GHQ69DrD6HFTSup5EAJbdS5KMCRCVb5y/nmmR7XUHEc9aqkdqK1FzwPZKeYkZNqkbo4Q6KpTXmRe/4NAFiMBpRlR/ZQovtGHo7LdEPR4VCAIwO+YBh1HdEVVE757YHDlGXbYTbo0R+klVRyINcdjM/FpjZPUMKoLCghwAFoJZWcuH1BNEVz6C7Ik/d9E48CHBk41dYHjgcy7Cbkyrgnbow7rZqmqaSnnIaKVlLJCcuhk39gTCup5ILNMDjTrXDYTRKXZvQowJGB+IZKrnPizLQ8Nt1AlY7UahQwrQkAZTmRPZT6/CGhF0ik0esLCqOvcu+J00oq+Yjf+VpJKMCRgeNCQyX/m4eGjeXjVLRnK/dKx2SglVRycVxBPXEhOZ1G/iQn1/PuRkIBjgzIfbO2eMJKKhrBkVR/3I7SU3PlHeAAsTyck3TfSOqEgnriwkoqH62kkhqbJpT7aPG5KMCRgeOtrNKR/83DyniylVZSSelUW6TCyUoxIytFnnuZxKOVVPLA7pvpMp+eAmgllZyw+2ZqnvwD43gU4EjMFwzjTFekJz5NATdPaRatpJIDocKJJn3LnTC1SQmjkjoVPe9uap6y7htagSed+F3IlVLfMBTgSKy23QOeBxw2E7IV0BOPX0lFvSrpsPwbJQTFQNxKqpZeyqeQUCwwVsZ9w1ZSnaC6RjK10aA4J9WMDLv826h4FOBILL4nLvcVVMx0OiFackJPXCENFTuN3kOn0UvGFwyjMbrztVLuG1pJJb2TbZHf/RSF3DPxKMCR2GmFNVQAMC1a1tNtFOBIhSX9KeW+MRn0KMuOjPyx4IwkV32HFxwPpFuNsj2D6ly0kkp6p1qV10YxFOBITInJW2yK6hQFOJIIczxq2yOVjlKmqIDYfUOBsTTi6xqljBaXZtuh0wG9vhDa+wJSF0eTlJbvF48CHImxm2dKjnJuHhbJn2rzUK9KAo2dXgTCHCxGPQozbFIXZ9SmCiN/NIIjhVMKG/UDAKvJgKLMyD1OgbE0WBulpM4Uk5QAZ9u2bSgrK4PVakVFRQX27ds35LXPPfccdDrdgIfVah1wDc/z2LJlCwoKCmCz2VBZWYkTJ06I/TUSjuP42PCfgm4etmlbT38QnR7qVSWbEBTnpsKgV0ZPHIjN4dPInzSUlmDMCIFxOwXGyRYKc6hrV1beVjzRA5xXXnkFmzZtwr333ouDBw9i/vz5qKqqQmtr65CvSU9PR3Nzs/Cor68f8POHH34Yjz76KLZv3469e/ciJSUFVVVV8PmUtQ28y+1DfzAMo16Hkiy71MUZNZvZgEnRkQPKp0i+WP6Nckb9gPgpKrpnpBBLTFfYfZMTDYxpqXjSnenqF0aLJylotJgRPcB55JFHsH79eqxbtw6zZs3C9u3bYbfb8cwzzwz5Gp1OB6fTKTzy8/OFn/E8j9/+9re4++67cfXVV2PevHl44YUX0NTUhNdee03sr5NQrEdVmm2HyaCs2UI24kTDxsmn1CHjqdGGyuX2weMPSVwabeF5XpH5fkBcYEwjOEkXP1qsV9BoMSNqqxoIBHDgwAFUVlbGPlCvR2VlJfbs2TPk6/r6+lBaWori4mJcffXVOHLkiPCz2tpauFyuAe/pcDhQUVEx5Hv6/X643e4BDzlQ4pw4w3KGaLoh+ZS2RJxx2E3C6p1aaqySyuX2wRtQ3mgxQMnpUlJygjEgcoDT3t6OcDg8YAQGAPLz8+FyuQZ9zYwZM/DMM8/gr3/9K/7whz+A4zgsW7YMZ86cAQDhdWN5z61bt8LhcAiP4uLiiX61hIjtKqqshgqIH8GhhiqZeJ4XpqiUNoIDxE03UGOVVCzXT5GjxdFAvrGrH/5QWOLSaIuSl4gDMlxFtXTpUqxduxYLFizAJZdcgr/85S/Izc3F73//+3G/5+bNm9HT0yM8GhsbE1ji8VPiCipmKo3gSKLDE0BPfxA6XSzZW0liWwxQYJxMSk0wBoC8NAtSLUaEOR4NHV6pi6MpSp3WZEQNcHJycmAwGNDS0jLg+ZaWFjidzlG9h8lkwsKFC3Hy5EkAEF43lve0WCxIT08f8JCD0yoYwWno9FKvKonY6E1xph1Wk0Hi0ozdVNokUhJKbqh0Oh0FxhKhKaphmM1mLFq0CLt27RKe4zgOu3btwtKlS0f1HuFwGIcOHUJBQQEAYPLkyXA6nQPe0+12Y+/evaN+Tzno84fgckcPMMtRXqXDelUcD+pVJZHSKxxqqKSh5BEcIDbKfbqdAuNk6fQE0OWNjBZPUWAbBSRhimrTpk148skn8fzzz+Po0aPYsGEDPB4P1q1bBwBYu3YtNm/eLFx/33334e2338bp06dx8OBBXH/99aivr8cPfvADAJFo/pZbbsHPf/5zvP766zh06BDWrl2LwsJCrFq1SuyvkzCsB5uTaoHDbpK4NGM3sFdFlU6yKO2IhnOxvXBq2/vAcbRJZLLEcimUGhizpeIUGCcLq9cnZdhgMytvtBgAjGJ/wHXXXYe2tjZs2bIFLpcLCxYswI4dO4Qk4YaGBuj1sTirq6sL69evh8vlQmZmJhYtWoSPPvoIs2bNEq6544474PF4cNNNN6G7uxvLly/Hjh07ztsQUM6U3hMHIo3s52d6qDeeROx3rcQEYwAozrTBZNDBF+TQ7PYpcm8NpYkfLVbigYlA/GZ/1JlKFiWv8mVED3AAYOPGjdi4ceOgP9u9e/eAf//mN7/Bb37zm2HfT6fT4b777sN9992XqCImnRJ3MD4XLRVPPlbpKLWhMhr0KM1OwcnWPpxu66MAJwnYaHFumgUOm/JGi4GBm0TyPK+Ys7SUTOnTmoAMV1FphRpuHhac0QhOcviCYTT19AOIVfhKJATGtDNtUqhhtHhyTgp0OjoeJpmE6fA85d43FOBIJLZDpHJvnvgVMXTopvgaOr3geSDNYkR2ilnq4ozbFDpbKKmUvpcJEDl0s9BBx8MkE/v7VGqCMUABjiTCHB87wEzBN09pth06HdDrC6Gtzy91cVSP7f5blpOi6CH6qXQmVVKx+0aJ+ybFox2NkycQ4tDYGWmjlNwJpwBHAmejB5iZDXpMylRuDoLVZEBRtPy11FiJrk41DRXtZpxMaglw6FTx5Gns8oLjAbvZgLw0i9TFGTcKcCRQ2xH5Ay3JtsOgwAPM4pVlRyrNug6qdMQWP4KjZGwEp7nHB2+ADt0UE8/zwt+mWu4bGsERH+tMlWUre7SYAhwJxN88Ssd6hbXttNmf2GI9cWUdlniuDLsZWdEcIpqmEldrrx/eQBh6XWT3ayWLjfzRPSM2tYz6UYAjAbU0VEDcCA4NG4sudt8oN2+LEXrjdN+Iit0zRZl2mI3Kru5ZLkhDpxeBECdxadQtNuqn7DZK2Xe8QqllyBiIRfg0RSUujz+E1t5IIvdkFYz8UWCcHGrJ2wIAZ7oVNpMBYY5HYxeNGIuJLYJR+iwDBTgSECodhd88QCxIq+vw0Nb7ImIBZFaKWZFHe5xLuG8owBEVy/dTQ4Cj0+lQmh0ZUainDpWoaIqKjEswzKGxK7JZ22QFL79jijJtMOgjW++39PqkLo5qCQnG2coeMmYoOT056lR231DOn/jiNxRV+iwDBThJdqarH2GOh9WkR36acs7OGorJoEcxWypOvXHR1KlkBRXD5vbr6CR6UQlTDaq5byLfg0ZwxCNsKGpV9oaiAAU4SRe/gkqv8CXiTGy6gRorscR2FVVJQxUdwen0BNDTH5S4NOrEcbEl4kqfamDYSBR1psQTPz2l5CXiAAU4SVeroiXiDE03iE9tIzgpFiNyoxuIUW9cHM1uH/whDka9TjWHmlJdIz41bWNCAU6SqWkFFRObF6dKRyxsKkcNlQ7DkuzpvhEHa6hKsuwwGtRR1bO65mxXPy0VF4laNhQFKMBJOjXtgcPQihhx9XhjJyirZaoBiMvDoalNUaipoWJy0yywmw3geNBScZGoqY2iACfJhBEcFfbE6zu9tFRcBGypb16aBSkWo8SlSZxSmm4QlZr2wGEiS8Up0VhMamqjKMBJokCIw1m2RFxFlU5hhhUmgw6BECcsLySJU9seOXtHTT1xgDaJFJsap8OB2MgCLRVPPG8ghBZ3dENRFdw3FOAkUUNn5ITWFLNBSLBUA6NBj+Ismm4QC6vI1bKCiqHdjMVVq6INReOV0n0jGlZ/Z9pNyLAre4k4QAFOUrE/yFKFn9A6GCFhlHrjCae2FVQMy8Hp8gbR46Wl4okUCnNo6GR74Cg/lyLeZJraFI3a8rYowEkite1JEY8SjcWjxq0FAMBuNiIvOpJJjVViNXX7EAzzMBv1KHSoY4k4w45roHsm8YQ2SiV1DQU4SRSLjtXVowIowBELz/PC73SKCo72OFcZ5eGIgo2klmbZVbOhKENLxcVDIzhk3NSUnX4umqISR3tfAL3+EHS6yH4makN74YhDrdOaAC0VF5PaVt5RgJNELIFLLTdPPDYq1djpRShMvapEYUFxocMGq8kgcWkSrzSHnQ5NDVUiqeU06MHELxWnEePEUlsaBQU4SaKmE1oHU+iwwWzUIxjm0dRNp4onipobKoBGcMSitobqXJPpsNaEc/uCaO+LbCiqljaKApwkEU5otSj/hNbB6PU6lEanUGiaKnFiK+/UNz0FUA6OWNR0ntBgaIuBxGO/y5xUC1JVsqEoBThJEp+8pbYl4gwlGiceW+qr1gCHfa9ubxDd3oDEpVGHYJhDowo3FI1Hh24mnpqOaGAowEkSNSf9MXToZuKxAKckS533jd1sRH46WypO0w2JcKarH2GOh81kEH63akMjf4lXr8IDfSnASZLY/gLqiY7PRb2qxGOVjlpHcACabkg09vdXmm1X8Whx5O+BloonjhrrGgpwkiR286gnOj5XWfQPo4F64gnR4w2ipz+yw68al4gzZZRonFDs70/N90xuqgUp0aXibJSTTExDZ+Tvr0RFbRQFOEmixuj4XKXRYePGLi/CdKr4hNV3xpL+1HSK+LnYdAOdDp0YsWlN9dY1dKp44gltlIruGwpwkiAQ4tAcXSJeouIAx5luhdnAlorTqeITpYWgGIg7HZpG/hJCK/dNmXCqOAU4E9UfCKO1N3KKuJrum6QEONu2bUNZWRmsVisqKiqwb9++Ia998skn8eUvfxmZmZnIzMxEZWXledffcMMN0Ol0Ax4rV64U+2uM25muyCnidrMBuanqTPoDAINeh6KsyLk3NGw8cVroiQO0+i7R1DjVMJgyYQSH6pqJYjtCp1mNcNhMEpcmcUQPcF555RVs2rQJ9957Lw4ePIj58+ejqqoKra2tg16/e/dufOc738G7776LPXv2oLi4GCtWrMDZs2cHXLdy5Uo0NzcLjz/+8Y9if5Vxq49rqNSa9Mew4U2qdCZOC7kUQOz79fTTqeITxfN8bGsBld83tKghceJH/dTURoke4DzyyCNYv3491q1bh1mzZmH79u2w2+145plnBr3+xRdfxA9/+EMsWLAA5eXleOqpp8BxHHbt2jXgOovFAqfTKTwyMzPF/irjxhqqYpVXOEAsiZrlj5DxY79DNQ0ZD8ZuNiI3eqo43TcT09rrhy/IwaDXYVKmuk4RPxeb7qfR4omrFw5nVdeon6gBTiAQwIEDB1BZWRn7QL0elZWV2LNnz6jew+v1IhgMIisra8Dzu3fvRl5eHmbMmIENGzago6NjyPfw+/1wu90DHsmklR4VEOuN00qqiWvQSC4FQCN/icJ+f4UZVpgM6k6xZH8XZ7v66fy7CRKmw1VW14j6F9De3o5wOIz8/PwBz+fn58Plco3qPe68804UFhYOCJJWrlyJF154Abt27cJDDz2E9957D5dffjnC4fCg77F161Y4HA7hUVxcPP4vNQ5aSfoDYt+RGqqJ8YfCaHZHzvRS6yZ/8ag3nhhaydsCgPw0K8xGPUIcnX83UWpcQQUAsl57+otf/AIvv/wydu/eDavVKjy/evVq4f/PnTsX8+bNw9SpU7F7925cdtll573P5s2bsWnTJuHfbrc7qUGOVpL+gFiAEzl7i1fVfG4yNXb2g48mpuekqu/ssnOxoXEa+ZuYhuhUgxaCYr1eh5IsO0629qG+06O60YdkUmtgLOoITk5ODgwGA1paWgY839LSAqfTOexrf/WrX+EXv/gF3n77bcybN2/Ya6dMmYKcnBycPHly0J9bLBakp6cPeCSLlpL+AKAo0w6dDujzh9DpobOFxksIijWQmA7EjfxRDs6E1Kv87LJz0dTmxIU5Hme6aIpqzMxmMxYtWjQgQZglDC9dunTI1z388MO4//77sWPHDixevHjEzzlz5gw6OjpQUFCQkHInkpaS/gDAajKgID0y2kZnC42fVlZQMcWUu5UQap1qGApNbU5cc08/gmEeJoMOBQ51tVGiZ6Ft2rQJTz75JJ5//nkcPXoUGzZsgMfjwbp16wAAa9euxebNm4XrH3roIdxzzz145plnUFZWBpfLBZfLhb6+PgBAX18fbr/9dnz88ceoq6vDrl27cPXVV2PatGmoqqoS++uMmZaS/phYpUO98fHSXE88+j2b3T74Q4Pn0pGRqTVZdCixERyqa8ZLWOWbaYdBr67RYtFzcK677jq0tbVhy5YtcLlcWLBgAXbs2CEkHjc0NECvjzX8jz/+OAKBAL71rW8NeJ97770XP/3pT2EwGPD555/j+eefR3d3NwoLC7FixQrcf//9sFjkt4meWpffDac0KwUfn+6kYeMJEEZwNJC3BQDZKWakmA3wBMJo7OzHtLxUqYukOL2+oDAtrJWRv1La7G/C6lUcFCclyXjjxo3YuHHjoD/bvXv3gH/X1dUN+142mw1vvfVWgkomPtaj0sIeOEwJHbo5YfUaytsCImcLlWSn4GizGw2dHgpwxoHVNVkpZqRZ1bMb7XCEqU1a1DBuap7W1MaciYS0tESciSWMUoAzHhwXl5iupfuGEkYnRGt5WwBQnGWDTgd4A2G099GihvFgqQRq7IRTgCMyLa2gYth0HDVU49PS60MgFElML8xQV9LfcGgPpYnRWt4WAFiMsUUNlGg8PrHOlPqmwynAEZnWkv6A2Hdt7/PD4w9JXBrlYT3xSRk2zSSmA7QiZqLUPNUwHFrUMH48z6t6lkE7tacE4pP+1BgdD8VhMyHTHskBoMZq7OpVuunWSGIjf9RQjYeWNhSNRyPG49ftDaLXF+mEqrG+oQBHROwPLjvFjFSLrDeNTriSbGqsxiu2gkp9Fc5wWA+ysasfHMdLXBrlUetutCOhRQ3jxzpT+ekWWE0GiUuTeBTgiEiL01MMJYyOn9ZWUDEFDiuMeh0CIQ4tvXS20FgEw5xwHpMapxqGQ4saxk/t25hQgCMirc6JA1TpTAQ7T0hrDZXRoEdRdLdvCozH5mxXP8IcD6tJj7w0+e0HJiaaoho/YZM/lbZRFOCIKP48Ia0poa33xy2Wg6POXtVw6MiG8YnP29LaXjC0qGH81L4dBQU4IqrX2G608YQdRmllw5j09AfR7Q0C0OjUJh26OS5aOkX8XA6bCQ4bLWoYD7VvLUABjojUvPxuJOw7N3X7EAxzEpdGORo7tZuYDtB0w3ipvSc+EtpDaXzUvjkkBTgiCYQ4NPf0A9BmDk5emgVWkx5hjsfZrn6pi6MY9RpdQcXQXjjjU6/yhmokwpQ4jfyNmi8YhsvNEtPVOfJHAY5Iznb3g+MBm8mAXI0l/QHRs4WyKNF4rNjUjBaDYoB64uOl5RWbQOy+ocB49NhocarFKOxbpjYU4IikviOWYKy1pD+G9QoaaC+cUdPaKeLnYkFxT38QPdFcJDI8nuc1eSRMPJraHLv4UT+1tlEU4IhE6z0qIFbZ1lGlM2pa3loAAOxmozDiSYnGo9PW54c3EIZeBxRlavO+oanNsdNC3hYFOCLRekMF0HTDeGih0hkJbRI5NmzUr8Bhg9mozSqd/b2c7epHiBY1jIoWOuHa/GtIAq0niwKxaRZK/BudQIhDUzQxXdv3DfXGx4KCYiA/zQqzUY8Qxws7OpPhqX0XY4ACHNFoeZM/pjQr1lDxPJ0tNJIzXV7wLDE9VXuJ6QyrcGmzv9HR+goqANDrdShmu2BTh2pU1L4HDkABjigGJP1pNFkUACZl2mDQ6+ALcmjt9UtdHNnT8m608UqyqaEaCy1MNYyGsLkoBcYjCnM8znRGR4tVHBhTgCOC1l4/fEEOeh0wKcMmdXEkYzLoUZhhBUCVzmho9RTxc5XQCM6YaGGqYTRKsmhqc7Rcbh8CYQ5GvQ4FDqvUxRENBTgiYH9ghRnaTfpjYss3qTc+EkpMj2BD5s1uH/yhsMSlkT/KwYmILWqgumYkrPNQlGmD0aDeNkq930xCWj6i4VyUMDp6LG9L6/dNdooZKWYDeB5o7KRdsIfj8YfQ3hcAQCN/tGpz9IQcUZWnUFCAIwItH3x3LlryO3paPpw1nk6noxV4o8Q6Dpl2E9Kt6tyNdrSEqU1a1DAirYwWU4AjAi1kp48WbaE+OrQb7UAUGI8OraCKKc6yQacDvIEwOjwBqYsja1ppoyjAEQFVOjHxvSoytNZeP/yhSGJ6oYYT0xmabhgdrUw1jIbFaEBBOi1qGA2Wg1Os8jaKAhwRNHRSgMOwvIBOTwC9PjpbaCisQqbE9AjK3RodrUw1jFbsvqGpzeEIK+9oBIeMRa8viM7o8Kjab57RSLUYkZ1iBkC9quFopcIZrVIa+RsV2gNnoBKa2hxRjzcIty8EQP2dcApwEoz9YWWlmJGm8aQ/hnrjI4uN+tFUAzAwd4vjKGF0KJS3NRDb7I/2UBoa20AzN80Cu9kocWnERQFOgtH01PkoYXRktLXAQAUOK4x6HQIhDi29dLbQYEJhDme76OyyeMIIDnWmhqSlaU0KcBKMNt06X2zJL1U6Q6Ge+EBGgx6T2NlCFBgPqqnbhxDHw2zUIz9NvbvRjgUlp49MS51wCnASTEvR8WjFDt2kxL+hUC7F+YSt96mxGlR93IG+er12zy6Lx3K32vv88AZCEpdGnli+nxbqGgpwEoyWbZ6vhHpVw4pPTNdCr2q0aA+l4VFn6nwOuwkOWyT3ke6bwWlpOjwpAc62bdtQVlYGq9WKiooK7Nu3b9jr//znP6O8vBxWqxVz587F3//+9wE/53keW7ZsQUFBAWw2GyorK3HixAkxv8KoaenmGS1WATd19yMQ4iQujfxQYvrghHPMqKEaVCON+g2KpqmG16ihBQ2iBzivvPIKNm3ahHvvvRcHDx7E/PnzUVVVhdbW1kGv/+ijj/Cd73wHN954Iz799FOsWrUKq1atwuHDh4VrHn74YTz66KPYvn079u7di5SUFFRVVcHnkzYZMRDi0NSt/iPoxyo3zQKbyQCOB85209lC59LSnPhYFAtTVDS1ORgawRlcMU1tDskfCqPZHWkntdAJFz3AeeSRR7B+/XqsW7cOs2bNwvbt22G32/HMM88Mev1//dd/YeXKlbj99tsxc+ZM3H///bjwwgvxu9/9DkBk9Oa3v/0t7r77blx99dWYN28eXnjhBTQ1NeG1114T++sM62x3PzgesJr0yEuzSFoWOdHpdLF8CuqNn4dG/QYn9MTpnhlUPY3gDEpYtUk5f+dp7OwHzwMpZoOwP5maiRrgBAIBHDhwAJWVlbEP1OtRWVmJPXv2DPqaPXv2DLgeAKqqqoTra2tr4XK5BlzjcDhQUVEx5Hv6/X643e4BDzEIyVtZduh0lPQXT9gLh3rj5xFOEaee+AAsKO72BtHTT7tgx+N5ng71HQJNUQ2N1TXFGmmjRA1w2tvbEQ6HkZ+fP+D5/Px8uFyuQV/jcrmGvZ7971jec+vWrXA4HMKjuLh4XN9nJLRZ29Boh9GhxVZQ0X0TL8ViRE5qZCSUphsG6vAE4AmEodNFDpkkMaz+baSRv/NobbRYE6uoNm/ejJ6eHuHR2NgoyufML8rAj/9lGr42r0CU91cymm4YGh3OOjRaSTU4ds8UpFthMRokLo28sHvmTFc/QmFa1BAvFuBoozMl6j7NOTk5MBgMaGlpGfB8S0sLnE7noK9xOp3DXs/+t6WlBQUFBQOuWbBgwaDvabFYYLGInxMzvzgD84szRP8cJaI9TQYXn5iulV7VWJRm2XGgvovyKc5BK6iGlp9uhdmgRyDMobnHp/oTs8eiUWMLGkQdwTGbzVi0aBF27dolPMdxHHbt2oWlS5cO+pqlS5cOuB4Adu7cKVw/efJkOJ3OAde43W7s3bt3yPck0iuN282Y5+lsIYYS04dHK2IGF1tBpY2e+FgY9DoUZdEu2IOp19hO+6JPUW3atAlPPvkknn/+eRw9ehQbNmyAx+PBunXrAABr167F5s2bhet/8pOfYMeOHfj1r3+NY8eO4ac//Sk++eQTbNy4EUBkRc4tt9yCn//853j99ddx6NAhrF27FoWFhVi1apXYX4eM06QMG/Q6oD8YRlufX+riyAYlpg+PEkYHJ+xirJGGaqxoJdX5OI7X3JYUoh8let1116GtrQ1btmyBy+XCggULsGPHDiFJuKGhAXp9LM5atmwZXnrpJdx99934j//4D0yfPh2vvfYa5syZI1xzxx13wOPx4KabbkJ3dzeWL1+OHTt2wGql81jkymzUozDDhjNd/Wjo8CKPzs4BQInpI6EcnME1UN7WsCIjxm1038Rp6fUhEOJg0OtQmKGNxPSknJW+ceNGYQTmXLt37z7vuWuvvRbXXnvtkO+n0+lw33334b777ktUEUkSlGTZcaarH/UdXiwuy5K6OLLQoLFVDWPFAr+mnsgu2GajJtZFjEhrUw1jRTl/52OjoJMybDAZtPF3pI1vSWSBVlKdjxqq4eWkmmE3G8DzwJkuum8AoD8QRltvZJqXcnAGR1Ob59NiZ4oCHJI0rDdOm/3FsEqHVnoMLn4XbAqMI9i0i8NmgsNOZ5cNJn7ndFrUEKG1/BuAAhySRDSCMxDPx5L+aBfjodF0w0DxielkcKzD0OcPodMTkLg08lBPAQ4h4mF/WLTDaERbrx/9wTD0OqAoUzuVzljRdMNADbQHzoisJgOc6ZGFDJRoHMFGzmmKihARsAq5vS+APn9I4tJIj/WoChw2Sp4dRomwhxJNbQJ0ivholdAKvAHqNbhik2pVkjTpVhMyozkDNN2gvXNhxquUTqIfgBLTR6eUzr8T9PQH0e2NHFirpZE/CnBIUlFvPKaBGqpRoYTRgegU8dGhqc0Y1qHMSTUj1ZKU3WFkgQIcklTUq4qpp4ZqVCZl2mDQ6+ALcmjt1fYu2KEwhzNddHbZaAjHfFBnKrbztcamNSnAIUlFO9PG0BTV6JgMehRmRBJGtR4YN/f4EOJ4mI16IYmWDI6df6f1ewbQ3iniDAU4JKmKKZ9CoMV9KcaLbWhXr/E9lNg9U5xpg15PZ5cNh40Wt/b60R8IS1waaWntFHGGAhySVDRFFdHrCwr7c9AIzshYYqTWtxjQak98PDLsJqRZI/kmjRrfBVuro8UU4JCkYhXz2e5+BMOcxKWRDqtwslLMSLPSbrQjKaXdjAFoN5diPHQ6HSUaR2l1QQMFOCSp8tIssBj1CHM8mrr7pS6OZGh6amxKaOQPAJ0iPlax+0a7U5v+UBhNPZG6VmsLGijAIUml1+uosYJ2h4zHizZti6D7ZmyE8+80fN+c6eoHzwN2swE5qWapi5NUFOCQpKOVVLGlq7Qb7eiwqc1OTwC9vqDEpZHGgLPLKMAZFaprBo766XTaSkynAIckHa2kivXESyhZdFRSLUZkp0R6n1od+ev0RI440dHZZaNWSge1avpwVgpwSNKV0rw4TTWMg9ZXUrEEa2e6FVaTQeLSKINwz3R5Eea0uQu2lo/2oACHJJ3WN+AKhDg0R5P+aIpq9Eo0vpKKEozHrsBhg8mgQzDMC39zWiPsgaPB0WIKcEjSxSeMavFsoTNdXnA8YDMZkJtmkbo4iqH1PZQo/2bsDHqdMJ2n1WkqLZ8+TwEOSbqiTBt0OsAbCKO9LyB1cZKuvlO7SX8TofWDWmmTv/HR8sgfx2k7MZ0CHJJ0FqMBBdFzdLSYaCxMNWiwwpkIrW/axgK7Yg32xCdCyyupWnv98Ic4GPQ6FGbYpC5O0lGAQyQRm6bSXm9cy0PGE8F+X00a3QWb7pvxKdHwSiq2kGNShg0mg/aae+19YyILscMTtVfpCHvg0AjOmOSmWWA16cHxwNkubSWM9gfCaO31A6D7ZqyERQ1a7ExpeHoKoACHSEQYwdFggEN74IyPTqfTbD4Fm15JtxqRYdfWbrQTFT+1qbVFDax+1eq0JgU4RBJCpaOxhmpA0p9GK52JELbe19geSmyqgRKMx644uoqq1xdCt1dbu2DXa7yuoQCHSKJUo2fExCf9TcrUXtLfRGk10Vg4nFWjUw0TYTMbkBfdjkFr9Y2WV1ABFOAQibCphrZeP7yBkMSlSR7WEy/MsGoy6W+itDryRwnGE6PV+6ZBOKZBmyN/VMMSSTjsJjhsJgDa6lXFhoy1WeFMFAuMtXZcg9Z74hOlxalNty+IruiUnFZH/ijAIZLR4nQD7YEzMSVxB7VqKWGUBThaTRadKC3XNTmpZqRajBKXRhoU4BDJaHF/Cq0n/U1UUaYd+ugu2G19fqmLkxRhjseZLtrFeCK0OEVVT2eXUYBDpBOrdLQzbNzQQXvgTITZqEeBI5KcrZXAOLKxIQ+zQQ9ndAdwMjbFmuxM0co7UQOczs5OrFmzBunp6cjIyMCNN96Ivr6+Ya//0Y9+hBkzZsBms6GkpAQ//vGP0dPTM+A6nU533uPll18W86sQEcSmG7SzaVvsHCrtVjoTpbXpBjY9VZRlg0FPZ5eNBxsxdbl98AXDEpcmOej0eZEDnDVr1uDIkSPYuXMn3nzzTbz//vu46aabhry+qakJTU1N+NWvfoXDhw/jueeew44dO3DjjTeed+2zzz6L5uZm4bFq1SoRvwkRg9YS/3q8QWEfDsrBGT+tnS1EK6gmLisllofCpvvULnY4q3bvG9Eyj44ePYodO3Zg//79WLx4MQDgsccewxVXXIFf/epXKCwsPO81c+bMwf/8z/8I/546dSoeeOABXH/99QiFQjAaY8XNyMiA0+kUq/gkCdgf3pmufoTCHIwqXzbNhoxzUi2aTfpLhOIsjQU4NNUwYWwX7C+a3ajv8GJaXprURRKdsHeShgNj0VqUPXv2ICMjQwhuAKCyshJ6vR579+4d9fv09PQgPT19QHADADfffDNycnKwZMkSPPPMM8OuqPD7/XC73QMeRHrOdCvMRj1CHI/mHp/UxREd9agSI3aOmTZG/miqITG0NLUZCHFo7olM/Wt5tFi0AMflciEvL2/Ac0ajEVlZWXC5XKN6j/b2dtx///3nTWvdd999+NOf/oSdO3fimmuuwQ9/+EM89thjQ77P1q1b4XA4hEdxcfHYvxBJOL1eh+Lobr5aqHToiIbE0OwUlYYbqkQo0dDI35kuLzgesJsNyE21SF0cyYw5wLnrrrsGTfKNfxw7dmzCBXO73bjyyisxa9Ys/PSnPx3ws3vuuQcXX3wxFi5ciDvvvBN33HEHfvnLXw75Xps3b0ZPT4/waGxsnHD5SGJo6aRfNuKg5R5VIrDfX3tfAH1+de+CzfM8bfKXICUaCozr46andDrtJqaPORHgtttuww033DDsNVOmTIHT6URra+uA50OhEDo7O0fMnent7cXKlSuRlpaGV199FSaTadjrKyoqcP/998Pv98NiOT9atVgsgz5PpKelXhX1xBMj3WpCpt2ELm8QjZ1ezCxIl7pIounyBoUgriiT7puJ0NLUJk1rRow5wMnNzUVubu6I1y1duhTd3d04cOAAFi1aBAB45513wHEcKioqhnyd2+1GVVUVLBYLXn/9dVitI+/7UF1djczMTApiFEhLm/010BLxhCnJsqPL24P6DnUHOKwxdqZbYTUZJC6NsrGORWNXPziOh17FS+6pMxUhWg7OzJkzsXLlSqxfvx779u3Dhx9+iI0bN2L16tXCCqqzZ8+ivLwc+/btAxAJblasWAGPx4Onn34abrcbLpcLLpcL4XBk74I33ngDTz31FA4fPoyTJ0/i8ccfx4MPPogf/ehHYn0VIiKtJP75gmG43JFEaq1XOolQks1Oo1d3b5waqsQpcFhh1OsQCHHC36Ja1UUD47IcbXemRF2r+uKLL2Ljxo247LLLoNfrcc011+DRRx8Vfh4MBlFTUwOvN/JHfPDgQWGF1bRp0wa8V21tLcrKymAymbBt2zbceuut4Hke06ZNwyOPPIL169eL+VWISOITRnmeV+188ZkuL3geSDEbkJ1ilro4iscStdUeGNe2RxqqyRpvqBLBaNCjKNOGug4v6ju8KMywSV0k0QgBjsa3FhA1wMnKysJLL7005M/LysoGLO++9NJLRzxAb+XKlVi5cmXCykikxfIK+vwhdHoCyFZpxr9wLkx2imqDuGTSSsJoXQftgZNIxVl21HV40djpxdKp2VIXRxShMIfG6N+F1kdw1L2zGpE9q8kgnK+j5saKdqNNLK2M4NRFv9/kHLpvEkEL59819/giZ5cZ9SjQ+NllFOAQyWmhNy70xKmhSgg2onG2ux/BMCdxacRT1065FIkUW0ml3rqGTWuWZtlVnUg9GhTgEMlpoTcu5FLQVENC5KVZYDXpEeZ4nO1S52GtXZ4AevojZ5eV0sq7hCjRwKIGmtaMoQCHSE4LK6loVUNi6fU6odGvVem+JnVxS8RtZloinggsWbuu3TNivqdS1bXTtCZDAQ6RnNqX/AZCnDDKQKthEie+sVKjWFBMDVWiRHb2BXr9IXR4AlIXRxTUmYqhAIdIriw6glPbrs4RnIbO2LkweWnqXCUmhTKVBzjs70HrS30TyWoyoNARWR6u1vtGyNui+4YCHCI91lC19/nR6wtKXJrEYxVOKS0RTyg2BF+r0qnNeuqJi4KNiNWqMMAJhTk0dtEScYYCHCK5dKsJOamRze/qVDiKw4aMaU48sVgPVf09cbpvEkmY2lRh7lZTNy0Rj0cBDpEFVumoMWG0loaMRcHumTNdXgRC6loqzvN87L6hnnhCxQJj9XamaIl4BAU4RBZYpVPbpr4Ah5L+xJGbZkGK2QCOV98eSt3eINy+yCnitEQ8sVhgfFqFI39U1wxEAQ6RhTIVDxvHlm1SpZNIOp1O2OtDbdNUtbREXDSsrqnvUN9S8Vqa1hyAAhwiC1PYFJXKGipfMIymnsgScZqiSjy15lPEdjCmhirRijPt0OsAbyCM1l6/1MVJKLaXGI3gRFCAQ2ShTKUBTuSUdCDVYhQSqUniqHVFTOwMKmqoEs1s1AuH/KruvqF8vwEowCGywP4ge/qD6FLRBly1cT1xWiKeeJNzUgGodwSHttsXhxo3iQyFOSEXjUZwIijAIbJgMxtQ4Igsa1TTSirqUYmLLb1X24oYIVmU7htRqHHVZlO3DyGOlojHowCHyIYaV1LF9sChhkoM7J5p6umHLxiWuDSJEb9EnO4bcbAkXDWN4NTSEvHzUIBDZGNyrvoSRmkPHHFlpZiRZjWCV9FS8S5vEL3RJeIlWZRkLAY15vzRztfnowCHyMbkbPVVOmzqhCodceh0uth0g0ruG/Y9Chy0RFwsk4Wl4l5wnDqWitMS8fNRgENkQ229qv5AGC63DwBNNYipTGWBMeuJl1JDJZpJGTYY9Tr4Qxyao3+jSldHO1+fhwIcIhvxKxvUsAEXm2pLtxqRaTdJXBr1Utup4nWUfyM6o0GPEpXl4bA9cCbTdLiAAhwiGyVZkQ24PIEw2lSwAVd8Q0VLxMUzWWV74bDT0SlvS1xqmhKPXyJeSoGxgAIcIhtq24CrlpL+kkJte+HEpqjovhGTmkb+znb30xLxQVCAQ2RFTWdS0R44ycF64i1uP7yBkMSlmRie54VtEmiKSlxqyvk7ze6Z7BRaIh6HAhwiK5Oj8+JqOOmXDtlMDofdJOQ4KX3Dv7ZeP3r9Ieh1dA6V2IQpKhV0pk619QEApuRSXROPAhwiK2raQp2mqJJHLSN/p6I98aJMOyxGWiIuJhZANnZ6EQpzEpdmYliHcGpuqsQlkRcKcIisxObFld0T7/OHhERpWtUgPrUkjJ5up554shQ6bDAb9QiGeTR1K3up+GkawRkUBThEVibH9cSVvAEXy6PITjHDQUvERaeWfAqWS0E9cfHp9TphUzylT1Ox+2YK3TcDUIBDZGVShg0mg/I34GJz4tRQJQfruSo9wKFciuRiHSo2AqJEvb4gWqOjxXTfDEQBDpEVo0GP4uj5O0o+dJOGjJOLBZInW/sUvUmk0BPPocA4Gdh9c1rRdU2k7DmpFqRbabQ4HgU4RHamCNMNyu1VnaKphqSKbKYI9PQH0ekJSF2ccfGHwjjTFck9m5pHgXEysL/PUwoewWF5W1OpM3UeCnCI7MQqHeX2qoQpKmqoksJqMqAo0wZAufdNfYcXHA+kWYzITbVIXRxNmJqnggCH8m+GJGqA09nZiTVr1iA9PR0ZGRm48cYb0dc3/I106aWXQqfTDXj8+7//+4BrGhoacOWVV8JutyMvLw+33347QiFlb/BFYuKnG5SI43ghF4SmGpJH6b3xU62xaU062iM52BRyi9uPXl9Q4tKMTywxnTpT5xI1wFmzZg2OHDmCnTt34s0338T777+Pm266acTXrV+/Hs3NzcLj4YcfFn4WDodx5ZVXIhAI4KOPPsLzzz+P5557Dlu2bBHzq5AkUnqv6mx3P/whDmaDXhhVIOITAhyFBsa0l0nypVtNyEuLjJYpNQ+HEtOHJlqAc/ToUezYsQNPPfUUKioqsHz5cjz22GN4+eWX0dTUNOxr7XY7nE6n8EhPTxd+9vbbb+OLL77AH/7wByxYsACXX3457r//fmzbtg2BgDLn3slA06IVfHOPD31+5Y3MsQqnNNsOo4FmgZNF8SM41FBJQsn3TfxoMQXG5xOt9t2zZw8yMjKwePFi4bnKykro9Xrs3bt32Ne++OKLyMnJwZw5c7B582Z4vbFN3/bs2YO5c+ciPz9feK6qqgputxtHjhwZ9P38fj/cbveAB5Evh92EnFTWq1JepUN7mUiDDdErNQeHcimkwfLklDglPnC0mI72OJdRrDd2uVzIy8sb+GFGI7KysuByuYZ83b/927+htLQUhYWF+Pzzz3HnnXeipqYGf/nLX4T3jQ9uAAj/Hup9t27dip/97GcT+TokyabmpqC9z49TbX2YV5QhdXHGhHri0mBTm41dXviCYVhNyjnqgOd52jtJIkoewWHTmqXZdhjokM3zjHkE56677jovCfjcx7Fjx8ZdoJtuuglVVVWYO3cu1qxZgxdeeAGvvvoqTp06Ne733Lx5M3p6eoRHY2PjuN+LJAdrrJTYq6KGShrZKWY4bCbwvPLOpGrvC6DXF4JOF2msSPIoedUm7bc1vDGP4Nx222244YYbhr1mypQpcDqdaG1tHfB8KBRCZ2cnnE7nqD+voqICAHDy5ElMnToVTqcT+/btG3BNS0sLAAz5vhaLBRYLLbtUkmlCwqgSK53oFFUeBTjJpNPpMDU3BQcbunGq1YNyZ/rIL5IJ1lAVZdoUNfKkBuzvtL7Dg2CYg0lBeXPUmRremAOc3Nxc5Obmjnjd0qVL0d3djQMHDmDRokUAgHfeeQccxwlBy2hUV1cDAAoKCoT3feCBB9Da2ipMge3cuRPp6emYNWvWGL8NkSulrqSibdOlNTU3NRLgKOy+OU3bCkimIN0Km8mA/mAYjZ1eReVAUd7W8EQLVWfOnImVK1di/fr12LdvHz788ENs3LgRq1evRmFhIQDg7NmzKC8vF0ZkTp06hfvvvx8HDhxAXV0dXn/9daxduxZf+cpXMG/ePADAihUrMGvWLHz3u9/FZ599hrfeegt33303br75ZhqlURGWMFrX4UEozElcmtFjFU5uGm2bLoUpCs2nYEvbqSeefHq9TuiMKG2aKhbgUGdqMKKOxb344osoLy/HZZddhiuuuALLly/HE088Ifw8GAyipqZGWCVlNpvxj3/8AytWrEB5eTluu+02XHPNNXjjjTeE1xgMBrz55pswGAxYunQprr/+eqxduxb33XefmF+FJFmhwwabyYBgmEdDp3fkF8iEkGCcQxWOFGIrqZQV4AgjONRQSUKJicYefwiu6IHEU2nkb1CiraICgKysLLz00ktD/rysrGzAwXjFxcV47733Rnzf0tJS/P3vf09IGYk8sV7VkSY3Trb2KWYIlvJvpCVMbbZ6wHE89ApZWULJotJS4iaRbP+bnFQzHHYaLR6McrKpiOYocXUDjeBIqyTLDqNeh/5gWOjdyp0/FEZjVz8AmqKSCtsLR0kjOGyFKeVtDY0CHCJb0xS4VJyVlUZwpGEy6IVl1kpprGrbPQhzPNKsRuHYAJJc8Z2p+FkFOTvR2gsAmJ5Pdc1QKMAhsqW0efFAiBOGjS/IT5O4NNqltOmGEy2Rcl6Qn0aHbEpkck4KdDqgpz+IDo8yjvw5Hr1vplNnakgU4BDZmha3VFwJvaq6Dg9CHI9UixGFDqvUxdGs2BYDypjaPNES7YlTQyUZq8kgHIyrlMCYjRZTZ2poFOAQ2SrNtkOvA3p9IbRF95aRM9YTn5aXSj1xCbERHKVMbQo9cWqoJCXcNwoYMfYFw6iP7tY9jaaohkQBDpEtq8mA4qxIPoUSKp3j1BOXBSF3SwH3DBDLpbiAGipJKSkwPtXWB44HMuwm5KZS3tZQKMAhsjZNQfkUsYaKeuJSYgFmW68fXTLPp/CHwqjriOzzND2P7hspsQCTjcTKGQvCptNo8bAowCGyxvIpTiggwIlNNVBPXEopFqOQT8FG1eQqfgVVfjr1xKXEOiY1Mr9ngLjRYupMDYsCHCJrrNKRe0MVCHGooxVUsjFDIffNcVpBJRssWFDCyN8JWkE1KhTgEFljDVWNq1fWK6niV1AV0AoqyV3gVEZv/CTlbclGqoJG/k7QCqpRoQCHyNr0/FTodECXN4i2PvmupGIVIq2gkgeWT3HcJe+pTVpBJS9KGDGOX0FFgfHwKMAhsmY1GVCWHdlGXc6NVWyzNqpw5EBoqFrlPfJ3nFZQyYoS8nBOt3nA8YDDZkIu7Xw9LApwiOyxyl/OlQ6toJKXqbmp0OuAbm9Qtnso+UNh1EdXUNF9Iw8znPIf+ROOaKDR4hFRgENkb4YzHQBQ43JLXJKh0VSDvFhNBpRFDzyVa2BMZ1DJjxJG/k5QXTNqFOAQ2RMSjWW6P0X8CiqaE5ePC/JiCepyRCuo5EcJI3+0oejoUYBDZG9GdEXMiZZecJz8elVsBVUaraCSlQuE+0aegTFbQUX5N/IRn/Mn15E/WkE1ehTgENkry7bDbNDDGwjjbHe/1MU5j7CCKp/mxOVkhswTRo8LZ5dRQyUnF+TLd+RvwAoqCoxHRAEOkT2jQS/saHxMhpXO8WiZLqCGSlZiW+/LM5/iWDSnbAb1xGVFziN/J1oiZ1Bl2k2UtzUKFOAQRSh3ynd/ii+aI2UqL6CGSk7KclJgMujgkeHIn8cfQn1nZAXVTLpvZEXOI39HmyNB8cyCdBotHgUKcIgiyHnYOL7SIfJhMuiFE6LlFhjXtPSC54G8NAuy6TRoWWFLxeWY83c0OupX7qS6ZjQowCGKIOxPIbOGqqc/KIwOzKRKR3ZYYCy3qU0WFJdTUCw7pdnyHfmLdaZo1G80KMAhisD2wjnV1odgmJO4NDHHohXOpAwbHHaTxKUh52Ir8I41yzPAoYZKfuJH/uQUGPM8j6PR+5hGi0eHAhyiCIUOK1ItRgTDPE63eaQujoAaKnmbVRhpCL5oltcmkSzgmkUNlSyx/y5HZXTfuNw+9PQHYdDrMI32wBkVCnCIIuh0OqE3LqdKh/XwaE5cnmZHG6rTbX3oD4QlLk0Ex/F038gcC4yPNPVIXJIYVu9NzU2B1WSQuDTKQAEOUYzZMuyNU4KxvOWmWZCTagbHy2dVzJmufvT5QzAb9JiSmyJ1ccgg5Djyx6anKCgePQpwiGLMllmvKszxQqNJU1TypNPpMKvQAQD4okkejRVrNKfnp8JkoCpYjtgUVWNnP3r6gxKXJoI6U2NHf11EMWZHG6ojTW5ZbNxW2+6BL8jBZjKgNJt64nLFGiu5BMZsgz9qqOQrw27GpAwbAPlMiVO+39hRgEMUY3p+Kox6Hbq9QTT1+KQujlDhzHCmwaCnTbfkSm7TDcIScSc1VHIm3DcyGPnzBcOojR7oS4Hx6FGAQxTDYjRgenRfkyNnpe+N05CxMrARnGPNvQjLYOO2o7SCShHYfx85BMbHW3rB8UBWipmOaBgDCnCIosTycKSvdGjIWBkm56TAatKjPxhGXYe0Wwy4fUE0RI9ooE3+5G22jEZwDp+NlGEWHdEwJhTgEEWRS4DD8zwORSudOZMckpaFDM+g1wkrT6RurA5HRx4nZdiQlWKWtCxkeGyK6kRrLwIhaTcXPRS9b+YWUV0zFqIGOJ2dnVizZg3S09ORkZGBG2+8EX19Q5/QWldXB51ON+jjz3/+s3DdYD9/+eWXxfwqRCaEYWOJE0Zdbh/a+/ww6HU01aAAcsnDOXQmct/Oo4ZK9iZl2JBujWwueqJV2i0GDp3tBgDMpc7UmIga4KxZswZHjhzBzp078eabb+L999/HTTfdNOT1xcXFaG5uHvD42c9+htTUVFx++eUDrn322WcHXLdq1SoxvwqRCdZQNfX40OUJSFaOz6MN1fS8VNp0SwHkMvJHPXHliGwxIP3Inz8UFg4ZpgBnbEQLcI4ePYodO3bgqaeeQkVFBZYvX47HHnsML7/8MpqamgZ9jcFggNPpHPB49dVX8e1vfxupqQO3ps7IyBhwndVqFeurEBlJs5pQmm0HIG1jRT1xZZkT3WLg0JluSbcYYAHOvEkZkpWBjB7bmuKQhIsaaly9CIZ5ZNpNKMq0SVYOJRItwNmzZw8yMjKwePFi4bnKykro9Xrs3bt3VO9x4MABVFdX48YbbzzvZzfffDNycnKwZMkSPPPMM8NWWn6/H263e8CDKBfrjR+WcJrqc6EnniFZGcjolRekwWTQocsbxJkuaU6I7vEGUd8RSTCeM4mmNZVgfnEGAOCzMxLWNdHPnjPJQQnGYyRagONyuZCXlzfgOaPRiKysLLhcrlG9x9NPP42ZM2di2bJlA56/77778Kc//Qk7d+7ENddcgx/+8Id47LHHhnyfrVu3wuFwCI/i4uKxfyEiG3Ojvd/Pz3RL8vk8z+NQ9LPn0ZCxIliMBiFXqrqxW5IysFGAkiw7MuyUYKwEC6IdmKNNbskSjVliOo0Wj92YA5y77rpryERg9jh27NiEC9bf34+XXnpp0NGbe+65BxdffDEWLlyIO++8E3fccQd++ctfDvlemzdvRk9Pj/BobGyccPmIdOYXR/7Qqxu6Jfn8M1396PIGYTLoUE5LxBVD6I1LFOB8zhJFqaFSjOIsGzLtJgTCnLADdbKxEZy5NK05ZsaxvuC2227DDTfcMOw1U6ZMgdPpRGtr64DnQ6EQOjs74XQ6R/yc//7v/4bX68XatWtHvLaiogL3338//H4/LJbzN0GyWCyDPk+UaV5RBnS6SKJxq9uHvPTk5l+xnvgMZxosRkowVop5RRkA6oUGI9mEnjiN+imGTqfDvKIMvHe8DZ81dkfvoeTxBcM4Hj3vjgLjsRtzgJObm4vc3NwRr1u6dCm6u7tx4MABLFq0CADwzjvvgOM4VFRUjPj6p59+Gl//+tdH9VnV1dXIzMykIEYjUi1GXJCXhpqWXlQ3dmPF7JED5kSiHpUyLSiOJYyGwhyMST7oUrhvqKFSlPnFkQCnurEH312a3M8+5upFiOORnWJGoYMW0oyVaH/hM2fOxMqVK7F+/Xrs27cPH374ITZu3IjVq1ejsLAQAHD27FmUl5dj3759A1578uRJvP/++/jBD35w3vu+8cYbeOqpp3D48GGcPHkSjz/+OB588EH86Ec/EuurEBlaEJ1ukCKfgu1JQXPiyjIlJxWpFiP6g2GcbBt6Py4xdHoCQnIzbQypLCww/kyCnD82WkwJxuMjahfmxRdfRHl5OS677DJcccUVWL58OZ544gnh58FgEDU1NfB6vQNe98wzz6CoqAgrVqw47z1NJhO2bduGpUuXYsGCBfj973+PRx55BPfee6+YX4XIzHyJAhyO44Ul4rQnhbLo9Trhv1my83BYQvzknBSkW01J/WwyMWxa6lRbH3p9waR+NsszpM7U+Ix5imossrKy8NJLLw3587KyskGXdz/44IN48MEHB33NypUrsXLlyoSVkSgTG8H5/EwPOI6HPkmneZ9u74PbF4LVpMcMOg1aceYXZ2DP6Q5UN/bguouS97kH67sAAAtLMpL3oSQhclItKMq04UxXPw6d7cGyqTlJ++xPGyL3zYWlmUn7TDWhs6iIIl2QnwqbyYA+fwinkjjdcCDaUM0vyoApyTkcZOLYdEOytxg4GO2JX1hCDZUSxVbgJS9BvdMTwOn2yOGwFxbTfTMeVEMTRTIa9EKy5qdJnG5gAc4i6lEpEptuOObqRX8gnJTPDHO80BOn+0aZ5kfrmurGrqR9Jhv1m5aXCoedpjXHgwIcolgLJcjDoQBH2QocVhQ4rJGgI0mNVY2rF55AOLL6L5+mNZVoYXTk7UB98o76OMimp2hac9wowCGKxfJwWE9HbF2eAE61RYaMF9JUgyLpdDosLssCAHxSl5z75kBDLP/GkKRcMZJYcyc5YDbo0d7nR12Hd+QXJAB1piaOAhyiWKyhqmnpRY9X/NUNrMc/JTcFWSm01b5SLSmLNBj76zqT8nmf1rOeODVUSmU1GYQd1PfXin/fBMOcsCyd7pvxowCHKFZumgVTclPA88An9eJXOkKPiiocRWOB8cH6LoTC4p8vdIDyb1Thouh9k4zA+FhzL3xBDulWI6bmpor+eWpFAQ5RtIrJkUpnXxJ6VWxKY3EZNVRKdkF+GtKsRngCYRxz9Yr6Wa29PtR3eKHTAQsol0LRkhng7K3tABBZHp6sLTDUiAIcomis0tkrcoDjC4aF1VpsBIAok0Gvw+LoaIrYgfGeU5GGanZhOm3wp3AXlmZCpwPqOrxo7fWJ+lkfn47cN1+aki3q56gdBThE0ZZER3AOn+2Bxx8S7XMO1nchEOKQn27BlJwU0T6HJIeQaCzy1CZrqJZSQ6V4DpsJ5c50AOImqIc5Xuiw0X0zMRTgEEUryrRjUoYNIY7Hp9HN1MTwUbQnvmxqDp0JowIsMN57uhMcJ96yXzaCs3QqNVRqcFF0enpvNHAVwxdNbvT6QkizGDG7MF20z9ECCnCI4rHG6mMRK5091BNXlflFGbCbDejwBHDU5RblM5p7+lHX4YVBrxOmUomyLYsGqh+cbBftM/acjrz3kslZST/xXm3ot0cUjwUdYlU6Hn9IOJyReuLqYDbqhfyGD0W6b9jozZxJDqRR/o0qLJ2aA70OONXmQXNPvyifQaN+iUMBDlG8L18QOfzu8zPd6PYGEv7+++s6EeJ4FGXaUJxlT/j7E2lcPC1y3/zzhDgBDpvWpFE/9XDYTMJxH2LcN6Ewh/3R/B5KMJ44CnCI4hU4bLggPxUcL84oDjVU6vTl6ZEAZ39dJ3zBxJ5LxfM89cRVank0MP5AhADnszPd6POH4LCZMKuA8m8migIcogpfnp4LAPjn8cRXOrtrWgEAy6MNIlGH6XmpyEuzwBfkEn7cx/GWPpzt7ofFqMcSyr9RFVYPfHiyPeEJ6u8ci9Q1X7kgl/a/SQAKcIgqfOWCSIDz/om2hB6G19jpxfGWPhj0OlwS/QyiDjqdTuiN/zPBI3+7jrUAiCSl2syGhL43kdaFJZmiJai/c6wNAPAv5VTXJAIFOEQVlpRlwWzUo7nHh1NtfQl733ejozeLSjKRYafzp9SG5W+9c7Q1oe/7brQn/i/leQl9XyK9+AT13TVtCXtfV48PR5vd0OmASy6g+yYRKMAhqmAzG4RjG3YlsLFi7/VVaqhU6asz8mDQ61DT0ov6Dk9C3rPbGxDOLaP7Rp0qZ+YDAN4+4krYe7LO1ILiDDrMN0EowCGqsWJWpNL538OJqXS8gZCw/81lM6mhUqMMu1kIjHd+0ZKQ93zveBs4HrggPxVFmbTqTo0qZ+VBpwM+O9OTsOXiLP/mX2ZQXZMoFOAQ1aia7YROB1Q3diek0vnwZAcCIQ6TMmyYnkcn+qoVC4zfPpKYAIdG/dQvL82KC0siuxr/IwGBcX8gLOzHRPdN4lCAQ1QjL92KRdFKZ0cCRnH+fqgZAPCvs/LpeAYV+9fZTgCRc6k6+vwTei9fMIxdRyMN3opZzgmXjcgXC4zfSkBgvLumFd5AGEWZNjqeIYEowCGqsnJOpFGZaIDjC4aFKYur5hdMuFxEviZl2DBnUjo4HvjH0Yk1VrtrWuEJhDEpw4YLSzISU0AiSyuigfHHpzvQ4w1O6L3e/DzSmbpyXgF1phKIAhyiKlXRSmd/XSdae33jfp/dNa3o84cwKcOGhcWZiSoekanL50SC2Nc+bZrQ+7xBDZVmTM5JQbkzDSGOx9+io73j4Q2EhG0Fvja3MFHFI6AAh6hMcZYdC4ozwPHAXyfQWL3+WeS1V84roA23NGDVwkkAIoeqnunyjus9en1BYbn5VfOoodKCb0Tvm/85eGbc7/H2kRb4ghxKsuyYM4mmpxKJAhyiOtcuLgIA/OmTxnFt+tfe5xemp65eQA2VFkzKsAlHcfy1enyB8eufNaE/GMbU3BRqqDTiGwsnQa8DDtR3obZ9fNsM/HFfAwDgmguLaNQvwSjAIapz1fxCWE16nGjtQ3X0FPCx+J8DZxAM85hf5MDsQkfiC0hk6RsXRnrjr+xvRHgcW/C/vK8RAPCdJSXUUGlEXrpVOCbmz580jvn1p9v6sLe2E3pdrGNGEocCHKI66VYTrojmVPy/j+vH9FqO44Ue1b9VlCS8bES+vjavAOlWIxo6vcJOxKN1+GwPDp3tgdmgxzcvpIZKS76zpBhAZCRmrIe2vrI/EhRdckEuCjNsCS+b1lGAQ1Rp7bIyAMDr1U1j2hNn17FW1HV4kWYx4muUR6EpdrMRq5dEgtrnPqob02ufeP80AODyuU7ahVZj/nWWE0WZNnR5g3jt07Ojfp3bF8RLeyOdqTUVpWIVT9MowCGqtKA4A0smZyHE8Xj2w7pRvYbnefzu3ZMAgOuXliLFYhSxhESO1i4thV4HfHCyHYfP9ozqNXXtHrz5eSRv5/98ZaqYxSMyZNDrcEO0Q/XkP0+PenrzDx/Xo9cfwvS8VDqzTCQU4BDV+j9fmQIgUpG0uEdeMv7+iXZ81tgNq0mPG5dPFrt4RIaKMu34+vzIyN1DO46N6jW/e/ckOD5ysOYs2qRNk759UTEcNhNOtXlGtaKq1xfEMx/UAgA2XDqVVmqKhAIcolr/Up6HC0sy4A2E8cu3aoa9NhDicP+bXwAA/m1JKXJSLckoIpGhTf86A0a9Dv880Y4PTrQPe211Y7fQoG38l2nJKB6RoXSrCRu/Gvnv/5udx9EfGD4X57F3TqK9L4CybDuumk9T4WIRLcB54IEHsGzZMtjtdmRkZIzqNTzPY8uWLSgoKIDNZkNlZSVOnDgx4JrOzk6sWbMG6enpyMjIwI033oi+vj4RvgFROp1Oh3u+NgsA8N8HzmBfbeeQ1z71wWmcbO1DdooZP7lserKKSGSoJNuONdEE882vfo4+f2jQ60JhDlv+ehg8D3zzwknC2UREm767tBSTMmxo7vENO/pX4+oVRm/uvWo2TAYaZxCLaL/ZQCCAa6+9Fhs2bBj1ax5++GE8+uij2L59O/bu3YuUlBRUVVXB54tNL6xZswZHjhzBzp078eabb+L999/HTTfdJMZXICqwsCQT344uv7zl5U/R1nv+WUMH6jvxm53HAQCbr5gJh92U1DIS+bmtagYmZdjQ2NmPLa8dHnQ/pYffqsHnZ3qQZjHirsvLJSglkROryYAHvzkXQCRJfdcgx370+oK4+aWDCHE8Kmfm0cGaIhMtwPnZz36GW2+9FXPnzh3V9TzP47e//S3uvvtuXH311Zg3bx5eeOEFNDU14bXXXgMAHD16FDt27MBTTz2FiooKLF++HI899hhefvllNDVNbIt1ol5brpqNsmw7mnp8+O7Te3G2O7aqal9tJ9Y9ux/BMI8r5jpxTXQvFKJt6VYTfv3t+dDrgL98ehb3vn4EwTAHAAhzPB7ZeVxYOfXQt+YhL80qZXGJTFxyQa6QcHzzSwfxzrFYkNPW68cNz+7HydY+5KVZ8Itr5klUSu2QzTKR2tpauFwuVFZWCs85HA5UVFRgz549WL16Nfbs2YOMjAwsXrxYuKayshJ6vR579+7FN77xjUHf2+/3w++P9dzdbrd4X4TITqrFiOfWLcG3tu/BMVcvKn/9Hipn5aPPF8Tu423geWBRaSYe/tZ82qCNCL40JRsPfGMuNv/lEF7YU4/3j7fhorIsfH6mBzUtvQCA26tm4Iq5dBgrifmPK2aivsODd2va8P3nPsHF07KRl2bFrqMtcPtCSLca8cwNF1GeXxLIZvLP5Yqc/pyfnz/g+fz8fOFnLpcLeXkDh/SMRiOysrKEawazdetWOBwO4VFcXJzg0hO5K8tJwas/XIYLSzLQHwzjjc+a8G5Nm5A/8fz3lyCVloWTc3xnSQm2X38hMu0m1HV48ecDZ1DT0osUswEPXzMPN3+VEovJQGajHtu/uwg3LCuDTgd8eLIDr356Fm5fCOXONPz3hmWYM4l2SE+GMdXod911Fx566KFhrzl69CjKy+U1H71582Zs2rRJ+Lfb7aYgR4OKs+z4nw3LsOd0Bz5t6IbFqMclF+Rien6a1EUjMrZyTgG+PD0XO79oQX2HFwUZVlTNdsJho1wtMjiL0YCffn02blhWht01rfAEwphdmI4vT8+FgZaEJ82YApzbbrsNN9xww7DXTJkyZVwFcTqdAICWlhYUFMSGfFtaWrBgwQLhmtbWgVuoh0IhdHZ2Cq8fjMVigcVCw4EksrJq2dQcLJuaI3VRiIKkWIzCieOEjFZZTgpuyKE9taQypgAnNzcXubm5ohRk8uTJcDqd2LVrlxDQuN1u7N27V1iJtXTpUnR3d+PAgQNYtGgRAOCdd94Bx3GoqKgQpVyEEEIIUR7RcnAaGhpQXV2NhoYGhMNhVFdXo7q6esCeNeXl5Xj11VcBRHrWt9xyC37+85/j9ddfx6FDh7B27VoUFhZi1apVAICZM2di5cqVWL9+Pfbt24cPP/wQGzduxOrVq1FYSJslEUIIISRCtKzKLVu24Pnnnxf+vXDhQgDAu+++i0svvRQAUFNTg56e2Hkvd9xxBzweD2666SZ0d3dj+fLl2LFjB6zW2BLMF198ERs3bsRll10GvV6Pa665Bo8++qhYX4MQQgghCqTjB9vBSuXcbjccDgd6enqQnk5nxxBCCCFKMJb2WzbLxAkhhBBCEoUCHEIIIYSoDgU4hBBCCFEdCnAIIYQQojoU4BBCCCFEdSjAIYQQQojqUIBDCCGEENWhAIcQQgghqkMBDiGEEEJUR7SjGuSMbd7sdrslLgkhhBBCRou126M5hEGTAU5vby8AoLi4WOKSEEIIIWSsent74XA4hr1Gk2dRcRyHpqYmpKWlQafTJfS93W43iouL0djYSOdciYh+z8lBv+fkoN9zctDvOXnE+l3zPI/e3l4UFhZCrx8+y0aTIzh6vR5FRUWifkZ6ejr9ASUB/Z6Tg37PyUG/5+Sg33PyiPG7HmnkhqEkY0IIIYSoDgU4hBBCCFEdCnASzGKx4N5774XFYpG6KKpGv+fkoN9zctDvOTno95w8cvhdazLJmBBCCCHqRiM4hBBCCFEdCnAIIYQQojoU4BBCCCFEdSjAIYQQQojqUICTQNu2bUNZWRmsVisqKiqwb98+qYukKlu3bsVFF12EtLQ05OXlYdWqVaipqZG6WKr3i1/8AjqdDrfccovURVGls2fP4vrrr0d2djZsNhvmzp2LTz75ROpiqUo4HMY999yDyZMnw2azYerUqbj//vtHdZ4RGdr777+Pq666CoWFhdDpdHjttdcG/JzneWzZsgUFBQWw2WyorKzEiRMnklY+CnAS5JVXXsGmTZtw77334uDBg5g/fz6qqqrQ2toqddFU47333sPNN9+Mjz/+GDt37kQwGMSKFSvg8XikLppq7d+/H7///e8xb948qYuiSl1dXbj44othMpnwv//7v/jiiy/w61//GpmZmVIXTVUeeughPP744/jd736Ho0eP4qGHHsLDDz+Mxx57TOqiKZrH48H8+fOxbdu2QX/+8MMP49FHH8X27duxd+9epKSkoKqqCj6fLzkF5ElCLFmyhL/55puFf4fDYb6wsJDfunWrhKVSt9bWVh4A/95770ldFFXq7e3lp0+fzu/cuZO/5JJL+J/85CdSF0l17rzzTn758uVSF0P1rrzySv773//+gOe++c1v8mvWrJGoROoDgH/11VeFf3McxzudTv6Xv/yl8Fx3dzdvsVj4P/7xj0kpE43gJEAgEMCBAwdQWVkpPKfX61FZWYk9e/ZIWDJ16+npAQBkZWVJXBJ1uvnmm3HllVcOuK9JYr3++utYvHgxrr32WuTl5WHhwoV48sknpS6W6ixbtgy7du3C8ePHAQCfffYZPvjgA1x++eUSl0y9amtr4XK5BtQfDocDFRUVSWsXNXnYZqK1t7cjHA4jPz9/wPP5+fk4duyYRKVSN47jcMstt+Diiy/GnDlzpC6O6rz88ss4ePAg9u/fL3VRVO306dN4/PHHsWnTJvzHf/wH9u/fjx//+Mcwm8343ve+J3XxVOOuu+6C2+1GeXk5DAYDwuEwHnjgAaxZs0bqoqmWy+UCgEHbRfYzsVGAQxTp5ptvxuHDh/HBBx9IXRTVaWxsxE9+8hPs3LkTVqtV6uKoGsdxWLx4MR588EEAwMKFC3H48GFs376dApwE+tOf/oQXX3wRL730EmbPno3q6mrccsstKCwspN+zitEUVQLk5OTAYDCgpaVlwPMtLS1wOp0SlUq9Nm7ciDfffBPvvvsuioqKpC6O6hw4cACtra248MILYTQaYTQa8d577+HRRx+F0WhEOByWuoiqUVBQgFmzZg14bubMmWhoaJCoROp0++2346677sLq1asxd+5cfPe738Wtt96KrVu3Sl001WJtn5TtIgU4CWA2m7Fo0SLs2rVLeI7jOOzatQtLly6VsGTqwvM8Nm7ciFdffRXvvPMOJk+eLHWRVOmyyy7DoUOHUF1dLTwWL16MNWvWoLq6GgaDQeoiqsbFF1983lYHx48fR2lpqUQlUiev1wu9fmBzZzAYwHGcRCVSv8mTJ8PpdA5oF91uN/bu3Zu0dpGmqBJk06ZN+N73vofFixdjyZIl+O1vfwuPx4N169ZJXTTVuPnmm/HSSy/hr3/9K9LS0oR5XIfDAZvNJnHp1CMtLe28vKaUlBRkZ2dTvlOC3XrrrVi2bBkefPBBfPvb38a+ffvwxBNP4IknnpC6aKpy1VVX4YEHHkBJSQlmz56NTz/9FI888gi+//3vS100Revr68PJkyeFf9fW1qK6uhpZWVkoKSnBLbfcgp///OeYPn06Jk+ejHvuuQeFhYVYtWpVcgqYlLVaGvHYY4/xJSUlvNls5pcsWcJ//PHHUhdJVQAM+nj22WelLprq0TJx8bzxxhv8nDlzeIvFwpeXl/NPPPGE1EVSHbfbzf/kJz/hS0pKeKvVyk+ZMoX/z//8T97v90tdNEV79913B62Tv/e97/E8H1kqfs899/D5+fm8xWLhL7vsMr6mpiZp5dPxPG3lSAghhBB1oRwcQgghhKgOBTiEEEIIUR0KcAghhBCiOhTgEEIIIUR1KMAhhBBCiOpQgEMIIYQQ1aEAhxBCCCGqQwEOIYQQQlSHAhxCCCGEqA4FOIQQQghRHQpwCCGEEKI6FOAQQgghRHX+PyzftjdAlFJmAAAAAElFTkSuQmCC\n",
|
||
"text/plain": [
|
||
"<Figure size 640x480 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"import jax.numpy as jnp\n",
|
||
"\n",
|
||
"x_jnp = jnp.linspace(0, 10, 1000)\n",
|
||
"y_jnp = 2 * jnp.sin(x_jnp) * jnp.cos(x_jnp)\n",
|
||
"plt.plot(x_jnp, y_jnp);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "kTZcsCJiuPG8"
|
||
},
|
||
"source": [
|
||
"The code blocks are identical aside from replacing `np` with `jnp`, and the results are the same. As we can see, JAX arrays can often be used directly in place of NumPy arrays for things like plotting.\n",
|
||
"\n",
|
||
"The arrays themselves are implemented as different Python types:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {
|
||
"id": "PjFFunI7xNe8",
|
||
"outputId": "d3b0007e-7997-45c0-d4b8-9f5699cedcbc"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"numpy.ndarray"
|
||
]
|
||
},
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"type(x_np)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {
|
||
"id": "kpv5K7QYxQnX",
|
||
"outputId": "ba68a1de-f938-477d-9942-83a839aeca09"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"jaxlib.xla_extension.ArrayImpl"
|
||
]
|
||
},
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"type(x_jnp)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "Mx94Ri7euEZm"
|
||
},
|
||
"source": [
|
||
"Python's [duck-typing](https://en.wikipedia.org/wiki/Duck_typing) allows JAX arrays and NumPy arrays to be used interchangeably in many places.\n",
|
||
"\n",
|
||
"However, there is one important difference between JAX and NumPy arrays: JAX arrays are immutable, meaning that once created their contents cannot be changed.\n",
|
||
"\n",
|
||
"Here is an example of mutating an array in NumPy:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {
|
||
"id": "fzp-y1ZVyGD4",
|
||
"outputId": "6eb76bf8-0edd-43a5-b2be-85a79fb23190"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"[10 1 2 3 4 5 6 7 8 9]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# NumPy: mutable arrays\n",
|
||
"x = np.arange(10)\n",
|
||
"x[0] = 10\n",
|
||
"print(x)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "nQ-De0xcJ1lT"
|
||
},
|
||
"source": [
|
||
"The equivalent in JAX results in an error, as JAX arrays are immutable:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {
|
||
"id": "l2AP0QERb0P7",
|
||
"outputId": "528a8e5f-538f-4739-fe95-1c3605ba8c8a"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Exception reporting mode: Minimal\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"%xmode minimal"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {
|
||
"id": "pCPX0JR-yM4i",
|
||
"outputId": "c7bf4afd-8b7f-4dac-d065-8189679861d6",
|
||
"tags": [
|
||
"raises-exception"
|
||
]
|
||
},
|
||
"outputs": [
|
||
{
|
||
"ename": "TypeError",
|
||
"evalue": "ignored",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
""
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# JAX: immutable arrays\n",
|
||
"x = jnp.arange(10)\n",
|
||
"x[0] = 10"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "yRYF0YgO3F4H"
|
||
},
|
||
"source": [
|
||
"For updating individual elements, JAX provides an [indexed update syntax](https://jax.readthedocs.io/en/latest/jax.ops.html#indexed-update-operators) that returns an updated copy:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {
|
||
"id": "8zqPEAeP3UK5",
|
||
"outputId": "20a40c26-3419-4e60-bd2c-83ad30bd7650"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"[0 1 2 3 4 5 6 7 8 9]\n",
|
||
"[10 1 2 3 4 5 6 7 8 9]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"y = x.at[0].set(10)\n",
|
||
"print(x)\n",
|
||
"print(y)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "886BGDPeyXCu"
|
||
},
|
||
"source": [
|
||
"## NumPy, lax & XLA: JAX API layering\n",
|
||
"\n",
|
||
"**Key concepts:**\n",
|
||
"\n",
|
||
"- `jax.numpy` is a high-level wrapper that provides a familiar interface.\n",
|
||
"- `jax.lax` is a lower-level API that is stricter and often more powerful.\n",
|
||
"- All JAX operations are implemented in terms of operations in [XLA](https://www.tensorflow.org/xla/) – the Accelerated Linear Algebra compiler."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "BjE4m2sZy4hh"
|
||
},
|
||
"source": [
|
||
"If you look at the source of `jax.numpy`, you'll see that all the operations are eventually expressed in terms of functions defined in `jax.lax`. You can think of `jax.lax` as a stricter, but often more powerful, API for working with multi-dimensional arrays.\n",
|
||
"\n",
|
||
"For example, while `jax.numpy` will implicitly promote arguments to allow operations between mixed data types, `jax.lax` will not:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {
|
||
"id": "c6EFPcj12mw0",
|
||
"outputId": "827d09eb-c8aa-43bc-b471-0a6c9c4f6601"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array(2., dtype=float32, weak_type=True)"
|
||
]
|
||
},
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"import jax.numpy as jnp\n",
|
||
"jnp.add(1, 1.0) # jax.numpy API implicitly promotes mixed types."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {
|
||
"id": "0VkqlcXL2qSp",
|
||
"outputId": "7e1e9233-2fe1-46a8-8eb1-1d1dbc54b58c",
|
||
"tags": [
|
||
"raises-exception"
|
||
]
|
||
},
|
||
"outputs": [
|
||
{
|
||
"ename": "TypeError",
|
||
"evalue": "ignored",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[0;31mTypeError\u001b[0m\u001b[0;31m:\u001b[0m lax.add requires arguments to have the same dtypes, got int32, float32. (Tip: jnp.add is a similar function that does automatic type promotion on inputs).\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from jax import lax\n",
|
||
"lax.add(1, 1.0) # jax.lax API requires explicit type promotion."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "aC9TkXaTEu7A"
|
||
},
|
||
"source": [
|
||
"If using `jax.lax` directly, you'll have to do type promotion explicitly in such cases:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {
|
||
"id": "3PNQlieT81mi",
|
||
"outputId": "4bd2b6f3-d2d1-44cb-f8ee-18976ae40239"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array(2., dtype=float32)"
|
||
]
|
||
},
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"lax.add(jnp.float32(1), 1.0)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "M3HDuM4x2eTL"
|
||
},
|
||
"source": [
|
||
"Along with this strictness, `jax.lax` also provides efficient APIs for some more general operations than are supported by NumPy.\n",
|
||
"\n",
|
||
"For example, consider a 1D convolution, which can be expressed in NumPy this way:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {
|
||
"id": "Bv-7XexyzVCN",
|
||
"outputId": "d570f64a-ca61-456f-8cab-6cd643cb8ea1"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array([1., 3., 4., 4., 4., 4., 4., 4., 4., 4., 3., 1.], dtype=float32)"
|
||
]
|
||
},
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"x = jnp.array([1, 2, 1])\n",
|
||
"y = jnp.ones(10)\n",
|
||
"jnp.convolve(x, y)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "0GPqgT7S0q8r"
|
||
},
|
||
"source": [
|
||
"Under the hood, this NumPy operation is translated to a much more general convolution implemented by [`lax.conv_general_dilated`](https://jax.readthedocs.io/en/latest/_autosummary/jax.lax.conv_general_dilated.html):"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {
|
||
"id": "pi4f6ikjzc3l",
|
||
"outputId": "0bb56ae2-7837-4c04-ff8b-6cbc0565b7d7"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array([1., 3., 4., 4., 4., 4., 4., 4., 4., 4., 3., 1.], dtype=float32)"
|
||
]
|
||
},
|
||
"execution_count": 13,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from jax import lax\n",
|
||
"result = lax.conv_general_dilated(\n",
|
||
" x.reshape(1, 1, 3).astype(float), # note: explicit promotion\n",
|
||
" y.reshape(1, 1, 10),\n",
|
||
" window_strides=(1,),\n",
|
||
" padding=[(len(y) - 1, len(y) - 1)]) # equivalent of padding='full' in NumPy\n",
|
||
"result[0, 0]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "7mdo6ycczlbd"
|
||
},
|
||
"source": [
|
||
"This is a batched convolution operation designed to be efficient for the types of convolutions often used in deep neural nets. It requires much more boilerplate, but is far more flexible and scalable than the convolution provided by NumPy (See [Convolutions in JAX](https://jax.readthedocs.io/en/latest/notebooks/convolutions.html) for more detail on JAX convolutions).\n",
|
||
"\n",
|
||
"At their heart, all `jax.lax` operations are Python wrappers for operations in XLA; here, for example, the convolution implementation is provided by [XLA:ConvWithGeneralPadding](https://www.tensorflow.org/xla/operation_semantics#convwithgeneralpadding_convolution).\n",
|
||
"Every JAX operation is eventually expressed in terms of these fundamental XLA operations, which is what enables just-in-time (JIT) compilation."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "NJfWa2PktD5_"
|
||
},
|
||
"source": [
|
||
"## To JIT or not to JIT\n",
|
||
"\n",
|
||
"**Key concepts:**\n",
|
||
"\n",
|
||
"- By default JAX executes operations one at a time, in sequence.\n",
|
||
"- Using a just-in-time (JIT) compilation decorator, sequences of operations can be optimized together and run at once.\n",
|
||
"- Not all JAX code can be JIT compiled, as it requires array shapes to be static & known at compile time.\n",
|
||
"\n",
|
||
"The fact that all JAX operations are expressed in terms of XLA allows JAX to use the XLA compiler to execute blocks of code very efficiently.\n",
|
||
"\n",
|
||
"For example, consider this function that normalizes the rows of a 2D matrix, expressed in terms of `jax.numpy` operations:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {
|
||
"id": "SQj_UKGc-7kQ"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import jax.numpy as jnp\n",
|
||
"\n",
|
||
"def norm(X):\n",
|
||
" X = X - X.mean(0)\n",
|
||
" return X / X.std(0)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "0yVo_OKSAolW"
|
||
},
|
||
"source": [
|
||
"A just-in-time compiled version of the function can be created using the `jax.jit` transform:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {
|
||
"id": "oHLwGmhZAnCY"
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"from jax import jit\n",
|
||
"norm_compiled = jit(norm)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "Q3H9ig5GA2Ms"
|
||
},
|
||
"source": [
|
||
"This function returns the same results as the original, up to standard floating-point accuracy:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"metadata": {
|
||
"id": "oz7zzyS3AwMc",
|
||
"outputId": "ed1c796c-59f8-4238-f6e2-f54330edadf0"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"True"
|
||
]
|
||
},
|
||
"execution_count": 16,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"np.random.seed(1701)\n",
|
||
"X = jnp.array(np.random.rand(10000, 10))\n",
|
||
"np.allclose(norm(X), norm_compiled(X), atol=1E-6)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "3GvisB-CA9M8"
|
||
},
|
||
"source": [
|
||
"But due to the compilation (which includes fusing of operations, avoidance of allocating temporary arrays, and a host of other tricks), execution times can be orders of magnitude faster in the JIT-compiled case (note the use of `block_until_ready()` to account for JAX's [asynchronous dispatch](https://jax.readthedocs.io/en/latest/async_dispatch.html)):"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"metadata": {
|
||
"id": "6mUB6VdDAEIY",
|
||
"outputId": "1050a69c-e713-44c1-b3eb-1ef875691978"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"815 µs ± 224 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
|
||
"656 µs ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"%timeit norm(X).block_until_ready()\n",
|
||
"%timeit norm_compiled(X).block_until_ready()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "B1eGBGn0tMba"
|
||
},
|
||
"source": [
|
||
"That said, `jax.jit` does have limitations: in particular, it requires all arrays to have static shapes. That means that some JAX operations are incompatible with JIT compilation.\n",
|
||
"\n",
|
||
"For example, this operation can be executed in op-by-op mode:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"metadata": {
|
||
"id": "YfZd9mW7CSKM",
|
||
"outputId": "6fdbfde4-7cde-447f-badf-26e1f8db288d"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array([-0.10570311, -0.59403396, -0.8680282 , -0.23489487], dtype=float32)"
|
||
]
|
||
},
|
||
"execution_count": 19,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"def get_negatives(x):\n",
|
||
" return x[x < 0]\n",
|
||
"\n",
|
||
"x = jnp.array(np.random.randn(10))\n",
|
||
"get_negatives(x)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "g6niKxoQC2mZ"
|
||
},
|
||
"source": [
|
||
"But it returns an error if you attempt to execute it in jit mode:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"metadata": {
|
||
"id": "yYWvE4rxCjPK",
|
||
"outputId": "9cf7f2d4-8f28-4265-d701-d52086cfd437",
|
||
"tags": [
|
||
"raises-exception"
|
||
]
|
||
},
|
||
"outputs": [
|
||
{
|
||
"ename": "NonConcreteBooleanIndexError",
|
||
"evalue": "ignored",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[0;31mNonConcreteBooleanIndexError\u001b[0m\u001b[0;31m:\u001b[0m Array boolean indices must be concrete; got ShapedArray(bool[10])\n\nSee https://jax.readthedocs.io/en/latest/errors.html#jax.errors.NonConcreteBooleanIndexError\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"jit(get_negatives)(x)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "vFL6DNpECfVz"
|
||
},
|
||
"source": [
|
||
"This is because the function generates an array whose shape is not known at compile time: the size of the output depends on the values of the input array, and so it is not compatible with JIT."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "BzBnKbXwXjLV"
|
||
},
|
||
"source": [
|
||
"## JIT mechanics: tracing and static variables\n",
|
||
"\n",
|
||
"**Key concepts:**\n",
|
||
"\n",
|
||
"- JIT and other JAX transforms work by *tracing* a function to determine its effect on inputs of a specific shape and type.\n",
|
||
"\n",
|
||
"- Variables that you don't want to be traced can be marked as *static*\n",
|
||
"\n",
|
||
"To use `jax.jit` effectively, it is useful to understand how it works. Let's put a few `print()` statements within a JIT-compiled function and then call the function:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"metadata": {
|
||
"id": "TfjVIVuD4gnc",
|
||
"outputId": "9f4ddcaa-8ab7-4984-afb6-47fede5314ea"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Running f():\n",
|
||
" x = Traced<ShapedArray(float32[3,4])>with<DynamicJaxprTrace(level=1/0)>\n",
|
||
" y = Traced<ShapedArray(float32[4])>with<DynamicJaxprTrace(level=1/0)>\n",
|
||
" result = Traced<ShapedArray(float32[3])>with<DynamicJaxprTrace(level=1/0)>\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array([0.25773212, 5.3623195 , 5.403243 ], dtype=float32)"
|
||
]
|
||
},
|
||
"execution_count": 21,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"@jit\n",
|
||
"def f(x, y):\n",
|
||
" print(\"Running f():\")\n",
|
||
" print(f\" x = {x}\")\n",
|
||
" print(f\" y = {y}\")\n",
|
||
" result = jnp.dot(x + 1, y + 1)\n",
|
||
" print(f\" result = {result}\")\n",
|
||
" return result\n",
|
||
"\n",
|
||
"x = np.random.randn(3, 4)\n",
|
||
"y = np.random.randn(4)\n",
|
||
"f(x, y)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "Ts1fP45A40QV"
|
||
},
|
||
"source": [
|
||
"Notice that the print statements execute, but rather than printing the data we passed to the function, though, it prints *tracer* objects that stand-in for them.\n",
|
||
"\n",
|
||
"These tracer objects are what `jax.jit` uses to extract the sequence of operations specified by the function. Basic tracers are stand-ins that encode the **shape** and **dtype** of the arrays, but are agnostic to the values. This recorded sequence of computations can then be efficiently applied within XLA to new inputs with the same shape and dtype, without having to re-execute the Python code.\n",
|
||
"\n",
|
||
"When we call the compiled function again on matching inputs, no re-compilation is required and nothing is printed because the result is computed in compiled XLA rather than in Python:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"metadata": {
|
||
"id": "xGntvzNH7skE",
|
||
"outputId": "43aaeee6-3853-4b00-fb2b-646df695204a"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array([1.4344584, 4.3004413, 7.9897013], dtype=float32)"
|
||
]
|
||
},
|
||
"execution_count": 22,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"x2 = np.random.randn(3, 4)\n",
|
||
"y2 = np.random.randn(4)\n",
|
||
"f(x2, y2)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "9EB9WkRX7fm0"
|
||
},
|
||
"source": [
|
||
"The extracted sequence of operations is encoded in a JAX expression, or *jaxpr* for short. You can view the jaxpr using the `jax.make_jaxpr` transformation:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 23,
|
||
"metadata": {
|
||
"id": "89TMp_Op5-JZ",
|
||
"outputId": "48212815-059a-4af1-de82-cd39ecac264a"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"{ lambda ; a:f32[3,4] b:f32[4]. let\n",
|
||
" c:f32[3,4] = add a 1.0\n",
|
||
" d:f32[4] = add b 1.0\n",
|
||
" e:f32[3] = dot_general[\n",
|
||
" dimension_numbers=(([1], [0]), ([], []))\n",
|
||
" preferred_element_type=float32\n",
|
||
" ] c d\n",
|
||
" in (e,) }"
|
||
]
|
||
},
|
||
"execution_count": 23,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from jax import make_jaxpr\n",
|
||
"\n",
|
||
"def f(x, y):\n",
|
||
" return jnp.dot(x + 1, y + 1)\n",
|
||
"\n",
|
||
"make_jaxpr(f)(x, y)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "0Oq9S4MZ90TL"
|
||
},
|
||
"source": [
|
||
"Note one consequence of this: because JIT compilation is done *without* information on the content of the array, control flow statements in the function cannot depend on traced values. For example, this fails:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 24,
|
||
"metadata": {
|
||
"id": "A0rFdM95-Ix_",
|
||
"outputId": "e37bf04e-6a6a-4536-e423-f082f52d5f11",
|
||
"tags": [
|
||
"raises-exception"
|
||
]
|
||
},
|
||
"outputs": [
|
||
{
|
||
"ename": "TracerBoolConversionError",
|
||
"evalue": "ignored",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[0;31mTracerBoolConversionError\u001b[0m\u001b[0;31m:\u001b[0m Attempted boolean conversion of traced array with shape bool[]..\nThe error occurred while tracing the function f at <ipython-input-24-acbedba5ce66>:1 for jit. This concrete value was not available in Python because it depends on the value of the argument neg.\nSee https://jax.readthedocs.io/en/latest/errors.html#jax.errors.TracerBoolConversionError\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"@jit\n",
|
||
"def f(x, neg):\n",
|
||
" return -x if neg else x\n",
|
||
"\n",
|
||
"f(1, True)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "DkTO9m8j-TYI"
|
||
},
|
||
"source": [
|
||
"If there are variables that you would not like to be traced, they can be marked as static for the purposes of JIT compilation:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 25,
|
||
"metadata": {
|
||
"id": "K1C7ZnVv-lbv",
|
||
"outputId": "e9d6cce3-b036-43da-ad99-887af9625ab0"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array(-1, dtype=int32, weak_type=True)"
|
||
]
|
||
},
|
||
"execution_count": 25,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from functools import partial\n",
|
||
"\n",
|
||
"@partial(jit, static_argnums=(1,))\n",
|
||
"def f(x, neg):\n",
|
||
" return -x if neg else x\n",
|
||
"\n",
|
||
"f(1, True)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "dD7p4LRsGzhx"
|
||
},
|
||
"source": [
|
||
"Note that calling a JIT-compiled function with a different static argument results in re-compilation, so the function still works as expected:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 26,
|
||
"metadata": {
|
||
"id": "sXqczBOrG7-w",
|
||
"outputId": "5fb7c278-b87e-4a6b-ef50-5e4e9c765b52"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array(1, dtype=int32, weak_type=True)"
|
||
]
|
||
},
|
||
"execution_count": 26,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"f(1, False)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "ZESlrDngGVb1"
|
||
},
|
||
"source": [
|
||
"Understanding which values and operations will be static and which will be traced is a key part of using `jax.jit` effectively."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "r-RCl_wD5lI7"
|
||
},
|
||
"source": [
|
||
"## Static vs traced operations\n",
|
||
"\n",
|
||
"**Key concepts:**\n",
|
||
"\n",
|
||
"- Just as values can be either static or traced, operations can be static or traced.\n",
|
||
"\n",
|
||
"- Static operations are evaluated at compile-time in Python; traced operations are compiled & evaluated at run-time in XLA.\n",
|
||
"\n",
|
||
"- Use `numpy` for operations that you want to be static; use `jax.numpy` for operations that you want to be traced.\n",
|
||
"\n",
|
||
"This distinction between static and traced values makes it important to think about how to keep a static value static. Consider this function:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 27,
|
||
"metadata": {
|
||
"id": "XJCQ7slcD4iU",
|
||
"outputId": "3646dea0-f6b6-48e9-9dc0-c4dec7816b7a",
|
||
"tags": [
|
||
"raises-exception"
|
||
]
|
||
},
|
||
"outputs": [
|
||
{
|
||
"ename": "TypeError",
|
||
"evalue": "ignored",
|
||
"output_type": "error",
|
||
"traceback": [
|
||
"\u001b[0;31mTypeError\u001b[0m\u001b[0;31m:\u001b[0m Shapes must be 1D sequences of concrete values of integer type, got [Traced<ShapedArray(int32[])>with<DynamicJaxprTrace(level=1/0)>].\nIf using `jit`, try using `static_argnums` or applying `jit` to smaller subfunctions.\nThe error occurred while tracing the function f at <ipython-input-27-5fa933a68063>:4 for jit. This value became a tracer due to JAX operations on these lines:\n\n operation a:i32[2] = convert_element_type[new_dtype=int32 weak_type=False] b\n from line <ipython-input-27-5fa933a68063>:6 (f)\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"import jax.numpy as jnp\n",
|
||
"from jax import jit\n",
|
||
"\n",
|
||
"@jit\n",
|
||
"def f(x):\n",
|
||
" return x.reshape(jnp.array(x.shape).prod())\n",
|
||
"\n",
|
||
"x = jnp.ones((2, 3))\n",
|
||
"f(x)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "ZO3GMGrHBZDS"
|
||
},
|
||
"source": [
|
||
"This fails with an error specifying that a tracer was found instead of a 1D sequence of concrete values of integer type. Let's add some print statements to the function to understand why this is happening:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 28,
|
||
"metadata": {
|
||
"id": "Cb4mbeVZEi_q",
|
||
"outputId": "30d8621f-34e1-4e1d-e6c4-c3e0d8769ec4"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"x = Traced<ShapedArray(float32[2,3])>with<DynamicJaxprTrace(level=1/0)>\n",
|
||
"x.shape = (2, 3)\n",
|
||
"jnp.array(x.shape).prod() = Traced<ShapedArray(int32[])>with<DynamicJaxprTrace(level=1/0)>\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"@jit\n",
|
||
"def f(x):\n",
|
||
" print(f\"x = {x}\")\n",
|
||
" print(f\"x.shape = {x.shape}\")\n",
|
||
" print(f\"jnp.array(x.shape).prod() = {jnp.array(x.shape).prod()}\")\n",
|
||
" # comment this out to avoid the error:\n",
|
||
" # return x.reshape(jnp.array(x.shape).prod())\n",
|
||
"\n",
|
||
"f(x)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "viSQPc3jEwJr"
|
||
},
|
||
"source": [
|
||
"Notice that although `x` is traced, `x.shape` is a static value. However, when we use `jnp.array` and `jnp.prod` on this static value, it becomes a traced value, at which point it cannot be used in a function like `reshape()` that requires a static input (recall: array shapes must be static).\n",
|
||
"\n",
|
||
"A useful pattern is to use `numpy` for operations that should be static (i.e. done at compile-time), and use `jax.numpy` for operations that should be traced (i.e. compiled and executed at run-time). For this function, it might look like this:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 29,
|
||
"metadata": {
|
||
"id": "GiovOOPcGJhg",
|
||
"outputId": "5363ad1b-23d9-4dd6-d9db-95a6c9de05da"
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Array([1., 1., 1., 1., 1., 1.], dtype=float32)"
|
||
]
|
||
},
|
||
"execution_count": 29,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from jax import jit\n",
|
||
"import jax.numpy as jnp\n",
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"@jit\n",
|
||
"def f(x):\n",
|
||
" return x.reshape((np.prod(x.shape),))\n",
|
||
"\n",
|
||
"f(x)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"id": "C-QZ5d1DG-dv"
|
||
},
|
||
"source": [
|
||
"For this reason, a standard convention in JAX programs is to `import numpy as np` and `import jax.numpy as jnp` so that both interfaces are available for finer control over whether operations are performed in a static matter (with `numpy`, once at compile-time) or a traced manner (with `jax.numpy`, optimized at run-time)."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"colab": {
|
||
"name": "thinking_in_jax.ipynb",
|
||
"provenance": []
|
||
},
|
||
"jupytext": {
|
||
"formats": "ipynb,md:myst"
|
||
},
|
||
"kernelspec": {
|
||
"display_name": "Python 3",
|
||
"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.7.6"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 0
|
||
}
|