{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "execution": {}, "id": "view-in-github" }, "source": [ "\"Open   \"Open" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "

\n", "Behavior classification starter kit 🐁🐀\n", "

\n", "This code is adapted from a notebook created by Dipam Chakraborty at AIcrowd for the Multi-Agent Behavior Challenge.\n" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Import necessary modules and packages 📚\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "import os\n", "import json\n", "import numpy as np\n", "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Download the dataset 📲\n", "\n", "The CalMS21 dataset is hosted by [Caltech](https://data.caltech.edu/records/1991). For now, we'll focus on the Task 1 data, which can be downloaded as follows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "execution": {} }, "outputs": [], "source": [ "# @title Download and unzip the data\n", "import os, requests, zipfile\n", "\n", "fname = 'task1_classic_classification.zip'\n", "url = \"https://data.caltech.edu/records/s0vdx-0k302/files/task1_classic_classification.zip?download=1\"\n", "\n", "if not os.path.isfile(fname):\n", " try:\n", " r = requests.get(url)\n", " except requests.ConnectionError:\n", " print(\"!!! Failed to download data !!!\")\n", " else:\n", " if r.status_code != requests.codes.ok:\n", " print(\"!!! Failed to download data !!!\")\n", " else:\n", " with open(fname, \"wb\") as fid:\n", " fid.write(r.content)\n", "else:\n", " print('Data have already been downloaded!!!')\n", "\n", "if not os.path.exists('task1_classic_classification'):\n", " # Unzip the file\n", " with zipfile.ZipFile(fname, 'r') as zip_ref:\n", " zip_ref.extractall('.')\n", "\n", "\n", "# Download the script\n", "fname = 'calms21_convert_to_npy.py'\n", "url = \"https://data.caltech.edu/records/s0vdx-0k302/files/calms21_convert_to_npy.py?download=1\"\n", "\n", "if not os.path.isfile(fname):\n", " try:\n", " r = requests.get(url)\n", " except requests.ConnectionError:\n", " print(\"!!! Failed to download data !!!\")\n", " else:\n", " if r.status_code != requests.codes.ok:\n", " print(\"!!! Failed to download data !!!\")\n", " else:\n", " with open(fname, \"wb\") as fid:\n", " fid.write(r.content)" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "The dataset files are stored as json files. For ease of handling, we'll first convert them to .npy files using the script we just downloaded, `calms21_convert_to_npy.py`. The output of this script is a pair of files, `calms21_task1_train.npy` and `calms21_task1_test.npy`.\n", "\n", "If you include the optional `parse_treba` flag, the script will create files `calms21_task1_train_features.npy` and `calms21_task1_test_features.npy`, which contain 32 features created using Task Programming.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Saving ./calms21_task1_test\n", "Saving ./calms21_task1_train\n" ] } ], "source": [ "!python calms21_convert_to_npy.py --input_directory '.' --output_directory '.'" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "#Load the data 💾\n", "The following loader function can be used to unpack the `.npy` files containing your train and test sets." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "def load_task1_data(data_path):\n", " \"\"\"\n", " Load data for task 1:\n", " The vocaubulary tells you how to map behavior names to class ids;\n", " it is the same for all sequences in this dataset.\n", " \"\"\"\n", " data_dict = np.load(data_path, allow_pickle=True).item()\n", " dataset = data_dict['annotator-id_0']\n", " # Get any sequence key.\n", " sequence_id = list(data_dict['annotator-id_0'].keys())[0]\n", " vocabulary = data_dict['annotator-id_0'][sequence_id]['metadata']['vocab']\n", " return dataset, vocabulary" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "training_data, vocab = load_task1_data('./calms21_task1_train.npy')\n", "test_data, _ = load_task1_data('./calms21_task1_test.npy')" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## Dataset Specifications\n", "\n", "`training_data` and `test_data` are both dictionaries with a key for each Sequence in the dataset, where a Sequence is a single resident-intruder assay. Each Sequence contains the following fields:\n", "\n", "\n", "\n", "The 'taskprog_features' file contains the additional field:\n", "\n", "\n", "\n", "NOTE: for all keypoints, mouse 0 is the resident (black) mouse and mouse 1 is the intruder (white) mouse. There are 7 tracked body parts, ordered (nose, left ear, right ear, neck, left hip, right hip, tail base)." ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## What does the data look like? 🔍\n", "\n", "### Data overview\n", "\n", "As described above, our dataset consists of train and test sets, which are both dictionaries of Sequences, and an accompanying vocabulary telling us which behavior is which:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sample dataset keys: ['task1/train/mouse001_task1_annotator1', 'task1/train/mouse002_task1_annotator1', 'task1/train/mouse003_task1_annotator1']\n", "Vocabulary: {'attack': 0, 'investigation': 1, 'mount': 2, 'other': 3}\n", "Number of train Sequences: 70\n", "Number of test Sequences: 19\n" ] } ], "source": [ "print(\"Sample dataset keys: \", list(training_data.keys())[:3])\n", "print(\"Vocabulary: \", vocab)\n", "print(\"Number of train Sequences: \", len(training_data))\n", "print(\"Number of test Sequences: \", len(test_data))" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "### Sample overview\n", "Next let's take a look at one example Sequence:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Name of our sample sequence: task1/train/mouse001_task1_annotator1\n", "Sequence keys: dict_keys(['keypoints', 'scores', 'annotations', 'metadata'])\n", "Sequence metadata: {'annotator-id': 0, 'vocab': {'attack': 0, 'investigation': 1, 'mount': 2, 'other': 3}}\n", "Number of Frames in Sequence \"task1/train/mouse001_task1_annotator1\": 21364\n", "Keypoints data shape of Sequence \"task1/train/mouse001_task1_annotator1\": (21364, 2, 2, 7)\n" ] } ], "source": [ "sequence_names = list(training_data.keys())\n", "sample_sequence_key = sequence_names[0]\n", "single_sequence = training_data[sample_sequence_key]\n", "print(\"Name of our sample sequence: \", sample_sequence_key)\n", "print(\"Sequence keys: \", single_sequence.keys())\n", "print(\"Sequence metadata: \", single_sequence['metadata'])\n", "print(f\"Number of Frames in Sequence \\\"{sample_sequence_key}\\\": \", len(single_sequence['annotations']))\n", "print(f\"Keypoints data shape of Sequence \\\"{sample_sequence_key}\\\": \", single_sequence['keypoints'].shape)" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Helper functions for visualization 💁\n", "\n", "\n", "This cell contains some helper functions that we'll use to create an animation of the mouse movements. You can ignore the contents, but be sure to run it or the next section won't work." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "from matplotlib import animation\n", "from matplotlib import colors\n", "from matplotlib import rc\n", "import matplotlib.patches as mpatches\n", "\n", "rc('animation', html='jshtml')\n", "\n", "# Note: Image processing may be slow if too many frames are animated.\n", "\n", "# Plotting constants\n", "FRAME_WIDTH_TOP = 1024\n", "FRAME_HEIGHT_TOP = 570\n", "\n", "RESIDENT_COLOR = 'lawngreen'\n", "INTRUDER_COLOR = 'skyblue'\n", "\n", "PLOT_MOUSE_START_END = [(0, 1), (0, 2), (1, 3), (2, 3), (3, 4),\n", " (3, 5), (4, 6), (5, 6), (1, 2)]\n", "class_to_color = {'other': 'white', 'attack' : 'red', 'mount' : 'green',\n", " 'investigation': 'orange'}\n", "class_to_number = {s: i for i, s in enumerate(vocab)}\n", "number_to_class = {i: s for i, s in enumerate(vocab)}\n", "\n", "\n", "def num_to_text(anno_list):\n", " return np.vectorize(number_to_class.get)(anno_list)\n", "\n", "\n", "def set_figax():\n", " fig = plt.figure(figsize=(6, 4))\n", "\n", " img = np.zeros((FRAME_HEIGHT_TOP, FRAME_WIDTH_TOP, 3))\n", "\n", " ax = fig.add_subplot(111)\n", " ax.imshow(img)\n", "\n", " ax.get_xaxis().set_visible(False)\n", " ax.get_yaxis().set_visible(False)\n", "\n", " return fig, ax\n", "\n", "\n", "def plot_mouse(ax, pose, color):\n", " # Draw each keypoint\n", " for j in range(7):\n", " ax.plot(pose[j, 0], pose[j, 1], 'o', color=color, markersize=5)\n", "\n", " # Draw a line for each point pair to form the shape of the mouse\n", "\n", " for pair in PLOT_MOUSE_START_END:\n", " line_to_plot = pose[pair, :]\n", " ax.plot(line_to_plot[:, 0], line_to_plot[\n", " :, 1], color=color, linewidth=1)\n", "\n", "\n", "def animate_pose_sequence(video_name, keypoint_sequence, start_frame = 0, stop_frame = 100,\n", " annotation_sequence = None):\n", " # Returns the animation of the keypoint sequence between start frame\n", " # and stop frame. Optionally can display annotations.\n", " seq = keypoint_sequence.transpose((0,1,3,2))\n", "\n", " image_list = []\n", "\n", " counter = 0\n", " for j in range(start_frame, stop_frame):\n", " if counter%20 == 0:\n", " print(\"Processing frame \", j)\n", " fig, ax = set_figax()\n", " plot_mouse(ax, seq[j, 0, :, :], color=RESIDENT_COLOR)\n", " plot_mouse(ax, seq[j, 1, :, :], color=INTRUDER_COLOR)\n", "\n", " if annotation_sequence is not None:\n", " annot = annotation_sequence[j]\n", " annot = number_to_class[annot]\n", " plt.text(50, -20, annot, fontsize=16,\n", " bbox=dict(facecolor=class_to_color[annot], alpha=0.5))\n", "\n", " ax.set_title(\n", " video_name + '\\n frame {:03d}.png'.format(j))\n", "\n", " ax.axis('off')\n", " fig.tight_layout(pad=0)\n", " ax.margins(0)\n", "\n", " fig.canvas.draw()\n", " image_from_plot = np.frombuffer(fig.canvas.tostring_rgb(),\n", " dtype=np.uint8)\n", " image_from_plot = image_from_plot.reshape(\n", " fig.canvas.get_width_height()[::-1] + (3,))\n", "\n", " image_list.append(image_from_plot)\n", "\n", " plt.close()\n", " counter = counter + 1\n", "\n", " # Plot animation.\n", " fig = plt.figure()\n", " plt.axis('off')\n", " im = plt.imshow(image_list[0])\n", "\n", " def animate(k):\n", " im.set_array(image_list[k])\n", " return im,\n", " ani = animation.FuncAnimation(fig, animate, frames=len(image_list), blit=True)\n", " return ani\n", "\n", "\n", "def plot_behavior_raster(annotation_sequence, start_frame=0,\n", " stop_frame=100,\n", " title=\"Behavior Labels\"):\n", " # Plot annotations as a behavior raster\n", "\n", " # Map annotations to a number.\n", " annotation_num = []\n", " for item in annotation_sequence[start_frame:stop_frame]:\n", " annotation_num.append(class_to_number[item])\n", "\n", " all_classes = list(set(annotation_sequence[start_frame:stop_frame]))\n", "\n", " cmap = colors.ListedColormap(['red', 'orange', 'green', 'white'])\n", " bounds=[-0.5, 0.5, 1.5, 2.5, 3.5]\n", " norm = colors.BoundaryNorm(bounds, cmap.N)\n", "\n", " height = 200\n", " arr_to_plot = np.repeat(np.array(annotation_num)[:, np.newaxis].transpose(),\n", " height, axis = 0)\n", "\n", " fig, ax = plt.subplots(figsize = (16, 3))\n", " ax.imshow(arr_to_plot, interpolation='none',cmap=cmap, norm=norm)\n", "\n", " ax.set_yticks([])\n", " ax.set_xlabel('Frame Number')\n", " plt.title(title)\n", "\n", " legend_patches = []\n", " for item in all_classes:\n", " legend_patches.append(mpatches.Patch(color=class_to_color[item], label=item))\n", "\n", " plt.legend(handles=legend_patches,loc='center left', bbox_to_anchor=(1, 0.5))\n", "\n", " plt.tight_layout()" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Visualize the animals' movements 🎥\n", "\n", "Let's make some gifs of our sample sequence to get a sense of what the raw data looks like! You can change the values of `start_frame` and `stop_frame` to look around." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Processing frame 5000\n", "Processing frame 5020\n", "Processing frame 5040\n", "Processing frame 5060\n", "Processing frame 5080\n" ] }, { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "
\n", " \n", "
\n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "keypoint_sequence = single_sequence['keypoints']\n", "annotation_sequence = single_sequence['annotations']\n", "\n", "ani = animate_pose_sequence(sample_sequence_key,\n", " keypoint_sequence,\n", " start_frame=5000,\n", " stop_frame=5100,\n", " annotation_sequence=annotation_sequence)\n", "\n", "# Display the animaion on colab\n", "ani" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "### We can also look at a **behavior raster**, which shows what behavior was annotated on each frame of this video." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABjUAAABnCAYAAABIFcDPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA2I0lEQVR4nO3dd1gU194H8O9SlyJFKTaqBRvYJVZAScCSiIk1KMEYOybcREVzo0IaamLXoDdR0URjiUZvFE2MSozGHrEiQQU1EcUGiEjd8/7BZV4Glr7Aot/P8/Dozpw5bX57dnbOzoxCCCFARERERERERERERESk5XRquwJERERERERERERERETlwUkNIiIiIiIiIiIiIiKqEzipQUREREREREREREREdQInNYiIiIiIiIiIiIiIqE7gpAYREREREREREREREdUJnNQgIiIiIiIiIiIiIqI6gZMaRERERERERERERERUJ3BSg4iIiIiIiIiIiIiI6gS92q4AERERERERERERET2/hBDIzc1FXl5ebVeFtJSuri709PSgUCjKTMtJDSIiIiIiIiIiIiKqFtnZ2UhKSkJGRkZtV4W0nLGxMRo1agQDA4NS0ymEEKKG6kRERERERERERERELwiVSoX4+Hjo6urC2toaBgYG5folPr1YhBDIzs7G/fv3kZeXhxYtWkBHp+QnZ/BKDSIiIiIiIiIiIiLSuOzsbKhUKtjZ2cHY2Li2q0NazMjICPr6+rh58yays7OhVCpLTMsHhRMRERERERERERFRtSntV/dEBcobJ4wmIiIiIiIiIiIiIiKqE3j7KSIiIiLSKo6OjmjXrh327NlTo+VGR0fDy8sLhw8fhqenZ42WXRWJiYlwcnLCF198genTp2skz7raF0RERERUd9xKvYUHGQ9qpCwrYyvYm9vXSFlU/TipQURERESVEhkZibFjx8qWWVtbo23btpg5cyb69+9fSzXTfgV9d/r0aXTp0qW2q0NEREREVKNupd6Cy0oXZOZm1kh5Sj0l4oLiOLHxnOCkBhERERFVyccffwwnJycIIXDv3j1ERkZiwIAB+OmnnzBo0KDarl659enTB8+ePYOBgUFtV4WIiIiI6Ln2IONBjU1oAEBmbiYeZDx4LiY1Cq6qfvz4MSwsLGq7OrWCkxpEREREVCX9+/eXXW0wbtw42Nra4vvvv69Tkxo6OjpQKpUay+/p06cwMTHRWH5ERERERETEB4UTERERkYZZWFjAyMgIenry38+oVCosXboUbdu2hVKphK2tLSZOnIjHjx+rzefo0aPo1q0blEolnJ2dsXHjRtn6R48eYfr06XB1dYWpqSnMzMzQv39/nD9/Xkpz79496OnpISwsrFj+cXFxUCgUWLlyJYD8XzwpFApER0fL0m3fvh2dO3eGkZERrKysMHr0aPzzzz+yNIGBgTA1NcX169cxYMAA1KtXD/7+/uXuM3Wys7Mxd+5cdO7cGebm5jAxMUHv3r1x+PDhErdZsmQJHBwcYGRkBA8PD1y6dKlYmqtXr2Lo0KGoX78+lEolunTpgv/+979l1ic+Ph5vvPEGGjZsCKVSiaZNm2LkyJFITU2tUjuJiIiIiLSRp6cnpk2bhuDgYFhaWsLW1hZff/01nj59irFjx6JevXpo3rw59u3bJ23z22+/oVu3bjA0NESjRo0wa9Ys5ObmSusdHR2xdOlSWTkdOnRAaGio9FqhUOCbb77BkCFDYGxsjBYtWkjH64mJifDy8gIAWFpaQqFQIDAwsNr6QFtxUoOIiIiIqiQ1NRUPHjzA/fv3cfnyZUyePBnp6ekYPXq0LN3EiRMxY8YM9OzZE8uWLcPYsWOxadMm+Pj4ICcnR5b22rVrGDp0KF5++WUsWrQIlpaWCAwMxOXLl6U0N27cwK5duzBo0CAsXrwYM2bMwMWLF+Hh4YE7d+4AAGxtbeHh4YFt27YVq/fWrVuhq6uLYcOGldi2yMhIDB8+HLq6uggPD8f48eOxc+dO9OrVCykpKbK0ubm58PHxgY2NDb788ku88cYbFe1KmbS0NHzzzTfw9PTEggULEBoaivv378PHxwcxMTHF0m/cuBHLly/H1KlTMXv2bFy6dAl9+/bFvXv3pDSXL1/GSy+9hNjYWMyaNQuLFi2CiYkJ/Pz88OOPP5ZYl+zsbPj4+ODEiROYNm0aVq1ahQkTJuDGjRvF+oGIiIiI6HmxYcMGWFlZ4dSpU5g2bRomT56MYcOGoUePHvjzzz/xyiuvYMyYMcjIyMA///yDAQMGoGvXrjh//jwiIiKwdu1afPrppxUuNywsDMOHD8eFCxcwYMAA+Pv749GjR7Czs8OOHTsA5P9IKykpCcuWLdN0s7Uebz9FRERERFXi7e0te21oaIh169bh5ZdflpYdPXoU33zzDTZt2oQ333xTWu7l5QVfX19s375dtjwuLg5HjhxB7969AQDDhw+HnZ0d1q9fjy+//BIA4Orqir/++gs6Ov//O50xY8agVatWWLt2LebMmQMAGDFiBCZOnIhLly6hXbt2UtqtW7fCw8MDtra2atuVk5ODkJAQtGvXDkeOHJFuTdWrVy8MGjQIS5YskV0BkpWVhWHDhiE8PLxiHVgCS0tLJCYmyp7xMX78eLRq1QorVqzA2rVrZemvXbuG+Ph4NGnSBADg6+sLd3d3LFiwAIsXLwYAvPfee7C3t8fp06dhaGgIAJgyZQp69eqFkJAQDBkyRG1drly5goSEBGzfvh1Dhw6Vls+dO1cjbSUiIiIi0kbt27fHRx99BACYPXs25s+fDysrK4wfPx5A/vFwREQELly4gJ9++gl2dnZYuXIlFAoFWrVqhTt37iAkJARz586VfW8pS2BgIEaNGgUA+Pzzz7F8+XKcOnUKvr6+qF+/PgDAxsbmhX2mBq/UICIiIqIqWbVqFQ4cOIADBw7gu+++g5eXF9555x3s3LlTSrN9+3aYm5vj5ZdfxoMHD6S/zp07w9TUtNgtldq0aSNNaACAtbU1XFxccOPGDWmZoaGh9MUgLy8PDx8+hKmpKVxcXPDnn39K6V5//XXo6elh69at0rJLly7hypUrGDFiRIntOnPmDJKTkzFlyhTZszYGDhyIVq1aYe/evcW2mTx5cnm6rFx0dXWlCQ2VSoVHjx4hNzcXXbp0kbWvgJ+fnzShAQDdunWDu7s7oqKiAOTfruvQoUMYPnw4njx5Iu2Dhw8fwsfHB/Hx8cVuq1XA3NwcAPDzzz8jIyNDY20kIiIiItJmbm5u0v91dXXRoEEDuLq6SssKfiCVnJyM2NhYdO/eHQqFQlrfs2dPpKen4++//650uSYmJjAzM0NycnJlm/Hc4aQGEREREVVJt27d4O3tDW9vb/j7+2Pv3r1o06YNgoKCkJ2dDSD/eQypqamwsbGBtbW17C89Pb3YAbq9vX2xciwtLWXP31CpVFiyZAlatGgBQ0NDWFlZwdraGhcuXJA958HKygr9+vWT3YJq69at0NPTw+uvv15iu27evAkAcHFxKbauVatW0voCenp6aNq0aWldVWEbNmyAm5sblEolGjRoAGtra+zdu1ftcyxatGhRbFnLli2RmJgIIP9KDiEE5syZU2wfzJs3DwBK/KLk5OSE999/H9988w2srKzg4+ODVatW8XkaRERERPRc09fXl71WKBSyZQUTGCqVqlz56ejoQAghW1b0VrwllVveMl4EvP0UEREREWmUjo4OvLy8sGzZMsTHx6Nt27ZQqVSwsbHBpk2b1G5jbW0te62rq6s2XeEvAJ9//jnmzJmDt99+G5988gnq168PHR0dBAcHFzvgHzlyJMaOHYuYmBh06NAB27ZtQ79+/WBlZVXF1v6/wleOaMJ3332HwMBA+Pn5YcaMGbCxsZGe7XH9+vUK51fQJ9OnT4ePj4/aNM2bNy9x+0WLFiEwMBC7d+/GL7/8gnfffRfh4eE4ceKExidziIiIiIjqmtatW2PHjh0QQkiTHceOHUO9evWk42Vra2skJSVJ26SlpSEhIaFC5RRczZ2Xl6ehmtc9nNQgIiIiIo3Lzc0FAKSnpwMAmjVrhl9//RU9e/aEkZGRRsr44Ycf4OXlVezZEikpKcUmK/z8/DBx4kTpFlR//fUXZs+eXWr+Dg4OAPKf79G3b1/Zuri4OGl9dfnhhx/g7OyMnTt3yi5hL7iqoqj4+Phiy/766y84OjoCAJydnQHk/+qr6HNQysvV1RWurq746KOP8Mcff6Bnz55YvXp1pR5+SERERET0PJkyZQqWLl2KadOmISgoCHFxcZg3bx7ef/996cdPffv2RWRkJF599VVYWFhg7ty5Jf6gqyQODg5QKBTYs2cPBgwYACMjI5iamlZHk7QWbz9FRERERBqVk5ODX375BQYGBmjdujWA/Ad95+Xl4ZNPPimWPjc3FykpKRUuR1dXt9il29u3b1f7XAgLCwv4+Phg27Zt2LJlCwwMDODn51dq/l26dIGNjQ1Wr16NrKwsafm+ffsQGxuLgQMHVrjOFVHw5aZwG0+ePInjx4+rTb9r1y5Z20+dOoWTJ0+if//+APIfJOjp6Yk1a9bIfh1W4P79+yXWJS0tTZqoKuDq6godHR1Z3xARERERlYeVsRWUesqyE2qIUk8JK2PNXaWtTpMmTRAVFYVTp06hffv2mDRpEsaNGyc9aBzIf9i4h4cHBg0ahIEDB8LPzw/NmjWrcDlhYWGYNWsWbG1tERQUpOmmaD1eqUFEREREVbJv3z5cvXoVQP4zGTZv3oz4+HjMmjULZmZmAAAPDw9MnDgR4eHhiImJwSuvvAJ9fX3Ex8dj+/btWLZsGYYOHVqhcgcNGoSPP/4YY8eORY8ePXDx4kVs2rRJuiKhqBEjRmD06NH46quv4OPjAwsLi1Lz19fXx4IFCzB27Fh4eHhg1KhRuHfvHpYtWwZHR0f861//qlB91Vm3bh32799fbPl7772HQYMGYefOnRgyZAgGDhyIhIQErF69Gm3atJGugCmsefPm6NWrFyZPnoysrCwsXboUDRo0wMyZM6U0q1atQq9eveDq6orx48fD2dkZ9+7dw/Hjx/H333/j/Pnzaut56NAhBAUFYdiwYWjZsiVyc3Px7bffQldXF2+88UaV+4GIiIiIXiz25vaIC4rDg4wHNVKelbEV7M2LP7evNNHR0cWWFTyvrrDCP0Ly8PDAqVOnSszTzMwMW7ZskS176623SsyvQNEfgc2ZMwdz5swpsZznHSc1iIiIiKhK5s6dK/1fqVSiVatWiIiIwMSJE2XpVq9ejc6dO2PNmjX48MMPoaenB0dHR4wePRo9e/ascLkffvghnj59is2bN2Pr1q3o1KkT9u7di1mzZqlN/9prr8HIyAhPnjzBiBEjylVGYGAgjI2NMX/+fISEhMDExARDhgzBggULypwUKY+IiIgSyw0MDMTdu3exZs0a/Pzzz2jTpg2+++47bN++Xe0XrICAAOjo6GDp0qVITk5Gt27dsHLlSjRq1EhK06ZNG5w5cwZhYWGIjIzEw4cPYWNjg44dO8r2Y1Ht27eHj48PfvrpJ/zzzz8wNjZG+/btsW/fPrz00ktV7gciIiIievHYm9tXeKKBCAAUQt3UDxERERERERERERFRFWRmZiIhIQFOTk5QKmvudlNUN5U3XvhMDSIiIiIiIiIiIiIiqhM4qUFERERERERERERERHUCJzWIiIiIiIiIiIiIiKhO4KQGERERERERERERERHVCZzUICIiIiIiIiIiIiKiOkGvMhupVCrcuXMH9erVg0Kh0HSdiIiIiIiIiIiIiKgOEELgyZMnaNy4MXR0+Bt6qn6VmtS4c+cO7OzsNF0XIiIiIiIiIiIiIqqDbt++jaZNm9Z2NegFUKlJjXr16gEAbi8HzIxKSDQ8FdhmXtl6ac7w1Px/C9dF3bLy5lPadoXTFFVWWSVtW3S7oumq0scVzatgn5bRTvPr5a9C6mw1eZWzTerKUZtfRRSUXcn4rUjbtUGV+6s0pfVfof7Vhj6r1n4AyoylsvqgxPqVNq6V9j6tiEJlaGJflbuv1bWtphXZbzURqxqPxcr0YwXHcU2r9vcjoB3xVVXleG+mNoN8bCirrXV131d13CspHv7XH6nNivdxajM16UmuHJ/z5drnZcSltC/+V5Ys7iuiEp93svoXaa/auCnaXk1/ZmtKCcct1XLsrSnVOa5r0TFrVWnN/iqgre+BkmgwFkrdFxUop9b2aTW9L4q2xzzcXO3yaqXuHIyGvxNVlrp+KOgjTeRVI8pzTFqbNHA8rHVjLVAzMZwFYMn/nzN+kXl6eqJDhw5YunRpbVfluVapSY2CW06ZGQFmxiUkMjMDSlpXk8zM8v81LmNZefMpbbvCaYoqq6ySti26XdF0VenjiuZVsE/LaqeyIlVQk1d526SmHLX5VURB2ZWN3wq0XRtUub9KU1r/Fe5fLeizau0HoOxYKqMPSqxfaeOaptpUuAwN7Kty97W6ttW0ovutBmJV47FYmX6s4DiuadX+fgS0I76qqhzvTbPCn9llfX4XpKmL+76q415J8fC//jBT0y9mmh5rn0fl+Jwv1z4vIy7NirwXzMoT6yWVUyif8jBT9/1AWaheReOmpGNvbYujko5bquPYW1Oqc1zXomPWqtKa/VVAW98DJdFgLJS6LypQTq3t02p6XxRrj7KE5dVJ3TkYDX8nqiy1/VDJ+tRq7Gjze14Dx8NaN9YCNRrDL9JjCqKjo+Hl5YXHjx/DwsKitqvzwuFNzoiIiIiIiIiIiIiItFB2dnZtV0HrcFKDiIiIiIiIiIiIiKiQrKwsvPvuu7CxsYFSqUSvXr1w+vRpJCYmwsvLCwBgaWkJhUKBwMBAaTuVSoWZM2eifv36aNiwIUJDQ2X5pqSk4J133oG1tTXMzMzQt29fnD9/XlofGhqKDh064JtvvoGTkxOUyufgklEN46QGEREREREREREREVEhM2fOxI4dO7Bhwwb8+eefaN68OXx8fFCvXj3s2LEDABAXF4ekpCQsW7ZM2m7Dhg0wMTHByZMnsXDhQnz88cc4cOCAtH7YsGFITk7Gvn37cPbsWXTq1An9+vXDo0ePpDTXrl3Djh07sHPnTsTExNRYm+uKSj1Tg4iIiIiIiIiIiIjoefT06VNEREQgMjIS/fv3BwB8/fXXOHDgANatW4euXbsCAGxsbIo9U8PNzQ3z5s0DALRo0QIrV67EwYMH8fLLL+Po0aM4deoUkpOTYWhoCAD48ssvsWvXLvzwww+YMGECgPxbTm3cuBHW1tY11OK6hZMaRERERERERERERET/c/36deTk5KBnz57SMn19fXTr1g2xsbHSpIY6bm5usteNGjVCcnIyAOD8+fNIT09HgwYNZGmePXuG69evS68dHBw4oVEKTmoQEREREREREREREWmAvr6+7LVCoYBKpQIApKeno1GjRoiOji62XeErPkxMTKqzinUeJzWIiIiIiIiIiIiIiP6nWbNmMDAwwLFjx+Dg4AAAyMnJwenTpxEcHAwDAwMAQF5eXoXy7dSpE+7evQs9PT04OjpqutovDD4onIiIiIiIiIiIiIjof0xMTDB58mTMmDED+/fvx5UrVzB+/HhkZGRg3LhxcHBwgEKhwJ49e3D//n2kp6eXK19vb290794dfn5++OWXX5CYmIg//vgD//73v3HmzJlqbtXzg5MaRERERERERERERESFzJ8/H2+88QbGjBmDTp064dq1a/j5559haWmJJk2aICwsDLNmzYKtrS2CgoLKladCoUBUVBT69OmDsWPHomXLlhg5ciRu3rwJW1vbam7R84O3nyIiIiIiIiIiIiIiKkSpVGL58uVYvny52vVz5szBnDlzZMvUPStj165dstf16tUrNd/Q0FCEhoZWpsovjEpNagghAABpz0pJlJYGZFQmdw1LS8v/N6OMZeXNp7TtCqcpqqyyStq26HZF01WljyuaV8E+LaudmRWpgpq8ytsmNeWoza8iCsqubPxWoO3aoMr9VZrS+q9w/2pBn1VrPwBlx1IZfVBi/Uob1zTVpsJlaGBflbuv1bWtphXdbzUQqxqPxcr0YwXHcU2r9vcjoB3xVVXleG+mFf7MLuvzuyBNXdz3VR33SoqH//VHmpp+SdP0WPs8KsfnfLn2eRlxmVbkvZBWnlgvqZxC+ZRHmrrvB5mF6lU0bko69ta2OCrpuKU6jr01pTrHdS06Zq0qrdlfBbT1PVASDcZCqfuiAuXU2j6tpvdFsfZklrC8Oqk7B6Ph70SVpbYfKlmfWo0dbX7Pa+B4WOvGWqBmYjgr/5+Cc8ZE1U0hKhFtN27cQLNmzaqjPkRERERERERERERUx9y+fRtNmzaVLcvMzERCQgKcnJygVCprqWZUV5Q3Xip1pUb9+vUBALdu3YK5uXnlakikYWlpabCzs8Pt27dhZmZW29UhAsC4JO3EuCRtxLgkbcS4JG3EuCRtxLgkbcXYrBlCCDx58gSNGzeu7arQC6JSkxo6OvnPFzc3N+eAQFrHzMyMcUlah3FJ2ohxSdqIcUnaiHFJ2ohxSdqIcUnairFZ/fjDd6pJOrVdASIiIiIiIiIiIiIiovLgpAYREREREREREREREdUJlZrUMDQ0xLx582BoaKjp+hBVGuOStBHjkrQR45K0EeOStBHjkrQR45K0EeOStBVjk+j5pBBCiNquBBERERERERERERE9XzIzM5GQkAAnJycolcrarg5pufLGS6UeFE5EREREREREREREVGlPbwFZD2qmLEMrwMS+Qpt4enqiQ4cOWLp0afXUSQNqso6Ojo4IDg5GcHBwtZdVFk5qEBEREREREREREVHNeXoL+MkFUGXWTHk6SuDVuApNbOzcuRP6+vrVWKnyi46OhpeXFx4/fgwLCwtpeXXUMTIyEsHBwUhJSZEtP336NExMTDRaVmVxUoOIiIiIiIiIiIiIak7Wg5qb0ADyy8p6UKFJjfr161djhTSjJutobW1dY2WVpVIPCiciIiIiIiIiIiIiel55enpKt1pydHTE559/jrfffhv16tWDvb09/vOf/0hpe/TogZCQENn29+/fh76+Po4cOQIAyMrKwvTp09GkSROYmJjA3d0d0dHRUvqbN2/i1VdfhaWlJUxMTNC2bVtERUUhMTERXl5eAABLS0soFAoEBgYWqyMAJCUlYeDAgTAyMoKTkxM2b94MR0dH2e2pFi9eDFdXV5iYmMDOzg5TpkxBeno6gPwrQsaOHYvU1FQoFAooFAqEhoZKfVA4n1u3bmHw4MEwNTWFmZkZhg8fjnv37knrQ0ND0aFDB3z77bdwdHSEubk5Ro4ciSdPnlRmd8hUalJj1apVcHR0hFKphLu7O06dOlXlihABQHh4OLp27Yp69erBxsYGfn5+iIuLk6Xx9PSU3lQFf5MmTZKluXXrFgYOHAhjY2PY2NhgxowZyM3NlaWJjo5Gp06dYGhoiObNmyMyMrK6m0d1VGhoaLGYa9WqlbQ+MzMTU6dORYMGDWBqaoo33nhDNogDjEnSPEdHx2JxqVAoMHXqVAAcK6lmHDlyBK+++ioaN24MhUKBXbt2ydYLITB37lw0atQIRkZG8Pb2Rnx8vCzNo0eP4O/vDzMzM1hYWGDcuHHSAXWBCxcuoHfv3lAqlbCzs8PChQuL1WX79u1o1aoVlEolXF1dERUVpfH2Ut1QWlzm5OQgJCRE+hLXuHFjBAQE4M6dO7I81I2x8+fPl6VhXFJFlDVeBgYGFos5X19fWRqOl6RpZcWlumNNhUKBL774QkrD8ZI0rTznhWryOzjPgVJhixYtQpcuXXDu3DlMmTIFkydPluLT398fW7ZsgRBCSr9161Y0btwYvXv3BgAEBQXh+PHj2LJlCy5cuIBhw4bB19dX+o40depUZGVl4ciRI7h48SIWLFgAU1NT2NnZYceOHQCAuLg4JCUlYdmyZWrrWHBsGx0djR07duA///kPkpOTZWl0dHSwfPlyXL58GRs2bMChQ4cwc+ZMAPmTM0uXLoWZmRmSkpKQlJSE6dOnFytHpVJh8ODBePToEX777TccOHAAN27cwIgRI2Tprl+/jl27dmHPnj3Ys2cPfvvtt2KfE5UiKmjLli3CwMBArFu3Tly+fFmMHz9eWFhYiHv37lU0K6JifHx8xPr168WlS5dETEyMGDBggLC3txfp6elSGg8PDzF+/HiRlJQk/aWmpkrrc3NzRbt27YS3t7c4d+6ciIqKElZWVmL27NlSmhs3bghjY2Px/vvviytXrogVK1YIXV1dsX///hptL9UN8+bNE23btpXF3P3796X1kyZNEnZ2duLgwYPizJkz4qWXXhI9evSQ1jMmqTokJyfLYvLAgQMCgDh8+LAQgmMl1YyoqCjx73//W+zcuVMAED/++KNs/fz584W5ubnYtWuXOH/+vHjttdeEk5OTePbsmZTG19dXtG/fXpw4cUL8/vvvonnz5mLUqFHS+tTUVGFrayv8/f3FpUuXxPfffy+MjIzEmjVrpDTHjh0Turq6YuHCheLKlSvio48+Evr6+uLixYvV3gekfUqLy5SUFOHt7S22bt0qrl69Ko4fPy66desmOnfuLMvDwcFBfPzxx7IxtPDxKOOSKqqs8fKtt94Svr6+sph79OiRLA3HS9K0suKycDwmJSWJdevWCYVCIa5fvy6l4XhJmlae80I19R2c50A149mzZ+LKlSuy7wBCCCEenhViE2r27+HZCtXdw8NDvPfee0KI/PFu9OjR0jqVSiVsbGxERESEECL/O7qenp44cuSIlKZ79+4iJCRECCHEzZs3ha6urvjnn39kZfTr10+KTVdXVxEaGqq2LocPHxYAxOPHj0usY2xsrAAgTp8+La2Pj48XAMSSJUtKbOf27dtFgwYNpNfr168X5ubmxdI5ODhI+fzyyy9CV1dX3Lp1S1p/+fJlAUCcOnVKCJF/Ps3Y2FikpaVJaWbMmCHc3d1LrEuJ8VJEhSc1unXrJqZOnSq9zsvLE40bNxbh4eEVzYqoTMnJyQKA+O2336Rlhd+s6kRFRQkdHR1x9+5daVlERIQwMzMTWVlZQgghZs6cKdq2bSvbbsSIEcLHx0ezDaDnwrx580T79u3VrktJSRH6+vpi+/bt0rKCD5Hjx48LIRiTVDPee+890axZM6FSqYQQHCup5hU9GaJSqUTDhg3FF198IS1LSUkRhoaG4vvvvxdCCHHlypViB9379u0TCoVCOtj/6quvhKWlpRSXQggREhIiXFxcpNfDhw8XAwcOlNXH3d1dTJw4UaNtpLpH3Um6ok6dOiUAiJs3b0rLCn9hU4dxSVVR0qTG4MGDS9yG4yVVt/KMl4MHDxZ9+/aVLeN4SdWt6HmhmvwOznOgmvE8TWosXLhQtt7NzU2EhYVJrwcMGCCNXTdu3BAAxIULF4QQQuzZs0cAECYmJrI/PT09MXz4cCGEEF9//bXQ09MTPXr0EHPnzhXnz5+X8i7PpMauXbuEnp6eyMvLk6WxtLSUjdUHDhwQffv2FY0bNxampqZCqVQKAOLp06dCiPJNaixbtkw4OjoWS2NhYSE2bNgghMg/n9amTRvZ+sWLFwsnJ6di2xUo76RGhW4/lZ2djbNnz8Lb21tapqOjA29vbxw/frzSV4sQlSQ1NRVA8YfebNq0CVZWVmjXrh1mz56NjIwMad3x48fh6uoKW1tbaZmPjw/S0tJw+fJlKU3hOC5IwzimksTHx6Nx48ZwdnaGv78/bt26BQA4e/YscnJyZPHUqlUr2NvbS/HEmKTqlp2dje+++w5vv/02FAqFtJxjJdWmhIQE3L17VxZD5ubmcHd3l42PFhYW6NKli5TG29sbOjo6OHnypJSmT58+MDAwkNL4+PggLi4Ojx8/ltIwVqmyCu4XbGFhIVs+f/58NGjQAB07dsQXX3whu2UF45KqQ3R0NGxsbODi4oLJkyfj4cOH0jqOl1Tb7t27h71792LcuHHF1nG8pOpU9LxQTX0H5zlQUkdfX1/2WqFQQKVSSa/9/f3xww8/ICcnB5s3b4arqytcXV0BAOnp6dDV1cXZs2cRExMj/cXGxkq3knrnnXdw48YNjBkzBhcvXkSXLl2wYsUKjbYhMTERgwYNgpubG3bs2IGzZ89i1apVAPLjXtPK6rPK0qtI4gcPHiAvL082KACAra0trl69WuXKEBWmUqkQHByMnj17ol27dtLyN998Ew4ODmjcuDEuXLiAkJAQxMXFYefOnQCAu3fvqo3RgnWlpUlLS8OzZ89gZGRUnU2jOsbd3R2RkZFwcXFBUlISwsLC0Lt3b1y6dAl3796FgYFBsRMhtra2ZcZbwbrS0jAmqTx27dqFlJQU6UFhAMdKqn0FcaQuhgrHmI2NjWy9np4e6tevL0vj5ORULI+CdZaWliXGakEeRCXJzMxESEgIRo0aBTMzM2n5u+++i06dOqF+/fr4448/MHv2bCQlJWHx4sUAGJekeb6+vnj99dfh5OSE69ev48MPP0T//v1x/Phx6OrqcrykWrdhwwbUq1cPr7/+umw5x0uqTurOC9XUd/DHjx/zHChV2ODBgzFhwgTs378fmzdvRkBAgLSuY8eOyMvLQ3JysvSMDXXs7OwwadIkTJo0CbNnz8bXX3+NadOmSZPDeXl5JW7r4uKC3NxcnDt3Dp07dwYAXLt2TZpEBvInBlUqFRYtWgQdnfzrHbZt2ybLx8DAoNRyAKB169a4ffs2bt++DTs7OwDAlStXkJKSgjZt2pS6rSZUaFKDqCZNnToVly5dwtGjR2XLJ0yYIP3f1dUVjRo1Qr9+/XD9+nU0a9aspqtJL4D+/ftL/3dzc4O7uzscHBywbds2ntQlrbB27Vr0798fjRs3lpZxrCQiKl1OTg6GDx8OIQQiIiJk695//33p/25ubjAwMMDEiRMRHh4OQ0PDmq4qvQBGjhwp/d/V1RVubm5o1qwZoqOj0a9fv1qsGVG+devWwd/fH0qlUrac4yVVp5LOCxFpKxMTE/j5+WHOnDmIjY3FqFGjpHUtW7aEv78/AgICsGjRInTs2BH379/HwYMH4ebmhoEDByI4OBj9+/dHy5Yt8fjxYxw+fBitW7cGADg4OEChUGDPnj0YMGAAjIyMYGpqKiu/VatW8Pb2xoQJExAREQF9fX188MEHMDIyku7q0Lx5c+Tk5GDFihV49dVXcezYMaxevVqWj6OjI9LT03Hw4EG0b98exsbGMDY2lqXx9vaGq6sr/P39sXTpUuTm5mLKlCnw8PCQXVlaXSp0+ykrKyvo6uri3r17suX37t1Dw4YNNVoxerEFBQVhz549OHz4MJo2bVpqWnd3dwD5M48A0LBhQ7UxWrCutDRmZmY8SU1lsrCwQMuWLXHt2jU0bNgQ2dnZSElJkaUpPC4yJqk63bx5E7/++iveeeedUtNxrKSaVhBHpR03NmzYEMnJybL1ubm5ePTokUbGUB6fUkkKJjRu3ryJAwcOyK7SUMfd3R25ublITEwEwLik6ufs7AwrKyvZ5zbHS6otv//+O+Li4so83gQ4XpLmlHReqKa+g/McKFWWv78/zp8/j969e8Pe3l62bv369QgICMAHH3wAFxcX+Pn54fTp01K6vLw8TJ06Fa1bt4avry9atmyJr776CgDQpEkThIWFYdasWbC1tUVQUJDa8jdu3AhbW1v06dMHQ4YMwfjx41GvXj1pUrp9+/ZYvHgxFixYgHbt2mHTpk0IDw+X5dGjRw9MmjQJI0aMgLW1NRYuXFisHIVCgd27d8PS0hJ9+vSBt7c3nJ2dsXXr1ir3YXlUaFLDwMAAnTt3xsGDB6VlKpUKBw8eRPfu3TVeOXrxCCEQFBSEH3/8EYcOHSp2mao6MTExAIBGjRoBALp3746LFy/KDvoLvqwWXP7UvXt3WRwXpGEcU3mkp6fj+vXraNSoETp37gx9fX1ZPMXFxeHWrVtSPDEmqTqtX78eNjY2GDhwYKnpOFZSTXNyckLDhg1lMZSWloaTJ0/KxseUlBScPXtWSnPo0CGoVCppIq579+44cuQIcnJypDQHDhyAi4sLLC0tpTSMVSqvggmN+Ph4/Prrr2jQoEGZ28TExEBHR0e6/Q/jkqrb33//jYcPH8o+tzleUm1Zu3YtOnfujPbt25eZluMlVVVZ54Vq6js4z4HWAEMrQEdZdjpN0VHml1kB0dHRWLp0KYD8Z1EEBwfL1sfExCA0NFS2rH///hBC4LfffiuWn76+PsLCwpCQkIDs7GzcuXMHO3fulJ67sWLFCly7dg2ZmZlITk7Gxo0bZceqc+bMQVJSElQqFSIjI4vVEcj/zh8VFYXMzEwkJiaid+/eSE5ORvPmzaU0//rXv3Dnzh1kZGRg//79GDNmDIQQstu6RURE4MGDBxBCSG0s2gf29vbYvXs30tPTkZaWhm3btslu2RYaGiqdiygQHBwsTXxXSamPEVdjy5YtwtDQUERGRoorV66ICRMmCAsLC3H37t2KZkVUzOTJk4W5ubmIjo4WSUlJ0l9GRoYQQohr166Jjz/+WJw5c0YkJCSI3bt3C2dnZ9GnTx8pj9zcXNGuXTvxyiuviJiYGLF//35hbW0tZs+eLaW5ceOGMDY2FjNmzBCxsbFi1apVQldXV+zfv7/G20za74MPPhDR0dEiISFBHDt2THh7ewsrKyuRnJwshBBi0qRJwt7eXhw6dEicOXNGdO/eXXTv3l3anjFJ1SUvL0/Y29uLkJAQ2XKOlVRTnjx5Is6dOyfOnTsnAIjFixeLc+fOiZs3bwohhJg/f76wsLAQu3fvFhcuXBCDBw8WTk5O4tmzZ1Ievr6+omPHjuLkyZPi6NGjokWLFmLUqFHS+pSUFGFrayvGjBkjLl26JLZs2SKMjY3FmjVrpDTHjh0Tenp64ssvvxSxsbFi3rx5Ql9fX1y8eLHmOoO0RmlxmZ2dLV577TXRtGlTERMTIzvezMrKEkII8ccff4glS5aImJgYcf36dfHdd98Ja2trERAQIJXBuKSKKi0unzx5IqZPny6OHz8uEhISxK+//io6deokWrRoITIzM6U8OF6SppX1OS6EEKmpqcLY2FhEREQU257jJVWHss4LCVFz38F5DlQznj17Jq5cuSL7DiBJvynEw7M185d+s3j5z6GDBw+K3bt3ixs3bohjx46Jnj17CkdHR5GdnV3bVSuXUuOlkApPagghxIoVK4S9vb0wMDAQ3bp1EydOnKhUJYmKAqD2b/369UIIIW7duiX69Okj6tevLwwNDUXz5s3FjBkzRGpqqiyfxMRE0b9/f2FkZCSsrKzEBx98IHJycmRpDh8+LDp06CAMDAyEs7OzVAZRUSNGjBCNGjUSBgYGokmTJmLEiBHi2rVr0vpnz56JKVOmCEtLS2FsbCyGDBkikpKSZHkwJqk6/PzzzwKAiIuLky3nWEk15fDhw2o/t9966y0hhBAqlUrMmTNH2NraCkNDQ9GvX79i8frw4UMxatQoYWpqKszMzMTYsWPFkydPZGnOnz8vevXqJQwNDUWTJk3E/Pnzi9Vl27ZtomXLlsLAwEC0bdtW7N27t9raTdqttLhMSEgo8Xjz8OHDQgghzp49K9zd3YW5ublQKpWidevW4vPPP5edXBaCcUkVU1pcZmRkiFdeeUVYW1sLfX194eDgIMaPH1/spBnHS9K0sj7HhRBizZo1wsjISKSkpBTbnuMlVYeyzgsJUbPfwXkOtOrKe5KaNGP//v2ibdu2wsjISNjY2Ag/Pz+RmJhY29Uqt/LGi0IIIap+vQcRERERERERERER0f/LzMxEQkICnJycpOc6EJWkvPFSoWdqEBERERERERERERER1RZOahARERERERERERERUZ3ASQ0iIiIiIiIiIiIiqjZ8AgKVR3njhJMaRERERERERERERKRx+vr6AICMjIxargnVBQVxUhA3JdGricoQERERERERERER0YtFV1cXFhYWSE5OBgAYGxtDoVDUcq1I2wghkJGRgeTkZFhYWEBXV7fU9ArBa3+IiIiIiIiIiIiIqBoIIXD37l2kpKTUdlVIy1lYWKBhw4ZlTnxxUoOIiIiIiIiIiIiIqlVeXh5ycnJquxqkpfT19cu8QqMAJzWIiIiIiOqYyMhIBAcH89duRERERET0wuGDwomIiIioxgUGBkKhUBT7u3btWm1XrVwcHR2hUChw4sQJ2fLg4GB4enrWTqWIiIiIiIheAJzUICIiIqJa4evri6SkJNmfk5NTsXTZ2dm1ULuyKZVKhISE1HY1NIq3AyAiIiIiIm3HSQ0iIiIiqhWGhoZo2LCh7E9XVxeenp4ICgpCcHAwrKys4OPjAwBYvHgxXF1dYWJiAjs7O0yZMgXp6elSfpGRkbCwsMCePXvg4uICY2NjDB06FBkZGdiwYQMcHR1haWmJd999F3l5edJ2WVlZmD59Opo0aQITExO4u7sjOjq6zPpPmDABJ06cQFRUVIlpPD09ERwcLFvm5+eHwMBA6bWjoyM+/fRTBAQEwNTUFA4ODvjvf/+L+/fvY/DgwTA1NYWbmxvOnDlTLP9du3ahRYsWUCqV8PHxwe3bt2Xrd+/ejU6dOkGpVMLZ2RlhYWHIzc2V1isUCkREROC1116DiYkJPvvsszLbTUREREREVJs4qUFEREREWmfDhg0wMDDAsWPHsHr1agCAjo4Oli9fjsuXL2PDhg04dOgQZs6cKdsuIyMDy5cvx5YtW7B//35ER0djyJAhiIqKQlRUFL799lusWbMGP/zwg7RNUFAQjh8/ji1btuDChQsYNmwYfH19ER8fX2odnZycMGnSJMyePRsqlapK7V2yZAl69uyJc+fOYeDAgRgzZgwCAgIwevRo/Pnnn2jWrBkCAgJQ+HF4GRkZ+Oyzz7Bx40YcO3YMKSkpGDlypLT+999/R0BAAN577z1cuXIFa9asQWRkZLGJi9DQUAwZMgQXL17E22+/XaV2EBERERERVTdOahARERFRrdizZw9MTU2lv2HDhknrWrRogYULF8LFxQUuLi4A8p9X4eXlBUdHR/Tt2xeffvoptm3bJsszJycHERER6NixI/r06YOhQ4fi6NGjWLt2Ldq0aYNBgwbBy8sLhw8fBgDcunUL69evx/bt29G7d280a9YM06dPR69evbB+/foy2/DRRx8hISEBmzZtqlJfDBgwABMnTkSLFi0wd+5cpKWloWvXrhg2bBhatmyJkJAQxMbG4t69e7K2rly5Et27d0fnzp2xYcMG/PHHHzh16hQAICwsDLNmzcJbb70FZ2dnvPzyy/jkk0+wZs0aWdlvvvkmxo4dC2dnZ9jb21epHURERERERNVNr7YrQEREREQvJi8vL0REREivTUxMpP937ty5WPpff/0V4eHhuHr1KtLS0pCbm4vMzExkZGTA2NgYAGBsbIxmzZpJ29ja2sLR0RGmpqayZcnJyQCAixcvIi8vDy1btpSVlZWVhQYNGpTZBmtra0yfPh1z587FiBEjytny4tzc3GT1AwBXV9diy5KTk9GwYUMAgJ6eHrp27SqladWqFSwsLBAbG4tu3brh/PnzOHbsmOzKjLy8vGJ91qVLl0rXm4iIiIiIqKZxUoOIiIiIaoWJiQmaN29e4rrCEhMTMWjQIEyePBmfffYZ6tevj6NHj2LcuHHIzs6WTtDr6+vLtlMoFGqXFdwuKj09Hbq6ujh79ix0dXVl6QpPhJTm/fffx1dffYWvvvqq2DodHR3ZLaMA9Q/jLlxHhUJR4rKK3OYqPT0dYWFheP3114utUyqV0v+L9jUREREREZE246QGEREREWm9s2fPQqVSYdGiRdDRyb+DatFbT1VGx44dkZeXh+TkZPTu3btSeZiammLOnDkIDQ3Fa6+9JltnbW2NpKQk6XVeXh4uXboELy+vKtUbAHJzc3HmzBl069YNABAXF4eUlBS0bt0aANCpUyfExcWVOHFERERERERUF/GZGkRERESk9Zo3b46cnBysWLECN27cwLfffis9QLwqWrZsCX9/fwQEBGDnzp1ISEjAqVOnEB4ejr1795Y7nwkTJsDc3BybN2+WLe/bty/27t2LvXv34urVq5g8eTJSUlKqXG8g/0qOadOm4eTJkzh79iwCAwPx0ksvSZMcc+fOxcaNGxEWFobLly8jNjYWW7ZswUcffaSR8omIiIiIiGoDJzWIiIiISOu1b98eixcvxoIFC9CuXTts2rQJ4eHhGsl7/fr1CAgIwAcffAAXFxf4+fnh9OnTFXpotr6+Pj755BNkZmbKlr/99tt46623EBAQAA8PDzg7O2vkKg0g//khISEhePPNN9GzZ0+Ymppi69at0nofHx/s2bMHv/zyC7p27YqXXnoJS5YsgYODg0bKJyIiIiIiqg0KUfQmv0RERERERERERERERFqIV2oQEREREREREREREVGdwEkNIiIiIiIiIiIiIiKqEzipQUREREREREREREREdQInNYiIiIiIiIiIiIiIqE7gpAYREREREREREREREdUJnNQgIiIiIiIiIiIiIqI6gZMaRERERERERERERERUJ3BSg4iIiIiIiIiIiIiI6gROahARERERERERERERUZ3ASQ0iIiIiIiIiIiIiIqoTOKlBRERERERERERERER1Aic1iIiIiIiIiIiIiIioTvg/4NG5elx1J5cAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "annotation_sequence = single_sequence['annotations']\n", "text_sequence = num_to_text(annotation_sequence)\n", "\n", "plot_behavior_raster(\n", " text_sequence,\n", " start_frame=0,\n", " stop_frame=len(annotation_sequence)\n", " )" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Basic exploratory data analysis 🤓\n", "Each Sequence has different amounts of each behavior, depending on what the mice do during the assay. Here, we get the percentage of frames of each behavior in each sequence. We can use this to split the training set into train and validation sets in a stratified way." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Percentage of frames in every sequence for every class\n" ] }, { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
attackinvestigationmountother
task1/train/mouse001_task1_annotator10.00000015.78824230.25182653.959933
task1/train/mouse002_task1_annotator19.06788022.7575870.00000068.174533
task1/train/mouse003_task1_annotator10.00000013.75737413.16744873.075178
task1/train/mouse004_task1_annotator10.00000016.4401997.73577375.824028
task1/train/mouse005_task1_annotator17.51639813.6146070.00000078.868995
\n", "
\n", " \n", "\n", "\n", "\n", "
\n", " \n", "
\n", "\n", "\n", "\n", " \n", "\n", " \n", " \n", "\n", " \n", "
\n", "
\n" ], "text/plain": [ " attack investigation mount \\\n", "task1/train/mouse001_task1_annotator1 0.000000 15.788242 30.251826 \n", "task1/train/mouse002_task1_annotator1 9.067880 22.757587 0.000000 \n", "task1/train/mouse003_task1_annotator1 0.000000 13.757374 13.167448 \n", "task1/train/mouse004_task1_annotator1 0.000000 16.440199 7.735773 \n", "task1/train/mouse005_task1_annotator1 7.516398 13.614607 0.000000 \n", "\n", " other \n", "task1/train/mouse001_task1_annotator1 53.959933 \n", "task1/train/mouse002_task1_annotator1 68.174533 \n", "task1/train/mouse003_task1_annotator1 73.075178 \n", "task1/train/mouse004_task1_annotator1 75.824028 \n", "task1/train/mouse005_task1_annotator1 78.868995 " ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def get_percentage(sequence_key):\n", " anno_seq = num_to_text(training_data[sequence_key]['annotations'])\n", " counts = {k: np.mean(np.array(anno_seq) == k)*100.0 for k in vocab}\n", " return counts\n", "\n", "\n", "anno_percentages = {k: get_percentage(k) for k in training_data}\n", "anno_perc_df = pd.DataFrame(anno_percentages).T\n", "print(\"Percentage of frames in every sequence for every class\")\n", "anno_perc_df.head()" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "## Percent of frames of each behavior in the full training set\n", "Having looked at behavior distributions in a couple example Sequences, let's now look at the average over the entire training set." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
BehaviorPercentage Frames
0attack2.765009
1investigation28.876113
2mount5.635781
3other62.723097
\n", "
\n", " \n", "\n", "\n", "\n", "
\n", " \n", "
\n", "\n", "\n", "\n", " \n", "\n", " \n", " \n", "\n", " \n", "
\n", "
\n" ], "text/plain": [ " Behavior Percentage Frames\n", "0 attack 2.765009\n", "1 investigation 28.876113\n", "2 mount 5.635781\n", "3 other 62.723097" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all_annotations = []\n", "for sk in training_data:\n", " anno = training_data[sk]['annotations']\n", " all_annotations.extend(list(anno))\n", "\n", "all_annotations = num_to_text(all_annotations)\n", "classes, counts = np.unique(all_annotations, return_counts=True)\n", "pd.DataFrame({\"Behavior\": classes,\n", " \"Percentage Frames\": counts/len(all_annotations)*100.0})" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Split training data into train/validation sets\n", "Because we don't want to overfit to our test set, we'll create a new validation set to test on while we're experimenting with our model.\n", "\n", "We'll use the first cell to create some helper functions, and then implement the split in the following cell." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "\n", "\n", "def num_to_text(number_to_class, anno_list):\n", " \"\"\"\n", " Convert list of class numbers to list of class names\n", " \"\"\"\n", " return np.vectorize(number_to_class.get)(anno_list)\n", "\n", "\n", "def split_validation(orig_pose_dictionary, vocabulary, seed=2021,\n", " test_size=0.5, split_videos=False):\n", " \"\"\"\n", " Split data into train and validation sets:\n", " * Full sequences are either put into train or validation to avoid data leakage\n", " * By default, the \"attack\" behavior's presence is used to stratify the split\n", " * Optionally, the sequences may be split into half and treated as separate sequences\n", " \"\"\"\n", "\n", " if test_size == 0.0:\n", " return orig_pose_dictionary, None\n", "\n", " number_to_class = {v: k for k, v in vocabulary.items()}\n", " if split_videos:\n", " pose_dictionary = {}\n", " for key in orig_pose_dictionary:\n", " key_pt1 = key + '_part1'\n", " key_pt2 = key + '_part2'\n", " anno_len = len(orig_pose_dictionary[key]['annotations'])\n", " split_idx = anno_len // 2\n", " pose_dictionary[key_pt1] = {\n", " 'annotations': orig_pose_dictionary[key]['annotations'][:split_idx],\n", " 'keypoints': orig_pose_dictionary[key]['keypoints'][:split_idx]}\n", " pose_dictionary[key_pt2] = {\n", " 'annotations': orig_pose_dictionary[key]['annotations'][split_idx:],\n", " 'keypoints': orig_pose_dictionary[key]['keypoints'][split_idx:]}\n", " else:\n", " pose_dictionary = orig_pose_dictionary\n", "\n", " def get_percentage(sequence_key):\n", " anno_seq = num_to_text(\n", " number_to_class, pose_dictionary[sequence_key]['annotations'])\n", " counts = {k: np.mean(np.array(anno_seq) == k) for k in vocabulary}\n", " return counts\n", "\n", " anno_percentages = {k: get_percentage(k) for k in pose_dictionary}\n", "\n", " anno_perc_df = pd.DataFrame(anno_percentages).T\n", "\n", " rng_state = np.random.RandomState(seed)\n", " try:\n", " idx_train, idx_val = train_test_split(anno_perc_df.index,\n", " stratify=anno_perc_df['attack'] > 0,\n", " test_size=test_size,\n", " random_state=rng_state)\n", " except:\n", " idx_train, idx_val = train_test_split(anno_perc_df.index,\n", " test_size=test_size,\n", " random_state=rng_state)\n", "\n", " train_data = {k: pose_dictionary[k] for k in idx_train}\n", " val_data = {k: pose_dictionary[k] for k in idx_val}\n", " return train_data, val_data" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of Sequences in train set: 52\n", "Number of Sequences in validation set: 18\n" ] } ], "source": [ "train, val = split_validation(training_data, vocab, test_size=0.25)\n", "print(\"Number of Sequences in train set: \", len(train))\n", "print(\"Number of Sequences in validation set: \", len(val))" ] }, { "cell_type": "markdown", "metadata": { "execution": {} }, "source": [ "# Preprocessing script\n", "\n", "We might also want to normalize the data, based on the information that the frame size is 1024x570\n", "\n", "The original data is of shape (sequence length, mouse, x y coordinate, keypoint)\n", " = (length, 2, 2, 7)\n", "\n", "If `rotate==True`, this code also swaps the x y and the keypoint axis, to make rotation of the poses (eg to center on one of the mice) easier." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "execution": {} }, "outputs": [], "source": [ "def normalize_data(orig_pose_dictionary, rotate=False):\n", " for key in orig_pose_dictionary:\n", " X = orig_pose_dictionary[key]['keypoints']\n", " if rotate:\n", " X = X.transpose((0, 1, 3, 2)) # last axis is x, y coordinates\n", " X[..., 0] = X[..., 0]/1024\n", " X[..., 1] = X[..., 1]/570\n", " else:\n", " X[:, :, 0, :] = X[:, :, 0, :] / 1024\n", " X[: ,:, 1, :] = X[:, :, 1, :] / 570\n", " orig_pose_dictionary[key]['keypoints'] = X\n", " return orig_pose_dictionary" ] } ], "metadata": { "colab": { "collapsed_sections": [], "include_colab_link": true, "name": "Loading_CalMS21_data", "provenance": [], "toc_visible": true }, "kernel": { "display_name": "Python 3", "language": "python", "name": "python3" }, "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.13" } }, "nbformat": 4, "nbformat_minor": 0 }