Created
December 28, 2021 05:21
-
-
Save ejmejm/5592b577e95cf77de0c77059e4995905 to your computer and use it in GitHub Desktop.
VISR.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/ejmejm/5592b577e95cf77de0c77059e4995905/visr.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "_29r97oJh7zK", | |
"outputId": "6fa74ed6-f6fa-4e22-928e-7e98ac54fbc5" | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"--2021-12-28 02:17:42-- http://www.atarimania.com/roms/Roms.rar\n", | |
"Resolving www.atarimania.com (www.atarimania.com)... 195.154.81.199\n", | |
"Connecting to www.atarimania.com (www.atarimania.com)|195.154.81.199|:80... connected.\n", | |
"HTTP request sent, awaiting response... 200 OK\n", | |
"Length: 11128004 (11M) [application/x-rar-compressed]\n", | |
"Saving to: ‘Roms.rar.1’\n", | |
"\n", | |
"Roms.rar.1 100%[===================>] 10.61M 261KB/s in 44s \n", | |
"\n", | |
"2021-12-28 02:18:26 (247 KB/s) - ‘Roms.rar.1’ saved [11128004/11128004]\n", | |
"\n", | |
"\n", | |
"UNRAR 5.50 freeware Copyright (c) 1993-2017 Alexander Roshal\n", | |
"\n", | |
"\n", | |
"Extracting from Roms.rar\n", | |
"\n", | |
"\n", | |
"Would you like to replace the existing file HC ROMS.zip\n", | |
"11826711 bytes, modified on 2019-12-22 11:24\n", | |
"with a new one\n", | |
"11826711 bytes, modified on 2019-12-22 11:24\n", | |
"\n", | |
"[Y]es, [N]o, [A]ll, n[E]ver, [R]ename, [Q]uit \n", | |
"User break\n", | |
"\n", | |
"User break\n", | |
"replace ROMS/128 in 1 Game Select ROM (128 in 1) (Unknown) ~.bin? [y]es, [n]o, [A]ll, [N]one, [r]ename: Requirement already satisfied: einops in /usr/local/lib/python3.7/dist-packages (0.3.2)\n", | |
"Traceback (most recent call last):\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3021, in _dep_map\n", | |
" return self.__dep_map\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 2815, in __getattr__\n", | |
" raise AttributeError(attr)\n", | |
"AttributeError: _DistInfoDistribution__dep_map\n", | |
"\n", | |
"During handling of the above exception, another exception occurred:\n", | |
"\n", | |
"Traceback (most recent call last):\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/base_command.py\", line 180, in _main\n", | |
" status = self.run(options, args)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/req_command.py\", line 199, in wrapper\n", | |
" return func(self, options, args)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/commands/install.py\", line 385, in run\n", | |
" conflicts = self._determine_conflicts(to_install)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/commands/install.py\", line 515, in _determine_conflicts\n", | |
" return check_install_conflicts(to_install)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/operations/check.py\", line 103, in check_install_conflicts\n", | |
" package_set, _ = create_package_set_from_installed()\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/operations/check.py\", line 45, in create_package_set_from_installed\n", | |
" package_set[name] = PackageDetails(dist.version, dist.requires())\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 2736, in requires\n", | |
" dm = self._dep_map\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3023, in _dep_map\n", | |
" self.__dep_map = self._compute_dependencies()\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3033, in _compute_dependencies\n", | |
" reqs.extend(parse_requirements(req))\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3094, in parse_requirements\n", | |
" yield Requirement(line)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3101, in __init__\n", | |
" super(Requirement, self).__init__(requirement_string)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/packaging/requirements.py\", line 113, in __init__\n", | |
" req = REQUIREMENT.parseString(requirement_string)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1943, in parseString\n", | |
" loc, tokens = self._parse(instring, 0)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4069, in parseImpl\n", | |
" loc, exprtokens = e._parse(instring, loc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4462, in parseImpl\n", | |
" return self.expr._parse(instring, loc, doActions, callPreParse=False)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4069, in parseImpl\n", | |
" loc, exprtokens = e._parse(instring, loc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4781, in parseImpl\n", | |
" return super(ZeroOrMore, self).parseImpl(instring, loc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4697, in parseImpl\n", | |
" loc, tokens = self_expr_parse(instring, loc, doActions, callPreParse=False)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4254, in parseImpl\n", | |
" ret = e._parse(instring, loc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4069, in parseImpl\n", | |
" loc, exprtokens = e._parse(instring, loc, doActions)\n", | |
"KeyboardInterrupt\n", | |
"\n", | |
"During handling of the above exception, another exception occurred:\n", | |
"\n", | |
"Traceback (most recent call last):\n", | |
" File \"/usr/local/bin/pip3\", line 8, in <module>\n", | |
" sys.exit(main())\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/main.py\", line 71, in main\n", | |
" return command.main(cmd_args)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/base_command.py\", line 104, in main\n", | |
" return self._main(args)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/base_command.py\", line 212, in _main\n", | |
" logger.critical(\"Operation cancelled by user\")\n", | |
" File \"/usr/lib/python3.7/logging/__init__.py\", line 1415, in critical\n", | |
" def critical(self, msg, *args, **kwargs):\n", | |
"KeyboardInterrupt\n", | |
"fatal: destination path 'gym-gridworld' already exists and is not an empty directory.\n", | |
"/content/gym-gridworld\n", | |
"Obtaining file:///content/gym-gridworld\n", | |
"Requirement already satisfied: gym in /usr/local/lib/python3.7/dist-packages (from gym-gridworld==0.0.1) (0.17.3)\n", | |
"Requirement already satisfied: scipy in /usr/local/lib/python3.7/dist-packages (from gym->gym-gridworld==0.0.1) (1.4.1)\n", | |
"Requirement already satisfied: numpy>=1.10.4 in /usr/local/lib/python3.7/dist-packages (from gym->gym-gridworld==0.0.1) (1.19.5)\n", | |
"Requirement already satisfied: cloudpickle<1.7.0,>=1.2.0 in /usr/local/lib/python3.7/dist-packages (from gym->gym-gridworld==0.0.1) (1.3.0)\n", | |
"Requirement already satisfied: pyglet<=1.5.0,>=1.4.0 in /usr/local/lib/python3.7/dist-packages (from gym->gym-gridworld==0.0.1) (1.5.0)\n", | |
"Requirement already satisfied: future in /usr/local/lib/python3.7/dist-packages (from pyglet<=1.5.0,>=1.4.0->gym->gym-gridworld==0.0.1) (0.16.0)\n", | |
"Traceback (most recent call last):\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3021, in _dep_map\n", | |
" return self.__dep_map\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 2815, in __getattr__\n", | |
" raise AttributeError(attr)\n", | |
"AttributeError: _DistInfoDistribution__dep_map\n", | |
"\n", | |
"During handling of the above exception, another exception occurred:\n", | |
"\n", | |
"Traceback (most recent call last):\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/base_command.py\", line 180, in _main\n", | |
" status = self.run(options, args)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/req_command.py\", line 199, in wrapper\n", | |
" return func(self, options, args)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/commands/install.py\", line 385, in run\n", | |
" conflicts = self._determine_conflicts(to_install)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/commands/install.py\", line 515, in _determine_conflicts\n", | |
" return check_install_conflicts(to_install)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/operations/check.py\", line 103, in check_install_conflicts\n", | |
" package_set, _ = create_package_set_from_installed()\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/operations/check.py\", line 45, in create_package_set_from_installed\n", | |
" package_set[name] = PackageDetails(dist.version, dist.requires())\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 2736, in requires\n", | |
" dm = self._dep_map\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3023, in _dep_map\n", | |
" self.__dep_map = self._compute_dependencies()\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3033, in _compute_dependencies\n", | |
" reqs.extend(parse_requirements(req))\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3094, in parse_requirements\n", | |
" yield Requirement(line)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pkg_resources/__init__.py\", line 3101, in __init__\n", | |
" super(Requirement, self).__init__(requirement_string)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/packaging/requirements.py\", line 113, in __init__\n", | |
" req = REQUIREMENT.parseString(requirement_string)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1943, in parseString\n", | |
" loc, tokens = self._parse(instring, 0)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4069, in parseImpl\n", | |
" loc, exprtokens = e._parse(instring, loc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4254, in parseImpl\n", | |
" ret = e._parse(instring, loc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1683, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4052, in parseImpl\n", | |
" loc, resultlist = self.exprs[0]._parse(instring, loc, doActions, callPreParse=False)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1687, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 4462, in parseImpl\n", | |
" return self.expr._parse(instring, loc, doActions, callPreParse=False)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 1687, in _parseNoCache\n", | |
" loc, tokens = self.parseImpl(instring, preloc, doActions)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 2899, in parseImpl\n", | |
" raise ParseException(instring, loc, self.errmsg, self)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_vendor/pyparsing.py\", line 304, in __init__\n", | |
" def __init__(self, pstr, loc=0, msg=None, elem=None):\n", | |
"KeyboardInterrupt\n", | |
"\n", | |
"During handling of the above exception, another exception occurred:\n", | |
"\n", | |
"Traceback (most recent call last):\n", | |
" File \"/usr/local/bin/pip3\", line 8, in <module>\n", | |
" sys.exit(main())\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/main.py\", line 71, in main\n", | |
" return command.main(cmd_args)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/base_command.py\", line 104, in main\n", | |
" return self._main(args)\n", | |
" File \"/usr/local/lib/python3.7/dist-packages/pip/_internal/cli/base_command.py\", line 212, in _main\n", | |
" logger.critical(\"Operation cancelled by user\")\n", | |
"KeyboardInterrupt\n" | |
] | |
} | |
], | |
"source": [ | |
"!wget http://www.atarimania.com/roms/Roms.rar\n", | |
"!unrar e Roms.rar\n", | |
"!unzip ROMS.zip > /dev/null\n", | |
"!python -m atari_py.import_roms ./ROMS > /dev/null\n", | |
"!pip install einops\n", | |
"!git clone https://github.com/xinleipan/gym-gridworld.git\n", | |
"%cd gym-gridworld\n", | |
"!pip install -e ." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "kHfTkNhEZ23Q" | |
}, | |
"outputs": [], | |
"source": [ | |
"import copy\n", | |
"import gym\n", | |
"from gym.wrappers import AtariPreprocessing, FrameStack, TransformObservation\n", | |
"from gym.wrappers import TimeLimit\n", | |
"import gym_gridworld\n", | |
"import matplotlib.pyplot as plt\n", | |
"import numpy as np\n", | |
"import torch\n", | |
"from torch import nn\n", | |
"import torch.nn.functional as F\n", | |
"import einops\n", | |
"import seaborn as sns\n", | |
"import cv2\n", | |
"from tqdm.notebook import tqdm\n", | |
"\n", | |
"%matplotlib inline\n", | |
"sns.set()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "oy8T5RcWaIEw" | |
}, | |
"outputs": [], | |
"source": [ | |
"### Gridworld Env ###\n", | |
"\n", | |
"class GridWorldWrapper(gym.ObservationWrapper):\n", | |
" def __init__(self, env):\n", | |
" super().__init__(env)\n", | |
"\n", | |
" obs_shape = (1, 16, 16)\n", | |
" self.observation_space = gym.spaces.Box(\n", | |
" low=0, high=1, shape=obs_shape, dtype=np.float32)\n", | |
"\n", | |
" def observation(self, observation):\n", | |
" observation = cv2.cvtColor(observation, cv2.COLOR_RGB2GRAY)\n", | |
" observation = cv2.resize(observation, self.observation_space.shape[1:],\n", | |
" interpolation=cv2.INTER_AREA)\n", | |
" observation = np.expand_dims(observation, 0)\n", | |
" return observation\n", | |
"\n", | |
"\n", | |
"class GridWorldWrapper(gym.ObservationWrapper):\n", | |
" def __init__(self, env):\n", | |
" super().__init__(env)\n", | |
"\n", | |
" obs_shape = (1, 16, 16)\n", | |
" self.observation_space = gym.spaces.Box(\n", | |
" low=0, high=1, shape=obs_shape, dtype=np.float32)\n", | |
"\n", | |
" def observation(self, observation):\n", | |
" observation = cv2.cvtColor(observation, cv2.COLOR_RGB2GRAY)\n", | |
" observation = cv2.resize(observation, self.observation_space.shape[1:],\n", | |
" interpolation=cv2.INTER_AREA)\n", | |
" observation = np.expand_dims(observation, 0)\n", | |
" return observation\n", | |
"\n", | |
"class SimpleMapWrapper(gym.Wrapper):\n", | |
" def __init__(self, env, randomized=False):\n", | |
" super().__init__(env)\n", | |
" self.random_start = randomized\n", | |
" self._reset_start_map()\n", | |
"\n", | |
" def _reset_start_map(self):\n", | |
" map = np.ones((16, 16), dtype=np.int64)\n", | |
" map [1:-1, 1:-1] = 0\n", | |
"\n", | |
" get_random_pos = lambda: np.random.randint(1, 15)\n", | |
" if self.random_start:\n", | |
" map[get_random_pos(), get_random_pos()] = 3\n", | |
" new_pos = (get_random_pos(), get_random_pos())\n", | |
" while map[new_pos[0], new_pos[1]] == 3:\n", | |
" new_pos = (get_random_pos(), get_random_pos())\n", | |
" map[new_pos[0], new_pos[1]] = 4\n", | |
" else:\n", | |
" map[-3, 2] = 3\n", | |
" map[-6, 4] = 4\n", | |
"\n", | |
" uenv = self.unwrapped\n", | |
" uenv.start_grid_map = map\n", | |
" uenv.current_grid_map = copy.deepcopy(uenv.start_grid_map) # current grid map\n", | |
" uenv.observation = uenv._gridmap_to_observation(uenv.start_grid_map)\n", | |
" uenv.grid_map_shape = uenv.start_grid_map.shape\n", | |
"\n", | |
" uenv.agent_start_state, uenv.agent_target_state = \\\n", | |
" uenv._get_agent_start_target_state(uenv.start_grid_map)\n", | |
" uenv.agent_state = copy.deepcopy(uenv.agent_start_state)\n", | |
"\n", | |
" def reset(self):\n", | |
" if self.random_start:\n", | |
" self._reset_start_map()\n", | |
" return super().reset()\n", | |
"\n", | |
"def create_gridworld_env(max_steps=1000):\n", | |
" global N_FRAME_STACK\n", | |
" N_FRAME_STACK = 1\n", | |
"\n", | |
" env = gym.make('gridworld-v0')\n", | |
" env = GridWorldWrapper(env)\n", | |
" env = TimeLimit(env, max_steps)\n", | |
" env = TransformObservation(env, torch.FloatTensor)\n", | |
" return env\n", | |
"\n", | |
"def create_simple_gridworld_env(randomized=False, max_steps=1000):\n", | |
" env = create_gridworld_env(max_steps)\n", | |
" env = SimpleMapWrapper(env, randomized)\n", | |
" return env\n", | |
"\n", | |
"\n", | |
"### Atari Env ###\n", | |
"\n", | |
"atari_wrappers = [\n", | |
" lambda env: AtariPreprocessing(env, scale_obs=True),\n", | |
" lambda env: FrameStack(env, N_FRAME_STACK),\n", | |
" lambda env: TransformObservation(env, torch.FloatTensor)\n", | |
"]\n", | |
"\n", | |
"def create_breakout_env():\n", | |
" global N_FRAME_STACK\n", | |
" N_FRAME_STACK = 4\n", | |
"\n", | |
" env = gym.make('BreakoutNoFrameskip-v4')\n", | |
" for wrapper in atari_wrappers:\n", | |
" env = wrapper(env)\n", | |
" return env\n", | |
"\n", | |
"# env = create_breakout_env()\n", | |
"# env = create_gridworld_env()\n", | |
"env = create_simple_gridworld_env(randomized=True)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "z1m8gi53cTpt" | |
}, | |
"outputs": [], | |
"source": [ | |
"class SFModel(nn.Module):\n", | |
" def __init__(self, obs_dim, n_acts, embed_size=128):\n", | |
" super().__init__()\n", | |
" self.embed_size = embed_size\n", | |
" self.n_acts = n_acts\n", | |
"\n", | |
" # Change network size depending on the size of the input\n", | |
" if obs_dim[1] <= 42 and obs_dim[2] <= 42:\n", | |
" create_convs = self.create_small_convs\n", | |
" linear_dim = 128\n", | |
" else:\n", | |
" create_convs = self.create_large_convs\n", | |
" linear_dim = 512\n", | |
"\n", | |
" test_input = torch.zeros(obs_dim)[None]\n", | |
"\n", | |
" # Feature layers\n", | |
" self.conv_feature_layers = create_convs(obs_dim[0])\n", | |
" feature_embed_dim = self.conv_feature_layers(test_input)\n", | |
" self.linear_feature_layers = nn.Sequential(\n", | |
" nn.Linear(feature_embed_dim.shape[1], linear_dim),\n", | |
" nn.ReLU(),\n", | |
" nn.Linear(linear_dim, embed_size)\n", | |
" )\n", | |
" self.feature_layers = nn.Sequential(\n", | |
" self.conv_feature_layers,\n", | |
" self.linear_feature_layers\n", | |
" )\n", | |
"\n", | |
" # Sucessor Feature Layers\n", | |
" self.conv_sf_layers = create_convs(obs_dim[0])\n", | |
" sf_embed_dim = self.conv_sf_layers(test_input)\n", | |
" self.linear_sf_layers = nn.Sequential(\n", | |
" nn.Linear(sf_embed_dim.shape[1] + embed_size, linear_dim),\n", | |
" nn.ReLU(),\n", | |
" nn.Linear(linear_dim, linear_dim),\n", | |
" nn.ReLU(),\n", | |
" nn.Linear(linear_dim, n_acts * embed_size)\n", | |
" )\n", | |
" self.sf_layers = nn.Sequential(\n", | |
" self.conv_sf_layers,\n", | |
" self.linear_sf_layers\n", | |
" )\n", | |
"\n", | |
" def create_large_convs(self, input_dim):\n", | |
" return nn.Sequential(\n", | |
" nn.Conv2d(input_dim, 32, 8, 4),\n", | |
" nn.ReLU(),\n", | |
" nn.Conv2d(32, 64, 4, 2),\n", | |
" nn.ReLU(),\n", | |
" nn.Conv2d(64, 64, 3, 1),\n", | |
" nn.ReLU(),\n", | |
" nn.Flatten()\n", | |
" )\n", | |
" \n", | |
" def create_small_convs(self, input_dim):\n", | |
" return nn.Sequential(\n", | |
" nn.Conv2d(input_dim, 8, 4, 2),\n", | |
" nn.ReLU(),\n", | |
" nn.Conv2d(8, 16, 3, 1),\n", | |
" nn.ReLU(),\n", | |
" nn.Flatten()\n", | |
" )\n", | |
"\n", | |
" def forward(self, obs, goal_vector=None):\n", | |
" features = self.feature_layers(obs)\n", | |
" features = F.normalize(features, dim=1)\n", | |
"\n", | |
" if goal_vector is None:\n", | |
" sfs = None\n", | |
" else:\n", | |
" sf_z = self.conv_sf_layers(obs)\n", | |
" sf_z = torch.cat((sf_z, goal_vector), dim=-1)\n", | |
" sfs = self.linear_sf_layers(sf_z)\n", | |
" sfs = sfs.reshape(-1, self.n_acts, self.embed_size)\n", | |
" return features, sfs\n", | |
"\n", | |
" def train(self, batch_data, optimizer, gamma=0.99, reward_loss_weight=1):\n", | |
" device = next(self.parameters()).device\n", | |
"\n", | |
" batch_data = np.array(batch_data)\n", | |
" obs, acts, next_obs, rewards, dones, skill_vectors = \\\n", | |
" [torch.from_numpy(np.stack(batch_data[:, i])).to(device) \\\n", | |
" for i in range(batch_data.shape[1])]\n", | |
"\n", | |
" _, next_sfs = self(next_obs, skill_vectors)\n", | |
" optimizer.zero_grad()\n", | |
" features, sfs = self(obs, skill_vectors)\n", | |
" q_vals = torch.bmm(next_sfs, skill_vectors.unsqueeze(2))\n", | |
" next_acts = q_vals.argmax(dim=1).unsqueeze(-1).repeat(1, 1, next_sfs.shape[2])\n", | |
" selected_next_sfs = next_sfs.gather(dim=1, index=next_acts)\n", | |
" selected_next_sfs = selected_next_sfs.squeeze(1)\n", | |
" terminals = 1 - dones.int()\n", | |
" y = features + gamma * selected_next_sfs * terminals.unsqueeze(1)\n", | |
"\n", | |
" sf_idxs = acts.unsqueeze(1).unsqueeze(2).repeat(1, 1, sfs.shape[2])\n", | |
" selected_sfs = sfs.gather(dim=1, index=sf_idxs)\n", | |
" selected_sfs = selected_sfs.squeeze(1)\n", | |
"\n", | |
" td_loss = (y.detach() - selected_sfs) ** 2\n", | |
" td_loss = torch.mean(torch.sum(td_loss, dim=1))\n", | |
"\n", | |
" reward_loss = 1.0 - torch.bmm(features.unsqueeze(1), skill_vectors.unsqueeze(2))\n", | |
" reward_loss = reward_loss.mean()\n", | |
"\n", | |
" total_loss = reward_loss_weight * reward_loss + td_loss\n", | |
"\n", | |
" optimizer.zero_grad()\n", | |
" total_loss.backward()\n", | |
" optimizer.step()\n", | |
"\n", | |
" return total_loss, reward_loss, td_loss" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "-7OjQ92s6oTN" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Adapted from: https://github.com/deepmind/deepmind-research/blob/master/visr/VISR_ICLR2020.ipynb\n", | |
"def sample_sphere(dim, n=1):\n", | |
" unnormed = np.random.randn(n, dim)\n", | |
" arr = unnormed / np.linalg.norm(unnormed, axis=-1, keepdims=True)\n", | |
" return torch.FloatTensor(arr)\n", | |
"\n", | |
"def sample_batch(buffer, n):\n", | |
" data_idxs = np.random.choice(range(len(buffer)), size=n, replace=False)\n", | |
" batch_data = []\n", | |
" for i in data_idxs:\n", | |
" batch_data.append(buffer[i])\n", | |
" return batch_data" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "O6qRisLM6wm-" | |
}, | |
"outputs": [], | |
"source": [ | |
"DEVICE = 'cuda'\n", | |
"\n", | |
"n_episodes = 100000\n", | |
"update_freq = 64\n", | |
"batch_size = 256\n", | |
"print_freq = update_freq * 500\n", | |
"max_steps = 100\n", | |
"randomize_env = True\n", | |
"exp_buffer_size = int(1e6)\n", | |
"\n", | |
"start_act_epsilon = 1\n", | |
"end_act_epsilon = 0.1\n", | |
"act_epsilon_anneal_steps = int(1e5)\n", | |
"\n", | |
"start_reward_weight = 10\n", | |
"end_reward_weight = 10\n", | |
"reward_anneal_steps = int(1e6)\n", | |
"\n", | |
"embed_dim = 32\n", | |
"lr = 1e-4\n", | |
"\n", | |
"\n", | |
"def anneal_func(step, start, end, n_steps):\n", | |
" if step >= n_steps:\n", | |
" return end\n", | |
" return start - ((start - end) * (step / n_steps))\n", | |
"\n", | |
"get_act_epsilon = lambda step: anneal_func(\n", | |
" step, start_act_epsilon, end_act_epsilon, act_epsilon_anneal_steps)\n", | |
"get_reward_weight = lambda step: anneal_func(\n", | |
" step, start_reward_weight, end_reward_weight, reward_anneal_steps)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "mGMc0FPPh2IV" | |
}, | |
"outputs": [], | |
"source": [ | |
"env = create_simple_gridworld_env(randomize_env, max_steps)\n", | |
"\n", | |
"obs_dim = env.observation_space.shape\n", | |
"n_acts = env.action_space.n\n", | |
"model = SFModel(obs_dim, n_acts, embed_dim)\n", | |
"model = model.to(DEVICE)\n", | |
"\n", | |
"optimizer = torch.optim.Adam(model.parameters(), lr=lr)\n", | |
"\n", | |
"sample_skill = lambda: sample_sphere(embed_dim)[0]\n", | |
"\n", | |
"exp_buffer = [] # [[obs, act, next_obs, reward, done, skill_vector], ...]\n", | |
"\n", | |
"all_rewards = []\n", | |
"loss_hist = [[], [], []]\n", | |
"step_idx = 0" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"colab": { | |
"background_save": true, | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "__s4jY95y7T5", | |
"outputId": "357466e9-640c-4501-efa3-7dcdda3d967e" | |
}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:81: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray\n" | |
] | |
}, | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Step: 32000\tLoss: 24.7084\tReward Loss: 0.9345\tTD Loss: 15.3632\tEx Reward: 0.15\n", | |
"Step: 64000\tLoss: 29.1705\tReward Loss: 0.9143\tTD Loss: 20.0273\tEx Reward: 0.13\n", | |
"Step: 96000\tLoss: 11.8866\tReward Loss: 0.8425\tTD Loss: 3.4617\tEx Reward: 0.10\n", | |
"Step: 128000\tLoss: 10.2671\tReward Loss: 0.8418\tTD Loss: 1.8491\tEx Reward: 0.09\n", | |
"Step: 160000\tLoss: 9.9769\tReward Loss: 0.8453\tTD Loss: 1.5240\tEx Reward: 0.08\n", | |
"Step: 192000\tLoss: 9.9873\tReward Loss: 0.8460\tTD Loss: 1.5270\tEx Reward: 0.08\n", | |
"Step: 224000\tLoss: 9.9653\tReward Loss: 0.8477\tTD Loss: 1.4880\tEx Reward: 0.07\n", | |
"Step: 256000\tLoss: 9.9219\tReward Loss: 0.8504\tTD Loss: 1.4176\tEx Reward: 0.07\n", | |
"Step: 288000\tLoss: 9.9181\tReward Loss: 0.8491\tTD Loss: 1.4267\tEx Reward: 0.07\n", | |
"Step: 320000\tLoss: 9.8990\tReward Loss: 0.8442\tTD Loss: 1.4570\tEx Reward: 0.06\n", | |
"Step: 352000\tLoss: 9.9144\tReward Loss: 0.8383\tTD Loss: 1.5316\tEx Reward: 0.06\n", | |
"Step: 384000\tLoss: 10.0145\tReward Loss: 0.8352\tTD Loss: 1.6622\tEx Reward: 0.06\n", | |
"Step: 416000\tLoss: 10.2442\tReward Loss: 0.8338\tTD Loss: 1.9065\tEx Reward: 0.06\n", | |
"Step: 448000\tLoss: 10.7727\tReward Loss: 0.8329\tTD Loss: 2.4435\tEx Reward: 0.06\n", | |
"Step: 480000\tLoss: 14.2633\tReward Loss: 0.8334\tTD Loss: 5.9294\tEx Reward: 0.06\n", | |
"Step: 512000\tLoss: 15.3901\tReward Loss: 0.8345\tTD Loss: 7.0455\tEx Reward: 0.06\n", | |
"Step: 544000\tLoss: 16.0420\tReward Loss: 0.8348\tTD Loss: 7.6939\tEx Reward: 0.06\n", | |
"Step: 576000\tLoss: 16.4977\tReward Loss: 0.8364\tTD Loss: 8.1338\tEx Reward: 0.06\n", | |
"Step: 608000\tLoss: 16.8128\tReward Loss: 0.8389\tTD Loss: 8.4240\tEx Reward: 0.05\n", | |
"Step: 640000\tLoss: 17.1703\tReward Loss: 0.8388\tTD Loss: 8.7820\tEx Reward: 0.06\n", | |
"Step: 672000\tLoss: 17.3322\tReward Loss: 0.8384\tTD Loss: 8.9487\tEx Reward: 0.05\n", | |
"Step: 704000\tLoss: 17.4789\tReward Loss: 0.8378\tTD Loss: 9.1005\tEx Reward: 0.05\n", | |
"Step: 736000\tLoss: 17.6233\tReward Loss: 0.8374\tTD Loss: 9.2495\tEx Reward: 0.05\n" | |
] | |
} | |
], | |
"source": [ | |
"# Episode loop\n", | |
"for episode_idx in range(n_episodes):\n", | |
" obs = env.reset()\n", | |
"\n", | |
" skill_vector = sample_skill()\n", | |
"\n", | |
" ep_rewards = []\n", | |
" done = False\n", | |
" episodes_passed = 0\n", | |
" while not done:\n", | |
" # Sample an action\n", | |
" if np.random.rand() < get_act_epsilon(step_idx):\n", | |
" # Random sample\n", | |
" act = env.action_space.sample()\n", | |
" else:\n", | |
" # Sample based off of successor features\n", | |
" with torch.no_grad():\n", | |
" _, sfs = model(obs.unsqueeze(0).to(DEVICE),\n", | |
" skill_vector.unsqueeze(0).to(DEVICE))\n", | |
" sfs = sfs.cpu()\n", | |
" q_vals = torch.matmul(sfs[0], skill_vector.unsqueeze(1))\n", | |
" act = torch.argmax(q_vals).item()\n", | |
"\n", | |
" # Take a step\n", | |
" next_obs, reward, done, _ = env.step(act)\n", | |
" exp_buffer.append([np.array(copy.deepcopy(obs)), act,\n", | |
" np.array(copy.deepcopy(next_obs)),\n", | |
" reward, done, np.array(skill_vector)])\n", | |
" ep_rewards.append(reward)\n", | |
" obs = next_obs\n", | |
"\n", | |
" # Delete extra data from the experience buffer\n", | |
" exp_buffer_overflow = len(exp_buffer) - exp_buffer_size\n", | |
" if exp_buffer_overflow > 0:\n", | |
" exp_buffer = exp_buffer[exp_buffer_overflow:]\n", | |
"\n", | |
" # Update the model\n", | |
" if step_idx % update_freq == 0 and len(exp_buffer) >= batch_size:\n", | |
" batch_data = sample_batch(exp_buffer, batch_size)\n", | |
" loss, reward_loss, td_loss = model.train(\n", | |
" batch_data, optimizer, reward_loss_weight=get_reward_weight(step_idx))\n", | |
" for i, l in enumerate([loss, reward_loss, td_loss]):\n", | |
" loss_hist[i].append(l.item())\n", | |
" batch_data = []\n", | |
"\n", | |
" # Print the agent training status\n", | |
" if step_idx != 0 and step_idx % print_freq == 0:\n", | |
" lookback = print_freq // update_freq\n", | |
" print('Step: {}\\tLoss: {:.4f}\\tReward Loss: {:.4f}\\tTD Loss: {:.4f}\\tEx Reward: {:.2f}'\n", | |
" .format(step_idx, *[np.mean(loss_hist[i][-lookback:]) \\\n", | |
" for i in range(len(loss_hist))],\n", | |
" np.mean(all_rewards[-episodes_passed:])))\n", | |
" episodes_passed = 0\n", | |
" \n", | |
" step_idx += 1\n", | |
" episodes_passed += 1\n", | |
" all_rewards.append(sum(ep_rewards))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 818 | |
}, | |
"id": "43o_HMRlyre_", | |
"outputId": "f8f1eb5b-795e-47b5-a90d-1b7f3c6fb06e" | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAELCAYAAADJF31HAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deWATZfoH8G+Opvd90QMLlMMCItAqKBaksAvK6Sori7L+FpH1wmtBWVFwOVYKiOiKi4qo66KsFxUQrUpBAUFBqFCQUm6hpUd60LtN5v39kWY6SSZnk2YmfT7/0GQmydN0ePLmeS8FY4yBEEKI7Cm9HQAhhBD3oIROCCE+ghI6IYT4CErohBDiIyihE0KIj6CETgghPoISOiECCxYswMsvvyx67LPPPsOf/vSnTo6IEMdRQieykpWVhR9++MFj5xMiZ5TQCSHER1BCJ7Ixf/58FBcX48EHH8SQIUPw1ltvAQB27tyJCRMmICMjAzNnzsSZM2dsnv/YY49hxIgRSE9Pxz333IOioiKX4jl8+DDuvPNOpKen484778Thw4f5Y5999hnGjBmDIUOGICsrC1u3bgUAXLhwAffeey/S09MxbNgwPPHEEx15SwgxxQiRkdGjR7N9+/bxt8+ePcuuv/56tnfvXtbS0sLefPNNNnbsWNbc3Cx6PmOMffzxx6y2tpY1NzezZcuWscmTJ/PHnnnmGbZmzRrR1/7000/Z9OnTGWOMVVVVsYyMDLZlyxbW2trKtm3bxjIyMlhlZSWrr69nQ4YMYWfOnGGMMVZaWspOnTrFGGPsySefZK+//jrT6/WsqamJHTx40H1vDunyqIVOZG3Hjh0YNWoURowYAT8/P9x///1oamrCkSNHrD7mrrvuQkhICDQaDebOnYuTJ0+itrbWqdfdvXs3UlJSMHXqVKjVakycOBG9evXCrl27AABKpRJFRUVoampCXFwc+vTpAwBQq9UoLi5GWVkZ/P39kZGR4fovT4gZSuhE1srKypCYmMjfViqVSEhIQGlpqej5er0eq1evxtixYzF06FBkZWUBAKqqqjr0ugCQmJiI0tJSBAUF4eWXX8bmzZtxyy23YM6cOSZlIMYY7rrrLkyYMAGffPKJU69LiC1qbwdASEfExcXh1KlT/G3GGEpKShAfHy96/rZt27Bz50688847SE5ORm1tLW644QYwJxcdjYuLQ3Fxscl9JSUlyMzMBABkZmYiMzMTTU1NWLt2LZ5//nl88MEHiI2NxbJlywAAhw4dwl/+8hfccMMNSElJcer1CRFDLXQiKzExMfjtt9/427fddhu+++477N+/H62trdi4cSM0Gg2GDBkien59fT00Gg0iIyPR2NiINWvWuBTHqFGjcP78eWzbtg06nQ47duzA6dOnceutt6KiogLffvstGhoaoNFoEBQUBKXS8F/tyy+/xJUrVwAA4eHhUCgU/DFCOoquJCIrc+bMwb///W9kZGTg7bffRq9evbBq1SosXboUw4cPx65du7B+/XpoNBrR86dOnYrExERkZmZiwoQJGDx4sEtxREZGYv369XjnnXcwbNgwbNiwAevXr0dUVBQ4jsO7776LzMxM3HjjjTh48CBeeOEFAMCxY8cwbdo0DBkyBA899BAWLlyI7t27u+vtIV2cgjn7XZMQQogkUQudEEJ8BCV0QgjxEZTQCSHER1BCJ4QQH0EJnRBCfIRTCf21115Dv379+Ikc+fn5mDx5MsaNG4dZs2ZBq9V6JEhCCCH2OTxT9Pjx48jPz0dSUhIAgOM4zJ8/Hy+++CIyMjLw+uuvY/Xq1XjxxRedCqCqqh4c5/zIyejoEGi1dU4/rrPJIU45xAhQnO4khxgBilOMUqlAZGSw6DGHEnpLSwuWLFmCl156CX/+858BAAUFBSaLC02fPh1jxoxxOqFzHHMpoRsfKwdyiFMOMQIUpzvJIUaA4nSGQyWXV155BZMnT0ZycjJ/X0lJicniRMYZctXV1e6PkhBCiF12W+hHjhxBQUEB5s2b55EAoqNDXH5sbGyoGyPxHDnEKYcYAYrTneQQI0BxOsNuQj948CDOnDmDMWPGAACuXLmC+++/HzNnzjRZba6yshJKpRIRERFOBaDV1rn0VSU2NhTl5c6tYe0NcohTDjECFKc7ySFGgOIUo1QqrDaE7ZZc5syZg7179yIvLw95eXno1q0b3n77bcyePRtNTU04dOgQAGDz5s0YP368eyMnhBDiMJfXQ1cqlVi5ciUWL16M5uZmJCUlYdWqVe6MjRBCiBOcTuh5eXn8z0OHDsW2bdvcGhAhhBDX0ExRL6ipa8asFXl4e/sJb4dCCPEhlNC94L2vCgEA+wqueDkSQogvoYTuBbWNLd4OgRDigyihe8g///szcn+6KHpMAUUnR0MI6QoooXvI6Us1+F/eaej1nMWx63tHeyEiQoivo4TuYZVXmy3uU9Eu74QQD6DM4gV6zrLVTgghHeUTCb2lVY/Tl2vwUd5pXC73/lKbjDHRn430EliVzV3Kqxtxqcz77zkhpAMzRaXk/dxCfgjgVz9dxMYFWV6NR5iwOcagMj+u952E/sz6/QDg9fecEOIjLfSLEmshChO22MJjnmqhF1fU42Kp9BcyIoR4hk8kdJWyfRhgTHiAFyMx0Alq5GLJOyig/YvRJTeWiJ7b8CNeeOeg255PKn4uLMdrnx3zdhiESJ5PJHShipomrP+8wKsx6Oy00IV19X/4YAJ2t3VbjuHwqXJvh0GI5Mk+oefsOYvzV0zLDD/9Wubw41t1HD77/gyaW/XgGBPtxHSWcOw5Z6dT1Jc6SAkh3iX7hL5133mrxy6V1eGp1/aipt76VPtdRy5j+w8X8OWBC5idvQv/yzvd4Zh0dhL2L6e1Dj3Pnl+Kseaj/A7H4yvc8WFLiC+TfUK35csfL6C6rgX7bSyCVVNvmPjT3KoHAHxz6LcOv65JC10koZ8ruerQ87zz5UkUnK1Eq46DTs91+fHrLbqu/fsTYo9PJ/SGJh0A4KNd1lvdXx4wrLdirHurVbbfEsaYRRll6XsHTVrS9W2vCwDHzzrWGreloakVc1btxgMrd3f4uTzl/BXHPqQ6oqXtQ5cQIs6nE3pjS3sCOHmhyua5urZWtVJpe+GsJe8ewgPZu0zuO1dSi4KzlfztLd+f5X/euO04ahs6trqiHOrsNXWu/Y4FZ7U2S2JClNAJsc2nE7pwBqOx1dzcqkfOnrN8Aje6XFFvON5iO2lcKK0FA1BdZ7lGS2tbSaDwYrXJ/Ss2HXY6dqG9R0s69HghPcehqtYydkcVV9Tj7S9OYOUHh03eQ5XK+RUkGWNY89EvePH9nx06/8zlGqdfg5CuxKcTukKQY4wdatt/OI+t+85jj1mSPH3JfrI4eLJ99MzHu85YHDe2xM1LMiXaBlTUNJrEIWQvUeXsPWc3NmF9va6x1ep5T7y6F39btw+NzTqr59jy0v/yse/YFZy8WI33vjzJ369SuJLQDf+WVTc6dH5YsAYcY/i5sJw6SAkR4bMJvblVj7SUSP72521J0dgCb7XTwdbcokeBWf37XUECO3DcsqPVViJ9+t/7wRiDWBpa7mAL1ZaW1vbf57FX9oieU9/Uyn9TcbWDUfhhJdxxSWWn78Heczl0PsfwfX4x1m05ZvGBDBj+pp9+d8butyxCfJXPJvQPvjmFnglh/G1jScVR7311Ems++gVXKhv4+4TldWMqErYUfzldYfM5OcbsfpC4ypH6snC8vp2uAquamsVfR+lCC11sBJAtrTqOr7dra5osju/Ov4wv9l/AFwfOOx2Ls5pb9dj2w/kuP/KISIvPJvQ9R0tstgCb7STAAydKAQBHigwzFGetyDMZvWIkfI1DhbZnM+78+bLd13WVI89rugqkm19HkM8rrzbhx7b3zxaxv4+tUtD7O37ll3nQiSRS4xo6nvrQFHpkzffY8v1Z7DtG+8IS6fDZhA6ItwCN9VrhSBRzwtZ8ebVlS9Bo1YdH8PVP7ePWf7OzSNjmnUUuJ1J7Gq20nIWaW2zPYBVz4nylQ+Pmvzxwgf/5xf8exhtbj9ttgZvn5JMXqvDIy9+j4Jz4UM/Ci1U4W2yIxVb4nVFeN75/7uywJqSjfDqhb9lj2ZlY32S9zm2krWnvpOufEon3vjppcU5STDB+vVCFj3dbdo7acq7YdnLc9M0pLHzrgFPPCdhu2Rqt29K+wBXHMew9WmIx2sfc6s35WPreIf52fFSQ6HllVe3vWeVVw4eg2IcGxxjWfvwLTpyvtDhe1NY5/H1+MUqrGiweCwD5bWUtZ8s1jtDpOaeHmKZ0C3V7HIS4yqcTupie3cLsniNc/lapVOC7/GKLc+zV5MOCNaL3C2vyYnb+fAklWsM5/bpHWByftSJP9HENTo5a2X/8Cjbu+NXm0gliggPEl9DPSk/GrBV5eP7tH/n+BbGk29yix9EzWqzenM+3tgFg1+FLfNP6UGE5/v7GAVypbBAdHgqIf1h8vs/wAW6rc9row2+LLN7Lf+cU4PFX99p9rJAc5giQrkP2Cb2blRajNVFh9pfXVQg6+HYdvuR0TIH+atx4bZzosby255szuT/Gpifz94sNw7PWet6w/YTFfQ0i9X1bPv3OUHKqc7JFaq3r8/3cQgDA5fL2Dzo9x9DcqsernxzlS13CvtO1H//S/vivT1k857NvHsBTr+0TfT3W9tbUNbby37qMo1uMHyStOr3FiJeP8k5j1oo80SUejhTZ7tQWY68jnJDO5FBCf/jhhzF58mRMnToVM2bMwK+//goAyMrKwvjx4zFlyhRMmTIFe/aID5fzJLWTE1qCzFqYYqMz/P3a35bj523PMBWj13NQq5XI6BdrccyYt/1UStwyKIG/X6zFaW3jjh8KruCz78+gVNDad7aFbtRqp+RixCdGJ95uxhiOndEi/3QFPmpb9Mxm7dvxp8bOtg/Gx17Zg7lrTa87Y4f2X1d/h4fWfGdy7KufLprcFvsWYat/QafnTD48f5fR3YmoCfEsh7agy87ORmiooVb47bff4tlnn8WWLVsAAK+++ir69u3ruQjtcPYbr/l/YLGW8arNrq1wODY9GW9tO44WHQe1SoHrekVbjHwxjs5QqZTwU7d/cHAcYD6U29Zoje0/XMD2Hy5gwzOjoVQosG2faX/Bui3HcOFKLVY+dDMA6ysVmg9DLK1sQG1DK3onh5vc/9Ca7zBv+mDUNdgvZxht3nka1/eONrxOiyEJmi91LCSswzvLvEO6TFCDr7zaZPWbmU7PQaNUmfStcByD0qyh0NSiw6ufHEVpVaPJTNuIEPHSGiHe4FAL3ZjMAaCurs6kJOFtYi2snglhSIgWL8UIa57WJvq4HAtj2H/c0Dq8WFon2tIzrnli/s3i+PlKl2Y/njhnWEPGfEjlz4XlqBCM1ba2Rrz52jV/f/MA/vlf8YlOqzfno9SJpLv3WAnf13Ci7ZvOrxcqrZ7/g41VMe0xrpppJOzIrbXxIfTgS9/h0MkyVAuStFhd/Pi5Spy8WG2xbALV0ImUOLxJ9MKFC7Fv3z4wxrBhwwb+/nnz5oExhvT0dDz11FMIC7Pf6ehOHGNQwPTrekSIBuXVhtatxk9pMotSmGSdnaloz67Dl/mfj57R4vrUaKvn+qmUCNC0v/2vfnIUQ/rE8Le//PGC2MMsrPnoFzz35wyrxxljUCgUeGPrcdHjtkpW7pheL3z2sqoGKJyp2ThBpzONVfgB19DW+rY2wun1nAIM7BXF39brGeBnek6gv/h/FUroREocTujLly8HAOTk5GDlypV46623sGnTJiQkJKClpQXLly/HkiVLsHr1aqcCiI4OcS5igdjYUCgUCtyanoxdPxtqqvPuScdnu0/jUnkdQoP8cPOgROS2jZEOiwhCUJA///iIiGC7r3Hr0GTsFnSMvjZ/NB5dtUv0XPP/2kHB7a8VGepv0rqLiQ5B3x5RSIwJRnFbK1bYKSe2Vow1y/5zyOoxdYDGZkdwYKChZHBR24Aegpm1NU16RLlhf9bgkPb34L3cUyi3MhzRFa9tad9q8NVPj1o9LzDYH7GxocjJsb4vqXC1zMioYItRSjut7Gka1Pbc5sTukxo5xAhQnM5wOKEbTZ06FYsWLUJVVRUSEgydehqNBjNmzMBDDz3kdABabZ1LY4pjY0NRXl4LnU6PlhYdHrtrEEKD/JCaGI7VbeOZaxtaoWvR80nzrgXbMW10Kv8cV8rsT5hRmLVSg5zohK252l7yuHlgN3yxv73VXVvbiPLyWowanIgPvy2y+hyTbu6BbT+cd/g1zVVU1EHf3N4yjYsINFkM68RZLTiO4QWzse+/FJbiiBv28dwsGL3y63nr5RZXHC50bKvBcm09ystrsXWP9clkQmVlV9Es+CACYPW9qKkx/B2FjNemlMkhRoDiFKNUKqw2hO3W0Ovr61FS0j4bLi8vD+Hh4fD390dtreEXYIxhx44dSEtLc1PIjuOYYZjh4N4xSE0Mtzh+4MQVDOsfz982jvEGgIs2OuiMOlJ2uDEtDr27R2D2xDT8YWQvk2PGjTTsrYHS0e4K8/jNVza8UtmAb36yLO+c+q0aJ+ysIe8IexOX3Kl7nPhF7uxiXc6UUTwxwYkQV9ltoTc2NuLxxx9HY2MjlEolwsPDsX79emi1WsydOxd6vR4cxyE1NRWLFy/ujJhNcByzmRTrm3Qm0/yFU7VL7EzyAZwbSies5U+9pSciQvzx8hOjRD+5jZOX7G2oUe7g0rLWONJPIPbBZq2DMik22GSsuZRYW3rB2fVz5r3+Ax6cMgBD+sTAT62yeS7V0ImU2E3oMTEx+Oijj0SP5eTkuD0gZzHG7CZFa77/xXIG6PD+8fw45ogQjVMt9KAANd8Zly4yBl3I2BmpshO7v6Dj9Lk/Z9isl4vZsP1XPHzHQJvnOFq6ANq36pMT45BJZ6z//Dg0fkqs/9utNs+j1RaJlMh+pijHXF8KtvKq6RC08GANYiMC+dsKhcJknPvAnlGwRTiywt6HTEy44XXsJfRAjQorH7oJL/51OHolhpksCeyIU79V41M7681csrOomJBOp0d6X9sfVlJzwYHSmhjh6ChrjDNuCZEC+Sd0kZJLYozp6JWsoUmijzVf8yMpNtikxqxUmJZo7vmdYQLVY3cOsniu5FjT+q29hO6vMXyVt5fQlUoFYsIDER9pGFf/+xucn5noztGZ2qvNHd4jtbOJLWusUTt26c9akYf/5VnvtCZESuSf0EVKLrNub++czegXi3t/38/u88ybPhgPTx1oto636fMaVxocLBgvblRWbVqPd3TDB7WdnX7Mn8eV8lKToIb88FTb5ZfYCPtDFU85sF2fo+beeZ1D50WG+tu8bU+J1rTu78yOTbk/Wa77QogU+UZCN0t6wlbvnaNSzR9iYfyN16B/jygEBZjOJtFetb4Wujnzr+diCf0Os5EugP01WMyfxt4HxcSbe1jcd0iwF2qGlUXDjDqzJNy/RyR6OLD6JQA8flf7t6LgALXdbzbmFr71o1PnEyJH8k/oHKAw+y2E/9kVbT8vnJlu9Tlu7G87yblCrCUtVi6xtymGecJT2viLxUcGoui3ascCtMLR2bN/v3doh14HAAb2jEaAxvYoEqO4yPa+jX89MdLljnBPoA2riVTIPqEzkRa68D97WJCh1R0aZDaXG+1f2x1tJTpDLOH4+1kmL1stzduGXWNR3rE1dX700GRcLLPfATg9q7fVY46Oq+6THIGFf07H8AHxLi9QxRhzuKWtMvskEy7klRLfPkPPG4tlHT5FS+gSaZB9QhfrFFUJZnMa10sR1qqNC3e16jinv7qbG9Y/XnQhMEef1tbrxwpapUbVgkWozNdh0aiVdsdNAzCZ4m/OmXHVqYnhmDNpAFY+dDMiQjQYcV03hx8LGL4NqERm3oq9J7beJ+H74Mzfc4jZh2WQlfVaAMOHv/CDQ8iZ0hwhniTrhG5cLdG8NawSqTOrBAl9zqQBAAyjXMwTmPmysUY3DYgXvX/OpP5Yev8wi/sdLQncfF2C1WNqkfpKb8FsWPPXUKuU8LPTyQoAIYGW31aMxMoHy2YPwyAbC42pVUqsefQWpPc1lK7iIgOx7smR/PHn77NcPOymAfHIGpoMlVKJf84ZbnLsD6Ms+xpsdR0oBO+DvY8j4Qe7+aYgtuYO6PQcrK3N6ewmK4R4iqwTurHea547VSJJTdhys5VsH73DMOpiklnn4uRbeprcHtA2Jl2hUIg+n62WorAlm2Q2xPKvkwfwG2OIrYTYrGsfsWJeHlEqrU9/F0qMCRZNsoB4DT0xJtikU/IWKx9ClysM/QFlVY0mqxOKjZ1/YNIA/hxhQlz98M18Wck4tDBAo+KXbDZ/vwDTD3Dh3AKxv4Dwg6FQ0N8wb/pg3Df+WtHfCzBMqLI2Lt3atnyEdDZZX4nGERnm67OLtTKFydHWzMGwYA02LsgCAJNFsYzjwI2e+uP1Jrf91EqTDSnMa75Gbz19q9X15I2va1zqVmzf0lZBUjGftalQKHD7TSn8RsrmrhEke2sTlBqbxafJC2OeOU58GGhc23vUv0ek6HGjF/863OqxqLAA3DokEcXaeqTEh2LTN6cw8vpEAMC7i36PhjrL8oa1D2h7rfWwID9cbVsrvX8Pwwf0db2iceys1uS80CA/NLXocW1KpOiesC2tetQ1ttr85kNIZ/CNFrrZf2ix/+DCr9q9Ep3rBB0zNNniPoVCYZLkzEsd1kajqJRKh8eoC9dX519HMCHmj6NNOzcVsFNrdnAyjS2DUqNNYjB/fQAI1FhvJ7zwlxssPhzNBWjUmHV7GkYPScKdo3rhjkxDCSY6PNBkDXkj4cJnUWG2x6cLO6bjooKw6P8ysHR2e8nsgUn9+Q8QwPB+6/UMej2zaIlPzTR8a3tj2wk89soeGu1CvE7WCZ3xJRf7Cd2k5CI433yGp5jhA8Xr5ybPL/gGMDWzp9UWupiwYI3F7FYAGNTbsm4dLGgFjh92Dd+qBwwfMrZyiiNj8m15+5nRJqUXc8b3Xayj0/iWW9tJytrzTbipBz+r1hrhezJ7Qn+b5wpnB6uVCvToFmZSxgkJ9MP/3dZeemnVcdDpOXCMwU+lxGtPtPcN9E8xtOqv1htmzjqzmxMhniDrhG4suZjnb3+RkR4KhQLXp0ZjzuT+Ji3rS+X21zFpdWBND2EIk0f0tHqemLVzb8EyQStxwk0phn+Hp1icK9YBZ6z390gINem4e+mRERgu6Mx1pfNu0f+119rNv5WYu753NMYPu4ZfImHqLT0xY2wfAICmrWVsrTwSGerv8obLxg/2+MhAXJvSXu4ZbWXJByNHt1I0zio9fr4Sgf7t15b5B1d+EQ1fJN4l7xp6239khVmSsNaie3za9aL3WzO4dwzyT1fwGzvbMqBnFL+faEfdOSrVqdb0HSN78bNQa+oMHX2pSWGIDPXHAUFM5sn0mRlDkP3BEZvP7cwYfZVSaVIGEnYkL5yZjvyiCqvfXF56ZITDr2Muom0zCvOJW/eM7WtRtooM9cfwAfH48sBFRNvYyUlM0aUakw8B87XeXVnVkRB38omELlaTvn9Cmt1arT3/d9u1+PLHC/xXa9vnprktoXdEcmwwNGolpmZaDv0LMJvY1O8a652X/3ois8NrsZvGFeJQectZ943vh0B/tUnpyUjs2wDHMdw1KhUJUcHIuNb1VSNHDU60uM/de9QS4ixZl1wYZ32TiBHXJVgdU+6osGAN7s7q49CYcmsdhZ0tKMAP6+fdigFtozbubpsVOjY92W4t2qh/j0gEB/h5ZAatuzz35wxMuCkFowbbLquYD8/Uc4ZNs28ZlCDawWqLsR9m44Is3Df+WovrwhMfWIQ4Q+YtdMO/ElrWQ3J+f0N39EmOQM8E8VmO/bpHQKVW4sS59v0++yRHdFZ4LuuVGGZ1tNLoIUn8GjmJ0aadzY5eK2kpkfjVbAs+YWep4blMn6zViRUcCfEEeSd0znrJxRuyH7ypU4auJUQH4aYBjk2zVygUNodpPnPPUMTGhmLBv77H8fNVbY9xS5heIxwnb95x+ajIWvZinpg2CF/9eBHfHLrEj4wRbn4CAKFm487f/uJXjLAx85cQT5NGncBF1sahe0tsRCA/ucaTlj8wXHSZ3I6YM3lA+xrjPlQKFg5X3bggC72THCvD+alVmDSip8kon6JLpitZxkRYrrVDiDf5RkKXe5NSAkKDNMgcZGhd+lA+d3hoojXGrQIB24t3ESIF8k7obSUXyufuRTMexcmhb4F0bfJO6MZOUYmUXOTu+t6G5WSvs7GyYleWFGs5m5cQKZH1d0jmhk7ReJE1x7uqnglhouO55e6RO65DTLhzk4jEOFK+0dY0ITZWfEQRIZ4m64TOzxTtQEJ//r4b3BUOkShb65y7W3Vds/2TCPEQWZdcGF9ycf6x909IQ1xkoMnaHIR0FHU/EG/yiRa6KyWXEdcl0Jhh4pCZv++LACsjXJ7+0xCs/LB9PZyG5lbR8wjpDA4l9IcffhiXLl2CUqlEUFAQnn/+eaSlpeHcuXNYsGABqqurERERgezsbPTo0cPDIbfjbEz9J8RdRoush290bUokNi7IwqwVeQDg0J6uhHiKQ8WK7OxsbN26FTk5OZg1axaeffZZAMDixYsxY8YM5ObmYsaMGVi0aJFHgzVH49CJ1Hy+56y3QyBdmEMJPTS0vde+rq4OCoUCWq0WJ06cwMSJEwEAEydOxIkTJ1BZWWntadyufep/p70kITZV1lKnKPEeh2voCxcuxL59+8AYw4YNG1BSUoL4+HioVIavmCqVCnFxcSgpKUFUlP3lZt2BxqETqeiZEIZzJVfRzYkdmQhxN4cT+vLlywEAOTk5WLlyJR5//HG3BBAd7fqSo2FtGxRERgZLeuyvlGMzkkOMgHTjnHPHdfj76/uQlXENAOnGKSSHGAGK0xlOj3KZOnUqFi1ahG7duqG0tBR6vR4qlQp6vR5lZWVISHBu5IhWW8eXTpwRGxuKqirDDuxXaxpRXl7r9HN0htjYUMnGZiSHGAFpx6nQ6wEA9fWGkotU4zSS8nspRHFaUioVVhvCdmvo9fX1KCkp4W/n5eUhPDwc0elBIcMAAB3DSURBVNHRSEtLw/bt2wEA27dvR1paWqeVWwDhFnSd9pKEiFKrDBeh3oXGCSHuYreF3tjYiMcffxyNjY1QKpUIDw/H+vXroVAo8MILL2DBggV4/fXXERYWhuzs7M6Imde+STTV0Il3GZfp1etpkwviPXYTekxMDD766CPRY6mpqfj444/dHpSjaNgikQpVWwtdRy104kWyLlbQxCIiFe0tdEroxHvkndAZjUMn0tBeQ6eSC/EeWSd0RuPQiUQY9y7VUQudeJGsEzrV0IlUKBUKKBUKaqETr5J3QjduQUctdCIBKpWCWujEq+Sd0KmGTiREpVRQpyjxKlkndL6GTiUXIgFqlRI6KrkQL5J1Qqdhi0RK6hpbsevwZW+HQboweSd0N+wpSgghvkLeCZ3WQyeEEJ68EzqNQyeEEJ68EzpH49AJIcTI6fXQpYTRxCIiIel9Y3GlssHbYZAuTN4tdGNCl/VvQXyFWq1EKy2fS7xI1qnQWEOnUS5ECvxUSrTqKKET75F1Qmc0Dp1IiJ9aCR210IkXyTqh0+JcREp+K69DbUMrLly56u1QSBcl+4ROyZxIxelLNQCAR1ft8nIkpKuSd0LnqEOUEEKMZJ0OOcaoQ5RIRkign7dDIF2cvBM6RyUXIh0De0Z5OwTSxck7oTNGJRciGQdOlHo7BNLFyTodMo5GuBDp6Nc9wtshkC5O1gmdauhESub/aQgA4LrUGC9HQroq2Sd0mlREpEKpVKBHt1D4a1TeDoV0UfJO6ByjtdCJpKhUCuho+j/xErurLVZVVeHpp5/GxYsXodFokJKSgiVLliAqKgr9+vVD3759oWzrmVy5ciX69evn8aCNqIVOpEatpH1FiffYTegKhQKzZ8/GsGHDAADZ2dlYvXo1/vnPfwIANm/ejODgYM9GaQVj1ClKpIVa6MSb7JZcIiIi+GQOAIMHD0ZxcbFHg3IUTf0nUqNW0QJdxHuc2uCC4zh8+OGHyMrK4u+bOXMm9Ho9Ro4ciblz50Kj0bg9SOvxMCio5EIkRKVUQKdn3g6DdFFOJfSlS5ciKCgI9957LwBg9+7dSEhIQF1dHebPn49169bhySefdCqA6OgQp84X8tOo4adWIjY21OXn6AxSjw+QR4yA9OMMCtKgvKZJ8nEC0n8vjShOxzmc0LOzs3HhwgWsX7+e7wRNSEgAAISEhGDatGl45513nA5Aq63j9wZ1RmxsKJoaW8E4hvLyWqcf31liY0MlHR8gjxgBecSp1+mh10v7mgTk8V4CFKcYpVJhtSHsUEJfs2YNCgoK8Oabb/IllZqaGvj7+yMgIAA6nQ65ublIS0tzX9QOoIlFRGqOnKpAc6ve22GQLspuQi8qKsIbb7yBHj16YPr06QCA5ORkzJ49G4sWLYJCoYBOp8OQIUPw+OOPezxgIY6jtVyItBiTOaPGBvECuwm9T58+KCwsFD22bds2twfkDI6GLRKJ0nMMahVdm6Rzybp9SxOLiNTcMbIXANBm0cQr5J3QaT10IjHBAYYvvS2U0IkXyDqhM0ZruRBp8VMb/ku1Usco8QJZJ3RDpyhldCIdGrVhpUVqoRNvkHdCB2gkAZEUjbGFTgmdeIGsEzqjFjqRGD8/w3+pFh2VXEjnk3VCp8W5iNRQyYV4k7wTOgdQPidSYuwULamo93IkpCuSd0KnFjqRGGPt/INvi7wcCemK5J/QqYZOJITaF8Sb5J3QaU9RIjEp8d5fQpV0XfJO6AzUQieSovFTeTsE0oXJOqEzmvpPCCE8WSd0Wg+dSNHYG65BZKi/t8MgXZDsEzqth06kRqVSQO/CLlyEdJSs0yGttkikSK1SQq+niUWk88k7oVOnKJEgtUoJHbXQiRfIOqEzmlhEJEitUkCvp4ROOp+sEzrHMZrIQSRHpVJCz1HJhXQ+eSd02lOUSJBaqQBjhk57QjqTzBM6Tf0n0qNuW6CLyi6ks8k6odPEIiJFXFuHqI5GupBOJuuEzjEGhax/A+KLvtp/HgBQXdfs1ThI1yPrdMhxVEMn0vOH0X0AACoqB5JOJu+ETsMWiQTFRQYCAOqbdF6OhHQ1sk3oxjoldYoSqTF2hRZerPZqHMS7mBdGOdlN6FVVVXjggQcwbtw4TJo0CY8++igqKysBAPn5+Zg8eTLGjRuHWbNmQavVejxgI+OQMMrnRGpiIwwtdPry2HVdKqvD/dm7UHixir+vvqkVp37z7Ie83YSuUCgwe/Zs5ObmYtu2bejevTtWr14NjuMwf/58LFq0CLm5ucjIyMDq1as9GqwQtdCJVIUGawAAQf5qL0dCvOX05RoAwP7jpfx9c9fuwYpNhz3aWW43oUdERGDYsGH87cGDB6O4uBgFBQXw9/dHRkYGAGD69On46quvPBaoufYWOiV0Ii0atWGTixYdDVvsqt7PLQQg/i3t411nPPa6TtXQOY7Dhx9+iKysLJSUlCAxMZE/FhUVBY7jUF3dOXVDYwud1kMnUqPxM/y3qm1o8XIkpDMwxsBxjF/ugeMYbFXP9x+/4rH6ulPfCZcuXYqgoCDce++9+Oabb9wSQHR0iEuPq29sBQCEhgYgNlba+zhKPT5AHjEC8ojTuBb66eKrko5XyrEJSS3Oexd/ieEDE/DotMEAgEl/+5w/Nm1MH9w4oBt/u5VjovGHRwbD3wPbFTqc0LOzs3HhwgWsX78eSqUSCQkJKC4u5o9XVlZCqVQiIiLCqQC02jq+te2MgGDDjjAN9c0oL691+vGdJTY2VNLxAfKIEZBXnADQ0qKXbLxyei+lFmdNXQtyD1zA3bem4v2vC02OfbyzCB/vLOJv/3C0BJP+9jnuGNnL5LwV7/yIh++4zqXXVyoVVhvCDpVc1qxZg4KCAqxbtw4ajaHDZ+DAgWhqasKhQ4cAAJs3b8b48eNdCtAV1ClKpM7YMUZ8x9V60zLarsOXHXrclu/Pmtw+VFjutpiE7LbQi4qK8MYbb6BHjx6YPn06ACA5ORnr1q3DypUrsXjxYjQ3NyMpKQmrVq3ySJBijJ2iVEInhHhCXWMrHntlDwDgsTsHYXCfGBw+1Z6Ia+o71kfiiYmRdhN6nz59UFhYKHps6NCh2LZtm1sDchTfQqeMTgjxgO/y21vfr356FHMm90diTDB/35P/2tuh5/dE5pLtQFljJzGVXIgU9UwIxbkSadV+iXPMB6K8ufUEP4LJVQnRQSjRNgDwzAg92SZ0ftiil+MgRExqUjiuVDZ4Owzigne//BUHT5ahsVlvcayl1fG5BXGRgSirajS5b2pmL/w7pwAPTx3Y4TjFyDehM+oUJdKlUavQShOLZEfPcfj+lxKnHhMV5o/Kq5azP5tbLT8QAv1V2Lggy+X47JHv4lzUKUokzE+thE7PXBqSS7zngZW7nX7MXaNS0S8l0mS55OH941FTZ9lp6umJkLJtofM1dMroRIL82raha9Vz8Fe6fwIJkY7hA7ph4qjeqKiow7mSq1j63iHcN/5aHDhRanFu78Rwj8Yi3xY6Tf0nEsYndCq7SNq+YyUmKyKKGXl9gsnt8LbF1wAgc5DhmDEP9UwIw8YFWfDXqBAbEQCgvdHZKzEM/hrPfrjLtoVOE4uIlFFCl743tx7nW9EL7hmK7E2HRc/rlRhuUlefM6k/Vm3OBwDc87u+Vp/fOLV/0f9loLFZh9Qkz7bOATkndFoPnUiYhk/olh1jxPt0es6kJLLCSjKPjQhA5qAEpMSHYtM3p3D6cg2E3SIaG+uxzJk8ADv2X0BSbDBUys4phsg3oVPJhUiYHy2hK2mvbylw6LwVf70JCoUCKd1C+aUcKq82Yc2jI6CtabL52OTYEMyZPKDDsTpDtjV06hQlUuanopKLlOWfrrB6LCzIj/9Z2GC8MS0OABAdHoCIEP9OKaE4S7YJnYYtEinz86OELhV6jsNVwdr0nJ21yEcPTRa9//4J/fHw1IHo3yPKrfG5k3xLLjSxiEiYuu267OgCTqTjNu88jZ0/X8JrT4zE6cs1WPvxL/yx5+/LwJc/XsSlsjpo/JS4WFqH24ZdgxJtPZIE67YAho7ujGvjOjt8p8g3oXPUQifSZZz2/8X+87hB4knA1+38+RIAYPPOIuw9ZjoLNCkmmJ+G39DUissV9dD4qfDgFM9Mzfc0+ZZcaLVFImFD+sQCAEYMTLBzJnG3mvoW7M63XKfcPJkD7cNLASAowA99kp3boEdqZNtCp05RImXGMcg6PdXQO9uy9w5Ce7UZvZPCLcom5nxtlJxsEzqVXIiUGTtFm1poHLqnHT5Vjr7dIxASaBidom1bKGvR2z95MyyvkG/JhTpFiYQZvzkeKizzciS+7VJ5HV777Bi/sxAARIb6O/TYDU+P9lRYXiP7hO5rX5mIbzFuZkA840fBbE9jTqiqtVzKVowvNgZlW3KhGjqRCz3HddrUb19wsbQWL7xzEP96IhOxds7tk9w+uWffsRJkDkq0eu6NaXH44+jeqG/SoXtciJuilRbZXmVUQydy4ejO8MTgP7mGPYz/l3fa7rnCPop3dpxEi8imEmFBflh6/42YPbE/osICfDaZAzJO6MbRAyof/NpEfMsvZ7TeDkE2GGM4W3wVALD3qGGY4a4jl7F68xHRGZ7mnc4PvvSdxTkqlRJJsSFQq2Sb7hwm299Q39ZCV3WBPxKRp+RYQ0vw+LlKL0ciHycumK5NzhjD+7mFOHG+CpfK6izOf/fLk6LP8/sbuvM/O1pT9wWyzYZ6aqETiZv3p8H8z8zO+iEEOH2pBi+1rTNudKDgCv/zC+8c5H+uqm22uU7OH7N64y+3X+v+ICVOtp2iOn1bC50SOpGo0MD2VftqG1oRJtjppivTcxxaWjkE+pumn3/+92eLc7/56YLJbcYYWnUc/rZun83XUCoUyByUiJT4UCTF2p5c5Evk20LnKKETaRMOqT14ksajGz2wcjceefl7m6sejkk3rHh40GxfzrUfH8Un352xOH9oX/HxMNfEh3apEUay/U31HJVciPQ9Me16b4cgWccEncU1de117tTEMMwY20f8MWe1+PbQJZP75kzqj0f/cB0Wzkz3TKAy4lBCz87ORlZWFvr164dTp07x92dlZWH8+PGYMmUKpkyZgj179th4FvfS66lTlEhfv+6GxZ42fXPKzpm+7XJ5HWatyDPZkPmVT47yPzc06/ifF/45w2LCoK3Zn9Hhhs2YU5PC8dDUgXjlsVvcFbbsOJQNx4wZg02bNiEpKcni2KuvvorPP/8cn3/+OTIzM90eoDXGFjpNLCJS5uld3qWouUWPbw/9ZlJSeb5tXZXsD46IPqa0qtHmc/7t7sFWj/VKDON/vuHaOIQGdd2+Coc6RTMyMjwdh9OMPdwqFSV0QqTk9ZwCHDurxaffncXrT42ErfE9L2z8CRcFwxFn3Z4mel5EiAbLHxiGhW/9aHGsK9XI7enwKJd58+aBMYb09HQ89dRTCAsLs/8gN/jhaDEAqqETIjXHzhpq482teuw+chm/Xqy2OCdAo0JTi94kmQPAsP7im4EEaNT8yDajmwbE4/j5KtHzu6oOJfRNmzYhISEBLS0tWL58OZYsWYLVq1c79RzR0a5Nw702JQqnL9UgoZv0Nmo1Fxsb6u0Q7JJDjIA840yMCUZxRT2CQwMQFOBn41GdyxPvZaOgFg4An+05h/rGVgDA4D6xyC8qBwCMv6kHckRGqyQmtG8wsXnZ7Zj+3A4AQHx8GCIE0/pffnIUektsMwopXJsdSugJCYbdWDQaDWbMmIGHHnrI6efQauv4dVmc4eengkatRHl5rdOP7UyxsaEUo5vINc4b0+KQs+ccCs9UIFki64h46r2ctSLP5LYxmQNA5nXdEBKgRkllPRIjA0Ufbx7Tu4t+j1NntSgvrzWZnBXur5LUtdCZ16ZSqbDaEHa5+NTQ0IDaWsMvwBjDjh07kJYmXv/yBL2eo/o5kYWBPaMBAKcv13g5Eu8q1tZj1oQ0LJyZgdAgy28qI6+3XCkxOjwQvdtWVFQoFLht+DUmKywSUw610JctW4avv/4aFRUV+Mtf/oKIiAisX78ec+fOhV6vB8dxSE1NxeLFiz0dL69VT0uSEnkIaUte/8ktxI1pcZIqu3REc4seeo4hwF8FpUKB8mrbI1WyhibzPwu/lc8c1w9NLTqT49ZMu7W36wF3AQ4l9Oeeew7PPfecxf05OTluD8hRej2jFjqRhbiI9vLCs2/9iLVz5T9OulWnx0Nr2lc2HDM0GTsPt0/4eemRESbT8zcuyDJ5fH1Te6391sGJtFGNm8i2iavTc1DTCBciM1frW2S/UFdDkw5/XW26TK0wmQOGiUDTbk1FcIAaT91tOVt2cJ8YAMBjdw2iZO5Gsl2cy9BCl+3nEelils4ehuc3GMZQV15t5mc3ylFNve3laF97YiQA4LbhKbhteIroOWqV0qLVTjpOthlRp+doDDqRjaSYYCS3rfr32pZjXo7GdbUNLVjUNuvTXO+kcKx++GYEBci2nSh7Mk/osg2fdEHz/jQEgCEpytX+46X8Sqfmnp2Zjqgw+X7z8AWyzYh6jjpFibyEta0x0tRsue+lHLS06rF5Z5HJfUvuvxHd40J8oqPXF8j2u5FOx0FNCZ3IUEOzDhzHoJRRyfDM5Rosf799A4o/je2D32UYtnn7x6wbvRUWMSPbFrqOo5ILka9fL8pnDRLGmEkyB8AncyItss2Iej2jTlEiO8/MMNTR388t9HIkjmGM4f7sXSb3LX9gmJeiIfbINqG36PTQqGUbPumienQzrEZaZmf9b6loMFtsq1tUEBKiu84enXIj2xp6SysHv2BK6ERehBte/FZWh+4SWazLGuF0fho3Ln2yzYgtrXr4UQudyNDUW3oCABZvFB/PLRWnL9VgybuHAACP3TnIy9EQR8g2I7bqKKETebr9pvbZk1cqG8AYQ86es9DWNHkxqnYcY5i1Ig///G97R2haSqQXIyKOkm1GbGnl4Kfqevs1EvlTq5R8h/6zbx7Axh2/Yuu+85j/7x+QX1Th1diqapsx26wTdN2TI7vk3qhyJN+EruPg5yfb8EkX9+b8W/mf9x27wv+848AFk/P+89VJzFqRh6pa2+unuMvOn00X2Xrxr8MR6C/brrYuR5YZkTFmKLnQ4lxEphQKBR6eOtDkvkGp0bhS2YCvfryIFf/9GbsOX8LufMPeucKlaD1J+IGy4ZnRiI8M6pTXJe4hy4/eVh0HxgANtdCJjGVcG4c3598Kxhh0eob/5BairrEVH+06DQA4dcl0h6ODJ8sQGeqPNz4vQIC/Gs/MGIor2ga+1v3KY7cgtG15AVfsL2j/pkAjWuRJlgnduDh+sI/s/EK6LnXbt0w/NZDeNxY/nig1OR4fFYTMQQn4ZPcZ/DunQHCkGY+9ssfk3Mdf3et0ItZzHDZ9U4SfC8tQ22DY//PlR0c4/4sQSZBpQjdceLRMJ/ElwhZ7RU0TlEoFX/L4ZPcZh55j1oo8bHhmNJRtm0bkn65ARIgGPbqFgeMY6ppaERakAWMMc9d+b7JzEGDY0Do8xN+9vxjpNLLMiA3GFnogtdCJbzG22M1nY25ckIXGZh2KK+qRmhQOjjFU1zZD46dCSKAfWlr1ePAlwy5Cs7N34e1nRuODb4ssOjnt+eNo2rNTzmSZ0KvrDD3+YR2oFxIiN4H+aqQmGXa8VyoUJmuPa/xU2PDMaH7Iofn6K9asePAmkz1PibzJMqFXXjUk9GhaTJ8QnlKhMEnqAPDoH65DRIg/lv3nEGb+vi9uSIvH/uNXcNP1SQihQQU+R5YJXXu1CcEBaqqhE2JGqVCIdowK7/tdRnfExoaivLy2M0MjnUCWH9HamibE0vhYQggxIcuErtNz6NM9wtthEEKIpMiyZvHYXYMQExOC6qoGb4dCCCGSIcsWulqlhJ+aFgsihBAhuwk9OzsbWVlZ6NevH06dOsXff+7cOdx9990YN24c7r77bpw/f96TcRJCCLHDbkIfM2YMNm3ahKSkJJP7Fy9ejBkzZiA3NxczZszAokWLPBYkIYQQ++wm9IyMDCQkJJjcp9VqceLECUycOBEAMHHiRJw4cQKVlZWeiZIQQohdLnWKlpSUID4+Hqq2DSZUKhXi4uJQUlKCqKgop54rOtr1PRVjY0NdfmxnkkOccogRoDjdSQ4xAhSnM7w+ykWrrQPHMacfJ5eJEXKIUw4xAhSnO8khRoDiFKNUKqw2hF0a5ZKQkIDS0lLo9XoAgF6vR1lZmUVphhBCSOdxqYUeHR2NtLQ0bN++HVOmTMH27duRlpbmdLkFMHzauKojj+1McohTDjECFKc7ySFGgOJ05nUUjDGb9Y5ly5bh66+/RkVFBSIjIxEREYEvvvgCZ86cwYIFC3D16lWEhYUhOzsbvXr1cnvwhBBCHGM3oRNCCJEHWc4UJYQQYokSOiGE+AhK6IQQ4iMooRNCiI+ghE4IIT6CEjohhPgISuiEEOIjKKETQoiP8PriXM46d+4cFixYgOrqakRERCA7Oxs9evTolNeuqqrC008/jYsXL0Kj0SAlJQVLlixBVFQU+vXrh759+0KpNHxGrly5Ev369QMA5OXlYeXKldDr9RgwYABefPFFBAYG2j3mqqysLGg0Gvj7+wMA5s2bh8zMTOTn52PRokVobm5GUlISVq1ahejoaABw+ZirLl26hEceeYS/XVtbi7q6Ovz0009W4++MOLOzs5Gbm4vLly9j27Zt6Nu3LwDb150njrkSp63rE4BXrlFr76cn/sau/v3FYrR1fXoqfrdgMjNz5kyWk5PDGGMsJyeHzZw5s9Neu6qqih04cIC/vWLFCvb3v/+dMcZY3759WV1dncVj6urq2M0338zOnTvHGGPs2WefZf/617/sHuuI0aNHs8LCQpP79Ho9Gzt2LDt48CBjjLF169axBQsWdOiYOy1btoz94x//sBp/Z8V58OBBVlxcbBGDrevOE8dcidPW9cmYd65Ra++nu//GHfn7W4tRSHh9eiJ+d5FVQq+oqGDp6elMp9MxxhjT6XQsPT2dabVar8Tz1Vdfsfvuu48xZv0/y44dO9icOXP420ePHmW333673WMdIXax/fLLL2zChAn8ba1WywYPHtyhY+7S3NzMhg0bxgoKCqzG39lxCmOwdd154pircZoTXp+MefcadTShe/M6tRaT+fXpifjdRVYlF3durNFRHMfhww8/RFZWFn/fzJkzodfrMXLkSMydOxcajQYlJSVITEzkz0lMTERJSQn/+1g71lHz5s0DYwzp6el46qmnLF4rKioKHMehurra5WMRERFuiTUvLw/x8fEYMGCA1fjDwsK8Fqet644x5vZj7riWxa5PQNrXaEf+xp78+4tdn+6O313/l6hT1EVLly5FUFAQ7r33XgDA7t278dlnn2HTpk04ffo01q1b57XYNm3ahK1bt+LTTz8FYwxLlizxWiyO+PTTT3HnnXfyt+UWvxSZX58AXaOuMr8+AenGL6uELpWNNbKzs3HhwgWsXbuW72AyxhASEoJp06bh8OHD/P3FxcX8Y4uLi/lzbR3rCONzaDQazJgxA4cPH7Z4rcrKSiiVSkRERLh8zB1KS0tx8OBBTJo0yWb8xvu9Eaet684TxzpK7Po0/h6AdK9Rsdfz9nUqdn16In53kVVCF26sAaBDG2u4as2aNSgoKMC6deug0WgAADU1NWhqagIA6HQ65ObmIi0tDQCQmZmJY8eO4fz58wCAzZs347bbbrN7zFUNDQ2orTVshcUYw44dO5CWloaBAweiqakJhw4d4l9r/PjxAODyMXfYsmULRo0ahcjISJvxezNOW9edJ451hNj1CcjjGgVc/xt76u9vfn16Kn53kd166N7cWKOoqAgTJ05Ejx49EBAQAABITk7G7NmzsWjRIigUCuh0OgwZMgTPPvssgoODAQDffvstVq1aBY7jkJaWhhUrViAoKMjuMVf89ttvmDt3LvR6PTiOQ2pqKp577jnExcXh8OHDWLx4scmQqZiYGABw+VhHjRs3DgsXLsTIkSPtxt8ZcbqyoYsnjrkS59q1a0Wvz3Xr1uHIkSNeuUbF4ly/fr1H/sau/v2t/c0By+sT8P41aovsEjohhBBxsiq5EEIIsY4SOiGE+AhK6IQQ4iMooRNCiI+ghE4IIT6CEjohhPgISuiEEOIjKKETQoiP+H+Fvu0Xl9TsvQAAAABJRU5ErkJggg==\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
}, | |
{ | |
"data": { | |
"image/png": "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\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
}, | |
{ | |
"data": { | |
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAELCAYAAADJF31HAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deWATZfoH8G+OpvROb1puKq3lvgQ5lXrgAaLrDw8EXZF1dV0EEbEqgouoFBBd3AJeuOsuKysrhyArqAjKJfdRznKUq6V3S+82M+/vjzTJJJncSTOTPp9/aDKT5GkzPHnzvJeCMcZACCFE9pT+DoAQQoh3UEInhJAAQQmdEEICBCV0QggJEJTQCSEkQFBCJ4SQAEEJnbQqGRkZ2L17t+ixzMxMfPDBBy0cESHeQwmdBAx7yZqQ1oASOiGEBAhK6CQgvPLKK8jPz8dzzz2Hfv364dNPPwUArF+/HqNGjcLgwYOxfPlyl57z66+/xl133YVBgwbhueeeQ2FhIQCAMYZ3330XQ4YMQf/+/TF27FicPXsWALBjxw7cd9996NevH0aMGIHPP//cu78oIfYwQgLEqFGj2K5du4y3c3NzWd++fdm+fftYQ0MDe/fdd1l6errZOUKvvvoqW7JkCWOMsd27d7NBgwaxnJwc1tDQwObNm8cmTJjAGGPsl19+YQ899BCrrKxkPM+zc+fOscLCQsYYY8OGDWP79+9njDFWUVHBcnJyfPkrE2KGWugkYH3//fe4/fbbccstt0Cj0WDatGlQKp275Ddu3IiHH34YPXr0gEajwYwZM3DkyBFcvXoVarUaNTU1uHDhAhhjSElJQUJCAgBArVbj3LlzqK6uRlRUFHr06OHLX5EQM5TQScAqKipC27ZtjbdDQ0Oh1Wqdfmy7du2Mt8PCwqDValFYWIghQ4bgiSeewLx58zBkyBC8+eabqK6uBgAsXboUO3bswKhRozBx4kQcPnzYu78UIXZQQicBKyEhAdevXzferqurQ0VFhdOPvXbtmvF2bW0tKioqkJiYCAB48sknsXbtWmzevBl5eXn47LPPAAC9e/fG8uXLsXv3btx5552YPn26F38jQuyjhE4CRlxcHK5cuWK8PXr0aGzfvh0HDhxAY2Mjli5dCp7nnXquMWPGYO3atTh16hQaGxuxZMkS9O7dG+3bt8exY8dw9OhRNDU1ISQkBBqNBkqlEo2Njfj2229RVVWFoKAghIWFOV3iIcQb6GojAePZZ5/F8uXLMXDgQHz++efo1q0b5syZg5kzZ2LEiBGIjIw0K8HYM3ToUEybNg1Tp07F8OHDceXKFeOko5qaGsyePRuDBg3CqFGjoNVq8cwzzwAANmzYgIyMDPTv3x+rV6/GokWLfPb7EmJJwRhtcEEIIYGAWuiEEBIgKKETQkiAoIROCCEBghI6IYQECErohBASICihE0JIgFD7O4Dy8hrwvOsjJ2Njw1FaWu2DiLxLDnHKIUaA4vQmOcQIUJxilEoFoqPDRI85ldD/9Kc/4erVq1AqlQgNDcWbb76J9PR0XLx4EZmZmaioqIBWq0VWVhY6d+7sUnA8z9xK6IbHyoEc4pRDjADF6U1yiBGgOF3hVELPyspCREQEAODHH3/E66+/jnXr1mHu3LmYMGECxo0bhw0bNmDOnDn48ssvfRowIYQQcU7V0A3JHACqq6uhUChQWlqKkydPYsyYMQD0a1+cPHkSZWVlvomUEEKIXU7X0N944w3s2rULjDF89tlnKCgoQGJiIlQqFQBApVIhISEBBQUFiImJ8VnAhBBCxDmd0N955x0A+i29Fi5ciGnTpnklgNjYcLcfGx8f4fgkCZBDnHKIEaA4vUkOMQIUpytcHuXy4IMPYs6cOWjbti0KCwvBcRxUKhU4jkNRURGSkpJcer7S0mq3OhPi4yNQXFzl8uNamhzilEOMAMXpTXKIEaA4xSiVCpsNYYc19JqaGhQUFBhvb9u2DVFRUYiNjUV6ejo2bdoEANi0aRPS09Op3EIIIX7isIVeV1eHadOmoa6uDkqlElFRUVixYgUUCgXeeustZGZmYtmyZYiMjERWVlZLxCx7lTWNeOmjnRiUnoDnxvX0dziEkADhMKHHxcXh66+/Fj2WkpKCNWvWeD2oQPfl96cBAPtOFeG5cX4OhhASMGjqv4/U1jehSSe+3dmNmsYWjoYQ0hpQQveRP3/4K974dK/oMYVC0cLREEJag4BI6FW1jdh5rADf7clDUXmtv8MxKqmsR32jzur+PjfF+iEaQkig8/viXN7w6caTyLmon6G68/h1vPfsrX6OyKSiqgEqi/vUqoD4HCWESExAZBZhTVpno27tLyql9Z+Yk8AiPoSQwBMQCV2pNNWk1Sr/16d5xkR/NuA4aX3oEEICg+wT+rXiauRdN83QKiyvw9Vi/66fzHGChC7SGg+kFvrf1h5H5sd7/B0GIQQBkND/8vf9VvfN+XyfHyIx0Qla4KItdB8ldB3H2xwq6SuHzhajqLyuRV+TECJO9gldx0mvtStM2GIt9OAgUzfp9TLvjcp5bvEO/HHxdq89n1Q0NHEoqaAPDUIckX1Cd6Sk0n4iYIzh4Jki0Za0u4Q1crGELqz5i33DcJc3fwcpyVp1CLNWUFmHEEcCOqH/ejQfs5bvwflrlTbP2Z1zHdnrcrDt4FWs//UCLl33fMU04bcGsSQrLMk0NHIev16gy/PCe0JIaxDQCf3kpXIAwA8Hrtg8p7yqAQBQdqMB3+7Kw/wvD3j8ujrelLDF6uWXC53rtL10vQrbD1/zOB5CSOsQ0Am9slqfrPedKkJdg/WMTQBY+8sFAOZJ2FUFpTUoEtR4HY1yOXS22Knn/cvf9+PLLWcCtpTiqkAaHUSILwR0Qhf+/z/d3Fq3xZCEVQ7Gsd+oaURpZb3ZfW98+hsyBTXe0hum4//cfMrZcG2qrm3CJxtP4NtdFz1+Ll9pbPJ96ahBZBkFQohJQCf0s1cqjD8bkjvH89h74jqYRavXMNxPpbSf0Kd/tBOvLN9t95w1P583/nwkt9jjujzHM+w9UYj1v0o3oZ/Ms/+B6Q2NTTQhixB7Ajah6zgeHRNM2zTV1DcBALbsu4JPNp7E3pOFZufvPK7flamuwbmW5pnL1gnM8BqWE5s8HclSUFrj0eO9ieN5VNY0otBiuKXSwQehLZkr9uCXo/lOnSu20BkhxCRgE/rX286hc1Kk8fbf/6ffVKKiuRO0urbJ5edc11xvB4CfDl61Om5vxMrlQn0r3fKbAQCU3ai3uk9o8eojzoboUGllPbbut91J7MiqH3Lx0kc78done3GieUE0wHGpSgxjDEUVdcb3xpG8ghsuvwYhrUnAJvQfD15FYnSIzeOOutcKy2vx5fenzTo1hS3JA2esOzbP2Rke+dYX+8EYE33dmcvsl3CcIYzTXq39leW7sfqnXFS6ucnGoTNFxp/f/4/pg0blxhrvrnb2RkcEo65Bh398f5pa64SICNiEDjgYFeEgmXzwn6PYfiTfOAbaUGqwfhrT8zhaQ4bjmdkIGG8qFoyysVVrzy8xlW7c3WPDVmnFnZKLqwOLdBzD1v1XsONIPn4Q+ZZRUlGHZxf9jGsl0ilREdKSAjqhi231VtF838bdeTYf19DIGYch/tZca//Dwu1W5zXpeLNJQpt2X7Ibz6GzxTaHT3rKmTXWDWPuAcDdNSkrqsVb9o46k8W42kIvu1Fv/CBqEvlg3H+mCDqOYdexApdjcdXJvDJMXrANhRLaUIUQ2Sd0YcenpR9F6twVzWPTa+ptJ9aLglqtWm07Uf1x8XYscqG+vWLDCbc7Dx0Rq83bO8fbQ7qrBH0S3/92GZMXbHMYk+UYfZ4x7D15XXTsPgAs+tcB4weH2BLEiuaPKfHClncZ+jV2tsCHByHOkn1CdzUxxUW1cXhOnaA+262dFm//w/YolXNXbdfNxRg6R225kH8D+08X2T1HDOdEQs8vNbUmbSVNSwtWHcKKDTkOz/v653PGn9c0/2yr5NXQxIFnzKqFvvNYAT759iS2HbL+IAb0VTJDqcXer9uS87BOOZjfQEhLkn1Cd6ZlKpQcG+bEc5p+5ngeFwtcH0eeFBsqer/hG4It8788gOXr9Qn05o5aq+NHz5WIPs6ZBL36p1zjz6WV9Zi8YJvZtxExZ69UYN8p0wdM1+RI0fPaxoSi7Ea92YgdsfdGx/F4/v0dWP1TrlXMhj6KfaeLkHu1wuqxAHCj+ZuA+LLEfPO/jv8WTTrOrAQFAHUNOpeHiPZJof1hiXTIPqG7WoeNCA0yuy1W+w3WmJa3zV7nuHVqKSRYhR5dYkSPGersz47tbjM5GjSJlBX++t9juCbS+erqN5U12/WtaGfHgDuS1lGLmct2m43YEev0NPQ5/HjgKj7+9oTx/vf+ddD4SXruaiXe+9chnL1SYbODU+wD7Jsd+mGl9matMsbAGMMHXx/Fy9m7zI4t+foI3vj0N5uPFXM+n4ZSEukIgIQORIZprO4XJuWwNqa9sC3zv9gHQpGba5Qnx4WhScehsYlHkEqJ4b2TrM4xzEhVq5SYdHea3eezNSLmzc/34UZto1lSYy5m9NzmUpHCxeEuts7+zzZTycUQCc8YSirrMHnBNhwWWb9GOLs092qlVeV7wapDePMz8QRreNsKy2vN1tEBgMbmv3FDE2fVCf3F/07jmayfcfqy/huA8BvF+WuuJ2dHcwgIaUmyT+iMZ+jeOdp4u2tyJPreFIdErWkMurADVJjA9a016+f859azbsXSu2ss/rh4BzieQaVSonPbCKtzDK+vUimgCTL9+cXKE/aWjZ2+dCeWC2rb+RalgqLyWof1egCornVuPPp/t5/Xt3xdyP88Y8ZlD3blXAfgoL5t45jw72TwU3Od/bWP95qtowOYRjc9//4OvPDBL2bHLDsxy25Yl8Dsfesrr2rAEUHZa/SgjjbPJaSlqR2dUF5ejlmzZuHy5cvQaDTo1KkT5s2bh5iYGKSlpSE1NRXK5p3tFy5ciLQ0+61Ob+MZgwIKPHxbV8RFhWBw90Rkrz2O8uoGKBUKtE8IM1uu1qxV6+VYqupMyfFIbjFG9Em2OsdQtw1SKREkGGrI4PpQwoNninG1qBrtE8KxYsMJs2OZH+8FAKzMzNA/v40kZXnvwTNFKCqvw723djK7f/PeS7hWXI1L153fr/W1j/fiibtSAZiWL7C30uRVG+UVhRN/GeGa96culZutn1Ne1YDoiGDRxxn6NIRDXHmeQWkx87WiugEz/mZeogHcX/KAEF9w2EJXKBSYMmUKtmzZgo0bN6JDhw5YvHix8fjq1auxYcMGbNiwocWTOaBPVEolcP+QzhjcPREAcPBsMapqm8Azhq6C6f86jjerNXt7ks+u49eNP18trkEbwVZzllQW48anZP2MC4J6rGWHnS2Hc51bitfWPquWfQjZ63KwZvt50XOPni81G3fvSHVdk3HCU0HzCBt747YP2BjdwzkxA6nOYuaocP0ce49ftj4Hh84Wo6quSXC+9XVxwUat3NnRQoS0BIcJXavVYvDgwcbbffv2RX6+dzrSvIFngNJOHZhnDAPS4gEAzy7abvYf0JnkNNKilT1v8iCnYxPWpzVq8z+1WqVAjMUQSuHmGpYddras+/UiJi/YZvO4oYPQVueirRam/sPP82QlnPB06lK5U61tS7Y+eIXvX5OdlRgNr2mr3v23tceNQy1tvV5IsPiXWVqjnUiJSzV0nufx1VdfISMjw3jfpEmTMG7cOLz//vtobHRvfRBP8Dyz27H3y9ECtIszDVWsbTC1xJxZw9uyBdvezkQmq9gECXHssM5mx9QqJZQKfanIntv7WpdtXFHrYGaq4bf74OujZh2Xx8+XIudCqUevDZj//Zb854jdGbq22EqZ05buNP780drjDp9n1Q+2+0aOnTf9rmIfZF/YWNeeEjqREoc1dKG3334boaGhmDhxIgBg+/btSEpKQnV1NV555RVkZ2fjpZdecimA2FjnE6Sl+PgIKBQKhIVqEB9v3QFp8O2uPOPPwun5l0ocj2YJbmM+zNHe61i6f2QK8oqqMW5kCjq1jTAOqwOA+LhwxMdHIDLC/kSnxHj3/z4AoNWGIV6wSFnnpEizVQv3nChETV0Tjl8oxXFhAler8MXmkx69NgB8JRj77u3k5+wyCtExYYiPCcXhXPEx/Ja02lBER5q/LyWV4q37UBvXnivXib/IIUaA4nSF0wk9KysLly5dwooVK4ydoElJ+mF54eHhGD9+PL744guXAygtrXarDhkfH4Hi4iroOB4NDU0oLnZ98s9xB/XnNhoVai1Ggdh7nZBgtTHJPHN/Oqoq6/DyhAEoLq5ChUXtuLy8FuFBSqvnt1Tr5qqIBmVl1YDOlPjElqD95udcq/v+s/UMKm2s2yJV7ePDRRdIKympgpJzfkelouIq6BqcW1658ka91TVhuDalTA4xAhSnGKVSYbMh7FTJZcmSJcjJyUF2djY0Gv2Y78rKStTX61stOp0OW7ZsQXp6updCdp6jkos9lyyG9YWHBOGOAe2Nt9toVC7NRDWMMQdgtha7PY5GSVwpcn5UiRhnWsV1IuvaWI7tNhCWr6TG1mqXrrYXZi7bjV+P5qNJ5/hDgDpFiZQ4TOi5ubn4+OOPUVRUhMceewzjxo3DCy+8gAsXLmD8+PF44IEH8MADD0CtVmPatGktEbMZBmbVKfqHMd3NbtuqU1uuw6JSKhAq6PxSKBRmCdHW7E8DYSedo9Fskc0zVu116AL6KfVdkyMRF9UGH8+83f6Tinh1xR6bIzQMNrmwV2mTjre5rIEvdUx0v/TkTtL94n+n8eJfdzo8z5mkT0hLcVhy6datG86cOSN6bOPGjV4PyFU8DygtPpZiBaNH7r6lA+4f0tmsfi1GG67BhDtTzVZoVCqA3TmmoYi/G6n/YHjhoV7IXmfeCdc+PgxXi00jSRy1vKPCg506T6lUYPaTA423HxzeBet3ura36I4j11w6354mjkeHxEjjMMSWIpxL4Kr8khoku/HNosGJTvN1v17E2GFd3AmLEK+T/UxRnlmXXITboQlLKLbc3FGLJX8ejoE3J5htLG2pS3MZxTAMUkiYzAHnd/D5+ZD9ZGuZ8Nu60Tr2ZlGgvKoBVzxIrv6wbL31ejzBduYICP1pyQ787zf769wTIhWyT+iMWZdc1ErzGZiAvlVtS2oH61UNAaBUZFq4s8Ra3u3irVuJjnY5snwaZ0o0loSzIN/5w2Cr40LxWsfLC9uqr7tj5mN9nTqvh2B5BwA2Z37aYvl3dqb1DQD1jRzW/Cw+0YoQqZF9Qud56+3UhC302Ej9f/z2IsnUYMzQzl6PS6yjdsYjziUvV59XaFivtlb3CcdYJzlYPtjZerOjlSKd8WjGTU53sj55z83Gn6Mjgl3eIcnWTFlCAon8E7pIC134n13V3FoX25U+KlwDhcK57dtcJdZCF2tVJmhtb2QNALf3a2d2214ie/yObvhJZJcmVzjbf+iNDycdx0PjZOlDuOzx+y8Mk9QaKt6YUUuIN8g6oRuGFFr+57ZcJwUwT9pvPDkAANDYxBsTvrt6p8SiV1frTQ6czTeDuifYPDbp7lRow80/BOxNplEqFWi0MwXeYOrDtstPzk7+CW2jxl9fHI6XHumDESLLBDsjLCTI6Za25ftUVG4q+7QXTL5ytRTjDbbWoCGkpck6oRtaRpZVCLVIkhAmDo1a3yqsa9BZrefSr1uc6GvdP6ST6P3Tx/fBS4/0sft69sRF2W6hi30wBQnWhFFbfOsIUisRJLLUrKVQG+uSAK4N8YsI1aBX11g8de/N6HtTHO691bWlZBnPRL85ibH39xQur+tKw92yLm/v7xIdEYxOIsshA7Y3ziakpck7oTfnYsuSi9hXYGELvaHRdofYlDHd0TExHH98oIfZ/UN7mtemHe1Naq/lHykoH1g+r5BlwgbMt7azfA2VUmG1CJiYeDtlHrGJVCtevg1/GNtd5Gw9pUKBF/+vN7q01dfVteEaLJsx0nh8wXNDrB7z4IguGNEnGSqlEgstjo+/PcXqfHtdB8L339HHkfAD0bI/4qb2UTYfp+N4m5PMkuNaflw+IWJkndBtlVzEauLC5BgTaftreUiwGm89Pci4FK+BZWfivGcG4cOpw423gywSqa0a78uP9sXcp00rNgpjfWTUTfhs1ij0vUn/LUHsQ0G4WYflSA2lQoEBabZLOAYxkW2w/OXbRI+JlVw0QSoM6WH64LH1bcWw3klFdSPaaEytXbF+ggeGdTH+7nGC4x9OHW5cMcyw05RCYUq+vUX28BT+qcU2rBASvis5F8uMPz9978144aGeNh+n45jZTGChEI1LSyIR4jOyTui2Si5iyVRYvtC6WGe9TWTFwzYatdnWd5YtY1slgh5dYmzWee8Z3BFKpcK4I84PB65YnWNvKQKFArjlZtsJvYNgpUhb47Dr7Xx7MXhopPjMW8MHpeEDyZZFzw+1eSwyTIPhvZKQ2j4K9zVvspHRXz+XYG3WWLz4cG+rx7i79INwm8IRfZIRpFbhpnbWrfSI0CBwHI+0jtFWxwD9Gu/7qY5OJEDWTQtbJZcQjXWyEp4j/FlsbLilEb0dL2ErTOAPjezqlVEYYs8gHBUy9/e3IOdiqWkWrML+Fm/BIn8XV/TqGotbeyTaHAtvSKz26uILnx9iNpNXTESoBpkTB4DjeTTqeNx9SwcA+m9BYn/X+4d0wpnmCWGxkcF25w+oVUrjnqOdEiNwW59ktBH8Xf4wtjtWbMjBxQL9Oj8atRI8z6DjmNnetIB+SYlvdlzAZ5v0S+sOeHWUw3kChPhSgLTQLTsHxRPXwueHmNV2AeBasfjGD0Kurtcx1sVx7X/+XS/MEOlY7Zho3QknHPXSqW0E7h9iei3LzSOEtXoAeOLOVJfisvTSI33MSi+WDIkxPCTI6pjhLYoKc/7bkUqpxLjhXWxuLmEgLNk8fZ/9BeKE68MrAAzp2Rb9Uk0zf+O1IXjzqVuMtxt1PJqaN/sIUinxt+mm6yetg3mL/fh5z9ePJ8QT8k7ozfVesc7DeZMHYcmfh5ndFxcVYlbbdaRn82JcDU4MBRQbuuis/qnx6Cl4vGFXpMfv7GZ1rli55r0/3orunaPRPzUeTNAt+N4fh5gl4KhwjdVjHVn8J9vlEUs9u8Rg4t2peDTjJgDAqH7t8EDzxh4RzUne3ihRex8W9hjKUInRIeje2bSA2nAHwymd/RZlGAqae60SIcGmxoLlNxFHs34J8TVZJ3RDB55Yvbp9QrjVGG5XPX1fOkb2SUL3zuK1UyHhTEZPtU8Ix8rMDKcnPCVGh2LmY/0QpFZC11xO6NY+CiHBauw5YVpczPKbjKNlAAB9B6qzFAoFMvq3N35oThqdhgdH6Ovtr00agCdHp9kc/bMyM8PuSBp7DN8I+nUzX2PnydHWe9yGtVEbRyi5Otv0xMUys7+hZSepMx/8hPiSrGvohjHknk4OsiU6Ihi/v9e5Nd4tR7n4S0q7KIzonSS6nEGwxRh1e8sAfDrrdqcmKTkrMToUidHeH943rFdbRIRq8MHU4cZvAQaio53USrz77K34cssZjPNglcRhvdpadcbbG8dOSEuQRhZyE2en5NJaqVVKPH1funGsuaHk0atrrNPlph6do6FSKh3Wrv3pmfvT0S4uDM/cr2/VR4VpREsof/6d+axYjmNQq5SYfF+6w85ZWz5/dRQm35du9Xr2hsMS0hKk+z/WCZyhhe6DtVjcMX/KYMmt6zFueBd0TY5Cz67im3PcfUsHhIRosOEX04qCXZNtT7CRimG9kjCsl3iNPLV9FPKu60epOFMuE5MYHYLCcvNVJSc1l3AMZRfLES00Y5T4m6wTelNzQpdKC92dTRTcMW54F6TamdUopFAoRCfjGDx2RzfEx0fgUn6lcfy7s9PxpSpz4gDjz5ZlF7G6upjZTw1E9trjOH3ZtD5+B4sNu0MthjGu/inXOMSSEH+QRtPWTRxn6BSV9a/hsnHDuyC9s/3t8Fw1+f5004xOaX3J8Iiw43NlZgYG2pl4JRTWJgizJvTHaxP7G++z3IPWF30ChHhC1pmQN07993MgASA8JAi39tAvdyC1spEn3J1FatCtvWnzk/pG2ytdEiIFsk6FhnHoNDuPtARP5hoQ0hLkndCbG5KeJPQhPRIdn9RKGFYbTBFZz4SYr3RJiBTJulOUt7HaojPUKgV0HMPk+50bZ94a9OwSi7++OBwRoa7PKJWyuwZ2QKe24Y5PdMDWkhJC14qrER8vvm46Ib4m64TOPCi5zH5yIA6dLW51HaqOBFoyB8SXUPCVOidWqyTEV2Sd0A0Ti9xpoXdMjBBd/IoQT9hb3pgQX5N185RGuZCW0KltBPrYGMv/+qQBZrft7flKiK/JOhXaWg+dEG+a+/tbMG289fLGAHBTuyiszMww3tY4UWcnxFdkndCNW9BRQicS8cnGE/4OgbRiDmvo5eXlmDVrFi5fvgyNRoNOnTph3rx5iImJwZEjRzBnzhw0NDSgXbt2WLRoEWJjW26srnGDCy/sDkSIJxTQT7CNjnBvwS9CvMFhC12hUGDKlCnYsmULNm7ciA4dOmDx4sXgeR6vvPIK5syZgy1btmDgwIFYvHhxS8RsZJpY1KIvS4iVtI76GaVRYYE3SojIh8OErtVqMXiwaSOEvn37Ij8/Hzk5OQgODsbAgQMBAI899hi+//5730UqwtBCd3WjAkK8bfwo/S5NA2+Od3AmIb7j0rBFnufx1VdfISMjAwUFBUhONm2eHBMTA57nUVFRAa1Wa+dZzMXGuj/hI6x5f8q4uAjEx0h3Fp8cJprIIUZAunFyzUOtwsP1JRepxikkhxgBitMVLiX0t99+G6GhoZg4cSJ++OEHrwRQWlptLJ24Ij4+ApU36gEAFeU1UHLSnNARHx+B4uIqxyf6kRxiBKQdp/FarNSvoS7VOA2k/LcUojitKZUKmw1hpxN6VlYWLl26hBUrVkCpVCIpKQn5+fnG42VlZVAqlS61zj1l+CDwdEU9Qjxl2GTFsOkKIf7g1LDFJUuWICcnB9nZ2dBo9J0+PXv2RH19PQ4cOAAAWL16NWVGfIIAABvsSURBVO655x7fRSqCebCWCyHeZOjH0XE0U5T4j8MWem5uLj7++GN07twZjz32GACgffv2yM7OxsKFCzF37lyzYYstyVCpoQY68TfDrlmcG+VDQrzFYULv1q0bzpw5I3qsf//+2Lhxo9eDchath06kwrDIm45KLsSPaKYoIV6gohY6kQBZJ3QquRCpUCoUUCoU1EInfiXzhE6dokQ6VCoFtdCJX8k6oVPJhUiJWqUAR6NciB/JOqGbxqH7ORBCoO8Y1fFUciH+I+uEbtgchkouRAqq65rw86Fr/g6DtGKyTujG5XP9HAchhEiB7BO6QkFT/wkhBJB5QmeMOkQJIcRA1gmd5xm1zgkhpJlLy+dKDc8YlLL+SCKBZEBqPK6X1fo7DNKKyTodUsmFSIlarUQTzRQlfiTrhE4lFyIlQSolmnSU0In/yDqh61vo/o6CEL0gtZLWciF+JeuErh+2SBmdSMPlwipU1TZhz/F8xycT4gOyT+g0S5RIxfn8GwCAd/++38+RkNZK1gmdMUYlF0IIaSbrhM7zNEuUSEdosKxHAZMAIO+EzhgNWySS0Ssl1t8hkFZO1gmd0cQiIiG/nSz0dwiklZN1OuQZlVyIdKR10Po7BNLKyTuh81RyIdLxyuP9AAC3dE/0cySktZJ1QmfNy+cSIgVKpQKdEiP8HQZpxWSd0HlGuxURaVGrFNDR9H/iJ7JO6IxGuRCJUamU0NFG0cRPZJ3Q9Ytz+TsKQkxUSgWt50L8xqmZEFlZWdiyZQuuXbuGjRs3IjU1FQCQkZEBjUaD4OBgAMDMmTMxYsQI30Vrgaflc4nEqFVK1DVx/g6DtFJOJfQ77rgDTz75JJ544gmrY0uXLjUm+JbGaC0XIjFqlQJcPbXQiX84ldAHDhzo6zjcwtMoFyIx+ho6JXTiHx4vPjFz5kwwxjBgwADMmDEDkZGR3ojLKTQOnUiNfpQLdYoS//Aooa9atQpJSUlobGzEO++8g3nz5mHx4sUuPUdsbLjbr68OUkENID5e2mN/pR4fII8YAenHufeEfvq/1OME5BEjQHG6wqOEnpSUBADQaDSYMGECnn/+eZefo7S0GjzveosmPj4CDQ06qJQKFBdXufz4lhIfHyHp+AB5xAjIJ04AKCy6Ielvj3L5W1Kc1pRKhc2GsNvDFmtra1FVpf8FGGPYvHkz0tPT3X06tzCaWEQkiqOx6MQPnGqhz58/H1u3bkVJSQmefvppaLVarFixAlOnTgXHceB5HikpKZg7d66v4zVDW9ARqRk/KgVrfj6PJh2PILWsp3kQGXIqoc+ePRuzZ8+2un/9+vVeD8gV1ClKpKZNkAoA0KTj4IUxB4S4RNZNCMZAW9ARSQlS6xN6I63nQvxA1gmdSi5EajRB+v9SlNCJP8g+oVOnKJESQ91cX3IhpGXJOqFTyYVIjcZQcmmiFjppebJO6PrVFimjE+kwtdApoZOWJ+uETotzEakx1NBPXy73cySkNZJ1QqfFuYjUGEot3+255OdISGsk74TO03roRFroGyPxJ1kndAaaWESkpUuS/xdoIq2XrBM6bUFHpEallPV/KSJzsr76eFqci0iQNiLY3yGQVkrWCZ0xKrkQ6bklPRHRlNSJH8g6oVPJhUiRSqUER9vQET+Qd0JnNMqFSI9aqQDnxqYthHhK1gmd0eJcRIJUKiV0lNCJH8g6oesX5/J3FISYU6sUtGMR8QtZp0NGJRciQWqqoRM/kXVCp8W5iBSpVEowwK3Nz0ngKK9qAGMtew3IO6FTyYVIkFqlb2RwPLXSW6tzVyvxcvYuHDhTbLzvzOVyzF25z6dJXtbpkEouRIoMS+fqqI7eal0qrAIAnLhYZrwv69+HcaWoGnnXq3z2urJN6Iavs1RyIVKzZa9+pcWK6gY/R0L8ZdUPZ20ee/sfB3z2uvJN6M1fW2jmP5Gax+5KBQCo6OJslXSCDnFb7U3eR2UXtU+etQUY6lDUQidSExsVAgCoqdf5ORLiC+euVSIiJAiJMaEAgJXfncLO4wUAgBf/rzdiI9sYz62oEv+WVlZZjzhtiNdjk21CN8zEo8W5iNQYrs3Tl8vRJSnSz9EQb3v3nwcBACszM3D+WqUxmQPA0v8eMzv36PlSTF6wDQNS483uf+2Tvfh01iivxybbkovhGwt1ihKpaRurb7mpVbL970VssBy59E5zcnfk4Nlis9u+WhpCtlecqVPUz4EQYiEsJAgAEByk8nMkxFO/HM3Hibwy3KhtBAAcyS0xHvO0Du6LeQoOE3pWVhYyMjKQlpaGs2dNPbcXL17Eo48+itGjR+PRRx9FXl6e14Ozx9QpShmdSIshkRuGLxJ5OplXhr//7zTeX30E05fuREV1g9m3ri+/P+3R8/uiXOwwod9xxx1YtWoV2rVrZ3b/3LlzMWHCBGzZsgUTJkzAnDlzvB6cPTzV0IlEaZoTetmNej9HQjxxyWK8eNaqQygXdHL+crTA8iEOWdbSvc1hQh84cCCSkpLM7istLcXJkycxZswYAMCYMWNw8uRJlJWViT2FT/CMSi5EmgwJ/eyVCj9HQtxRXtWAshv1+PHgVbP7C8vr8OWWM04/jzZcY3XfyL7JePaB7vh45m0exynGrVEuBQUFSExMhEqlv3BVKhUSEhJQUFCAmJgYrwZoi7GFThmdSIxh/LmvxhoT33o5e5dXnidYowbQaHafQgHc2r2tV55fjN+HLcbGhrv1uJKKOgBAZGQI4uOlvdO61OMD5BEjIJ84AeBiQZWk45VybEItGWdpZZ3Lj3l41E1Yt+O8WSdneucYnMqzrljEaMN8+vu4ldCTkpJQWFgIjuOgUqnAcRyKioqsSjPOKC2tdqu3lzV/O6iprkdxse/WRvBUfHyEpOMD5BEjIK84DaQar5z+li0Z5+QF21x+TEbfZPxuVDcUXK/Eln1X8MOBK5h0dype/2Sv1bkJkRqPfx+lUmGzIezWsMXY2Fikp6dj06ZNAIBNmzYhPT29xcotgGCUC3WKEkJ8qFfXWJvHgjUqhASrERmmQUxkGzx+ZzeszMxA25hQJDXPRzDomBju87kJDlvo8+fPx9atW1FSUoKnn34aWq0W3333Hd566y1kZmZi2bJliIyMRFZWlk8DtUSdokTKurWPQu7VSn+HQRw4dr4EsZFt0C7eduk3LqqN2e1HRt2Er38+BwB47Yn+Nh8X1Jy85/7+FtTUNyG1g9YLEdvnMKHPnj0bs2fPtro/JSUFa9as8UlQzqBOUSJlndtG4mpxtb/DIHYcPFOM7HXHAQBjhnbCpt2XRM8bM7QziivrUFndiCtF1eiUaEr+HRJsfxBMGp2G1dtykRwXhiB1y8zhlO1MUePUfyq5EAkKUivR2EQTi6SKMWZM5gBsJvNHRt2E6IhgzHikL6qaZ4s26HhMGZOOft3i7C4OmNIuCm9MGthiyRyQwCgXd9F66ETKgtRKcDwDzzNqdEjQul8vOnXePYM7Gn+uqNYn9KraRozonYyhPV0fBOJrsm2h03roRMo0za2yJtosWpL2nSx0+TEvPNQLAJDWMdrb4XiNfBM61dCJhKkNCZ3Wc5Gkogrb480z+rcTvX9AWjxWZmYgwQfrmHuLfEsutMEFkbAgSuiSceJiGTbsvIhXn+gHpUKB7/aY6uXTx/fG+l8voqK6wVhSGT/qJnRICDfbqEIuZJvQTZ2i/o2DEDHGkouO83Mk5MM1R8HxDDuO5ONfW833+uzWXos5v78FjDHUN3IorqhDcJAKt/UVb6VLnWzTIcdRyYVIV5BaP5O5kVrofmfYTMIymQNAG43+fVIoFAgJVqNjojyWQ7BFtgld17xzCG3ES6TIMKmESi4t78DpIkxesA0NjY6/HQVayVa2CZ1vbqGraJsvIkFBQZTQ/WXZ+hwAwKGzxahraF0bdcu2hm5oodMYXyJF6ubr8kZNo4MziacyV+zBU/fejPRO+uGEcVFtUFJZj083nbT7uL9MHtQS4bUo2TZvDTV0KrkQKSoorQUAbNyd599AAtzxC6UoqqjDoq8OG+8rqXRupyh70/blSr4JnWroRML6N281NqyX9GYTBpLLhaalaB2NKIoK1+DJ0WnomBCOhc8P8XVofiHbhK6jFjqRMMNG0RzNFHXZvlOFmLxgG4rtTP4xEK6SaGs9FgAYPagDMp/oj9v7tcNbkwchLkq6k4M8IduEbviPQp2iRIoMnaINTTQO3VWGMtVH3xy3fyKA+kZTp+fG3XlmLXaDLkkReDSjGxKjQ62OBRrZZkPD2FLqFCVSZJgfsev4dT9HIi88z3CtuAYAjMsPr//1At7710HRPVqrapvMbr/1xX6rcy4WSH9nJm+RbUI3lFzUlNCJhJXecK6DjuidvVJhdpsxhm935SH3aiUuXbdOzF/9mCv6PIE4gsUZsk3oPHWKEpmg6f/Oyb1agYWC0SoAsPU3U1387X8cMP5cWlmPRjvlrA4J4cakPiAt3suRSpd8x6FzVHIh8vDTwWtm62oTce/965DVfX9bc9TsNs8YdDoeryzf7fD5OiSEY2VmhtfikwPZttBNwxZl+yuQVuJIbrG/Q5CUyQu2YfKCbWAiNXGDp++9WfT+Rf8+jB1H8q3uf3Zsd6/FJ2eyzYbGiUUqaqETaUpJjgQAnKXNokWVVzUYfxbOqO2dEovhvcXH75+5UoGvfjKvm08f3xu39miL7JdGAgAiQoN8EK08yDah0+JcROqmP9LH+LO91mhrwDOGc1croROMy5+5zFQ2qRWsuTJ9fB+rRbOiwjQ2nzs0WJ/AQ4LVWJmZgb++OMJbYcuObGvoHNXQicSFBpv+e1XVNiHSTlIKdFOyfrZ7vNzBaKCZj/fDm5/9Jnqsa/M3ISLjFjrHMygUtB46kS5hK/PgmSI/RtKyzlwux+QF21DWnKTtfTs5f60S768+jEWrjwAAnronTfQ8bbgG86cMFj1GjToT+SZ0jqcOUSJ5mU/0BwAoWlHSWfhv/dDDmct2o7yqwWryj9A7/zyIE3nlxtu39mgrel6IRo2wEPPa+IPDuxhXWCR6ss2IHM+oQ5RIXsdE/VojX35/xs+RtBxhe3z1T7mY/tFOq3NsbcRsWAMHAJZOM9XClUqFcXchQP9B+cDwLnjl8X6eBxxAZJvQdRwPFZVbiMS10ci2m8otx86XmN3ef9pUavrDGNPQwvbxjpeuDQ8Jwqev34kZj+o7lw37tAJAagetp6EGJNlebRxHLXRCpObDNcdsHlOpFMaJPqcvlVsd73tTnNV9bWPDoGoe0aZQKNA7JVZ0CQCi53FCz8jIgEajQXBwMABg5syZGDHC98OGOJ7RkEVCZEQtWBlV+HPHhHCo1Uo8cVeqw+eYPr6Pw3NaM6+00JcuXYrUVMdvhjfpOJ4SOpGFdvFhuFZcg4ZGDsGCOrDcld2oR1F5HSLDNEiOC8N3e/KMx+4f0gnf7TGtwzJ9fG/0TjG1wPNLa4w/vzZpgFntnLhP3iUXGuVCZKBX11hcK65BSWWd2YYMctbQxJlNDLL08G0p2Hm8AJXV+hmgwmQOAAPT4vH3/53GsJ5tKZl7kYJ5OIUtIyMD4eHhYIxhwIABmDFjBiIjfT/QP+vL/biYfwMrMu/w+WsR4olTF8sw62+/YuyIrnj2wV7+DsdjtfVNePSNzTaP902Nx9t/HAqO48FgXl4RqqxuQHiohr5pe5HHLfRVq1YhKSkJjY2NeOeddzBv3jwsXrzY6ceXllaD513/TNFvcMFQXCztDpL4+AiK0UvkGqeuUT8Oe+OvF3BHv2REhvp/xqgnf8sCQblEzJ8f6un0c5fVNdo9Ltf33JeUSgViY8W/6Xlcs0hK0i+io9FoMGHCBBw6ZL0Epi/oSy70yU6kr22Maeuz6Uutx2TLiY7j8cm3J0WP/fl3vbAyM4Nmb/uRRwm9trYWVVX6TyXGGDZv3oz09HSvBOaIjqdOUSJPOhlvHL0n5zouiezbCQD9U1vPRhJS5VHJpbS0FFOnTgXHceB5HikpKZg7d663YrOLpv4TOXn7mUF48/N9AIDrZbVOTayRGp4xbD1wxey+xX8aih1H8jFmaCc/RUWEPEroHTp0wPr1670Vi0toHDqRk3bx4bitbzJ2HMnHwn8fNpvWLgeNTRw+/+6UcQPnuwZ2wON3dgMAPDSyqz9DIwKybeJyHKNV1oisPH6HPgFybgwC8Lfn3t9hNo3fkMyJtMg2oes4nqb+E1nRNI+3Dmsjr+kfiyw2bn5uXA8/RUIckW1C53hGi3MRWSqprAcvkx2MmnQ8TlmsuzIoPdFP0RBH5NVUEOA4HiobExYIkbrCslokxYb5OwyHSirrjD8vf/k2mtUpcbLNiNQpSuTo9YkDAACrfjjr50ic88an+m3fErQhlMxlQLYt9CYdDzXV0InMdE6KAACczLNePlZKrpXUmO3hOfVh+S9Z0BrINqE3NHHGTiZC5EK4rsmx86XonRLrx2isMcYwZ+U+4/BEQJ/MA2VRsUAn25JLYxOHILVswyet2IMjugAAPlxz1M+RWPv1WIFZMp/xaB/060YzQOVCthmxsYmDRk0tdCI/Y4d2Nv584HQRiirqMHnBNkxesA2FZbX+CwzA7pzrxp/vvqUDenSO8WM0xFWyTOgcz0PHMWiCZBk+aeUUCgWmjNGvebRsfQ4yV+wxHpv3j/1m56787hQmL9iG2vomn8dVWd2As1cq9K+bmYHH7ugGBQ0NlhVZZsTGJv3iRtRCJ3I1tGeS6P0J0aEoqazDzmMFWLEhBzuPFwAA/v6/06Ln84zh16P52Lg7z6N4GGN4tfmD5cl70jx6LuI/suwUbdLpEzrV0ImcfTZrFKYs/BkAMLJPMpp0PPacuI5Zy/dYnXvgTDF+PZaPg2eKcex8qejzbT98De+/MMylGPadKsSKDSfM7ru9bzuXnoNIhywTekMTBwA0LpbImlKpwMrMDOPtnw9fw54T183OCQlWYfJ96chel4MvNou30g3Kqxrw4ZqjZhspl92oRxuNCqFtgtCk43D+2g2kddSivKoekxdss3qO3997s4e/FfEnWSb0qlp9PTEiNMjPkRDiPbf3TUbbmFCU3ahHclwY2mhUorNJHxrZFet+uWC8/f4Lw5B3/QY++uY4jp0vxdL/HsOL/9cbJRV1mNVcRkmIDkFReZ3VcwH6DThmPzkQe05cx8g+yb755UiLkGVCv1Gr37YqMsz/W3kR4i0KhQLpnaJFjxla8owxKBQKs5EyABAdEY/xt6dgzfbzOHKuxKr1LZbMI0KD8OHU4caOzzsGtPfCb0H8SZ4JvUaf0KmFTlobe6NO7r21E/qnxeO1j/ca7xvSIxEPDOuC1z7Zi4l3p2JYryT8d/t5PPu73qipqm+JkEkLknlCpxY6IUKJ0aH45JXbUd/IoY1GZZyZKqzVP3FXKkLbBFFCD0CyTOilN+oRGaahTlFCRKhVSoSH0Aiw1kiW73pJZT0SBDupE0IIkWlCB4Bu7bX+DoEQQiRFliWXFx/ujfj4cFSU+3fdC0IIkRJZttCD1EoE0bR/QggxI8uETgghxBoldEIICRCU0AkhJEBQQieEkABBCZ0QQgIEJXRCCAkQfh+HrlS6v8WVJ49tSXKIUw4xAhSnN8khRoDidOV1FIwx1iJREEII8SkquRBCSICghE4IIQGCEjohhAQISuiEEBIgKKETQkiAoIROCCEBghI6IYQECErohBASICihE0JIgPD71H9XXbx4EZmZmaioqIBWq0VWVhY6d+7cIq9dXl6OWbNm4fLly9BoNOjUqRPmzZuHmJgYpKWlITU1FUql/jNy4cKFSEtLAwBs27YNCxcuBMdx6NGjB9577z2EhIQ4POaujIwMaDQaBAcHAwBmzpyJESNG4MiRI5gzZw4aGhrQrl07LFq0CLGxsQDg9jF3Xb16FS+88ILxdlVVFaqrq7Fv3z6b8bdEnFlZWdiyZQuuXbuGjRs3IjU1FYD9684Xx9yJ0971CcAv16itv6cv3mN333+xGO1dn76K3yuYzEyaNImtX7+eMcbY+vXr2aRJk1rstcvLy9nevXuNtxcsWMBee+01xhhjqamprLq62uox1dXVbOjQoezixYuMMcZef/119tFHHzk85olRo0axM2fOmN3HcRy788472f79+xljjGVnZ7PMzEyPjnnT/Pnz2V/+8heb8bdUnPv372f5+flWMdi77nxxzJ047V2fjPnnGrX19/T2e+zJ+28rRiHh9emL+L1FVgm9pKSEDRgwgOl0OsYYYzqdjg0YMICVlpb6JZ7vv/+ePfXUU4wx2/9ZNm/ezJ599lnj7WPHjrH77rvP4TFPiF1sR48eZffff7/xdmlpKevbt69Hx7yloaGBDR48mOXk5NiMv6XjFMZg77rzxTF347QkvD4Z8+816mxC9+d1aismy+vTF/F7i6xKLgUFBUhMTIRKpd8gWqVSISEhAQUFBcavlS2F53l89dVXyMjIMN43adIkcByHkSNHYurUqdBoNCgoKEBycrLxnOTkZBQUFBh/H1vHPDVz5kwwxjBgwADMmDHD6rViYmLA8zwqKircPqbVar0S67Zt25CYmIgePXrYjD8yMtJvcdq77hhjXj/mjWtZ7PoEpH2NevIe+/L9F7s+vR2/t/4vUaeom95++22EhoZi4sSJAIDt27dj7dq1WLVqFc6dO4fs7Gy/xbZq1Sp8++23+Oabb8AYw7x58/wWizO++eYbPPzww8bbcotfiiyvT4CuUXdZXp+AdOOXVUJPSkpCYWEhOI4DAHAch6KiIiQlJbVoHFlZWbh06RI+/PBDYweTIYbw8HCMHz8ehw4dMt6fn59vfGx+fr7xXHvHPGF4Do1GgwkTJuDQoUNWr1VWVgalUgmtVuv2MW8oLCzE/v37MXbsWLvxG+73R5z2rjtfHPOU2PVp+D0A6V6jYq/n7+tU7Pr0RfzeIquEHhsbi/T0dGzatAkAsGnTJqSnp7douWXJkiXIyclBdnY2NBoNAKCyshL19fUAAJ1Ohy1btiA9PR0AMGLECBw/fhx5eXkAgNWrV+Pee+91eMxdtbW1qKqqAgAwxrB582akp6ejZ8+eqK+vx4EDB4yvdc899wCA28e8Yd26dbjtttsQHR1tN35/xmnvuvPFMU+IXZ+APK5RwP332Ffvv+X16av4vUV2G1ycP38emZmZuHHjBiIjI5GVlYWuXbu2yGvn5uZizJgx6Ny5M9q0aQMAaN++PaZMmYI5c+ZAoVBAp9OhX79+eP311xEWFgYA+PHHH7Fo0SLwPI/09HQsWLAAoaGhDo+548qVK5g6dSo4jgPP80hJScHs2bORkJCAQ4cOYe7cuWZDpuLi4gDA7WOeGj16NN544w2MHDnSYfwtEef8+fOxdetWlJSUIDo6GlqtFt99953d684Xx9yJ88MPPxS9PrOzs3H48GG/XKNica5YscIn77G777+t9xywvj4B/1+j9sguoRNCCBEnq5ILIYQQ2yihE0JIgKCETgghAYISOiGEBAhK6IQQEiAooRNCSICghE4IIQGCEjohhASI/wcGubZgZfz3wAAAAABJRU5ErkJggg==\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"loss_labels = ['total loss', 'reward loss', 'td loss']\n", | |
"window = 100 // 2\n", | |
"for i, label in enumerate(loss_labels):\n", | |
" plt.title(label)\n", | |
" smoothed_loss = [np.mean(loss_hist[i][j-window:j+window]) \\\n", | |
" for j in range(window, len(loss_hist[i])-window)]\n", | |
" plt.plot(smoothed_loss, label=label)\n", | |
" plt.show()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 302 | |
}, | |
"id": "wdACSHErVls9", | |
"outputId": "4f967bac-f4cc-4809-c1d0-7d4f5fc6901a" | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Text(0.5, 1.0, 'extrinsic reward')" | |
] | |
}, | |
"execution_count": 44, | |
"metadata": {}, | |
"output_type": "execute_result" | |
}, | |
{ | |
"data": { | |
"image/png": "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\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"window = 20 // 2\n", | |
"smoothed_rewards = [np.mean(all_rewards[i-window:i+window]) \\\n", | |
" for i in range(window, len(all_rewards)-window)]\n", | |
"plt.plot(smoothed_rewards)\n", | |
"plt.title('extrinsic reward')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "Ac3yXTB3lzJg" | |
}, | |
"outputs": [], | |
"source": [ | |
"def fit_skill_vector(skill_vector, batch_data, optimizer, model):\n", | |
" device = next(model.parameters()).device\n", | |
"\n", | |
" batch_data = np.array(batch_data)\n", | |
" obs, _, _, rewards, _, _ = \\\n", | |
" [torch.from_numpy(np.stack(batch_data[:, i])).to(device) \\\n", | |
" for i in range(batch_data.shape[1])]\n", | |
"\n", | |
" batch_svs = einops.repeat(skill_vector, 'e -> b e', b=obs.shape[0])\n", | |
" batch_svs = batch_svs.to(device)\n", | |
" with torch.no_grad():\n", | |
" features, _ = model(obs, batch_svs)\n", | |
"\n", | |
" pred_rewards = torch.bmm(features.unsqueeze(1), batch_svs.unsqueeze(2))\n", | |
" pred_rewards = pred_rewards.squeeze()\n", | |
"\n", | |
" residuals = (rewards - pred_rewards) ** 2\n", | |
" loss = residuals.mean()\n", | |
"\n", | |
" optimizer.zero_grad()\n", | |
" loss.backward()\n", | |
" optimizer.step()\n", | |
"\n", | |
" return loss.item()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "6dX5_Ojpvq9n" | |
}, | |
"outputs": [], | |
"source": [ | |
"fit_steps = 500\n", | |
"ds_batch_size = 256\n", | |
"ds_print_freq = 50\n", | |
"test_episodes = 100\n", | |
"\n", | |
"ds_lr = 1e-3\n", | |
"\n", | |
"skill_vector = sample_skill()\n", | |
"skill_vector.requires_grad = True\n", | |
"\n", | |
"sv_optimizer = torch.optim.Adam((skill_vector,), lr=ds_lr)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 759 | |
}, | |
"id": "O_tqI1tlv5Ya", | |
"outputId": "7b5d2687-55be-4405-c685-0d6ad9191506" | |
}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:4: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray\n", | |
" after removing the cwd from sys.path.\n" | |
] | |
}, | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"SV Reward Loss: 0.0172\n", | |
"SV Reward Loss: 0.0030\n", | |
"SV Reward Loss: 0.0011\n", | |
"SV Reward Loss: 0.0010\n", | |
"SV Reward Loss: 0.0008\n", | |
"SV Reward Loss: 0.0014\n", | |
"SV Reward Loss: 0.0015\n", | |
"SV Reward Loss: 0.0008\n", | |
"SV Reward Loss: 0.0008\n", | |
"SV Reward Loss: 0.0011\n", | |
"SV Reward Loss: 0.0014\n", | |
"SV Reward Loss: 0.0016\n", | |
"SV Reward Loss: 0.0008\n", | |
"SV Reward Loss: 0.0012\n", | |
"SV Reward Loss: 0.0008\n", | |
"SV Reward Loss: 0.0011\n", | |
"SV Reward Loss: 0.0009\n" | |
] | |
}, | |
{ | |
"ename": "KeyboardInterrupt", | |
"evalue": "ignored", | |
"output_type": "error", | |
"traceback": [ | |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", | |
"\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", | |
"\u001b[0;32m<ipython-input-47-65009799b424>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0msv_losses\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[1;32m 2\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mstep_idx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfit_steps\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----> 3\u001b[0;31m \u001b[0mbatch_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msample_batch\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexp_buffer\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mds_batch_size\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 4\u001b[0m \u001b[0mloss\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfit_skill_vector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mskill_vector\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbatch_data\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msv_optimizer\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0msv_losses\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mloss\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", | |
"\u001b[0;32m<ipython-input-24-7a61dba9e776>\u001b[0m in \u001b[0;36msample_batch\u001b[0;34m(buffer, n)\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0msample_batch\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbuffer\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn\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----> 8\u001b[0;31m \u001b[0mdata_idxs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mchoice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbuffer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mreplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\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 9\u001b[0m \u001b[0mbatch_data\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[1;32m 10\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mdata_idxs\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", | |
"\u001b[0;31mKeyboardInterrupt\u001b[0m: " | |
] | |
} | |
], | |
"source": [ | |
"sv_losses = []\n", | |
"for step_idx in range(fit_steps):\n", | |
" batch_data = sample_batch(exp_buffer, ds_batch_size)\n", | |
" loss = fit_skill_vector(skill_vector, batch_data, sv_optimizer, model)\n", | |
" sv_losses.append(loss)\n", | |
"\n", | |
" if step_idx != 0 and step_idx % ds_print_freq == 0:\n", | |
" print('SV Reward Loss: {:.4f}'.format(np.mean(sv_losses[-ds_print_freq:])))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 68, | |
"referenced_widgets": [ | |
"b9abaa3d1e714738988eca0eaa59b4f3", | |
"6a3600d8cd21492bacaa5c1a2d6e83b3", | |
"f90af20614914c8f994619174be2b4c8", | |
"07c4759dcb534616a0c497c6f979607d", | |
"f20aa911d3fe489791a6e3006ac28a38", | |
"44735900376d48258c7a5f035f93685f", | |
"1e1a06065e9349039d53bb167a19fd19", | |
"4e2ecd91fbcb4a199ed38751743c8460", | |
"c570c2d58b974e688b6059d6b31a043c", | |
"4221d18fb26d4bdbb4b2f729beea8a03", | |
"eac0871963cd4420a923e77c785f64f4" | |
] | |
}, | |
"id": "WFPJy1oRxd8a", | |
"outputId": "ceaf2f7d-a90c-42af-83aa-5742035cf6c6" | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "b9abaa3d1e714738988eca0eaa59b4f3", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
" 0%| | 0/100 [00:00<?, ?it/s]" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
}, | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Test Avg. Reward: 0.13\n" | |
] | |
} | |
], | |
"source": [ | |
"test_rewards = []\n", | |
"for episode_idx in tqdm(range(test_episodes)):\n", | |
" obs = env.reset()\n", | |
"\n", | |
" ep_rewards = []\n", | |
" done = False\n", | |
" while not done:\n", | |
" # Sample an action\n", | |
" if np.random.rand() < end_act_epsilon:\n", | |
" act = env.action_space.sample()\n", | |
" else:\n", | |
" with torch.no_grad():\n", | |
" _, sfs = model(obs.unsqueeze(0).to(DEVICE),\n", | |
" skill_vector.unsqueeze(0).to(DEVICE))\n", | |
" sfs = sfs.cpu()\n", | |
" q_vals = torch.matmul(sfs[0], skill_vector.unsqueeze(1))\n", | |
" act = torch.argmax(q_vals).item()\n", | |
"\n", | |
" # Make a step\n", | |
" next_obs, reward, done, _ = env.step(act)\n", | |
" reward = np.float32(reward)\n", | |
" ep_rewards.append(reward)\n", | |
" obs = next_obs\n", | |
"\n", | |
" test_rewards.append(sum(ep_rewards))\n", | |
"\n", | |
"print('Test Avg. Reward: {:.2f}'.format(np.mean(test_rewards)))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "9G4YTac3DwRG" | |
}, | |
"outputs": [], | |
"source": [ | |
"# ds_fit_episodes = 100\n", | |
"# ds_print_freq = 2500\n", | |
"\n", | |
"# ds_lr = 0.1\n", | |
"\n", | |
"# skill_vector = sample_skill()\n", | |
"# skill_vector.requires_grad = True\n", | |
"\n", | |
"# sv_optimizer = torch.optim.Adam((skill_vector,), lr=ds_lr)\n", | |
"\n", | |
"# ds_all_rewards = []\n", | |
"# step_idx = 0\n", | |
"# for episode_idx in range(ds_fit_episodes):\n", | |
"# obs = env.reset()\n", | |
"\n", | |
"# ep_rewards = []\n", | |
"# batch_data = []\n", | |
"# done = False\n", | |
"# while not done:\n", | |
"# # Sample an action\n", | |
"# if np.random.rand() < end_act_epsilon:\n", | |
"# act = env.action_space.sample()\n", | |
"# else:\n", | |
"# with torch.no_grad():\n", | |
"# features, sfs = model(obs.unsqueeze(0).to(DEVICE),\n", | |
"# skill_vector.unsqueeze(0).to(DEVICE))\n", | |
"# sfs = sfs.cpu()\n", | |
"# q_vals = torch.matmul(sfs[0], skill_vector.unsqueeze(1))\n", | |
"# act = torch.argmax(q_vals).item()\n", | |
"\n", | |
"# # Make a step\n", | |
"# next_obs, reward, done, _ = env.step(act)\n", | |
"# reward = np.float32(reward)\n", | |
"# batch_data.append([features.detach().cpu().numpy(), reward])\n", | |
"# ep_rewards.append(reward)\n", | |
"# obs = next_obs\n", | |
"\n", | |
"# if step_idx % ds_print_freq == 0:\n", | |
"# loss, r_2 = fit_skill_vector(skill_vector, batch_data, sv_optimizer)\n", | |
"# print('Step: {}\\t\\tReward Fit Loss: {:.4f}\\tr^2: {:.4f}'\n", | |
"# .format(step_idx, loss, r_2))\n", | |
"# batch_data = []\n", | |
"\n", | |
"# step_idx += 1\n", | |
"# ds_all_rewards.append(sum(ep_rewards))\n", | |
"# if episode_idx % 10 == 0:\n", | |
"# print('Avg Reward: {:.1f}'.format(np.mean(ds_all_rewards[-10:])))\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "PeCUpqlbuT4D" | |
}, | |
"outputs": [], | |
"source": [ | |
"" | |
] | |
} | |
], | |
"metadata": { | |
"accelerator": "GPU", | |
"colab": { | |
"collapsed_sections": [], | |
"name": "VISR.ipynb", | |
"provenance": [], | |
"authorship_tag": "ABX9TyPUL/Y6PHTPv8KB7tLzGzom", | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"display_name": "Python 3", | |
"name": "python3" | |
}, | |
"language_info": { | |
"name": "python" | |
}, | |
"widgets": { | |
"application/vnd.jupyter.widget-state+json": { | |
"07c4759dcb534616a0c497c6f979607d": { | |
"model_module": "@jupyter-widgets/controls", | |
"model_module_version": "1.5.0", | |
"model_name": "HTMLModel", | |
"state": { | |
"_dom_classes": [], | |
"_model_module": "@jupyter-widgets/controls", | |
"_model_module_version": "1.5.0", | |
"_model_name": "HTMLModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/controls", | |
"_view_module_version": "1.5.0", | |
"_view_name": "HTMLView", | |
"description": "", | |
"description_tooltip": null, | |
"layout": "IPY_MODEL_4221d18fb26d4bdbb4b2f729beea8a03", | |
"placeholder": "", | |
"style": "IPY_MODEL_eac0871963cd4420a923e77c785f64f4", | |
"value": " 100/100 [00:18<00:00, 5.00it/s]" | |
} | |
}, | |
"1e1a06065e9349039d53bb167a19fd19": { | |
"model_module": "@jupyter-widgets/controls", | |
"model_module_version": "1.5.0", | |
"model_name": "DescriptionStyleModel", | |
"state": { | |
"_model_module": "@jupyter-widgets/controls", | |
"_model_module_version": "1.5.0", | |
"_model_name": "DescriptionStyleModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/base", | |
"_view_module_version": "1.2.0", | |
"_view_name": "StyleView", | |
"description_width": "" | |
} | |
}, | |
"4221d18fb26d4bdbb4b2f729beea8a03": { | |
"model_module": "@jupyter-widgets/base", | |
"model_module_version": "1.2.0", | |
"model_name": "LayoutModel", | |
"state": { | |
"_model_module": "@jupyter-widgets/base", | |
"_model_module_version": "1.2.0", | |
"_model_name": "LayoutModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/base", | |
"_view_module_version": "1.2.0", | |
"_view_name": "LayoutView", | |
"align_content": null, | |
"align_items": null, | |
"align_self": null, | |
"border": null, | |
"bottom": null, | |
"display": null, | |
"flex": null, | |
"flex_flow": null, | |
"grid_area": null, | |
"grid_auto_columns": null, | |
"grid_auto_flow": null, | |
"grid_auto_rows": null, | |
"grid_column": null, | |
"grid_gap": null, | |
"grid_row": null, | |
"grid_template_areas": null, | |
"grid_template_columns": null, | |
"grid_template_rows": null, | |
"height": null, | |
"justify_content": null, | |
"justify_items": null, | |
"left": null, | |
"margin": null, | |
"max_height": null, | |
"max_width": null, | |
"min_height": null, | |
"min_width": null, | |
"object_fit": null, | |
"object_position": null, | |
"order": null, | |
"overflow": null, | |
"overflow_x": null, | |
"overflow_y": null, | |
"padding": null, | |
"right": null, | |
"top": null, | |
"visibility": null, | |
"width": null | |
} | |
}, | |
"44735900376d48258c7a5f035f93685f": { | |
"model_module": "@jupyter-widgets/base", | |
"model_module_version": "1.2.0", | |
"model_name": "LayoutModel", | |
"state": { | |
"_model_module": "@jupyter-widgets/base", | |
"_model_module_version": "1.2.0", | |
"_model_name": "LayoutModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/base", | |
"_view_module_version": "1.2.0", | |
"_view_name": "LayoutView", | |
"align_content": null, | |
"align_items": null, | |
"align_self": null, | |
"border": null, | |
"bottom": null, | |
"display": null, | |
"flex": null, | |
"flex_flow": null, | |
"grid_area": null, | |
"grid_auto_columns": null, | |
"grid_auto_flow": null, | |
"grid_auto_rows": null, | |
"grid_column": null, | |
"grid_gap": null, | |
"grid_row": null, | |
"grid_template_areas": null, | |
"grid_template_columns": null, | |
"grid_template_rows": null, | |
"height": null, | |
"justify_content": null, | |
"justify_items": null, | |
"left": null, | |
"margin": null, | |
"max_height": null, | |
"max_width": null, | |
"min_height": null, | |
"min_width": null, | |
"object_fit": null, | |
"object_position": null, | |
"order": null, | |
"overflow": null, | |
"overflow_x": null, | |
"overflow_y": null, | |
"padding": null, | |
"right": null, | |
"top": null, | |
"visibility": null, | |
"width": null | |
} | |
}, | |
"4e2ecd91fbcb4a199ed38751743c8460": { | |
"model_module": "@jupyter-widgets/base", | |
"model_module_version": "1.2.0", | |
"model_name": "LayoutModel", | |
"state": { | |
"_model_module": "@jupyter-widgets/base", | |
"_model_module_version": "1.2.0", | |
"_model_name": "LayoutModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/base", | |
"_view_module_version": "1.2.0", | |
"_view_name": "LayoutView", | |
"align_content": null, | |
"align_items": null, | |
"align_self": null, | |
"border": null, | |
"bottom": null, | |
"display": null, | |
"flex": null, | |
"flex_flow": null, | |
"grid_area": null, | |
"grid_auto_columns": null, | |
"grid_auto_flow": null, | |
"grid_auto_rows": null, | |
"grid_column": null, | |
"grid_gap": null, | |
"grid_row": null, | |
"grid_template_areas": null, | |
"grid_template_columns": null, | |
"grid_template_rows": null, | |
"height": null, | |
"justify_content": null, | |
"justify_items": null, | |
"left": null, | |
"margin": null, | |
"max_height": null, | |
"max_width": null, | |
"min_height": null, | |
"min_width": null, | |
"object_fit": null, | |
"object_position": null, | |
"order": null, | |
"overflow": null, | |
"overflow_x": null, | |
"overflow_y": null, | |
"padding": null, | |
"right": null, | |
"top": null, | |
"visibility": null, | |
"width": null | |
} | |
}, | |
"6a3600d8cd21492bacaa5c1a2d6e83b3": { | |
"model_module": "@jupyter-widgets/controls", | |
"model_module_version": "1.5.0", | |
"model_name": "HTMLModel", | |
"state": { | |
"_dom_classes": [], | |
"_model_module": "@jupyter-widgets/controls", | |
"_model_module_version": "1.5.0", | |
"_model_name": "HTMLModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/controls", | |
"_view_module_version": "1.5.0", | |
"_view_name": "HTMLView", | |
"description": "", | |
"description_tooltip": null, | |
"layout": "IPY_MODEL_44735900376d48258c7a5f035f93685f", | |
"placeholder": "", | |
"style": "IPY_MODEL_1e1a06065e9349039d53bb167a19fd19", | |
"value": "100%" | |
} | |
}, | |
"b9abaa3d1e714738988eca0eaa59b4f3": { | |
"model_module": "@jupyter-widgets/controls", | |
"model_module_version": "1.5.0", | |
"model_name": "HBoxModel", | |
"state": { | |
"_dom_classes": [], | |
"_model_module": "@jupyter-widgets/controls", | |
"_model_module_version": "1.5.0", | |
"_model_name": "HBoxModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/controls", | |
"_view_module_version": "1.5.0", | |
"_view_name": "HBoxView", | |
"box_style": "", | |
"children": [ | |
"IPY_MODEL_6a3600d8cd21492bacaa5c1a2d6e83b3", | |
"IPY_MODEL_f90af20614914c8f994619174be2b4c8", | |
"IPY_MODEL_07c4759dcb534616a0c497c6f979607d" | |
], | |
"layout": "IPY_MODEL_f20aa911d3fe489791a6e3006ac28a38" | |
} | |
}, | |
"c570c2d58b974e688b6059d6b31a043c": { | |
"model_module": "@jupyter-widgets/controls", | |
"model_module_version": "1.5.0", | |
"model_name": "ProgressStyleModel", | |
"state": { | |
"_model_module": "@jupyter-widgets/controls", | |
"_model_module_version": "1.5.0", | |
"_model_name": "ProgressStyleModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/base", | |
"_view_module_version": "1.2.0", | |
"_view_name": "StyleView", | |
"bar_color": null, | |
"description_width": "" | |
} | |
}, | |
"eac0871963cd4420a923e77c785f64f4": { | |
"model_module": "@jupyter-widgets/controls", | |
"model_module_version": "1.5.0", | |
"model_name": "DescriptionStyleModel", | |
"state": { | |
"_model_module": "@jupyter-widgets/controls", | |
"_model_module_version": "1.5.0", | |
"_model_name": "DescriptionStyleModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/base", | |
"_view_module_version": "1.2.0", | |
"_view_name": "StyleView", | |
"description_width": "" | |
} | |
}, | |
"f20aa911d3fe489791a6e3006ac28a38": { | |
"model_module": "@jupyter-widgets/base", | |
"model_module_version": "1.2.0", | |
"model_name": "LayoutModel", | |
"state": { | |
"_model_module": "@jupyter-widgets/base", | |
"_model_module_version": "1.2.0", | |
"_model_name": "LayoutModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/base", | |
"_view_module_version": "1.2.0", | |
"_view_name": "LayoutView", | |
"align_content": null, | |
"align_items": null, | |
"align_self": null, | |
"border": null, | |
"bottom": null, | |
"display": null, | |
"flex": null, | |
"flex_flow": null, | |
"grid_area": null, | |
"grid_auto_columns": null, | |
"grid_auto_flow": null, | |
"grid_auto_rows": null, | |
"grid_column": null, | |
"grid_gap": null, | |
"grid_row": null, | |
"grid_template_areas": null, | |
"grid_template_columns": null, | |
"grid_template_rows": null, | |
"height": null, | |
"justify_content": null, | |
"justify_items": null, | |
"left": null, | |
"margin": null, | |
"max_height": null, | |
"max_width": null, | |
"min_height": null, | |
"min_width": null, | |
"object_fit": null, | |
"object_position": null, | |
"order": null, | |
"overflow": null, | |
"overflow_x": null, | |
"overflow_y": null, | |
"padding": null, | |
"right": null, | |
"top": null, | |
"visibility": null, | |
"width": null | |
} | |
}, | |
"f90af20614914c8f994619174be2b4c8": { | |
"model_module": "@jupyter-widgets/controls", | |
"model_module_version": "1.5.0", | |
"model_name": "FloatProgressModel", | |
"state": { | |
"_dom_classes": [], | |
"_model_module": "@jupyter-widgets/controls", | |
"_model_module_version": "1.5.0", | |
"_model_name": "FloatProgressModel", | |
"_view_count": null, | |
"_view_module": "@jupyter-widgets/controls", | |
"_view_module_version": "1.5.0", | |
"_view_name": "ProgressView", | |
"bar_style": "success", | |
"description": "", | |
"description_tooltip": null, | |
"layout": "IPY_MODEL_4e2ecd91fbcb4a199ed38751743c8460", | |
"max": 100, | |
"min": 0, | |
"orientation": "horizontal", | |
"style": "IPY_MODEL_c570c2d58b974e688b6059d6b31a043c", | |
"value": 100 | |
} | |
} | |
} | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment