diff --git a/demos/demos.ipynb b/demos/demos.ipynb
index 7c1e0cb..bc87c1f 100644
--- a/demos/demos.ipynb
+++ b/demos/demos.ipynb
@@ -66,34 +66,101 @@
},
{
"cell_type": "code",
- "execution_count": 29,
+ "execution_count": 3,
"metadata": {},
"outputs": [
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Model: \"sequential_12\"\n",
- "_________________________________________________________________\n",
- "Layer (type) Output Shape Param # \n",
- "=================================================================\n",
- "wraparound2d_12 (Wraparound2 (None, 12, 12, 1) 0 \n",
- "_________________________________________________________________\n",
- "conv2d_4 (Conv2D) (None, 10, 10, 10) 100 \n",
- "_________________________________________________________________\n",
- "reshape_12 (Reshape) (None, None, 10) 0 \n",
- "_________________________________________________________________\n",
- "dense_42 (Dense) (None, None, 10) 110 \n",
- "_________________________________________________________________\n",
- "dense_43 (Dense) (None, None, 10) 110 \n",
- "_________________________________________________________________\n",
- "dense_44 (Dense) (None, None, 2) 22 \n",
- "=================================================================\n",
- "Total params: 342\n",
- "Trainable params: 342\n",
- "Non-trainable params: 0\n",
- "_________________________________________________________________\n"
- ]
+ "data": {
+ "text/html": [
+ "
Model: \"sequential\"\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "\u001b[1mModel: \"sequential\"\u001b[0m\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+ "┃ Layer (type) ┃ Output Shape ┃ Param # ┃\n",
+ "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+ "│ wraparound2d (Wraparound2D) │ (None, 12, 12, 1) │ 0 │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ conv2d (Conv2D) │ (None, 10, 10, 10) │ 100 │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ reshape (Reshape) │ (None, 100, 10) │ 0 │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ dense (Dense) │ (None, 100, 10) │ 110 │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ dense_1 (Dense) │ (None, 100, 10) │ 110 │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ dense_2 (Dense) │ (None, 100, 2) │ 22 │\n",
+ "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+ "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n",
+ "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+ "│ wraparound2d (\u001b[38;5;33mWraparound2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m12\u001b[0m, \u001b[38;5;34m12\u001b[0m, \u001b[38;5;34m1\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ conv2d (\u001b[38;5;33mConv2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m, \u001b[38;5;34m10\u001b[0m, \u001b[38;5;34m10\u001b[0m) │ \u001b[38;5;34m100\u001b[0m │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ reshape (\u001b[38;5;33mReshape\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m10\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m10\u001b[0m) │ \u001b[38;5;34m110\u001b[0m │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ dense_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m10\u001b[0m) │ \u001b[38;5;34m110\u001b[0m │\n",
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+ "│ dense_2 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m2\u001b[0m) │ \u001b[38;5;34m22\u001b[0m │\n",
+ "└─────────────────────────────────┴────────────────────────┴───────────────┘\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " Total params: 342 (1.34 KB)\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m342\u001b[0m (1.34 KB)\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " Trainable params: 342 (1.34 KB)\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m342\u001b[0m (1.34 KB)\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ " Non-trainable params: 0 (0.00 B)\n",
+ "
\n"
+ ],
+ "text/plain": [
+ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
}
],
"source": [
@@ -107,41 +174,44 @@
"except:\n",
" pass\n",
"\n",
- "loss = lambda x, y : tf.keras.losses.categorical_crossentropy(tf.reshape(x, shape=(-1, num_classes)), \n",
- " tf.reshape(y, shape=(-1, num_classes)), \n",
- " from_logits=True)\n",
+ "@tf.keras.utils.register_keras_serializable()\n",
+ "def loss(x, y):\n",
+ " return tf.keras.losses.categorical_crossentropy(\n",
+ " tf.reshape(x, shape=(-1, num_classes)), \n",
+ " tf.reshape(y, shape=(-1, num_classes)), \n",
+ " from_logits=True\n",
+ " )\n",
+ " \n",
"model = initialize_model((wspan, hspan), layer_dims, num_classes=num_classes)\n",
"# model = initialize_model((wspan, hspan), [10, 10, 10, 10], num_classes=num_classes, totalistic=True, bc=\"periodic\")\n",
- "model.compile(optimizer=tf.keras.optimizers.Adam(lr=1e-2), loss=loss)\n",
+ "model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=1e-2), loss=loss)\n",
"\n",
"model.summary()"
]
},
{
"cell_type": "code",
- "execution_count": 26,
+ "execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- "[]"
+ "[]"
]
},
- "execution_count": 26,
+ "execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
- "image/png": "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\n",
+ "image/png": "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rVu3hvnz54dVq1bF6zU1NWH69Onh+uuvj6fXvva18TYAAKhUNhB0KIn29vbwwAMPhH/5l38Ja9eu7fLY+eefHwee2bNnh8suuyxMmjQpDB482DsPAEDRBB0Ss2PHjvCDH/wgfO973ws/+clPwksvvdTl8SjkXHDBBeHiiy/unC688MIwZsyY0NzcHM4555xQX1+fWPsBAKjSoBOVFr777rvDzp07w+TJk+P7qkRDlXryzW9+M9xxxx3hueeeiz/URpW7/uzP/qzkPwzpE91r56c//Wkcen75y1+GZ555Jhw9evSMx40aNSoOPNEUhZ/o9x/97jvmJ08jRoyIp+HDh3dOHetDhgwxbA4AIEfKFnRWrFgR5s6dG+6///4wY8aMsHTp0jjIbNiwIZx77rmn7R99uH3Tm94UlixZEv78z/88fOMb34iDzrp168IVV1xR0h+GbAxx2759e9i4cWNcpa1jHoXgPXv2hL1798aV3Eop6h0aOnToafMoBNXV1fU4j3qeoqm75UGDBsVTx/LJ2zqm6Car3W3r2N6x3N16xxRd29Td9pMf627e23J36909Fulpn+6mU/fvbb23ZQCARIJOFG6uuuqqcN9993V+cJ04cWK45ZZbwm233Xba/nPmzAmHDx8O3//+9zu3XX311WHKlClxWOrOsWPH4unkHyZ6DUEn/6LzKfo9R6GnI/hEU3QORFP0WMdyxxSdX1HPUcc8mo4fP570j8IAnRqETp339tip+/S2X1+3FfvYqcvFPFaq5+ktPBbz+r0d29/jkn6snM+blucs17FJtLWSz1nO503L6yX1mlloy0Dk5efozQ033BBuvPHGkJWgU9QV4a2trfGF5gsXLuzcFn37O2vWrLB69epuj4m2L1iwoMu26KL0b3/72z2+TtT784lPfKKYppET0fl01llnxdMll1zS7+eJgk4UfDpCczRc7tR5dD5H+3U3j26AGi1H8+6Wo16naIrWu1uOAlvH8slTtL1jOnW/6DuHkx8/eTr5sVP3i9Y7tnU3P/Xx7h7rbr+kdbQHAEiHa665JmRJUUGnY1hRdNH4yaL1p556qttjout4uts/2t6TKEidHI46enSgr6IhZk1NTd6wEugpEJ08nbpfb+s9Lfdlv562nfr4mea9Hdfbsb0t9/WxM732mZ6np/0G0rbenre35zlTeyr5nMU8diaVfs1KP2e5ji3HFxPl+rIjS23NSnvS9vNX+89Rrp/xkgF8CZ2EVNb4ja6hUHUL0sH1MwBAFtUWs3NU/Sq6aPrUO99H62PHju32mGh7MfsDAABUNOhE1aimTp0aVq1a1bktGs8frc+cObPbY6LtJ+8f+fGPf9zj/gAAABUfuhZdOzNv3rwwbdq0+N45UXnp6KLv+fPnx49HpacnTJgQFxSI3HrrreHaa68NX/jCF8J1110Xli9fHn7961+HBx54YMCNBwAAKEnQicpFR2V/Fy1aFBcUiMpEr1y5srPgwJYtW+LKWR3e8IY3xPfO+ad/+qfw8Y9/PL5haFRxra/30AEAAChW0ffRSYIbhgIAAMVkg6Ku0QEAAMgCQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMgdQQcAAMidwSEDCoVCPG9paUm6KQAAQII6MkFHRsh00Dl48GA8nzhxYtJNAQAAUpIRGhsbe3y8pnCmKJQC7e3tYceOHWHUqFGhpqYm8QQZBa6tW7eGhoaGRNtCdjhvcO7gbw5p598qsnLuRPElCjnjx48PtbW12e7RiX6A8847L6RJ9EsUdHDe4G8OaebfKpw35PVvTm89OR0UIwAAAHJH0AEAAHJH0ClSfX19WLx4cTwH5w3l5m8Ozhsqxd8b8nbuZKIYAQAAQDH06AAAALkj6AAAALkj6AAAALkj6AAAALkj6AAAALkj6BRh2bJlYdKkSWHo0KFhxowZYc2aNeX7zZBJS5YsCVdddVUYNWpUOPfcc8Pb3/72sGHDhi77HD16NNx0003h7LPPDiNHjgzvfOc7w65duxJrM+lz1113hZqamvDhD3+4c5vzhu5s3749/M3f/E3892TYsGHhta99bfj1r3/d+XhUWHXRokVh3Lhx8eOzZs0KGzdu9GZWsba2tnDHHXeEV7/61fE5ceGFF4ZPfepT8bnSwXlD5H/+53/C9ddfH8aPHx//m/Ttb387nKwv58mLL74YbrjhhtDQ0BCamprC+973vnDo0KFQKYJOH61YsSIsWLAgrhG+bt26MHny5DB79uywe/fu8v6GyJSf//zncYj51a9+FX784x+H48ePh7e+9a3h8OHDnft85CMfCd/73vfCN7/5zXj/HTt2hHe84x2Jtpv0eOyxx8KXvvSl8LrXva7LducNp9q3b1+45pprQl1dXfjRj34UnnzyyfCFL3whnHXWWZ37fO5znwv//M//HO6///7w6KOPhhEjRsT/dkXBmer02c9+Nnzxi18M9913X1i/fn28Hp0n9957b+c+zhsi0WeX6PNu9EV/d/pynkQh53e/+138mej73/9+HJ4++MEPhoqJ7qPDmU2fPr1w0003da63tbUVxo8fX1iyZIm3jx7t3r07+oqs8POf/zxe379/f6Gurq7wzW9+s3Of9evXx/usXr3aO1nlDh48WLj44osLP/7xjwvXXntt4dZbb423O2/ozsc+9rHCH/7hH/b45rS3txfGjh1buPvuuzu3RedSfX194T/+4z+8qVXquuuuK/zt3/5tl23veMc7CjfccEO87LyhO9HnlG9961ud6305T5588sn4uMcee6xznx/96EeFmpqawvbt2wuVoEenD1pbW8PatWvjLrkOtbW18frq1avLmUPJuAMHDsTz0aNHx/PoPIp6eU4+ly699NJw/vnnO5eIewOvu+66LueH84aefPe73w3Tpk0L73rXu+KhsldeeWV48MEHOx9/9tlnw86dO7ucT42NjfHQa/92Va83vOENYdWqVeHpp5+O13/zm9+EX/ziF+FP//RP43XnDX3Rl/MkmkfD1aK/Ux2i/aPP0FEPUCUMrsirZNzevXvjMa1jxozpsj1af+qppxJrF+nW3t4eX2MRDS254oor4m3RH4UhQ4bE/+Ofei5Fj1G9li9fHg+LjYauncp5Q3c2bdoUD0GKhlV//OMfj8+dv//7v4//xsybN6/zb0p3/3b5e1O9brvtttDS0hJ/yTZo0KD4882nP/3peIhRxHlDX/TlPInm0ZcwJxs8eHD85W+l/gYJOlDGb+f/7//+L/6mDHqzdevWcOutt8ZjmKNiJ9DXL1Oib0o/85nPxOtRj070NycaLx8FHejOf/7nf4avf/3r4Rvf+EZ4zWteEx5//PH4S7nognPnDXlj6FofNDc3x996nFoZK1ofO3ZsuX43ZNjNN98cX3T3s5/9LJx33nmd26PzJRoKuX///i77O5eqWzSkMSps8vrXvz7+tiuaokIV0UWe0XL0DZnzhlNFlY4uv/zyLtsuu+yysGXLlni5498n/3Zxsn/8x3+Me3Xe/e53x1X63vve98bFTqKqoc4b+qovf1+i+alFu06cOBFXYqvU52dBpw+iYQBTp06Nx7Se/E1atD5z5sxy/n7ImOh6vSjkfOtb3wo//elP4/KdJ4vOo6hC0snnUlR+Ovpg4lyqXm9+85vDE088EX+z2jFF39RHQ0k6lp03nCoaFntq+frouotXvepV8XL09yf6MHHy35toyFI0Nt7fm+p15MiR+BqJk0Vf5kafayLOG/qiL+dJNI++2I2+zOsQfTaKzrXoWp6KqEjJgxxYvnx5XEniK1/5SlxF4oMf/GChqampsHPnzqSbRorceOONhcbGxsIjjzxSeP755zunI0eOdO7zd3/3d4Xzzz+/8NOf/rTw61//ujBz5sx4gpOdXHXNeUN31qxZUxg8eHDh05/+dGHjxo2Fr3/964Xhw4cXvva1r3Xuc9ddd8X/Vn3nO98p/Pa3vy287W1vK7z61a8uvPTSS97UKjVv3rzChAkTCt///vcLzz77bOGhhx4qNDc3Fz760Y927uO8oaMS6P/+7//GUxQZ7rnnnnh58+bNfT5P/uRP/qRw5ZVXFh599NHCL37xi7iy6Hve855CpQg6Rbj33nvjD6hDhgyJy03/6le/Kt9vhkyK/hB0N/3bv/1b5z7RH4APfehDhbPOOiv+UPKXf/mXcRiC3oKO84bufO973ytcccUV8Rdxl156aeGBBx7o8nhUAvaOO+4ojBkzJt7nzW9+c2HDhg3ezCrW0tIS/22JPs8MHTq0cMEFFxRuv/32wrFjxzr3cd4Q+dnPftbtZ5ooLPf1PHnhhRfiYDNy5MhCQ0NDYf78+XGAqpSa6D+V6TsCAACoDNfoAAAAuSPoAAAAuSPoAAAAuSPoAAAAuSPoAAAAuSPoAAAAuSPoAAAAuSPoAAAAuSPoAAAAuSPoAAAAuSPoAAAAIW/+P2QoWlpJk5tCAAAAAElFTkSuQmCC",
"text/plain": [
- ""
+ ""
]
},
- "metadata": {
- "needs_background": "light"
- },
+ "metadata": {},
"output_type": "display_data"
}
],
@@ -155,7 +225,7 @@
},
{
"cell_type": "code",
- "execution_count": 27,
+ "execution_count": 5,
"metadata": {},
"outputs": [
{
@@ -164,20 +234,18 @@
"Text(0.5, 1.0, 'Observed Output')"
]
},
- "execution_count": 27,
+ "execution_count": 5,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
- "image/png": "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\n",
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAA7YAAAE7CAYAAADpSx23AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAGqxJREFUeJzt3Qm4bXP5B/B1uBkzZZ4zlaGkkJ4kKVIJJSlkqGhAigbRINIgmRqkJBUlhKQJiRIlyhSVSKISZY6M+/981/9Z59nn3H3uPfe6g/fez+d5Lvfss85ea69z97vXd/2moV6v12sAAACgqDlm9gEAAADAEyHYAgAAUJpgCwAAQGmCLQAAAKUJtgAAAJQm2AIAAFCaYAsAAEBpgi0AAAClCbYAAACUJtgCwAy26667Nk9/+tOdd2CSPvaxjzVDQ0PNv//979nuTOV15/XDeAm2s7Gvf/3rbdG4/PLLZ/ahNA888EBbvC688MKZfSjANKotY/359a9/XeIcX3fddW1d+utf/zpTj6PX6zUnnnhi8+IXv7hZeOGFm/nmm6959rOf3Rx88MHNf//73zKv75hjjmn/bcDs7tprr23e9KY3Ncsuu2wz99xzN8sss0yz4447to8zdf7zn/8073//+5tnPvOZzTzzzNM87WlPazbffPPmBz/4wRM6pd/+9rebo446aob8Wv7xj3+0NfnKK6+cIfubFU2Y2QcAXbA96KCD2r+/5CUvcVJgFpDgtdJKK030+KqrrtpUkOCXupSaNLNaVx977LFmhx12aE499dRmo402ai96Emwvuuii9thOO+205qc//Wmz5JJLPulfX4LtYost1rZWw+zqjDPOaLbffvs2eL31rW9ta2RuLh1//PHNd7/73eY73/lO89rXvnZmH2Ypf/rTn5qXvexlzR133NG8+c1vbtZbb73m7rvvbr71rW81W265ZfO+972vOeyww6Y62P7+979v3vOe9zQzItimJqcer7POOtN9f7MiwRaA6eKVr3xle4HB1PvMZz7ThtrRF2Zve9vbmu222655zWte0wbFH//4x04zPMndeOONzU477dSsvPLKzS9+8Ytm8cUXH/7eu9/97vbmVb5/9dVXt9s8mTz++OPNww8/3LaGPpk88sgjzbbbbtvcdddd7TndYIMNhr+3zz77tC3hn/3sZ9vPoje84Q0z9ViZ/nRFZlgujp761Kc2f//739uLpfw9RTcXVGk16OTOYroTplAceeSRzYorrtjMO++8zcYbb9ze1eqXloBBLbD948vyfF1xz52qrruicRUwazvwwAObOeaYozn//PNHPJ7QNtdcczVXXXVV+3WGKKQmnHLKKc0BBxzQLLXUUs3888/fbLXVVs0tt9wy0fNeeumlzSte8YpmoYUWals3U5suvvjiibZLrUuLSboBpjtgWk7e+c53thdv6TL7+te/vt1uk002Ga5L/cMlEiZzIZpjWWCBBZottthiYFfC733ve82znvWs9oIw/z/zzDPHdX4efPDBNsw+4xnPaD71qU9N9P20ROyyyy7NT37ykxHdu8eqn6m5XWvp5F5ftn31q1/dnHvuuW3LQY59zTXXbFubBo3/G6s7etfNOc+Xc/Pzn/98eF965zC7yfs5PdS+8pWvjAi1kd4MX/7yl9vhBbmhNVrG2OZm1oILLtgsuuiibRD+3//+N2Kb8847r3nRi17UDlnINVy65aZm9nvooYfa2pueM6l7yy+/fPOBD3ygfbxf3qN77bVX2+q51lprtdueffbZbUtzWkVHu/fee9s6kWvGKd1Xvk4IzTlJLU1tv/XWW8d1Tk8//fT22vODH/zgiFAbc845Z3tOcz76a+Lo+tTpPmu6Opga9cMf/rC5+eabh+tWd+06JZ9L/bV3rGvkPN/666/f/j3nt9uf4RtTRostIyTAZkxCikOCa7q4HX744c0qq6zSXvD1++Y3v9ncd999zZ577tkW16OPPrp56Utf2lxzzTVT1C0uhexLX/pS+/zpfrPNNtu0j6+99tp+O1DYPffcM9GEJ/mgzkVZfPjDH24vlBIuUzdyQXPOOec0xx13XPPxj3+8ec5znjPiZz/xiU+0P7/ffvs1t99+ezvuadNNN23HI+XmWvzsZz9rW4rXXXfd4eB8wgkntLUp3Xef//znD3f5yt/TXS1BevXVV2+DbroC5sIz41n33nvv5nOf+1x70bLGGmu0P9f9P2NeEypTLw899ND2Z1LHclF5xRVXDF/8JBi+7nWva0NhwmnGgeWiZbnllpvs+fvlL3/ZtkLkAnbChMEf1zvvvHP7+jKO7AUveMG4fzeTe33x5z//uW3heMc73tG+1uwnYThBerPNNmumRH5X73rXu9qL7Q996EPtY1PTfRoqS71LbcgNsbHel/l+wtRoCbX5XupIbmTlvZv6kGuxyI2j3IzKtVOGgSRI3nDDDSNu6qXVNcErtSV1L+/31N40Ulx//fXtTbh+qafpMZKAm+C92mqrtddpucGVwJgbkJ38bALqG9/4xine12677dacdNJJ7bCLF77whe1+c6NwvOe0q4WD5Abn1ltv3XzjG99oz8eUDIVJrcrnWEJ2jjtSw6b0c2k8cn7ye/voRz/anq/u30jOB1Ogx2zrhBNO6OWfwGWXXdZ+vcsuu7RfH3zwwSO2e+5zn9tbd911h7++6aab2u3mnXfe3q233jr8+KWXXto+vs8++ww/tvHGG7d/Rsu+VlxxxeGv77jjjvZnDzzwwGn+OoGZU1sG/Zl77rlHbHvNNdf05pprrt5uu+3Wu+uuu3rLLrtsb7311us98sgjw9tccMEF7c/me/fee+/w46eeemr7+NFHH91+/fjjj/dWW2213uabb97+vfPAAw/0Vlpppd5mm202/NjOO+/cm2OOOYbrX7/uZ0877bT2+bP/fvfdd19v4YUX7u2+++4jHr/tttt6Cy200IjH11lnnd7SSy/du/vuu4cfO/fcc9vn7a+Bgxx11FHtdmeeeeaY29x5553tNttss83wY2PV0uwvtbcz1uvrts33Tj/99OHH7rnnnva15DOhk/0MupTo/g3k86Kz1lprDfw8gNlBakDeE1tvvfUkt9tqq63a7bpa173H8ni/PfbYo338qquuar8+8sgj269zPTWWE088sa17F1100YjHjz322PZnL7744uHH8nW2vfbaa0dse84557TfO/vss0c8/qpXvaq38sorT/G+rrzyyvbrvJ5+O+yww7iuC1NjU3cn5Ygjjmif6/vf//6Y9an/s6a/Jm6xxRYDa/V4P5cG1d6xrpHzeZSfzfExdXRFZiK5O98vd43+8pe/TLRduitnRr9OWj/S0vujH/3IWQWaL37xi23XuP4/o8eCpmtuhiB89atfbVs/08KbO+uDWihzRz6tup2Mq1p66aWHa07ukKeVMXf90zKa58qfdO3LxCIZf5VWhPxJa0G68g4aAzyoa22/vI609GYCmG4f+ZNub6mBF1xwQbvdP//5z/aY0tqZVoNOWjvTgjs56RET/a95tO576QY4raWLdv8kNukCmd9BWqRvu+22ab4/mJWN5/08qfd0esf1Sw+I6OpfutvGWWed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",
"text/plain": [
- ""
+ ""
]
},
- "metadata": {
- "needs_background": "light"
- },
+ "metadata": {},
"output_type": "display_data"
}
],
@@ -214,14 +282,14 @@
},
{
"cell_type": "code",
- "execution_count": 345,
+ "execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"### Save and load a model\n",
- "model.save('path_to_my_model.h5')\n",
+ "model.save('path_to_my_model.keras')\n",
"del model\n",
- "#model = tf.keras.models.load_model('path_to_my_model.h5', custom_objects={'Wraparound2D': Wraparound2D})"
+ "model = tf.keras.models.load_model('path_to_my_model.keras')\n"
]
},
{
@@ -233,47 +301,70 @@
},
{
"cell_type": "code",
- "execution_count": 28,
+ "execution_count": 7,
"metadata": {},
"outputs": [
{
- "ename": "IndexError",
- "evalue": "index 2 is out of bounds for axis 2 with size 2",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mj\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0mlayer_im\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhstack\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mmin_max_scaler\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlayer_outs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m...\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 19\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0mpattern\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlayer_outs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mwspan\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhspan\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mj\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0mlayer_im\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhstack\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mmin_max_scaler\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlayer_outs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m...\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 19\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0mpattern\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlayer_outs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mwspan\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhspan\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mIndexError\u001b[0m: index 2 is out of bounds for axis 2 with size 2"
- ]
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'Convolutional filters')"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAzYAAAF4CAYAAACGgmx0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAPslJREFUeJzt3Ql4U9XW8PFdhrZMLZO0VApCQUCQwSrIcAUFQaYXFLnO4lVUFFAGRauIFxARR66KIA44IsNV9IIveBGhCAICggooymTLPElbWimU5n3Wfr70S0Kz06ZDstP/73kiJuuc5OTkJD3r7L3XDnM4HA4FAAAAABYrF+gNAAAAAICiIrEBAAAAYD0SGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBypi77rpLXXTRRQF57X/+858qLCxM2e7w4cPqxhtvVLVq1dLvZ9q0afkut3fvXh1/8cUXi3XfyHKyfHE+Z3GTY0yOtbIukN+3QMnvuCvo8fDee+/pdeW7E2hl8bMDbEdiAwSZN954Q/9hb9++vd/PceDAAX1ysWXLFlXasrKy9GuvXLlShapRo0apr776SiUlJakPP/xQXXfddYHeJMAvzuTb+X2V/5fkwtOePXvU8OHD1cUXX6wqV66sb5dccokaNmyY+umnn4J+70uS0rVrV/3/8vtkY8Lyv//7vwW6oAGUZRUCvQEA3H388cf6j+7333+vdu7cqRo3buxXYjNhwgT9PG3atHGLvfXWWyo3N7dEExt5beE8kXAaN26cevzxx5XtvvnmG9W/f3/1yCOPFNtzhsq+gSrV71tpWLx4sbrppptUhQoV1G233aZat26typUrp3799Vf12WefqRkzZujEp0GDBl6fY8eOHXodmwTbZyeJzfTp00luAAMSGyCIyMnBd999p08W7r//fp3kPP3008X6GhUrVlSBIidGcrPdkSNHVPXq1Yv1OUNl39ggJydHn7CGh4eX+GsF8vtWHHbt2qVuvvlmnbQsX75c1a1b1y0+depU3crsK2mJiIhQgZCZmamqVKlSJj87oCyy6/IJEOIkkalRo4bq06ePHsMh9/Nz8uRJ3R1KWmTkhKFevXrqzjvvVMeOHdNdSq644gq93D/+8Q/dtcS1e4lrv/GzZ8+qmjVr6uU8paenq8jIyLxWiTNnzqjx48erxMREFR0drU8W/va3v6kVK1a4dWu54IIL9P9Lq43ztZ3dJ/Lrey8nmZMmTVIJCQn6vci2PfHEEyo7O9ttOXm8b9++avXq1apdu3Z62xo1aqQ++OADt+XkPclrN2nSRC8j42A6d+6sli1b5nP/7969Ww0aNEjvE+lqc+WVV6ovv/zyvP7/DodDXzl1vr+CmDVrVt57lM9nw4YNbvH89o3sA/mcZZ9Wq1ZN/c///I/at29fvs8v+0WeV96zvM6bb77pdVs++ugj/TlWqlRJv1c5cU1NTXVbRlrbWrZsqbZv366uvvpqvT8uvPBC9fzzzyt/nDhxQh9Ll156qapataqKiopSvXr1Uj/++GPeMqdOndLH1cMPP3ze+vK+y5cvr6ZMmeL2PRg5cqSKj4/X+1VaN+VE2/Uqu+s4JxkL5fwM5H2J1157TbVo0UK/P/nuXX755WrOnDk+388ff/yhPw/Z3jp16uR1T3Tt1lWU75vz85cLG/K+ZJvlfY4dO/a874a8pnQT+/zzz/VnJsvKe1q6dKkqKvm8JTmYPXv2eUmNkGT8oYce0ttmkt8Ym23btqlrrrlGH4fyG/bMM894bSFZsmSJ/r2R/S3fBfmNlPVdyfPLsSXJWO/evfVy0sJUXGNsXI8lX99n57bIb0rPnj31dsfFxamJEyfq3w8nOVY8jxnX13L93ZbfHOH83QmF8YpAcePyIBBEJJG54YYb9JXkW265RXfxkD+YzkTFefInf+B/+eUXdffdd6vLLrtMJzT/+c9/9Mlf8+bN9R9PSULuu+8+vazo2LFjvlckr7/+et1CJCfCrlew5SRJTqDkpNd54vX222/r7br33ntVRkaGeuedd/Qfbek2J13e5ARctvmBBx7QzyvvRbRq1crrex4yZIh6//33dSI3ZswYtX79en3yKu9v4cKFbstK1zxZ7p577lGDBw9W7777rv6DLyfpciLnTBBkfXleSYBkuzdu3Kh++OEHde211xoLAsg+kq50cqImCZFsl5y8/vvf/9bv56qrrtJjau644w79XJJMFoScKMv+klY4ORmRk0XZN3LSY7oqLO9BkpBbb71Vb5t0gZMTOk8///yz6tGjh97/8v4lWZQT4piYmPOWnTx5snrqqafU3//+d/38R48e1Sf38t42b97s1hL1559/6vFDsq2yvOyHxx57TCcnkpQUhrxXOaYkcWzYsKHe33LMdenSRScZctInJ4Kyn+fNm6defvllncg4ffLJJ/qE0HmiKp+TrLt//369X+vXr69bO2Xc08GDB88r6CAn5qdPn9bfCTkZlQRDuhrJZy3HlCRTEpfxInIMyj73Rk705YRcXkfWi42N1Z+xa5Kfn8J83+QEX449SVhlm+V7LZ/zK6+8on777Te9vCtZTp73wQcf1Cf0r776qho4cKBKSUnRx3JRuqFJYlWUMX/5OXTokE6Y5ViVLphy4i/JgiQ5nuQ7J993+a2RxFU+e/mdkQsWcsy6Jh/yfLKcxCQBkYS1uBX0+3zu3Dn9/ZELJLKMJJryvZRtlN/owpDXki7GcoFG9gcALxwAgsLGjRvlMp5j2bJl+n5ubq6jXr16jocffthtufHjx+vlPvvss/OeQ9YRGzZs0MvMnj37vGUGDx7saNCgQd79r776Si+7aNEit+V69+7taNSoUd79nJwcR3Z2ttsyf/75pyMmJsZx99135z129OhR/XxPP/30ea8tj7n+7GzZskXfHzJkiNtyjzzyiH78m2++yXtMtlkeW7VqVd5jR44ccURERDjGjBmT91jr1q0dffr0cRTWyJEj9fN/++23eY9lZGQ4GjZs6Ljooosc586dy3tclhs2bJjP59yzZ49etlatWo4TJ07kPf7FF1+ct8+97ZsHH3zQ7TlvvfXW8/bvgAEDHJGRkY4//vgj77Ht27c7ypcv7/ace/fu1Y9NnjzZ7Tl//vlnR4UKFdwe79Kli173gw8+yHtMPv/Y2FjHwIEDfb53+bzkWHM6ffq02z507h/5/CZOnHje8bhkyRK3ZVu1aqW3yWnSpEmOKlWqOH777Te35R5//HH9HlNSUvJeQ54vKipKHy+u+vfv72jRooWjsF566SX9nJ9//nneY3/99ZejWbNm+vEVK1YU+fv24YcfOsqVK+d2PIqZM2fq9desWZP3mNwPDw937Ny5M++xH3/8UT/+2muvOfyVlpamn0OOL0/y3ZfvuvOWlZXl9VjO73hwft/Wr1+f95h8PtHR0fpx+dyc38Hq1as77r33XrfnO3TokF7W9XF5fllXjoHi4PnZFeb77NyWESNGuP0+y2+TfFayz4QcK57HjOtruf6Gy28Op22AGV3RgCBqrZEr7HIVU8iVQBmwO3fuXH3lz+nTTz/Vg3flyq8nf7omyJXn2rVr66vkrlfq5cqgvL6TXD13XmGWq8nStUiuPErXHWkN8XcwrBg9erTb49JyI1y7gQmpwuRsgRLSQtG0aVN9pdRJWhyki8rvv/9e6G2RFh650uskLQhytVy6hTi7LvlD9qN0c3JyvgfX7c5ve4S0KLiSrleu5NiQLlADBgzQrRZOcoVfrly7kiv68tlJ64u08jlv0uIgXfc8Wxzk/d9+++159+Xzl31k2m5vpJXEOQ5Dtvn48eP6+eXzcz1+unfvrltvXLthbt26VbekuG7LggUL9H6U/er6XmR9ef5Vq1a5vb60Xji7SboeK9LK6dmNyBe58i7d8qRFxUm6kUlLZnF93+T9yWfYrFkzt/cn6wvPz0ret3SNcpJWUunu589n5SStnUI+J0/SVVH2p/Pm7CZVUHJ8S0uGHE9O8jyeXcdkv0iXQ2kpdt0P8nskrUj5tZJJi3FJKsz3WboIenYZlG69X3/9dYluI1BWkdgAQUBOxCSBkaRGCghIlyu5yR9u6bIjg3adpP+49KMvLtJHXk76vvjii7y++3ICLOMBXE+0hHTNkhMm59gVORGR5CMtLc2v15ZxCnKy61n5TU605aRT4q5cT9yd5ARDTgydpIuHnAhJWVrpMvXoo48WqBytvJacZHuSk0tn3F+e2+08KXLdbm/7xvVkVXhuo3Ql++uvv3Ri4slzWUn25AK/LOt6Uio36fonRRFcybgHz2TZc38XlCRU0o1KXluSHDm5l9eVz8b1+JH3LCe30tVKuhwJSXLkmJNubK7vRRIMz/chJ/jC871I9zdP0q1OTtrl5Fq2S0oXr1mzxud7kc9GPhfPfVOQCoYF/b7J+5ME3fP9yXGd3/sryHejsKRLm7P7qyfpSidJh3SV9Ifsw4Ies0ISOs998d///ve8/SD7V47bklTQ77McyzIO0JXz8wuGeXqAUMQYGyAIyNgJ6a8vyY3cPMmJnYyhKCnSr19OVGSArlz5nz9/vr5SLC1DTnICI+NZJC7JggyYdg7mlmSrKAra0uQ65sKV62BcGSsi2yMnjnLiI+OC5IR65syZekxJIBRku0uDJBeyr+Vzzm+bPK/MF+d2P/vss3psj4wLk2IRMsZFTvykBcpzwLiMXXrhhRd0ciNX6mVMgxSOkKIVru9FxjnJYPr8OE8gnfIbuyFJq5QhlnEkkiRJa6hU+JLxac6S5YH6vsn7k8Rcxhrlx3OwfkkcY7K/pWCAtJh5co65KekTdOexIeNK5IKHJ89Kgq4tgyWlOPe1t98+11Z6AAVHYgMEAUlcJFHIrzuHXM2VQfRyYi4nZ3KlOL8TjaJ0SZNkQE5gpHuMdMWSROvJJ590W0YGjsvVR9ke1+f3LEddmNeWErJy4iJXZZ0tI0JaqaTVxTQvhomz8pTc5GqzvD8ZVG9KbOS15CTXk8zV4YyXJue+kSTN9Sq25zbKlWs5LvLreue5rBw7cvIlrReeJ/4lTY4faZGUghOu5HOW1htX0iLZtm1b/b2Qq+8yAF4KHHi+F/lsnS00/pJB69JSIjfpIiSDwKXAghQhkFYib5+NdE2Ufel6vEsra3F93+T9ScW4bt26BbT6lRSrkIsDUiDEtdtYUck+LOgxK+T3saifdWmT7690T3P9rknhB+EseOBs7ZHvgav8Woipggb4Rlc0IMCkG5EkC3JFWqozed6kT7ZU4JGqZ0K6scgJj2fFMNcrhs55Gzz/WHojVzjltRYtWqSvjMrYGc9uaM6rlK5XJaV61Nq1a92Wc1YhKshrS0lW4VnBynmVOr8KYL7I2A3PVgjpIuRZIje/bZGTN9f3I9WvpFKTnITI+J7S5Kw6JtWtXHnuK/lcZCyNtG5IAuAkXctk7I0rOWmX5aU1wvPqstz33HfFSV7X8zVlHIlUNcuPVJ6TFjd5v9Lt0bMKm4wTks/K8z06jz05hn3xfL8yhkg+Z9lO6Rrmjexv2W7nd1JIRTWpslZc3zd5f/Ia+T2n/GbIsVkapEVMvtPS0iYXHIqrRUi+b+vWrdPfOddulZ4l7mVfy1ghafHL7zORdYLZ66+/7rav5L5UTpOE1ZngyXfDc0yYtBx6KuzvOlAW0WIDBJicHEni4joQ2ZUMsJWr8vIHX05+pBuYXP2W8QZysiGljmUgvzyPtOpIdxa5yiljVOS+9JOXP4jSdSS/cQZO8txyVVxaYKQLjGsLipDESxIwKVogCYeMBZLnlxNB1z740nogj8nVaLlSKa0ncgU+v3FBsq1SxlWSB/ljLeV75URHxvJIFx1nIYXCkNeWgc2yX+S1pdSz7C/XQbz5kZKzUlJYTqBlwL6sK9sh71O6KJX2rOlSPlu6YckJjoxBkXLPMtYqv1YBSVSkK5UMYpZyv3Ki7JyfxXV8kRwXMleItEZIFyLZx3J8yHuURFkKJbjOo1Kc5PiR8U/SiibvRUoXyzHtOQbBScoty0m1bJcMBvcsiy3fAznm5XmdJb/lZF+eVz5veX+eLUGepHundG/q1KmTLtwhyaCceMrx7Rxf4q30riwnn4+Ue5bWF+c4oIJeWff1fZPETrqoDR06VA+Ql22U7knSgiiPS0InhTtKmoyDka6A8l6l5VDGP8n3Vk7S5biRmHw3CjuuRT5bSeqkHLLsQ2e5ZznRdz1mJamR0s6yP6S0vXTjk99DSeJlfJ/sF9fkIZjI8SDfS/mNk99f6Xoo2yzzdDkLWUh3P/ktl2NBjhv5jkrXSM+xQ0KOcSG/T5LwSULkLA8O4P/xUTUNQAnr16+fLtWbmZnpdZm77rrLUbFiRcexY8f0/ePHjzuGDx/uuPDCC3XpUCkLLeVFnXFnCdJLLrlEl/F1LRvqWcLUtRRpfHy8XvaZZ57JN/7ss8/qdaVEb9u2bR2LFy/O9/m+++47R2Jiot4219LE+ZWBPXv2rGPChAm6rLK8R9mGpKQkXR7YlbxGfmWcpQSwaxlg2fZ27drpErGVKlXSJXiljPGZM2ccvuzatctx44036nXlM5HnkffoqbDlnl944YV8n8O1ZHN++0ZKCD/00EO6vKyUNpZjJTU1Nd9y2snJyXn7XMoGS1ng/J5TfPrpp47OnTvr55Sb7CN5Pzt27MhbRvZpfqWQvR0/BSn3LGW569atqz+XTp06OdauXXve5+dZAlm2X46n/EgpYDlWGjdurN937dq1HR07dnS8+OKLeZ+36TN48803HVdddZXev3JMJyQkOB599FFd5tiX3bt36+NR3ssFF1yg35vsV3mtdevW+dxfvr5vQt7D1KlT9ecg21ejRg39Gcv3xXUbvR2Pnp9BUUgp6QceeEDva/luOL9bQ4cO1aXJXRWk3LP46aef9Gcvzye/ZVLC+5133nEr9+wk5ZB79uypSzzL8vJZye+ilMl3kueX47m4eCv3XJDvs3Nb5DelR48ejsqVK+vS+LKMZ9lzKf0sJdRlGfmM77//fsfWrVvPK/csJfelfLQcb2FhYZR+BvIRJv9xJjkAAAQLaR2UFpiCjl0JNOk2N2rUKF1CWspBo+ySVkRpOcyvohyAksMYGwBA0JEqgdJtR7ogBSMZ5+JKxthIpTPpukVSAwCBwRgbAEDQkHEbMpeMVOKScTUyniUYSSEGmc9ExkLJGCgphy7jXzwHvwMASg+JDQAgaCQnJ+sCA5I0SPGG/OYuCQYyeFuSL0lkZFC/FK2QOag8q5sBAEoPY2wAAAAAWI8xNgAAAACsR2IDAAAAwHpBN8YmNzdXHThwQE+OVpBJzgAAAACEJpmZRiYyj4uL8zlZdoklNtOnT1cvvPCCOnTokJ6lWGbVbdeunc/1JKmJj48vqc0CAAAAYJnU1FRVr1690k9s5s2bp0aPHq1mzpyp2rdvryctkwoyO3bsUHXq1DGuKy01QGl56qmn2NmFNGnSJPYZEMTGjx8f6E2wct4kFN5bb73FbkOpKUiOUCKJzcsvv6zuvfdeXbJTSIIjE629++676vHHHzeuS/czlKbIyEh2OICQwu9a4YWHh5fAJwGgOBUkRyj24gFnzpxRmzZtUt27d///L1KunL6/du3a85bPzs5W6enpbjcAAAAAKIxiT2yOHTumJyuLiYlxe1zuy3gbT1OmTFHR0dF5N8bXAAAAALCu3HNSUpJKS0vLu8nAIAAAAAAojGIfY1O7dm1Vvnx5dfjwYbfH5X5sbOx5y0dEROgbAAAAAARNi40MwEtMTFTLly93m5tG7nfo0KG4Xw4AAAAASqYqmpR6Hjx4sLr88sv13DVS7jkzMzOvShoAAAAABH1ic9NNN6mjR4/qWvpSMKBNmzZq6dKl5xUUAAAAAICgTWzE8OHD9Q0AAAAAQr4qGgAAAAAUFYkNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwHokNAAAAAOtVCPQGBJsqVaoY41WrVvUaO3z4cAlsUehLSEgwxnft2qVCUUxMjDF+4sQJr7GcnBzjug6HQ5VFvXr1MsaXLFlSatsClEX79+83xrOysrzGBg0aZFx3y5YtKhTNnz/fGE9PTzfGY2NjjfG+ffv6tV2hrGvXrsb4ypUrS21bULxosQEAAABgPRIbAAAAANYjsQEAAABgPRIbAAAAANYjsQEAAABgPRIbAAAAANYjsQEAAABgPeax8ZCZmel3/JZbbjGu+8knnxTmsykzKlSo4Pc8NzbPcTNkyBBj/O233/Yau+KKK4zrfvnllyE5z01iYmKR5ql5/vnnjfGxY8eqsujFF1/0GpswYYJx3YyMDFUWVa9e3RgPCwszxv/8808Vinr27GmM79mzx2ts69atxnXbtGkTkvPcHD161Bjv1KmTMb5mzRpjfPHixV5jZXWOG1/7jHlu7EWLDQAAAADrkdgAAAAAsB6JDQAAAADrkdgAAAAAsB6JDQAAAADrkdgAAAAAsF6xJzb//Oc/dZlL11uzZs2K+2UAAAAAoGTnsWnRooX6+uuvCzxPSWmqUqWK3/M5iKFDh3qNXXfddcZ1L7vsMmP8hx9+UKHI15wpM2bMMMbr1KnjNXbjjTeqYBUTE1Ok/VK1alWvsebNmxvXnTVrVpHmewlW/fv3N8Y3btxojN9+++3GeOfOnb3GVq9erWzVp08fY7x3795eY2PGjCnSb2pWVpYKxWPt888/N8anTp1qjH/44YdeY9u2bVPBav/+/cb4E088YYxv3rzZayw8PNy4buXKla2dx2b+/PklNueKL3/88UeR1g9Fu3fv9nvuH7Fy5cpi3iIUlxLJOCSRiY2NLYmnBgAAAIDSGWPz+++/q7i4ONWoUSN12223qZSUlJJ4GQAAAAAomRab9u3bq/fee081bdpUHTx4UE2YMEH97W9/U1u3blXVqlU7b/ns7Gx9c0pPTy/uTQIAAAAQ4oo9senVq1fe/7dq1UonOg0aNND9S++5557zlp8yZYpOfgAAAAAgaMs9V69eXV188cVq586d+caTkpJUWlpa3i01NbWkNwkAAABAiCnxxObUqVNq165dqm7duvnGIyIiVFRUlNsNAAAAAALaFe2RRx5R/fr1093PDhw4oJ5++mlVvnx5dcstt6hgkJmZaYw/8MADxvjYsWO9xjIyMozrNm7cWJVFL730kjHetm1bY3zPnj3KRkOGDClSfM6cOX6VwBbz5s0zxoP5AkJiYqLX2Ouvv16k587NzfW7xLbN2rRpY4yfO3fOa2zdunXGdWvWrBmS5Z6//PLLIk0N4Ot3a+/evcpGPXv2NMZHjBhhjC9YsMBrbNy4ccZ1N23apGx19OhRv3+PfY099jV1gMwnCHfx8fFF2qe+zhURQonNvn37dBJz/PhxdcEFF+h5IeQPo/w/AAAAAFiR2MydO7e4nxIAAAAAAjvGBgAAAABKGokNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwXrFXRbNdrVq1jPGWLVt6jf3yyy/GdXfu3KlCUYsWLYo0N8j27duN8QkTJigb7d+/3xg/ceKE3/M9JCUlGdetUaOGMT5o0CAVrFJSUrzG+vbtW6R5anJycozxFStWqFD00UcfGePHjh3zGtu2bZvPEv+hqF69esb4hg0bjPFvv/22SHOqBStfvx2+/h7Ur1/fa2zz5s3GdX39jQ1m4eHhXmPJycnGdb/77jtj/MyZM0Waxwrnmz9/PrvFUrTYAAAAALAeiQ0AAAAA65HYAAAAALAeiQ0AAAAA65HYAAAAALAeiQ0AAAAA65HYAAAAALBemMPhcKggkp6erqKjowO9GSgjJk+eHOhNsM6TTz4Z6E0AYPDss8+yf4p53jHkb/r06ewalJq0tDQVFRVlXIYWGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBAAAAYD0SGwAAAADWI7EBAAAAUPYSm1WrVql+/fqpuLg4FRYWpj7//HO3uMPhUOPHj1d169ZVlSpVUt27d1e///57cW4zAAAAABQtscnMzFStW7dW06dPzzf+/PPPq1dffVXNnDlTrV+/XlWpUkX17NlTnT59urAvBQAAAAAFUkEVUq9evfQtP9JaM23aNDVu3DjVv39//dgHH3ygYmJidMvOzTffXNiXAwAAAIDSHWOzZ88edejQId39zCk6Olq1b99erV27tjhfCgAAAAD8b7ExkaRGSAuNK7nvjHnKzs7WN6f09PTi3CQAAAAAZUDAq6JNmTJFt+o4b/Hx8YHeJAAAAABlObGJjY3V/x4+fNjtcbnvjHlKSkpSaWlpebfU1NTi3CQAAAAAZUCxJjYNGzbUCczy5cvdupZJdbQOHTrku05ERISKiopyuwEAAABAiY6xOXXqlNq5c6dbwYAtW7aomjVrqvr166uRI0eqZ555RjVp0kQnOk899ZSe82bAgAGFfSkAAAAAKJnEZuPGjerqq6/Ouz969Gj97+DBg9V7772nxo4dq+e6ue+++9TJkydV586d1dKlS1VkZGRhXwoAAAAASiax6dq1q56vxpuwsDA1ceJEfQMAAACAMlEVDQAAAACKisQGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYr0KgNyDYVKlSxRivWrWq19jhw4dLYItCX0JCgjG+a9cuFYpiYmKM8RMnTniN5eTkGNd1OByqLOrVq5cxvmTJklLbFqAs2r9/vzGelZXlNTZo0CDjulu2bFGhaP78+cZ4enq6MR4bG2uM9+3b16/tCmVdu3Y1xleuXFlq24LiRYsNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwHuWePWRmZvodv+WWW4zrfvLJJ4X5bMqMChUq+F0O2uZS0EOGDDHG3377ba+xK664wrjul19+GZLloBMTE4tUzvn55583xseOHavKohdffNFrbMKECcZ1MzIyVFlUvXp1YzwsLMwY//PPP1Uo6tmzpzG+Z88er7GtW7ca123Tpk1IloM+evSoMd6pUydjfM2aNcb44sWLvcbKailoX/uMctD2osUGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYj8QGAAAAQNmbx2bVqlXqhRdeUJs2bVIHDx5UCxcuVAMGDMiL33XXXer9998/r6790qVLVTCoUqWK3/M5iKFDh3qNXXfddcZ1L7vsMmP8hx9+UKHI15wpM2bMMMbr1KnjNXbjjTeqYBUTE1Ok/VK1alWvsebNmxvXnTVrVpHmewlW/fv3N8Y3btxojN9+++3GeOfOnb3GVq9erWzVp08fY7x3795eY2PGjCnSb2pWVpYKxWPt888/N8anTp1qjH/44YdeY9u2bVPBav/+/cb4E088YYxv3rzZayw8PNy4buXKla2dx2b+/PklNueKL3/88UeR1g9Fu3fv9nvuH7Fy5cpi3iIErMVGJqhs3bq1mj59uvEEX5Ie542JKQEAAAAEVYtNr1699M0kIiJCxcbGFmW7AAAAACCwY2ykiU66DzVt2lQ98MAD6vjx416Xzc7OVunp6W43AAAAAAhoYiPd0D744AO1fPly3cc4OTlZt/CcO3cu3+WnTJmioqOj827x8fHFvUkAAAAAQlyhu6L5cvPNN+f9/6WXXqpatWqlEhISdCtOt27dzls+KSlJjR49Ou++tNiQ3AAAAAAIqnLPjRo1UrVr11Y7d+70Oh4nKirK7QYAAAAAQZXY7Nu3T4+xqVu3bkm/FAAAAIAyqtBd0U6dOuXW+rJnzx5dO75mzZr6NmHCBDVw4EBdFW3Xrl1q7NixqnHjxnoum2Ag5apNpNiBibwfbzIyMozryn4oi1566SVjvG3btsa4HGM2GjJkSJHic+bM8WtuHzFv3jxjPJhbRhMTE73GXn/99SI9d25urt9zB9msTZs2xri3MZBi3bp1xnXldz8U57H58ssvizTnma/frb179yob+fpbPmLECGN8wYIFXmPjxo0zrivz59nq6NGjfv8e+yqq5GtOtLCwMB9bV/b4GvLga5/6OleERYmNTIB39dVX5913jo8ZPHiwnmjxp59+0hN0njx5UsXFxakePXqoSZMm6S5nAAAAABAUiU3Xrl2NmexXX31V1G0CAAAAgOAaYwMAAAAAJY3EBgAAAID1SGwAAAAAWI/EBgAAAID1SGwAAAAAlL2qaKGuVq1axnjLli29xn755Rfjuq7z/4SSFi1aFGlukO3btxvjMjeSjfbv32+Mnzhxwu/5HpKSkozr1qhRwxgfNGiQClYpKSleY3379i3SPDU5OTnG+IoVK1Qo+uijj4zxY8eOeY1t27bN5yTMoahevXrG+IYNG4zxb7/9tkhzqgUrX78dvv4e1K9f32ts8+bNxnV9/Y0NZuHh4V5jycnJxnW/++47Y/zMmTNFmscK55s/fz67xVK02AAAAACwHokNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwHokNAAAAAOuFORwOhwoi6enpKjo6OtCbgTJi8uTJgd4E6zz55JOB3gQABs8++yz7p5jL8yN/06dPZ9eg1KSlpamoqCjjMrTYAAAAALAeiQ0AAAAA65HYAAAAALAeiQ0AAAAA65HYAAAAALAeiQ0AAAAA65HYAAAAALAeiQ0AAAAA65HYAAAAALAeiQ0AAAAA65HYAAAAALAeiQ0AAAAA65HYAAAAALAeiQ0AAAAA65HYAAAAALBemMPhcBR04SlTpqjPPvtM/frrr6pSpUqqY8eOaurUqapp06Z5y5w+fVqNGTNGzZ07V2VnZ6uePXuqN954Q8XExBToNdLT01V0dLR/7wZAiZs2bRp72Q8jR45kv6FUtG/fnj1dSOvXr2efoVSsWLGCPV1ImZmZqm/fviotLU1FRUUVX4tNcnKyGjZsmFq3bp1atmyZOnv2rOrRo4d+QadRo0apRYsWqQULFujlDxw4oG644YbCvgcAAAAAKLAKBV9UqaVLl7rdf++991SdOnXUpk2b1FVXXaUzqXfeeUfNmTNHXXPNNXqZ2bNnq+bNm+tk6MorryzMywEAAABAyY+xkURG1KxZU/8rCY604nTv3j1vmWbNmqn69eurtWvX5vsc0l1Nup+53gAAAACgVBKb3Nxc3We8U6dOqmXLlvqxQ4cOqfDwcFW9enW3ZWV8jcS8jduRMTXOW3x8vL+bBAAAAKCM8juxkbE2W7du1UUCiiIpKUm3/DhvqampRXo+AAAAAGVPocbYOA0fPlwtXrxYrVq1StWrVy/v8djYWHXmzBl18uRJt1abw4cP61h+IiIi9A0AAAAASqXFRipDS1KzcOFC9c0336iGDRu6xRMTE1XFihXV8uXL8x7bsWOHSklJUR06dPB7IwEAAACg2FpspPuZVDz74osvVLVq1fLGzcjYGJnXRv6955571OjRo3VBAak1PWLECJ3UUBENAAAAQFAkNjNmzND/du3a1e1xKel811136f9/5ZVXVLly5dTAgQPdJugEAAAAgKBIbKQrmi+RkZFq+vTp+gYAAAAAQT+PDQAAAAAEAxIbAAAAANYjsQEAAABgPRIbAAAAANYjsQEAAABgPRIbAAAAANYjsQEAAABgPRIbAAAAANYjsQEAAABgPRIbAAAAANYjsQEAAABgPRIbAAAAANarEOgNAICC2rNnjzF+6tQpY/yyyy4zxs+ePcuHARRBZmamMd6lSxevsUOHDhnX3bdvn9/bhdATFhZmjDdo0MBrbO/evaos2r17tzGenZ3t9/dXHDlyRAUaLTYAAAAArEdiAwAAAMB6JDYAAAAArEdiAwAAAMB6JDYAAAAArEdiAwAAAMB6JDYAAAAArMc8NiiyVq1aGeMJCQnGeHJysjF+4sQJv7YLZW/eguuuu84YX7NmjTHepEmTMjnHTa9evbzGvv76a+O6obxfTCIjI43x8PBwYzw9PV2FoqpVqxrjs2fP9ism5s+fb4yX1XluTPO1iD/++EOVxWPNNFfNTTfdZFx33rx5KhTl5uYa49u3bzfGW7ZsaYzXqVMn4HPc0GIDAAAAwHokNgAAAACsR2IDAAAAwHokNgAAAACsR2IDAAAAwHokNgAAAADKVmIzZcoUdcUVV6hq1arpkm4DBgxQO3bscFuma9euuiSr623o0KHFvd0AAAAA4N88NjLfyLBhw3Ryk5OTo5544gnVo0cPXfe6SpUqecvde++9auLEiXn3K1euXJiXgWV81YOX48SkefPmZXIem4oVKxrjZ86c8Rrr0qWLcd1Vq1YpW+3Zs8drbMmSJcZ1p02bZoy7/i7l59SpU15jERERylaTJk0yxseNG+c19tFHHxnXveOOO1QoatOmjTG+efNmY3zhwoV+H4tbtmxRwSozM9MYb9u2rTF++vRpv7/fw4cPN8Yff/xxZaNbbrnFGJ8zZ44xPnr0aGP8iy++8BrbvXu3snXesiFDhhjjL7/8stdY7969jesmJiYa45s2bVLBarfhM/V1LK1YscIY//77743x9evXB3wem0IlNkuXLnW7/9577+mWG/mAr7rqKrdEJjY2tvi2EgAAAABKaoxNWlqa/rdmzZpuj3/88ceqdu3aeobSpKQklZWVVZSXAQAAAIDia7FxlZubq0aOHKk6deqkExinW2+9VTVo0EDFxcWpn376ST322GN6HM5nn32W7/NkZ2frm1N6erq/mwQAAACgjPI7sZGxNlu3blWrV692e/y+++7L+/9LL71U1a1bV3Xr1k3t2rVLJSQk5FuQYMKECf5uBgAAAAD41xVNBvAtXrxYDzKqV6+ecdn27dvrf3fu3JlvXLqqSZc25y01NZWPBQAAAEDJtdg4HA41YsQIXe1l5cqVqmHDhj7XcVZ3kZYbb5WGbK42BAAAAMCyxEa6n0mpOCkdKHPZHDp0SD8eHR2tKlWqpLubSVzK6NWqVUuPsRk1apSumNaqVauSeg8oBabP79FHHy1Sycay6uzZs8a4dOX0RrqBhirT8fLII48Y1z127JgxLi3E/paL9XZxxgbffPONMe5art/T3LlzVVkk0xiYvP3228a45xxvnipU8LsneEBVrVrVGP/www+N8Y4dO3qNRUVFGdeVefJC0SeffGKMexZoKkwJbZGRkaFC8Vh79dVX/d4vvsZz29x7KDc316/zCrFmzZoiTR0QDMXCCvXLOmPGjHx/XGbPnq3uuusuFR4err7++ms9l4TUuo+Pj1cDBw40zpEAAAAAAKXeFc1EEhmZxBMAAAAArJnHBgAAAACCAYkNAAAAAOuR2AAAAACwHokNAAAAAOuR2AAAAACwnp2F9FHqZE4ib6TMN4rf77//XiZ36549e7zG4uLijOuuXbvWGH/zzTeN8VA9ln1Vq4yMjPQa+/7771VZVLFiRWN89erVRYrLvG82uvDCC4s0j83evXv9nrdk/PjxKhQlJCT4PS+JWL9+vTF+9OhRZaOcnBxj/KKLLjLGjx8/7jWWkpJiXPfIkSPKVtu2bfMa69KlS5HmPGrUqJEx/uuvv6pAo8UGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYj8QGAAAAgPVIbAAAAABYj8QGAAAAgPXCHA6HQwWR9PR0FR0dHejNAODFtGnT2Dd+GDlyJPsNpaJ9+/bs6ULyNRcMUFxWrFjBziykzMxM1bdvX5WWlqaioqKMy9JiAwAAAMB6JDYAAAAArEdiAwAAAMB6JDYAAAAArEdiAwAAAMB6JDYAAAAArEdiAwAAAMB6JDYAAAAArEdiAwAAAMB6JDYAAAAArEdiAwAAAMB6JDYAAAAArEdiAwAAAMB6JDYAAAAArBfmcDgcBV14xowZ+rZ37159v0WLFmr8+PGqV69e+v7p06fVmDFj1Ny5c1V2drbq2bOneuONN1RMTEyBNyg9PV1FR0erBQsWqMqVK/vznsqkPn36BHoTABikpaWxfwqpWbNm7DM/VKhQgf1WSAkJCewzP2zfvp39VkhHjhxhnxXh72hUVFTxtdjUq1dPPffcc2rTpk1q48aN6pprrlH9+/dX27Zt0/FRo0apRYsW6aQkOTlZHThwQN1www3+bj8AAAAAFEihLuv069fP7f7kyZN1C866det00vPOO++oOXPm6IRHzJ49WzVv3lzHr7zyysK8FAAAAACU/Bibc+fO6S5nmZmZqkOHDroV5+zZs6p79+5u3Qjq16+v1q5d6+/LAAAAAIBPhe6I+/PPP+tERsbTVK1aVS1cuFBdcsklasuWLSo8PFxVr17dbXkZX3Po0CGvzydjceTmOsYGAAAAAEq0xaZp06Y6iVm/fr164IEH1ODBg4s0eGzKlCm6WIDzFh8f7/dzAQAAACibCp3YSKtM48aNVWJiok5KWrdurf71r3+p2NhYdebMGXXy5Em35Q8fPqxj3iQlJekqB85bamqqf+8EAAAAQJlV5HlscnNzdVcySXQqVqyoli9fnhfbsWOHSklJ0V3XvImIiNCl21xvAAAAAFBiY2ykdUXmrJGCABkZGboC2sqVK9VXX32lu5Hdc889avTo0apmzZo6QRkxYoROaqiIBgAAACBoEhuZVOjOO+9UBw8e1IlMq1atdFJz7bXX6vgrr7yiypUrpwYOHOg2QScAAAAABE1iI/PUmERGRqrp06frGwAAAABYM8YGAAAAAAKNxAYAAACA9UhsAAAAAFiPxAYAAACA9UhsAAAAAFiPxAYAAACA9UhsAAAAAFiPxAYAAACA9UhsAAAAAFiPxAYAAACA9UhsAAAAAFiPxAYAAACA9UhsAAAAAFivQqA3INgcP37cGE9LS/Mau/jii43r5uTk+L1dAOCvlJQUY/zUqVNeY1deeaVx3fT0dBWKTL/1olw583XBGjVqlMm/B+XLlzfGIyMjvcYyMjKKtM9tdeDAAWO8SZMmxvjZs2eN8TNnzqhQFBERYYynpqb6/dx16tTxe10EVmj+SgAAAAAoU0hsAAAAAFiPxAYAAACA9UhsAAAAAFiPxAYAAACA9UhsAAAAAFiPcs+FLMHZuXNnr7HFixcb123Xrl2ZLP8JILAcDocxnp2d7TW2dOlS47rXXXddSJaD9lVauH79+kVa31RO2ua/BaZyzuLgwYNeY127djWuu3HjxpAsB+2rnPM111xjjPuaauK1114LyVLQvr4npt+9sLAw47pHjhwxxikHHbzs/BUAAAAAABckNgAAAACsR2IDAAAAwHokNgAAAACsR2IDAAAAwHokNgAAAACsR2IDAAAAoGzNYzNjxgx927t3r77fokULNX78eNWrV6+8GvTJyclu69x///1q5syZKlgcP37cGP/vf/9rjN99991eY999951x3aNHjxrjFSowrRBQlHkqzp07V6S5R1JTU638AFJSUozxNm3aGOO5ubl+v/by5cuN8csvv1wFK9NcMpdeeqlx3XXr1hnjc+bMMcbfffddr7Ht27erYFW+fHljXM4LTH799VevsWHDhhnXXb9+vTE+a9YsFawOHDjgNbZjx44izZni69zivvvu8xr77bffVLCKiIgwxn3NseVrrhqEpkKdSderV08999xzejIpmfjo/fffV/3791ebN2/O+zG799571cSJE/PWqVy5cvFvNQAAAAD4m9j069fP7f7kyZN1C45cuXImNpLIxMbGFuZpAQAAACAwY2yky8fcuXNVZmam6tChQ97jH3/8sapdu7Zq2bKlSkpKUllZWcbnyc7OVunp6W43AAAAACiMQg/q+Pnnn3Uic/r0aVW1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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
}
],
"source": [
"import tensorflow.keras.backend as K\n",
"\n",
- "inp = model.input # input placeholder\n",
- "outputs = [layer.output for layer in model.layers] # all layer outputs\n",
- "functor = K.function(inp, outputs) # evaluation function\n",
+ "_ = model(X_test)\n",
"\n",
- "layer_outs = functor([X_test, 1.])\n",
+ "layer_outputs = [layer.output for layer in model.layers]\n",
+ "activation_model = tf.keras.Model(inputs=model.inputs, outputs=layer_outputs)\n",
+ "layer_outs = activation_model(X_test, training=False)\n",
"\n",
- "\n",
- "\n",
- "# Plot activations of different neurons in different layers \n",
"all_layer_activations = list()\n",
+ "min_max_scaler = lambda x: (x - np.min(x)) / (np.max(x) - np.min(x) + 1e-8)\n",
"\n",
- "min_max_scaler = lambda x : (x - np.min(x))/(np.max(x) - np.min(x))\n",
- "# min_max_scaler = lambda x : (x - np.mean(x))\n",
+ "# Layers 1-4: conv2d, reshape, dense, dense_1\n",
"for j in range(1, 5):\n",
- " if j==1:\n",
- " layer_im = np.hstack([min_max_scaler(layer_outs[1][0][..., i]) for i in range(10)])\n",
- " else:\n",
- " pattern = np.reshape(layer_outs[j][0], (wspan, hspan, -1))\n",
- " layer_im = np.hstack([min_max_scaler(pattern[..., i]) for i in range(10)])\n",
+ " out = layer_outs[j][0].numpy()\n",
+ " out_shape = out.shape\n",
+ "\n",
+ " if len(out_shape) == 3:\n",
+ " # Conv2D: already spatial (10, 10, 10)\n",
+ " pattern = out\n",
+ " elif len(out_shape) == 2:\n",
+ " # Dense/Reshape: (100, N) -> reshape to (10, 10, N)\n",
+ " n_channels = out_shape[-1]\n",
+ " spatial = int(round(out_shape[0] ** 0.5))\n",
+ " pattern = out.reshape(spatial, spatial, n_channels)\n",
+ "\n",
+ " n_channels = pattern.shape[-1]\n",
+ " layer_im = np.hstack([min_max_scaler(pattern[..., i]) for i in range(n_channels)])\n",
" all_layer_activations.append(layer_im)\n",
"\n",
- " \n",
"plt.figure()\n",
"plt.imshow(np.vstack(all_layer_activations))\n",
"plt.title(\"Activations of hidden layers given \\\"Glider\\\" input\")\n",
@@ -282,25 +373,11 @@
"plt.imshow(np.squeeze(np.dstack(model.layers[1].weights[0].numpy())))\n",
"plt.title(\"Convolutional filters\")"
]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3",
+ "display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@@ -314,7 +391,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.6.9"
+ "version": "3.12.10"
}
},
"nbformat": 4,
diff --git a/train_ca.py b/train_ca.py
index bcef5fd..79de175 100644
--- a/train_ca.py
+++ b/train_ca.py
@@ -1,13 +1,12 @@
import tensorflow as tf
-import numpy as np
-
import collections
+
def periodic_padding(imbatch, padding=1):
- '''
- Create a periodic padding (wrap) around an image batch, to emulate
+ """
+ Create a periodic padding (wrap) around an image batch, to emulate
periodic boundary conditions. Padding occurs along the middle two axes
- '''
+ """
pad_u = imbatch[:, -padding:, :]
pad_b = imbatch[:, :padding, :]
@@ -17,37 +16,40 @@ def periodic_padding(imbatch, padding=1):
pad_r = partial_image[..., :padding, :]
padded_imbatch = tf.concat([pad_l, partial_image, pad_r], axis=2)
-
-
+
return padded_imbatch
+
+@tf.keras.utils.register_keras_serializable()
class Wraparound2D(tf.keras.layers.Layer):
"""
- Apply periodic boundary conditions on an image by padding
+ Apply periodic boundary conditions on an image by padding
along the axes
- padding : int or tuple, the amount to wrap around
+ padding : int or tuple, the amount to wrap around
"""
- def __init__(self, padding=2, **kwargs):
+ def __init__(self, padding=1, **kwargs):
super(Wraparound2D, self).__init__()
self.padding = padding
-
- def get_config(self):
+ def get_config(self):
config = super().get_config().copy()
- config.update({
- 'vocab_size': 0,
- 'num_layers': 1,
- 'units': 0,
- 'dropout': 0,
- })
+ config.update({"padding": self.padding})
return config
-
+
def call(self, inputs):
return periodic_padding(inputs, self.padding)
-
-def initialize_model(shape, layer_dims, nhood=1, num_classes=2, totalistic=False,
- nhood_type="moore", bc="periodic"):
+
+
+def initialize_model(
+ shape,
+ layer_dims,
+ nhood=1,
+ num_classes=2,
+ totalistic=False,
+ nhood_type="moore",
+ bc="periodic",
+):
"""
Given a domain size and layer specification, initialize a model that assigns
each pixel a class
@@ -56,127 +58,156 @@ def initialize_model(shape, layer_dims, nhood=1, num_classes=2, totalistic=False
num_classes : int, the number of output classes for the automaton
totalistic : bool, whether to assume that the CA is radially symmetric, making
it outer totalistic
- nhood_type : string, default "moore". The type of neighborhood to use for the
+ nhood_type : string, default "moore". The type of neighborhood to use for the
CA. Currently, the only other option, "Neumann," only works when "totalistic"
is set to True
bc : string, whether to use "periodic" or "constant" (zero padded) boundary conditions
"""
wspan, hspan = shape
- diameter = 2*nhood+1
+ diameter = 2 * nhood + 1
model = tf.keras.Sequential()
model.add(tf.keras.layers.InputLayer((wspan, hspan, 1)))
-
+
if bc == "periodic":
model.add(Wraparound2D(padding=nhood))
- conv_pad = 'valid'
+ conv_pad = "valid"
else:
- conv_pad = 'same'
-
+ conv_pad = "same"
+
if totalistic:
model.add(SymmetricConvolution(nhood, n_type=nhood_type, bc=bc))
- model.add(tf.keras.layers.Reshape(target_shape=(-1, nhood+1)))
+ model.add(tf.keras.layers.Reshape(target_shape=(-1, nhood + 1)))
else:
- model.add(tf.keras.layers.Conv2D(layer_dims[0], kernel_size=[diameter, diameter], padding=conv_pad,
- activation='relu', kernel_initializer=tf.keras.initializers.he_normal(),
- bias_initializer=tf.keras.initializers.he_normal()))
+ model.add(
+ tf.keras.layers.Conv2D(
+ layer_dims[0],
+ kernel_size=[diameter, diameter],
+ padding=conv_pad,
+ activation="relu",
+ kernel_initializer=tf.keras.initializers.he_normal(),
+ bias_initializer=tf.keras.initializers.he_normal(),
+ )
+ )
model.add(tf.keras.layers.Reshape(target_shape=(-1, layer_dims[0])))
-
+
for i in range(1, len(layer_dims)):
- model.add(tf.keras.layers.Dense(layer_dims[i], activation='relu',
- kernel_initializer=tf.keras.initializers.he_normal(),
- bias_initializer=tf.keras.initializers.he_normal()))
- model.add(tf.keras.layers.Dense(num_classes, activation='relu',
- kernel_initializer=tf.keras.initializers.he_normal(),
- bias_initializer=tf.keras.initializers.he_normal()))
- #model.add(tf.keras.layers.Reshape(target_shape=(-1, wspan, hspan)))
+ model.add(
+ tf.keras.layers.Dense(
+ layer_dims[i],
+ activation="relu",
+ kernel_initializer=tf.keras.initializers.he_normal(),
+ bias_initializer=tf.keras.initializers.he_normal(),
+ )
+ )
+ model.add(
+ tf.keras.layers.Dense(
+ num_classes,
+ activation="relu",
+ kernel_initializer=tf.keras.initializers.he_normal(),
+ bias_initializer=tf.keras.initializers.he_normal(),
+ )
+ )
+ # TODO - use softmax or no activation instead of relu?
+ # model.add(tf.keras.layers.Reshape(target_shape=(-1, wspan, hspan)))
return model
def logit_to_pred(logits, shape=None):
"""
- Given logits in the form of a network output, convert them to
+ Given logits in the form of a network output, convert them to
images
"""
-
- labels = tf.argmax(tf.nn.softmax(logits),
- axis=-1),
- if shape:
+ labels = tf.argmax(tf.nn.softmax(logits), axis=-1)
+ if shape:
out = tf.reshape(labels, shape)
return out
+
def augment_data(x, y, n=None):
"""
Generate an augmented training dataset with random reflections
and 90 degree rotations
- x, y : Image sets of shape (Samples, Width, Height, Channels)
+ x, y : Image sets of shape (Samples, Width, Height, Channels)
training images and next images
n : number of training examples
"""
n_data = x.shape[0]
-
+
if not n:
n = n_data
x_out, y_out = list(), list()
-
+
for i in range(n):
r = tf.random.uniform((1,), minval=0, maxval=n_data, dtype=tf.int32)[0]
x_r, y_r = x[r], y[r]
-
- if tf.random.uniform((1,))[0]<0.5:
+
+ if tf.random.uniform((1,))[0] < 0.5:
x_r = tf.image.flip_left_right(x_r)
y_r = tf.image.flip_left_right(y_r)
- if tf.random.uniform((1,))[0]<0.5:
+ if tf.random.uniform((1,))[0] < 0.5:
x_r = tf.image.flip_up_down(x_r)
y_r = tf.image.flip_up_down(y_r)
-
+
num_rots = tf.random.uniform((1,), minval=0, maxval=4, dtype=tf.int32)[0]
x_r = tf.image.rot90(x_r, k=num_rots)
y_r = tf.image.rot90(y_r, k=num_rots)
-
+
x_out.append(x_r), y_out.append(y_r)
return tf.stack(x_out), tf.stack(y_out)
-
-
-
+
def make_square_filters(rad):
"""
rad : the pixel radius for the filters
"""
- m = 2*rad + 1
- square_filters = tf.stack([tf.pad(tf.ones([i, i]), [[int((m-i)/2), int((m-i)/2)],
- [int((m-i)/2), int((m-i)/2)]])
- for i in range(1, m+1, 2)])
- square_filters = [square_filters[0]] + [item for item in square_filters[1:] - square_filters[:-1]]
+ m = 2 * rad + 1
+ square_filters = tf.stack(
+ [
+ tf.pad(
+ tf.ones([i, i]),
+ [
+ [int((m - i) / 2), int((m - i) / 2)],
+ [int((m - i) / 2), int((m - i) / 2)],
+ ],
+ )
+ for i in range(1, m + 1, 2)
+ ]
+ )
+ square_filters = [square_filters[0]] + [
+ item for item in square_filters[1:] - square_filters[:-1]
+ ]
square_filters = tf.stack(square_filters)[..., tf.newaxis]
-
+
return square_filters
+
def make_circular_filters(rad):
"""
rad : the pixel radius for the filters
"""
-
- m = 2*rad + 1
- qq = tf.range(m) - int((m-1)/2)
- pp = tf.sqrt(tf.cast(qq[..., None]**2 + qq[None, ...]**2, tf.float32))
+ m = 2 * rad + 1
+
+ qq = tf.range(m) - int((m - 1) / 2)
+ pp = tf.sqrt(tf.cast(qq[..., None] ** 2 + qq[None, ...] ** 2, tf.float32))
- val_range = tf.cast(tf.range((m+1)/2), tf.float32)
- circ_filters = make_square_filters(rad)*val_range[..., None, None, None]
- rr = circ_filters*(1/pp)[None, ..., None]
+ val_range = tf.cast(tf.range((m + 1) / 2), tf.float32)
+ circ_filters = make_square_filters(rad) * val_range[..., None, None, None]
+ rr = circ_filters * (1 / pp)[None, ..., None]
rr = tf.where(tf.math.is_nan(rr), tf.zeros_like(rr), rr)
return tf.stack([make_square_filters(rad)[0]] + [item for item in rr][1:])
+
+@tf.keras.utils.register_keras_serializable()
class SymmetricConvolution(tf.keras.layers.Layer):
"""
- A non-trainable convolutional layer that extracts the
+ A non-trainable convolutional layer that extracts the
summed values in the neighborhood of each pixel. No activation
is applied because this feature extractor does not change during training
parametrized by the radius
r : int, the max neighborhood size
nhood_type : "moore" (default) uses the Moore neighborhood, while "neumann"
- uses the generalized von Neumann neighborhood, which is similar
+ uses the generalized von Neumann neighborhood, which is similar
to a circle at large neighborhood radii
bc : "periodic" or "constant"
TODO : implement the "hard" von Neumann neighborhood
@@ -184,9 +215,9 @@ class SymmetricConvolution(tf.keras.layers.Layer):
def __init__(self, r, nhood_type="moore", bc="periodic", **kwargs):
super(SymmetricConvolution, self).__init__()
-
+
self.r = r
-
+
if nhood_type == "moore":
filters = make_square_filters(r)
elif nhood_type == "neumann":
@@ -195,20 +226,25 @@ def __init__(self, r, nhood_type="moore", bc="periodic", **kwargs):
filters = make_square_filters(r)
warnings.warn("Neighborhood specification not recognized.")
self.filters = tf.squeeze(tf.transpose(filters))[..., None, :]
-
+
if bc == "periodic":
- self.pad_type="VALID"
+ self.pad_type = "VALID"
else:
- self.pad_type="SAME"
-
+ self.pad_type = "SAME"
+
+ self.nhood_type = nhood_type
+ self.bc = bc
+
def get_config(self):
config = super().get_config().copy()
- config.update({
- 'num_layers': 1,
- 'units': 0,
- 'dropout': 0,
- })
+ config.update(
+ {
+ "r": self.r,
+ "nhood_type": self.nhood_type, # needs to be saved in __init__ too
+ "bc": self.bc, # needs to be saved in __init__ too
+ }
+ )
return config
-
+
def call(self, inputs):
- return tf.nn.convolution(inputs, self.filters, padding=self.pad_type)
\ No newline at end of file
+ return tf.nn.convolution(inputs, self.filters, padding=self.pad_type)