diff --git a/Amazon GPU howto.md b/Amazon GPU howto.md index a24c1c82d..21fd21924 100644 --- a/Amazon GPU howto.md +++ b/Amazon GPU howto.md @@ -1,17 +1,17 @@ -# How to set up GPU on EC2 instance +**Warning: this guide has not been updated since we migrated away from Theano/Lasagne, which happened a long time ago.** -## Create EC2 instance +# How to set up an Amazon EC2 GPU instance + +## Create an instance Use `p2.xlarge` instance type and `ami-e00a8180` AMI image. [Details](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html) -Open ports `22` (ssh) and `80` (http) on your freshly created instance, -you create a [security group](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html) -and attach it your instance to get ports open +Open ports `22` (ssh) and `80` (http) on your freshly created instance, then create a [security group](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html) and attach it to your instance to get the ports open. ## Launch notebook -Instance you have created contains all you need: fresh versions of theano, lasagne, CUDA driver and cuDNN, -just lunch ipython and get hands dirty: +The instance you have created contains all you need: fresh versions of theano, lasagne, CUDA driver and cuDNN, +just launch Jupyter and get your hands dirty: ```bash $ sudo su @@ -19,4 +19,3 @@ $ export THEANO_FLAGS='cuda.root=/usr/local/cuda,device=gpu,floatX=float32' $ export PATH=/usr/local/cuda-8.0/bin${PATH:+:${PATH}} $ jupyter notebook ``` - diff --git a/README.md b/README.md index 90d17b2c9..ea1453fd4 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,6 @@ Taught on-campus at [HSE](https://cs.hse.ru) and [YSDA](https://yandexdataschool [![Github contributors](https://img.shields.io/github/contributors/yandexdataschool/Practical_RL.svg?logo=github&logoColor=white)](https://github.com/yandexdataschool/Practical_RL/graphs/contributors) # Course info -* __Chat room__ for YSDA & HSE students is [here](http://t.me/practical_rl_2020) -* __Grading__ rules for YSDA & HSE students is [here](https://github.com/yandexdataschool/Practical_RL/wiki/Homeworks-and-grading) * __FAQ:__ [About the course](https://github.com/yandexdataschool/Practical_RL/wiki/Practical-RL), [Technical issues thread](https://github.com/yandexdataschool/Practical_RL/issues/1), [Lecture Slides](https://yadi.sk/d/loPpY45J3EAYfU), [Online Student Survival Guide](https://github.com/yandexdataschool/Practical_RL/wiki/Online-student's-survival-guide) @@ -65,7 +63,7 @@ The syllabus is approximate: the lectures may occur in a slightly different orde * Seminar: REINFORCE, advantage actor-critic * [__week07_seq2seq__](./week07_seq2seq) Reinforcement Learning for Sequence Models - * Lecture: Problems with sequential data. Recurrent neural netowks. Backprop through time. Vanishing & exploding gradients. LSTM, GRU. Gradient clipping + * Lecture: Problems with sequential data. Recurrent neural networks. Backprop through time. Vanishing & exploding gradients. LSTM, GRU. Gradient clipping * Seminar: character-level RNN language model * [__week08_pomdp__](./week08_pomdp) Partially Observed MDP @@ -86,7 +84,7 @@ The syllabus is approximate: the lectures may occur in a slightly different orde # Course staff Course materials and teaching by: _[unordered]_ -- [Pavel Shvechikov](https://github.com/bestxolodec) - lectures, seminars, hw checkups, reading group +- [Pavel Shvechikov](https://github.com/pshvechikov) - lectures, seminars, hw checkups, reading group - [Nikita Putintsev](https://github.com/qwasser) - seminars, hw checkups, organizing our hot mess - [Alexander Fritsler](https://github.com/Fritz449) - lectures, seminars, hw checkups - [Oleg Vasilev](https://github.com/Omrigan) - seminars, hw checkups, technical support diff --git a/docker/README.md b/docker/README.md index e2e354bb8..e9eab249b 100644 --- a/docker/README.md +++ b/docker/README.md @@ -7,7 +7,7 @@ _tl;dr [dockerhub url](https://hub.docker.com/r/justheuristic/practical_rl/)_ We recommend you to use either native docker (recommended for linux) or kitematic(recommended for windows). * Installing [kitematic](https://kitematic.com/), a simple interface to docker (all platforms) * Pure docker: Guide for [windows](https://docs.docker.com/docker-for-windows/), [linux](https://docs.docker.com/engine/installation/), or [macOS](https://docs.docker.com/docker-for-mac/). -* If you want to use your GPU make sure you have [nvidia-docker](https://github.com/NVIDIA/nvidia-docker) and [NVidia driver](https://www.nvidia.com/en-us/drivers/unix/) + [CUDA 10.2](https://developer.nvidia.com/cuda-downloads) installed +* If you want to use your GPU make sure you have [nvidia-container-toolkit](https://github.com/NVIDIA/nvidia-container-toolkit) and [NVidia driver](https://www.nvidia.com/en-us/drivers/unix/) + [CUDA 10.2](https://developer.nvidia.com/cuda-downloads) installed Below are the instructions for both approaches. diff --git a/setup_colab.sh b/setup_colab.sh index 5e1db94ee..c9b812bf9 100755 --- a/setup_colab.sh +++ b/setup_colab.sh @@ -2,4 +2,16 @@ apt-get -qq update apt-get -qq install -y xvfb -wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/xvfb -O ../xvfb +wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/xvfb -O ../xvfb + +# Download & import Atari ROMs (Colab stopped bundling them around the beginning of June 2021) + +gdown -q https://drive.google.com/uc?id=1c6_W2Fig92hm5FRIc2Mpc_ZZyr6o52lF + +# Alternative download: +# wget -q http://www.atarimania.com/roms/Roms.rar + +pip install -q unrar +mkdir ./roms +unrar x Roms.rar ./roms > /dev/null 2>&1 +python -m atari_py.import_roms ./roms > /dev/null 2>&1 diff --git a/week01_intro/README.md b/week01_intro/README.md index 6120dbe34..0c81dc013 100644 --- a/week01_intro/README.md +++ b/week01_intro/README.md @@ -11,7 +11,7 @@ ## More materials: -* __[recommended]__ - awesome openai post about evolution strategies - [blog post](https://blog.openai.com/evolution-strategies/), [article](https://arxiv.org/abs/1703.03864) +* __[recommended]__ - awesome openai post about evolution strategies - [blog post](https://openai.com/research/evolution-strategies), [article](https://arxiv.org/abs/1703.03864) * __[recommended]__ - formal explanation of crossentropy method in [general](https://people.smp.uq.edu.au/DirkKroese/ps/CEEncycl.pdf) and for [optimization](https://people.smp.uq.edu.au/DirkKroese/ps/CEopt.pdf) * Deep learning course (if you want to learn in parallel) - https://github.com/yandexdataschool/HSE_deeplearning * Video on genetic algorithms (english) - [video](https://www.youtube.com/watch?v=ejxfTy4lI6I) @@ -23,10 +23,10 @@ ## Practice assignment -Instant dive in: [__seminar_gym_interface__](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week01_intro/seminar_gym_interface.ipynb), [__crossentropy_method__](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week01_intro/crossentropy_method.ipynb), +Instant dive in: [__seminar_gymnasium_interface__](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week01_intro/seminar_gymnasium_interface.ipynb), [__crossentropy_method__](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week01_intro/crossentropy_method.ipynb), [__deep_crossentropy_method__](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week01_intro/deep_crossentropy_method.ipynb) -* Open `gym_interface.ipynb` and follow instructions from there +* Open `seminar_gymnasium_interface.ipynb` and follow instructions from there * After you're done there, proceed to `crossentropy_method.ipynb` * You can find homework and bonus assignment descriptions at the end of that notebook. -* Note: so far it's enough to say `pip install gym` on top of any data-science-stuffed python, but we'd appreciate if you gradually switch to [full installation](https://github.com/openai/gym#installing-everything). +* Note: so far it's enough to say `pip install gymnasium` on top of any data-science-stuffed python, but we'd appreciate if you gradually switch to [full installation](https://github.com/Farama-Foundation/Gymnasium). diff --git a/week01_intro/crossentropy_method.ipynb b/week01_intro/crossentropy_method.ipynb index 16e2a5f2b..40ae90548 100644 --- a/week01_intro/crossentropy_method.ipynb +++ b/week01_intro/crossentropy_method.ipynb @@ -1,422 +1,508 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Crossentropy method\n", - "\n", - "This notebook will teach you to solve reinforcement learning problems with crossentropy method. We'll follow-up by scaling everything up and using neural network policy." - ] + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "7XGyc-FCG35I" + }, + "source": [ + "# Crossentropy method\n", + "\n", + "This notebook will teach you to solve reinforcement learning problems with crossentropy method. We'll follow-up by scaling everything up and using neural network policy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2jwz8moTG35K" + }, + "outputs": [], + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display to draw game images on.\n", + "# It will have no effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "oe7EKolvLC67" + }, + "outputs": [], + "source": [ + "!pip install gymnasium[toy_text]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ltjzx5AFG35K" + }, + "outputs": [], + "source": [ + "import gymnasium as gym\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "env = gym.make(\"Taxi-v3\", render_mode=\"rgb_array\")\n", + "print(env.reset(seed=0))\n", + "plt.imshow(env.render())\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "O6waF01eG35L", + "outputId": "8ca46444-7a7f-4091-c50c-0cab96a995e9" + }, + "outputs": [], + "source": [ + "n_states = env.observation_space.n\n", + "n_actions = env.action_space.n\n", + "\n", + "print(f\"n_states={n_states}, n_actions={n_actions}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IHXnU2QWG35L" + }, + "source": [ + "# Create stochastic policy\n", + "\n", + "This time our policy should be a probability distribution.\n", + "\n", + "```policy[s,a] = P(take action a | in state s)```\n", + "\n", + "Since we still use integer state and action representations, you can use a 2-dimensional array to represent the policy.\n", + "\n", + "Please initialize the policy __uniformly__, that is, probabililities of all actions should be equal." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "9qL5eW-rG35L" + }, + "outputs": [], + "source": [ + "def initialize_policy(n_states, n_actions):\n", + " \n", + "\n", + " return policy\n", + "\n", + "\n", + "policy = initialize_policy(n_states, n_actions)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "G1SeRRGgG35L" + }, + "outputs": [], + "source": [ + "assert type(policy) in (np.ndarray, np.matrix)\n", + "assert np.allclose(policy, 1.0 / n_actions)\n", + "assert np.allclose(np.sum(policy, axis=1), 1)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9zR1fCUrG35L" + }, + "source": [ + "# Play the game\n", + "\n", + "Just like before, but we also record all states and actions we took." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "d4v8WmvlG35L" + }, + "outputs": [], + "source": [ + "def generate_session(env, policy, t_max=10**4):\n", + " \"\"\"\n", + " Play game until end or for t_max ticks.\n", + " :param policy: an array of shape [n_states,n_actions] with action probabilities\n", + " :returns: list of states, list of actions and sum of rewards\n", + " \"\"\"\n", + " states, actions = [], []\n", + " total_reward = 0.0\n", + "\n", + " s, _ = env.reset()\n", + "\n", + " for t in range(t_max):\n", + " # Hint: you can use np.random.choice for sampling action\n", + " # https://numpy.org/doc/stable/reference/random/generated/numpy.random.choice.html\n", + "\n", + " a = \n", + "\n", + " new_s, r, terminated, truncated, _ = env.step(a)\n", + "\n", + " # Record information we just got from the environment.\n", + " states.append(s)\n", + " actions.append(a)\n", + " total_reward += r\n", + "\n", + " s = new_s\n", + " if terminated or truncated:\n", + " break\n", + "\n", + " return states, actions, total_reward\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "id": "a1EUUZ29G35M" + }, + "outputs": [], + "source": [ + "s, a, r = generate_session(env, policy)\n", + "assert type(s) == type(a) == list\n", + "assert len(s) == len(a)\n", + "assert type(r) in [float, np.float64]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_5YEDTKnG35M" + }, + "outputs": [], + "source": [ + "# let's see the initial reward distribution\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "sample_rewards = [generate_session(env, policy, t_max=1000)[-1] for _ in range(200)]\n", + "\n", + "plt.hist(sample_rewards, bins=20)\n", + "plt.vlines([np.percentile(sample_rewards, 50)], [0], [100], label=\"50'th percentile\", color='green')\n", + "plt.vlines([np.percentile(sample_rewards, 90)], [0], [100], label=\"90'th percentile\", color='red')\n", + "plt.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EeWtL3F5G35M" + }, + "source": [ + "### Crossentropy method steps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "00WWzr0KG35N" + }, + "outputs": [], + "source": [ + "def select_elites(states_batch, actions_batch, rewards_batch, percentile):\n", + " \"\"\"\n", + " Select states and actions from games that have rewards >= percentile\n", + " :param states_batch: list of lists of states, states_batch[session_i][t]\n", + " :param actions_batch: list of lists of actions, actions_batch[session_i][t]\n", + " :param rewards_batch: list of rewards, rewards_batch[session_i]\n", + "\n", + " :returns: elite_states,elite_actions, both 1D lists of states and respective actions from elite sessions\n", + "\n", + " Please return elite states and actions in their original order\n", + " [i.e. sorted by session number and timestep within session]\n", + "\n", + " If you are confused, see examples below. Please don't assume that states are integers\n", + " (they will become different later).\n", + " \"\"\"\n", + "\n", + " reward_threshold = \n", + "\n", + " elite_states = \n", + " elite_actions = \n", + "\n", + " return elite_states, elite_actions\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "teOLBGojG35N" + }, + "outputs": [], + "source": [ + "states_batch = [\n", + " [1, 2, 3], # game1\n", + " [4, 2, 0, 2], # game2\n", + " [3, 1], # game3\n", + "]\n", + "\n", + "actions_batch = [\n", + " [0, 2, 4], # game1\n", + " [3, 2, 0, 1], # game2\n", + " [3, 3], # game3\n", + "]\n", + "rewards_batch = [\n", + " 3, # game1\n", + " 4, # game2\n", + " 5, # game3\n", + "]\n", + "\n", + "test_result_0 = select_elites(states_batch, actions_batch, rewards_batch, percentile=0)\n", + "test_result_30 = select_elites(\n", + " states_batch, actions_batch, rewards_batch, percentile=30\n", + ")\n", + "test_result_90 = select_elites(\n", + " states_batch, actions_batch, rewards_batch, percentile=90\n", + ")\n", + "test_result_100 = select_elites(\n", + " states_batch, actions_batch, rewards_batch, percentile=100\n", + ")\n", + "\n", + "assert np.all(test_result_0[0] == [1, 2, 3, 4, 2, 0, 2, 3, 1]) and np.all(\n", + " test_result_0[1] == [0, 2, 4, 3, 2, 0, 1, 3, 3]\n", + "), \"For percentile 0 you should return all states and actions in chronological order\"\n", + "assert np.all(test_result_30[0] == [4, 2, 0, 2, 3, 1]) and np.all(\n", + " test_result_30[1] == [3, 2, 0, 1, 3, 3]\n", + "), \"For percentile 30 you should only select states/actions from two first\"\n", + "assert np.all(test_result_90[0] == [3, 1]) and np.all(\n", + " test_result_90[1] == [3, 3]\n", + "), \"For percentile 90 you should only select states/actions from one game\"\n", + "assert np.all(test_result_100[0] == [3, 1]) and np.all(\n", + " test_result_100[1] == [3, 3]\n", + "), \"Please make sure you use >=, not >. Also double-check how you compute percentile.\"\n", + "\n", + "print(\"Ok!\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wYLBHFFwG35N" + }, + "outputs": [], + "source": [ + "def get_new_policy(elite_states, elite_actions):\n", + " \"\"\"\n", + " Given a list of elite states/actions from select_elites,\n", + " return a new policy where each action probability is proportional to\n", + "\n", + " policy[s_i,a_i] ~ #[occurrences of s_i and a_i in elite states/actions]\n", + "\n", + " Don't forget to normalize the policy to get valid probabilities and handle the 0/0 case.\n", + " For states that you never visited, use a uniform distribution (1/n_actions for all states).\n", + "\n", + " :param elite_states: 1D list of states from elite sessions\n", + " :param elite_actions: 1D list of actions from elite sessions\n", + "\n", + " \"\"\"\n", + "\n", + " new_policy = np.zeros([n_states, n_actions])\n", + "\n", + " \n", + " # Don't forget to set 1/n_actions for all actions in unvisited states.\n", + "\n", + " return new_policy\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "I1VbNcpoG35O" + }, + "outputs": [], + "source": [ + "elite_states = [1, 2, 3, 4, 2, 0, 2, 3, 1]\n", + "elite_actions = [0, 2, 4, 3, 2, 0, 1, 3, 3]\n", + "\n", + "new_policy = get_new_policy(elite_states, elite_actions)\n", + "\n", + "assert np.isfinite(\n", + " new_policy\n", + ").all(), \"Your new policy contains NaNs or +-inf. Make sure you don't divide by zero.\"\n", + "assert np.all(\n", + " new_policy >= 0\n", + "), \"Your new policy can't have negative action probabilities\"\n", + "assert np.allclose(\n", + " new_policy.sum(axis=-1), 1\n", + "), \"Your new policy should be a valid probability distribution over actions\"\n", + "\n", + "reference_answer = np.array(\n", + " [\n", + " [1.0, 0.0, 0.0, 0.0, 0.0],\n", + " [0.5, 0.0, 0.0, 0.5, 0.0],\n", + " [0.0, 0.33333333, 0.66666667, 0.0, 0.0],\n", + " [0.0, 0.0, 0.0, 0.5, 0.5],\n", + " ]\n", + ")\n", + "assert np.allclose(new_policy[:4, :5], reference_answer)\n", + "\n", + "print(\"Ok!\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "WVvZq1fSG35O" + }, + "source": [ + "# Training loop\n", + "Generate sessions, select N best and fit to those." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "3CmH7Aj4G35O" + }, + "outputs": [], + "source": [ + "from IPython.display import clear_output\n", + "\n", + "\n", + "def show_progress(rewards_batch, log, percentile, reward_range=[-990, +10]):\n", + " \"\"\"\n", + " A convenience function that displays training progress.\n", + " No cool math here, just charts.\n", + " \"\"\"\n", + "\n", + " mean_reward = np.mean(rewards_batch)\n", + " threshold = np.percentile(rewards_batch, percentile)\n", + " log.append([mean_reward, threshold])\n", + "\n", + " plt.figure(figsize=[8, 4])\n", + " plt.subplot(1, 2, 1)\n", + " plt.plot(list(zip(*log))[0], label=\"Mean rewards\")\n", + " plt.plot(list(zip(*log))[1], label=\"Reward thresholds\")\n", + " plt.legend()\n", + " plt.grid()\n", + "\n", + " plt.subplot(1, 2, 2)\n", + " plt.hist(rewards_batch, range=reward_range)\n", + " plt.vlines(\n", + " [np.percentile(rewards_batch, percentile)],\n", + " [0],\n", + " [100],\n", + " label=\"percentile\",\n", + " color=\"red\",\n", + " )\n", + " plt.legend()\n", + " plt.grid()\n", + " clear_output(True)\n", + " print(\"mean reward = %.3f, threshold=%.3f\" % (mean_reward, threshold))\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tz0Yd964G35O" + }, + "outputs": [], + "source": [ + "# reset policy just in case\n", + "policy = initialize_policy(n_states, n_actions)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-cNq5hndG35O" + }, + "outputs": [], + "source": [ + "n_sessions = 250 # sample this many sessions\n", + "percentile = 50 # discard this percentage of sessions with lowest rewards\n", + "learning_rate = 0.5 # how quickly the policy is updated, on a scale from 0 to 1\n", + "\n", + "log = []\n", + "\n", + "for i in range(100):\n", + " %time sessions = [ ]\n", + "\n", + " states_batch, actions_batch, rewards_batch = zip(*sessions)\n", + "\n", + " elite_states, elite_actions = \n", + "\n", + " new_policy = \n", + "\n", + " policy = learning_rate * new_policy + (1 - learning_rate) * policy\n", + "\n", + " # display results on chart\n", + " show_progress(rewards_batch, log, percentile)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "K5LIoVTuG35O" + }, + "source": [ + "### Reflecting on results\n", + "\n", + "You may have noticed that the taxi problem quickly converges from less than -1000 to a near-optimal score and then descends back into -50/-100. This is in part because the environment has some innate randomness. Namely, the starting points of passenger/driver change from episode to episode.\n", + "\n", + "In case CEM failed to learn how to win from one distinct starting point, it will simply discard it because no sessions from that starting point will make it into the \"elites\".\n", + "\n", + "To mitigate that problem, you can either reduce the threshold for elite sessions (duct tape way) or change the way you evaluate strategy (theoretically correct way). For each starting state, you can sample an action randomly, and then evaluate this action by running _several_ games starting from it and averaging the total reward. Choosing elite sessions with this kind of sampling (where each session's reward is counted as the average of the rewards of all sessions with the same starting state and action) should improve the performance of your policy." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ubIHBgQ-G35O" + }, + "source": [ + "\n", + "### You're not done yet!\n", + "\n", + "Go to [`./deep_crossentropy_method.ipynb`](./deep_crossentropy_method.ipynb) for a more serious task" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys, os\n", - "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - " !touch .setup_complete\n", - "\n", - "# This code creates a virtual display to draw game images on.\n", - "# It will have no effect if your machine has a monitor.\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "import numpy as np\n", - "\n", - "env = gym.make(\"Taxi-v3\")\n", - "env.reset()\n", - "env.render()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n_states = env.observation_space.n\n", - "n_actions = env.action_space.n\n", - "\n", - "print(\"n_states=%i, n_actions=%i\" % (n_states, n_actions))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Create stochastic policy\n", - "\n", - "This time our policy should be a probability distribution.\n", - "\n", - "```policy[s,a] = P(take action a | in state s)```\n", - "\n", - "Since we still use integer state and action representations, you can use a 2-dimensional array to represent the policy.\n", - "\n", - "Please initialize the policy __uniformly__, that is, probabililities of all actions should be equal." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def initialize_policy(n_states, n_actions):\n", - " \n", - " \n", - " return policy\n", - "\n", - "policy = initialize_policy(n_states, n_actions)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert type(policy) in (np.ndarray, np.matrix)\n", - "assert np.allclose(policy, 1./n_actions)\n", - "assert np.allclose(np.sum(policy, axis=1), 1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Play the game\n", - "\n", - "Just like before, but we also record all states and actions we took." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def generate_session(env, policy, t_max=10**4):\n", - " \"\"\"\n", - " Play game until end or for t_max ticks.\n", - " :param policy: an array of shape [n_states,n_actions] with action probabilities\n", - " :returns: list of states, list of actions and sum of rewards\n", - " \"\"\"\n", - " states, actions = [], []\n", - " total_reward = 0.\n", - "\n", - " s = env.reset()\n", - "\n", - " for t in range(t_max):\n", - " # Hint: you can use np.random.choice for sampling action\n", - " # https://numpy.org/doc/stable/reference/random/generated/numpy.random.choice.html\n", - " a = \n", - "\n", - " new_s, r, done, info = env.step(a)\n", - "\n", - " # Record information we just got from the environment.\n", - " states.append(s)\n", - " actions.append(a)\n", - " total_reward += r\n", - "\n", - " s = new_s\n", - " if done:\n", - " break\n", - "\n", - " return states, actions, total_reward" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s, a, r = generate_session(env, policy)\n", - "assert type(s) == type(a) == list\n", - "assert len(s) == len(a)\n", - "assert type(r) in [float, np.float]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# let's see the initial reward distribution\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "\n", - "sample_rewards = [generate_session(env, policy, t_max=1000)[-1] for _ in range(200)]\n", - "\n", - "plt.hist(sample_rewards, bins=20)\n", - "plt.vlines([np.percentile(sample_rewards, 50)], [0], [100], label=\"50'th percentile\", color='green')\n", - "plt.vlines([np.percentile(sample_rewards, 90)], [0], [100], label=\"90'th percentile\", color='red')\n", - "plt.legend()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Crossentropy method steps" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def select_elites(states_batch, actions_batch, rewards_batch, percentile):\n", - " \"\"\"\n", - " Select states and actions from games that have rewards >= percentile\n", - " :param states_batch: list of lists of states, states_batch[session_i][t]\n", - " :param actions_batch: list of lists of actions, actions_batch[session_i][t]\n", - " :param rewards_batch: list of rewards, rewards_batch[session_i]\n", - "\n", - " :returns: elite_states,elite_actions, both 1D lists of states and respective actions from elite sessions\n", - "\n", - " Please return elite states and actions in their original order \n", - " [i.e. sorted by session number and timestep within session]\n", - "\n", - " If you are confused, see examples below. Please don't assume that states are integers\n", - " (they will become different later).\n", - " \"\"\"\n", - "\n", - " reward_threshold = \n", - "\n", - " elite_states = \n", - " elite_actions = \n", - "\n", - " return elite_states, elite_actions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "states_batch = [\n", - " [1, 2, 3], # game1\n", - " [4, 2, 0, 2], # game2\n", - " [3, 1], # game3\n", - "]\n", - "\n", - "actions_batch = [\n", - " [0, 2, 4], # game1\n", - " [3, 2, 0, 1], # game2\n", - " [3, 3], # game3\n", - "]\n", - "rewards_batch = [\n", - " 3, # game1\n", - " 4, # game2\n", - " 5, # game3\n", - "]\n", - "\n", - "test_result_0 = select_elites(states_batch, actions_batch, rewards_batch, percentile=0)\n", - "test_result_30 = select_elites(states_batch, actions_batch, rewards_batch, percentile=30)\n", - "test_result_90 = select_elites(states_batch, actions_batch, rewards_batch, percentile=90)\n", - "test_result_100 = select_elites(states_batch, actions_batch, rewards_batch, percentile=100)\n", - "\n", - "assert np.all(test_result_0[0] == [1, 2, 3, 4, 2, 0, 2, 3, 1]) \\\n", - " and np.all(test_result_0[1] == [0, 2, 4, 3, 2, 0, 1, 3, 3]), \\\n", - " \"For percentile 0 you should return all states and actions in chronological order\"\n", - "assert np.all(test_result_30[0] == [4, 2, 0, 2, 3, 1]) and \\\n", - " np.all(test_result_30[1] == [3, 2, 0, 1, 3, 3]), \\\n", - " \"For percentile 30 you should only select states/actions from two first\"\n", - "assert np.all(test_result_90[0] == [3, 1]) and \\\n", - " np.all(test_result_90[1] == [3, 3]), \\\n", - " \"For percentile 90 you should only select states/actions from one game\"\n", - "assert np.all(test_result_100[0] == [3, 1]) and\\\n", - " np.all(test_result_100[1] == [3, 3]), \\\n", - " \"Please make sure you use >=, not >. Also double-check how you compute percentile.\"\n", - "\n", - "print(\"Ok!\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def update_policy(elite_states, elite_actions):\n", - " \"\"\"\n", - " Given old policy and a list of elite states/actions from select_elites,\n", - " return new updated policy where each action probability is proportional to\n", - "\n", - " policy[s_i,a_i] ~ #[occurences of si and ai in elite states/actions]\n", - "\n", - " Don't forget to normalize policy to get valid probabilities and handle 0/0 case.\n", - " In case you never visited a state, set probabilities for all actions to 1./n_actions\n", - "\n", - " :param elite_states: 1D list of states from elite sessions\n", - " :param elite_actions: 1D list of actions from elite sessions\n", - "\n", - " \"\"\"\n", - "\n", - " new_policy = np.zeros([n_states, n_actions])\n", - "\n", - " \n", - " # Don't forget to set 1/n_actions for all actions in unvisited states.\n", - "\n", - " return new_policy" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "elite_states = [1, 2, 3, 4, 2, 0, 2, 3, 1]\n", - "elite_actions = [0, 2, 4, 3, 2, 0, 1, 3, 3]\n", - "\n", - "new_policy = update_policy(elite_states, elite_actions)\n", - "\n", - "assert np.isfinite(new_policy).all(), \\\n", - " \"Your new policy contains NaNs or +-inf. Make sure you don't divide by zero.\"\n", - "assert np.all(new_policy >= 0), \\\n", - " \"Your new policy can't have negative action probabilities\"\n", - "assert np.allclose(new_policy.sum(axis=-1), 1), \\\n", - " \"Your new policy should be a valid probability distribution over actions\"\n", - "\n", - "reference_answer = np.array([\n", - " [1., 0., 0., 0., 0.],\n", - " [0.5, 0., 0., 0.5, 0.],\n", - " [0., 0.33333333, 0.66666667, 0., 0.],\n", - " [0., 0., 0., 0.5, 0.5]])\n", - "assert np.allclose(new_policy[:4, :5], reference_answer)\n", - "\n", - "print(\"Ok!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Training loop\n", - "Generate sessions, select N best and fit to those." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import clear_output\n", - "\n", - "def show_progress(rewards_batch, log, percentile, reward_range=[-990, +10]):\n", - " \"\"\"\n", - " A convenience function that displays training progress. \n", - " No cool math here, just charts.\n", - " \"\"\"\n", - "\n", - " mean_reward = np.mean(rewards_batch)\n", - " threshold = np.percentile(rewards_batch, percentile)\n", - " log.append([mean_reward, threshold])\n", - " \n", - " plt.figure(figsize=[8, 4])\n", - " plt.subplot(1, 2, 1)\n", - " plt.plot(list(zip(*log))[0], label='Mean rewards')\n", - " plt.plot(list(zip(*log))[1], label='Reward thresholds')\n", - " plt.legend()\n", - " plt.grid()\n", - "\n", - " plt.subplot(1, 2, 2)\n", - " plt.hist(rewards_batch, range=reward_range)\n", - " plt.vlines([np.percentile(rewards_batch, percentile)],\n", - " [0], [100], label=\"percentile\", color='red')\n", - " plt.legend()\n", - " plt.grid()\n", - " clear_output(True)\n", - " print(\"mean reward = %.3f, threshold=%.3f\" % (mean_reward, threshold))\n", - " plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# reset policy just in case\n", - "policy = initialize_policy(n_states, n_actions)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n_sessions = 250 # sample this many sessions\n", - "percentile = 50 # take this percent of session with highest rewards\n", - "learning_rate = 0.5 # how quickly the policy is updated, on a scale from 0 to 1\n", - "\n", - "log = []\n", - "\n", - "for i in range(100):\n", - " %time sessions = [ ]\n", - "\n", - " states_batch, actions_batch, rewards_batch = zip(*sessions)\n", - "\n", - " elite_states, elite_actions = \n", - "\n", - " new_policy = \n", - "\n", - " policy = learning_rate * new_policy + (1 - learning_rate) * policy\n", - "\n", - " # display results on chart\n", - " show_progress(rewards_batch, log, percentile)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Reflecting on results\n", - "\n", - "You may have noticed that the taxi problem quickly converges from less than -1000 to a near-optimal score and then descends back into -50/-100. This is in part because the environment has some innate randomness. Namely, the starting points of passenger/driver change from episode to episode.\n", - "\n", - "In case CEM failed to learn how to win from one distinct starting point, it will simply discard it because no sessions from that starting point will make it into the \"elites\".\n", - "\n", - "To mitigate that problem, you can either reduce the threshold for elite sessions (duct tape way) or change the way you evaluate strategy (theoretically correct way). For each starting state, you can sample an action randomly, and then evaluate this action by running _several_ games starting from it and averaging the total reward. Choosing elite sessions with this kind of sampling (where each session's reward is counted as the average of the rewards of all sessions with the same starting state and action) should improve the performance of your policy." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### You're not done yet!\n", - "\n", - "Go to [`./deep_crossentropy_method.ipynb`](./deep_crossentropy_method.ipynb) for a more serious task" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/week01_intro/deep_crossentropy_method.ipynb b/week01_intro/deep_crossentropy_method.ipynb index 786d2b8f9..6cf7aa349 100644 --- a/week01_intro/deep_crossentropy_method.ipynb +++ b/week01_intro/deep_crossentropy_method.ipynb @@ -1,446 +1,524 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Deep Crossentropy method\n", - "\n", - "In this section we'll extend your CEM implementation with neural networks! You will train a multi-layer neural network to solve simple continuous state space games. __Please make sure you're done with tabular crossentropy method from the previous notebook.__\n", - "\n", - "![img](https://tip.duke.edu/independent_learning/greek/lesson/digging_deeper_final.jpg)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys, os\n", - "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - "\n", - " !touch .setup_complete\n", - "\n", - "# This code creates a virtual display to draw game images on.\n", - "# It will have no effect if your machine has a monitor.\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "\n", - "# if you see \" has no attribute .env\", remove .env or update gym\n", - "env = gym.make(\"CartPole-v0\").env\n", - "\n", - "env.reset()\n", - "n_actions = env.action_space.n\n", - "state_dim = env.observation_space.shape[0]\n", - "\n", - "plt.imshow(env.render(\"rgb_array\"))\n", - "print(\"state vector dim =\", state_dim)\n", - "print(\"n_actions =\", n_actions)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Neural Network Policy\n", - "\n", - "For this assignment we'll utilize the simplified neural network implementation from __[Scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPClassifier.html)__. Here's what you'll need:\n", - "\n", - "* `agent.partial_fit(states, actions)` - make a single training pass over the data. Maximize the probabilitity of :actions: from :states:\n", - "* `agent.predict_proba(states)` - predict probabilities of all actions, a matrix of shape __[len(states), n_actions]__\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.neural_network import MLPClassifier\n", - "\n", - "agent = MLPClassifier(\n", - " hidden_layer_sizes=(20, 20),\n", - " activation='tanh',\n", - ")\n", - "\n", - "# initialize agent to the dimension of state space and number of actions\n", - "agent.partial_fit([env.reset()] * n_actions, range(n_actions), range(n_actions))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def generate_session(env, agent, t_max=1000):\n", - " \"\"\"\n", - " Play a single game using agent neural network.\n", - " Terminate when game finishes or after :t_max: steps\n", - " \"\"\"\n", - " states, actions = [], []\n", - " total_reward = 0\n", - "\n", - " s = env.reset()\n", - "\n", - " for t in range(t_max):\n", - " \n", - " # use agent to predict a vector of action probabilities for state :s:\n", - " probs = \n", - "\n", - " assert probs.shape == (env.action_space.n,), \"make sure probabilities are a vector (hint: np.reshape)\"\n", - " \n", - " # use the probabilities you predicted to pick an action\n", - " # sample proportionally to the probabilities, don't just take the most likely action\n", - " a = \n", - " # ^-- hint: try np.random.choice\n", - "\n", - " new_s, r, done, info = env.step(a)\n", - "\n", - " # record sessions like you did before\n", - " states.append(s)\n", - " actions.append(a)\n", - " total_reward += r\n", - "\n", - " s = new_s\n", - " if done:\n", - " break\n", - " return states, actions, total_reward" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dummy_states, dummy_actions, dummy_reward = generate_session(env, agent, t_max=5)\n", - "print(\"states:\", np.stack(dummy_states))\n", - "print(\"actions:\", dummy_actions)\n", - "print(\"reward:\", dummy_reward)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### CEM steps\n", - "Deep CEM uses exactly the same strategy as the regular CEM, so you can copy your function code from previous notebook.\n", - "\n", - "The only difference is that now each observation is not a number but a `float32` vector." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def select_elites(states_batch, actions_batch, rewards_batch, percentile=50):\n", - " \"\"\"\n", - " Select states and actions from games that have rewards >= percentile\n", - " :param states_batch: list of lists of states, states_batch[session_i][t]\n", - " :param actions_batch: list of lists of actions, actions_batch[session_i][t]\n", - " :param rewards_batch: list of rewards, rewards_batch[session_i]\n", - "\n", - " :returns: elite_states,elite_actions, both 1D lists of states and respective actions from elite sessions\n", - "\n", - " Please return elite states and actions in their original order \n", - " [i.e. sorted by session number and timestep within session]\n", - "\n", - " If you are confused, see examples below. Please don't assume that states are integers\n", - " (they will become different later).\n", - " \"\"\"\n", - "\n", - " \n", - " \n", - " return elite_states, elite_actions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Training loop\n", - "Generate sessions, select N best and fit to those." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import clear_output\n", - "\n", - "def show_progress(rewards_batch, log, percentile, reward_range=[-990, +10]):\n", - " \"\"\"\n", - " A convenience function that displays training progress. \n", - " No cool math here, just charts.\n", - " \"\"\"\n", - "\n", - " mean_reward = np.mean(rewards_batch)\n", - " threshold = np.percentile(rewards_batch, percentile)\n", - " log.append([mean_reward, threshold])\n", - "\n", - " clear_output(True)\n", - " print(\"mean reward = %.3f, threshold=%.3f\" % (mean_reward, threshold))\n", - " plt.figure(figsize=[8, 4])\n", - " plt.subplot(1, 2, 1)\n", - " plt.plot(list(zip(*log))[0], label='Mean rewards')\n", - " plt.plot(list(zip(*log))[1], label='Reward thresholds')\n", - " plt.legend()\n", - " plt.grid()\n", - "\n", - " plt.subplot(1, 2, 2)\n", - " plt.hist(rewards_batch, range=reward_range)\n", - " plt.vlines([np.percentile(rewards_batch, percentile)],\n", - " [0], [100], label=\"percentile\", color='red')\n", - " plt.legend()\n", - " plt.grid()\n", - "\n", - " plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n_sessions = 100\n", - "percentile = 70\n", - "log = []\n", - "\n", - "for i in range(100):\n", - " # generate new sessions\n", - " sessions = [ ]\n", - "\n", - " states_batch, actions_batch, rewards_batch = map(np.array, zip(*sessions))\n", - "\n", - " elite_states, elite_actions = \n", - "\n", - " \n", - "\n", - " show_progress(rewards_batch, log, percentile, reward_range=[0, np.max(rewards_batch)])\n", - "\n", - " if np.mean(rewards_batch) > 190:\n", - " print(\"You Win! You may stop training now via KeyboardInterrupt.\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Record sessions\n", - "\n", - "import gym.wrappers\n", - "\n", - "with gym.wrappers.Monitor(gym.make(\"CartPole-v0\"), directory=\"videos\", force=True) as env_monitor:\n", - " sessions = [generate_session(env_monitor, agent) for _ in range(100)]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Show video. This may not work in some setups. If it doesn't\n", - "# work for you, you can download the videos and view them locally.\n", - "\n", - "from pathlib import Path\n", - "from IPython.display import HTML\n", - "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", - "\n", - "HTML(\"\"\"\n", - "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Homework part I\n", - "\n", - "### Tabular crossentropy method\n", - "\n", - "You may have noticed that the taxi problem quickly converges from -100 to a near-optimal score and then descends back into -50/-100. This is in part because the environment has some innate randomness. Namely, the starting points of passenger/driver change from episode to episode.\n", - "\n", - "### Tasks\n", - "- __1.1__ (1 pts) Find out how the algorithm performance changes if you use a different `percentile` and/or `n_sessions`.\n", - "- __1.2__ (2 pts) Tune the algorithm to end up with positive average score.\n", - "\n", - "It's okay to modify the existing code.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "``````" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Homework part II\n", - "\n", - "### Deep crossentropy method\n", - "\n", - "By this moment you should have got enough score on [CartPole-v0](https://gym.openai.com/envs/CartPole-v0) to consider it solved (see the link). It's time to try something harder.\n", - "\n", - "* if you have any trouble with CartPole-v0 and feel stuck, feel free to ask us or your peers for help.\n", - "\n", - "### Tasks\n", - "\n", - "* __2.1__ (3 pts) Pick one of environments: `MountainCar-v0` or `LunarLander-v2`.\n", - " * For MountainCar, get average reward of __at least -150__\n", - " * For LunarLander, get average reward of __at least +50__\n", - "\n", - "See the tips section below, it's kinda important.\n", - "__Note:__ If your agent is below the target score, you'll still get most of the points depending on the result, so don't be afraid to submit it.\n", - " \n", - " \n", - "* __2.2__ (up to 6 pt) Devise a way to speed up training against the default version\n", - " * Obvious improvement: use [`joblib`](https://joblib.readthedocs.io/en/latest/). However, note that you will probably need to spawn a new environment in each of the workers instead of passing it via pickling.\n", - " * Try re-using samples from 3-5 last iterations when computing threshold and training.\n", - " * Experiment with the number of training iterations and learning rate of the neural network (see params).\n", - " \n", - "__Please list what you did in Anytask submission form. You must measure your improvement experimentally. Your score depends on this improvement.__\n", - "\n", - "* __If the algorithm converges 2x faster, you obtain 3 pts.__\n", - "* __If the algorithm converges 4x faster, you obtain 6 pts.__\n", - " \n", - " \n", - "### Tips\n", - "* Gym page: [MountainCar](https://gym.openai.com/envs/MountainCar-v0), [LunarLander](https://gym.openai.com/envs/LunarLander-v2)\n", - "* Sessions for MountainCar may last for 10k+ ticks. Make sure ```t_max``` param is at least 10k.\n", - " * Also it may be a good idea to cut rewards via \">\" and not \">=\". If 90% of your sessions get reward of -10k and 10% are better, than if you use percentile 20% as threshold, R >= threshold __fails cut off bad sessions__ whule R > threshold works alright.\n", - "* _issue with gym_: Some versions of gym limit game time by 200 ticks. This will prevent cem training in most cases. Make sure your agent is able to play for the specified __t_max__, and if it isn't, try `env = gym.make(\"MountainCar-v0\").env` or otherwise get rid of TimeLimit wrapper.\n", - "* If you use old _swig_ lib for LunarLander-v2, you may get an error. See this [issue](https://github.com/openai/gym/issues/100) for solution.\n", - "* If it won't train it's a good idea to plot reward distribution and record sessions: they may give you some clue. If they don't, call course staff :)\n", - "* 20-neuron network is probably not enough, feel free to experiment.\n", - "\n", - "You may find the following snippet useful:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "I_i1q1TWG9zH" + }, + "source": [ + "# Deep Crossentropy method\n", + "\n", + "In this section we'll extend your CEM implementation with neural networks! You will train a multi-layer neural network to solve simple continuous state space games. __Please make sure you're done with tabular crossentropy method from the previous notebook.__\n", + "\n", + "![img](https://watanimg.elwatannews.com/old_news_images/large/249765_Large_20140709045740_11.jpg)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "t4CJ1sRyG9zJ" + }, + "outputs": [], + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display to draw game images on.\n", + "# It will have no effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "C2xd5vPwPVCb" + }, + "outputs": [], + "source": [ + "# Install gymnasium if you didn't\n", + "!pip install gymnasium[toy_text,classic_control]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_2zbc7ahG9zK" + }, + "outputs": [], + "source": [ + "import gymnasium as gym\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "# if you see \" has no attribute .env\", remove .env or update gym\n", + "env = gym.make(\"CartPole-v0\", render_mode=\"rgb_array\").env\n", + "\n", + "env.reset()\n", + "n_actions = env.action_space.n\n", + "state_dim = env.observation_space.shape[0]\n", + "\n", + "plt.imshow(env.render())\n", + "print(\"state vector dim =\", state_dim)\n", + "print(\"n_actions =\", n_actions)\n", + "\n", + "env.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Z72_alhdG9zK" + }, + "source": [ + "# Neural Network Policy\n", + "\n", + "For this assignment we'll utilize the simplified neural network implementation from __[Scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPClassifier.html)__. Here's what you'll need:\n", + "\n", + "* `agent.partial_fit(states, actions)` - make a single training pass over the data. Maximize the probability of :actions: from :states:\n", + "* `agent.predict_proba(states)` - predict probabilities of all actions, a matrix of shape __[len(states), n_actions]__\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wLItY4unG9zL" + }, + "outputs": [], + "source": [ + "from sklearn.neural_network import MLPClassifier\n", + "\n", + "agent = MLPClassifier(\n", + " hidden_layer_sizes=(20, 20),\n", + " activation=\"tanh\",\n", + ")\n", + "\n", + "# initialize agent to the dimension of state space and number of actions\n", + "agent.partial_fit([env.reset()[0]] * n_actions, range(n_actions), range(n_actions))\n" + ] + }, { - "data": { - "image/png": "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331W7W8/Ju5UfXz7e5+7j3LPdSIily9flt69e8s999wjwcHB8thjj8mPP/4oAOS9994zt3Pk+LD3PKIVu4hIcnKy1K5dW4oVKybx8fHywQcfaJ5bRez7LNytO50jtN7z3377TR599FEJCgqSUqVKSd++fWXBggUCQPbu3WtuZ+97K6JW9VerVk2MRqPTIwcUNYrIHW7GIaICxcbGokaNGpqD8XqLffv24f7778esWbMwaNAgvcMpNJKTk9G+fXvs3bsXNWvWdPj527dvR+PGjbFo0SLNCmzyHYsXL8bTTz+Nbdu2mUcucPb4KKr69euHJUuW4NKlS3e8JYlcj5ePiQqxo0eP4uTJkxg3bhyioqLuejJ60rZ582Z069bNri/8lJQUpKamIjExEcWKFcPevXvx5ptvonLlyjYLQsg7LVmyBH/++Sdq1qwJg8GAH3/8EdOnT8fDDz9sMZSVI8dHUTVp0iSUK1cO8fHxuHbtGr755ht88sknGD9+PBNCHTApJCrEJk+ebJ5e7IsvvrjjfUnkuOnTp9vdtkSJEtiwYQPeffddXL16FaVLl0abNm0wderUO441Sd4nNDQUS5cuxeuvv47r16+b/+B6/fXXLdo5cnwUVUajEdOnT8eZM2eQnZ2NypUr4+2338awYcP0Dq1I4uVjIiIiIgJnNCEiIiIiJoVERERExKSQiIiIiMBCE5cwmUw4e/YsQkNDnZqajYiIiKggIoKrV6+iXLlydzXIty1MCl3g7NmzqFChgt5hEBERURFy+vRplC9f3mXrY1LoAnlzfZ4CUELPUIiIiKjQywBQ8a7mGr8TJoUukHfJuASYFBIREZEnuPqWNRaaEBERERGTQiIiIiJiUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERPDBpHD27NmIi4tDUFAQEhMTsXXr1ju2/+6775CYmIigoCDEx8dj7ty5Vm2uXLmC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\n", - "text/plain": [ - "
" + "cell_type": "code", + "execution_count": 45, + "metadata": { + "id": "eyFS3oUmG9zL" + }, + "outputs": [], + "source": [ + "def generate_session(env, agent, t_max=1000):\n", + " \"\"\"\n", + " Play a single game using agent neural network.\n", + " Terminate when game finishes or after :t_max: steps\n", + " \"\"\"\n", + " states, actions = [], []\n", + " total_reward = 0\n", + "\n", + " s, _ = env.reset()\n", + "\n", + " for t in range(t_max):\n", + "\n", + " # use agent to predict a vector of action probabilities for state :s:\n", + " probs = \n", + "\n", + " assert probs.shape == (env.action_space.n,), \"make sure probabilities are a vector (hint: np.reshape)\"\n", + "\n", + " # use the probabilities you predicted to pick an action\n", + " # sample proportionally to the probabilities, don't just take the most likely action\n", + " a = \n", + " # ^-- hint: try np.random.choice\n", + "\n", + " new_s, r, terminated, truncated, _ = env.step(a)\n", + "\n", + " # record sessions like you did before\n", + " states.append(s)\n", + " actions.append(a)\n", + " total_reward += r\n", + "\n", + " s = new_s\n", + " if terminated or truncated:\n", + " break\n", + " return states, actions, total_reward\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4xgrTCgJG9zL" + }, + "outputs": [], + "source": [ + "dummy_states, dummy_actions, dummy_reward = generate_session(env, agent, t_max=5)\n", + "print(\"states:\", np.stack(dummy_states))\n", + "print(\"actions:\", dummy_actions)\n", + "print(\"reward:\", dummy_reward)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "p85lt16qG9zL" + }, + "source": [ + "### CEM steps\n", + "Deep CEM uses exactly the same strategy as the regular CEM, so you can copy your function code from previous notebook.\n", + "\n", + "The only difference is that now each observation is not a number but a `float32` vector." + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "id": "4On-p7p4G9zL" + }, + "outputs": [], + "source": [ + "def select_elites(states_batch, actions_batch, rewards_batch, percentile=50):\n", + " \"\"\"\n", + " Select states and actions from games that have rewards >= percentile\n", + " :param states_batch: list of lists of states, states_batch[session_i][t]\n", + " :param actions_batch: list of lists of actions, actions_batch[session_i][t]\n", + " :param rewards_batch: list of rewards, rewards_batch[session_i]\n", + "\n", + " :returns: elite_states,elite_actions, both 1D lists of states and respective actions from elite sessions\n", + "\n", + " Please return elite states and actions in their original order\n", + " [i.e. sorted by session number and timestep within session]\n", + "\n", + " If you are confused, see examples below. Please don't assume that states are integers\n", + " (they will become different later).\n", + " \"\"\"\n", + "\n", + " \n", + "\n", + " return elite_states, elite_actions\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xc40V4DaG9zM" + }, + "source": [ + "# Training loop\n", + "Generate sessions, select N best and fit to those." + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "id": "PPwVKwF7G9zM" + }, + "outputs": [], + "source": [ + "from IPython.display import clear_output\n", + "\n", + "\n", + "def show_progress(rewards_batch, log, percentile, reward_range=[-990, +10]):\n", + " \"\"\"\n", + " A convenience function that displays training progress.\n", + " No cool math here, just charts.\n", + " \"\"\"\n", + "\n", + " mean_reward = np.mean(rewards_batch)\n", + " threshold = np.percentile(rewards_batch, percentile)\n", + " log.append([mean_reward, threshold])\n", + "\n", + " clear_output(True)\n", + " print(\"mean reward = %.3f, threshold=%.3f\" % (mean_reward, threshold))\n", + " plt.figure(figsize=[8, 4])\n", + " plt.subplot(1, 2, 1)\n", + " plt.plot(list(zip(*log))[0], label=\"Mean rewards\")\n", + " plt.plot(list(zip(*log))[1], label=\"Reward thresholds\")\n", + " plt.legend()\n", + " plt.grid()\n", + "\n", + " plt.subplot(1, 2, 2)\n", + " plt.hist(rewards_batch, range=reward_range)\n", + " plt.vlines(\n", + " [np.percentile(rewards_batch, percentile)],\n", + " [0],\n", + " [100],\n", + " label=\"percentile\",\n", + " color=\"red\",\n", + " )\n", + " plt.legend()\n", + " plt.grid()\n", + "\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "euK7WRQiG9zM" + }, + "outputs": [], + "source": [ + "n_sessions = 100\n", + "percentile = 70\n", + "log = []\n", + "\n", + "for i in range(100):\n", + " # generate new sessions\n", + " sessions = [ ]\n", + "\n", + " states_batch, actions_batch, rewards_batch = map(np.array, zip(*sessions))\n", + "\n", + " elite_states, elite_actions = \n", + "\n", + " \n", + "\n", + " show_progress(\n", + " rewards_batch, log, percentile, reward_range=[0, np.max(rewards_batch)]\n", + " )\n", + "\n", + " if np.mean(rewards_batch) > 190:\n", + " print(\"You Win! You may stop training now via KeyboardInterrupt.\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yeNWKjtsG9zM" + }, + "source": [ + "# Results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RJwsWl4kG9zM" + }, + "outputs": [], + "source": [ + "# Record sessions\n", + "\n", + "from gymnasium.wrappers import RecordVideo\n", + "\n", + "with RecordVideo(\n", + " env=gym.make(\"CartPole-v0\", render_mode=\"rgb_array\"),\n", + " video_folder=\"./videos\",\n", + " episode_trigger=lambda episode_number: True,\n", + ") as env_monitor:\n", + " sessions = [generate_session(env_monitor, agent) for _ in range(100)]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kLPXdME7G9zN" + }, + "outputs": [], + "source": [ + "# Show video. This may not work in some setups. If it doesn't\n", + "# work for you, you can download the videos and view them locally.\n", + "\n", + "from pathlib import Path\n", + "from base64 import b64encode\n", + "from IPython.display import HTML\n", + "\n", + "video_paths = sorted([s for s in Path(\"videos\").iterdir() if s.suffix == \".mp4\"])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if \"google.colab\" in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open(\"rb\") as fp:\n", + " mp4 = fp.read()\n", + " data_url = \"data:video/mp4;base64,\" + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", + "\n", + "HTML(\n", + " \"\"\"\n", + "\n", + "\"\"\".format(\n", + " data_url\n", + " )\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6d_3oOQ1G9zN" + }, + "source": [ + "# Homework part I\n", + "\n", + "### Tabular crossentropy method\n", + "\n", + "You may have noticed that the taxi problem quickly converges from -100 to a near-optimal score and then descends back into -50/-100. This is in part because the environment has some innate randomness. Namely, the starting points of passenger/driver change from episode to episode.\n", + "\n", + "### Tasks\n", + "- __1.1__ (2 pts) Find out how the algorithm performance changes if you use a different `percentile` and/or `n_sessions`. Provide here some figures so we can see how the hyperparameters influence the performance.\n", + "- __1.2__ (1 pts) Tune the algorithm to end up with positive average score.\n", + "\n", + "It's okay to modify the existing code.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L88LySiVG9zN" + }, + "source": [ + "``````" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7LpAJc4rG9zN" + }, + "source": [ + "# Homework part II\n", + "\n", + "### Deep crossentropy method\n", + "\n", + "By this moment, you should have got enough score on [CartPole-v0](https://gymnasium.farama.org/environments/classic_control/cart_pole/) to consider it solved (see the link). It's time to try something harder.\n", + "\n", + "* if you have any trouble with CartPole-v0 and feel stuck, feel free to ask us or your peers for help.\n", + "\n", + "### Tasks\n", + "\n", + "* __2.1__ (3 pts) Pick one of environments: `MountainCar-v0` or `LunarLander-v2`.\n", + " * For MountainCar, get average reward of __at least -150__\n", + " * For LunarLander, get average reward of __at least +50__\n", + "\n", + "See the tips section below, it's kinda important.\n", + "__Note:__ If your agent is below the target score, you'll still get some of the points depending on the result, so don't be afraid to submit it.\n", + " \n", + " \n", + "* __2.2__ (up to 6 pts) Devise a way to speed up training against the default version\n", + " * Obvious improvement: use [`joblib`](https://joblib.readthedocs.io/en/latest/). However, note that you will probably need to spawn a new environment in each of the workers instead of passing it via pickling. (2 pts)\n", + " * Try re-using samples from 3-5 last iterations when computing threshold and training. (2 pts)\n", + " * Obtain __-100__ at `MountainCar-v0` or __+200__ at `LunarLander-v2` (2 pts). Feel free to experiment with hyperparameters, architectures, schedules etc.\n", + " \n", + "__Please list what you did in Anytask submission form__. This reduces probability that somebody misses something.\n", + " \n", + " \n", + "### Tips\n", + "* Gymnasium pages: [MountainCar](https://gymnasium.farama.org/environments/classic_control/mountain_car/), [LunarLander](https://gymnasium.farama.org/environments/box2d/lunar_lander/)\n", + "* Sessions for MountainCar may last for 10k+ ticks. Make sure ```t_max``` param is at least 10k.\n", + " * Also it may be a good idea to cut rewards via \">\" and not \">=\". If 90% of your sessions get reward of -10k and 10% are better, than if you use percentile 20% as threshold, R >= threshold __fails to cut off bad sessions__ while R > threshold works alright.\n", + "* _issue with gym_: Some versions of gym limit game time by 200 ticks. This will prevent cem training in most cases. Make sure your agent is able to play for the specified __t_max__, and if it isn't, try `env = gym.make(\"MountainCar-v0\").env` or otherwise get rid of TimeLimit wrapper.\n", + "* If you use old _swig_ lib for LunarLander-v2, you may get an error. See this [issue](https://github.com/openai/gym/issues/100) for solution.\n", + "* If it doesn't train, it's a good idea to plot reward distribution and record sessions: they may give you some clue. If they don't, call course staff :)\n", + "* 20-neuron network is probably not enough, feel free to experiment.\n", + "\n", + "You may find the following snippet useful:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qcjz-nm_G9zN" + }, + "outputs": [], + "source": [ + "def visualize_mountain_car(env, agent):\n", + " # Compute policy for all possible x and v (with discretization)\n", + " xs = np.linspace(env.min_position, env.max_position, 100)\n", + " vs = np.linspace(-env.max_speed, env.max_speed, 100)\n", + "\n", + " grid = np.dstack(np.meshgrid(xs, vs[::-1])).transpose(1, 0, 2)\n", + " grid_flat = grid.reshape(len(xs) * len(vs), 2)\n", + " probs = (\n", + " agent.predict_proba(grid_flat).reshape(len(xs), len(vs), 3).transpose(1, 0, 2)\n", + " )\n", + "\n", + " # # The above code is equivalent to the following:\n", + " # probs = np.empty((len(vs), len(xs), 3))\n", + " # for i, v in enumerate(vs[::-1]):\n", + " # for j, x in enumerate(xs):\n", + " # probs[i, j, :] = agent.predict_proba([[x, v]])[0]\n", + "\n", + " # Draw policy\n", + " f, ax = plt.subplots(figsize=(7, 7))\n", + " ax.imshow(\n", + " probs,\n", + " extent=(env.min_position, env.max_position, -env.max_speed, env.max_speed),\n", + " aspect=\"auto\",\n", + " )\n", + " ax.set_title(\"Learned policy: red=left, green=nothing, blue=right\")\n", + " ax.set_xlabel(\"position (x)\")\n", + " ax.set_ylabel(\"velocity (v)\")\n", + "\n", + " # Sample a trajectory and draw it\n", + " states, actions, _ = generate_session(env, agent)\n", + " states = np.array(states)\n", + " ax.plot(states[:, 0], states[:, 1], color=\"white\")\n", + "\n", + " # Draw every 3rd action from the trajectory\n", + " for (x, v), a in zip(states[::3], actions[::3]):\n", + " if a == 0:\n", + " plt.arrow(x, v, -0.1, 0, color=\"white\", head_length=0.02)\n", + " elif a == 2:\n", + " plt.arrow(x, v, 0.1, 0, color=\"white\", head_length=0.02)\n", + "\n", + "\n", + "with gym.make(\"MountainCar-v0\", render_mode=\"rgb_arrary\").env as env:\n", + " visualize_mountain_car(env, agent)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Dzk41lDPG9zO" + }, + "source": [ + "### Bonus tasks\n", + "\n", + "* __2.3 bonus__ (2 pts) Try to find a network architecture and training params that solve __both__ environments above (_Points depend on implementation. If you attempted this task, please mention it in Anytask submission._)\n", + "\n", + "* __2.4 bonus__ (4 pts) Solve continuous action space task with `MLPRegressor` or similar.\n", + " * Since your agent only predicts the \"expected\" action, you will have to add noise to ensure exploration.\n", + " * Choose one of [MountainCarContinuous-v0](https://gymnasium.farama.org/environments/classic_control/mountain_car_continuous/) (90+ pts to solve), [LunarLanderContinuous-v2](https://gymnasium.farama.org/environments/box2d/lunar_lander/) (`env = gym.make(\"LunarLander-v2\", continuous=True)`)(200+ pts to solve)\n", + " * 4 points for solving. Slightly less for getting some results below solution threshold. Note that discrete and continuous environments may have slightly different rules, aside from action spaces." ] - }, - "metadata": {}, - "output_type": "display_data" } - ], - "source": [ - "def visualize_mountain_car(env, agent):\n", - " # Compute policy for all possible x and v (with discretization)\n", - " xs = np.linspace(env.min_position, env.max_position, 100)\n", - " vs = np.linspace(-env.max_speed, env.max_speed, 100)\n", - " \n", - " grid = np.dstack(np.meshgrid(xs, vs[::-1])).transpose(1, 0, 2)\n", - " grid_flat = grid.reshape(len(xs) * len(vs), 2)\n", - " probs = agent.predict_proba(grid_flat).reshape(len(xs), len(vs), 3).transpose(1, 0, 2)\n", - "\n", - " # # The above code is equivalent to the following:\n", - " # probs = np.empty((len(vs), len(xs), 3))\n", - " # for i, v in enumerate(vs[::-1]):\n", - " # for j, x in enumerate(xs):\n", - " # probs[i, j, :] = agent.predict_proba([[x, v]])[0]\n", - "\n", - " # Draw policy\n", - " f, ax = plt.subplots(figsize=(7, 7))\n", - " ax.imshow(probs, extent=(env.min_position, env.max_position, -env.max_speed, env.max_speed), aspect='auto')\n", - " ax.set_title('Learned policy: red=left, green=nothing, blue=right')\n", - " ax.set_xlabel('position (x)')\n", - " ax.set_ylabel('velocity (v)')\n", - " \n", - " # Sample a trajectory and draw it\n", - " states, actions, _ = generate_session(env, agent)\n", - " states = np.array(states)\n", - " ax.plot(states[:, 0], states[:, 1], color='white')\n", - " \n", - " # Draw every 3rd action from the trajectory\n", - " for (x, v), a in zip(states[::3], actions[::3]):\n", - " if a == 0:\n", - " plt.arrow(x, v, -0.1, 0, color='white', head_length=0.02)\n", - " elif a == 2:\n", - " plt.arrow(x, v, 0.1, 0, color='white', head_length=0.02)\n", - "\n", - "with gym.make('MountainCar-v0').env as env:\n", - " visualize_mountain_car(env, agent_mountain_car)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Bonus tasks\n", - "\n", - "* __2.3 bonus__ (2 pts) Try to find a network architecture and training params that solve __both__ environments above (_Points depend on implementation. If you attempted this task, please mention it in Anytask submission._)\n", - "\n", - "* __2.4 bonus__ (4 pts) Solve continuous action space task with `MLPRegressor` or similar.\n", - " * Since your agent only predicts the \"expected\" action, you will have to add noise to ensure exploration.\n", - " * Choose one of [MountainCarContinuous-v0](https://gym.openai.com/envs/MountainCarContinuous-v0) (90+ pts to solve), [LunarLanderContinuous-v2](https://gym.openai.com/envs/LunarLanderContinuous-v2) (200+ pts to solve) \n", - " * 4 points for solving. Slightly less for getting some results below solution threshold. Note that discrete and continuous environments may have slightly different rules aside from action spaces.\n", - "\n", - "\n", - "If you're still feeling unchallenged, consider the project (see other notebook in this folder)." - ] + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/week01_intro/primer_python_for_ml/recap_ml.ipynb b/week01_intro/primer_python_for_ml/recap_ml.ipynb index b40d81f62..c94760b29 100644 --- a/week01_intro/primer_python_for_ml/recap_ml.ipynb +++ b/week01_intro/primer_python_for_ml/recap_ml.ipynb @@ -121,7 +121,7 @@ "\n", "import sys\n", "if 'google.colab' in sys.modules:\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week01_intro/primer_python_for_ml/train.csv" + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week01_intro/primer_python_for_ml/train.csv" ] }, { diff --git a/week01_intro/project_starter_evolution_strategies.ipynb b/week01_intro/project_starter_evolution_strategies.ipynb index 68f869cdf..d21475cbf 100644 --- a/week01_intro/project_starter_evolution_strategies.ipynb +++ b/week01_intro/project_starter_evolution_strategies.ipynb @@ -8,7 +8,7 @@ "\n", "![img](https://t4.ftcdn.net/jpg/00/17/46/81/240_F_17468143_wY3hsHyfNYoMdG9BlC56HI4JA7pNu63h.jpg)\n", "\n", - "Remember the idea behind Evolution Strategies? Here's a neat [blog post](https://blog.openai.com/evolution-strategies/) about 'em.\n", + "Remember the idea behind Evolution Strategies? Here's a neat [blog post](https://openai.com/research/evolution-strategies) about 'em.\n", "\n", "Can you reproduce their success? You will have to implement evolutionary strategies and see how they work.\n", "\n", diff --git a/week01_intro/seminar-es-task.ipynb b/week01_intro/seminar-es-task.ipynb new file mode 100644 index 000000000..38d4e3946 --- /dev/null +++ b/week01_intro/seminar-es-task.ipynb @@ -0,0 +1,656 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evolution Strategies\n", + "\n", + "![img](https://t4.ftcdn.net/jpg/00/17/46/81/240_F_17468143_wY3hsHyfNYoMdG9BlC56HI4JA7pNu63h.jpg)\n", + "\n", + "[The paper about the algorithm](https://arxiv.org/abs/1703.03864)\n", + "\n", + "Plan:\n", + "* Study how to use OpenAI gym\n", + "* Basic prototype of evolutionary strategies that works in one thread on CartPole\n", + "* Modify the code to make them work in parallel\n", + "* Use the algorithm to solve the LunarLander\n", + "* Analyse the influence of hyperparameters" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display to draw game images on.\n", + "# It will have no effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import torch\n", + "import torch.nn as nn\n", + "import time\n", + "from copy import deepcopy\n", + "from joblib import Parallel, delayed\n", + "from IPython.display import clear_output\n", + "from IPython import display\n", + " \n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# OpenAI gym environment" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Observation space: Box([-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38], [4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38], (4,), float32)\n", + "Action space: Discrete(2)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import gym\n", + "\n", + "tmp_env = gym.make(\"CartPole-v0\")\n", + "tmp_env.reset()\n", + "\n", + "plt.imshow(tmp_env.render('rgb_array'))\n", + "print(\"Observation space:\", tmp_env.observation_space)\n", + "print(\"Action space:\", tmp_env.action_space)\n", + "state_size = tmp_env.observation_space.shape[0]\n", + "n_actions = tmp_env.action_space.n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### How to interact with the environment" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Initial observation: [-0.0441675 0.0355158 -0.03658269 -0.02903847]\n", + "At each step it returns:\n", + "new observation code: [-0.04345718 -0.15906295 -0.03716346 0.25188148]\n", + "reward: 1.0\n", + "is game over?: False\n" + ] + } + ], + "source": [ + "print(\"Initial observation:\", tmp_env.reset())\n", + "\n", + "new_s, reward, done, _ = tmp_env.step(0)\n", + "print(\"At each step it returns:\")\n", + "\n", + "print(\"new observation code:\", new_s)\n", + "print(\"reward:\", reward)\n", + "print(\"is game over?:\", done)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Display an episode" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def display_session(env, agent, t_max=500):\n", + " total_reward = 0\n", + " plt.figure(figsize=(4, 3))\n", + " display.clear_output(wait=True)\n", + "\n", + " s = env.reset()\n", + " \n", + " for t in range(t_max):\n", + " plt.gca().clear()\n", + " \n", + " a = agent.get_action(torch.tensor(s).float())\n", + " new_s, r, done, info = env.step(a)\n", + " s = new_s\n", + " total_reward += r\n", + " # Draw game image on display.\n", + " plt.imshow(env.render('rgb_array'))\n", + "\n", + " display.display(plt.gcf())\n", + " display.clear_output(wait=True)\n", + " \n", + " if done:\n", + " break\n", + " \n", + " return total_reward" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Random policy" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "class RandomPolicy:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total reward: 16.0\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "total_reward = display_session(tmp_env, RandomPolicy(n_actions))\n", + "print('Total reward: ', total_reward)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The challenge of the day" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Algorithm](https://i.ibb.co/zFm6BrB/Screenshot-from-2021-09-17-13-38-00.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Model evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def generate_session(env, agent, t_max=500):\n", + " total_reward = 0\n", + " s = env.reset()\n", + " \n", + " for t in range(t_max):\n", + " a = agent.get_action(torch.tensor(s).float())\n", + " new_s, r, done, info = env.step(a)\n", + " total_reward += r\n", + " s = new_s\n", + " \n", + " if done:\n", + " break\n", + " \n", + " return total_reward\n", + "\n", + "\n", + "def score(env, agent, n=10, t_max=500):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Modification of the model using a noise " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def add_noise_to_model(model, noise, copy=False):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Controller of the evolution\n", + "\n", + "#### Task 1: Implement the algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "class EvolutionManager:\n", + " def __init__(self, get_env_function, lr=0.001, std=0.01, n_samples = 64, normalize=True):\n", + " super().__init__()\n", + " \n", + " self.lr = lr\n", + " self.std = std\n", + " self.normalize = normalize\n", + " self.n_samples = n_samples\n", + " self.mean_reward_history = []\n", + " \n", + " self.env = get_env_function()\n", + " \n", + " def get_noised_model(self, model):\n", + " pass\n", + "\n", + " def optimize(self, model, noises, rewards):\n", + " pass\n", + " \n", + " def step(self, model):\n", + " pass\n", + " \n", + " def update_log(self, rewards):\n", + " mean_reward = np.mean(rewards)\n", + " self.mean_reward_history.append(mean_reward)\n", + "\n", + " clear_output(True)\n", + " print(\"last mean reward = %.3f\" % mean_reward)\n", + " plt.figure(figsize=[8, 4])\n", + " plt.subplot(1, 2, 1)\n", + " plt.plot(self.mean_reward_history, label='Mean rewards')\n", + " plt.legend()\n", + " plt.grid()\n", + "\n", + " plt.subplot(1, 2, 2)\n", + " plt.hist(rewards)\n", + " plt.grid()\n", + "\n", + " plt.show()\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Task 2: Implement a neural network-based policy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Neural policy" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "class MLPPolicy(nn.Module):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Environment 1: CartPole-v0" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "def get_env_function():\n", + " env = gym.make('CartPole-v0').env\n", + " return env\n", + "tmp_env = get_env_function()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "n_states = tmp_env.observation_space.shape[0]\n", + "n_actions = tmp_env.action_space.n\n", + "model = <>" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "last mean reward = 493.230\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.485602855682373\n" + ] + } + ], + "source": [ + "algorithm = <>\n", + "\n", + "for i in range(15):\n", + " t = time.time()\n", + " algorithm.step(model)\n", + " print(time.time() - t)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "500.0" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "display_session(tmp_env, model, t_max=500)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Task 3: Implement and compare the parallelized version of the algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "model = <>" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "last mean reward = 353.210\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAecAAAD4CAYAAADW+i6uAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deXRV5b3/8fc3EBKmMBMCAQLKDDIkIiogVUAUFLVO1AGXWtpaqy71Kg5V9JZe61XbXq/tr2itVL0oKhYUteKQgjgyQ5iHAIFAGIQkQCDD8/sjJ2mQBBJyztn75Hxea2XlnJ0zfHKSJ9/sfZ7nu805h4iIiPhHjNcBRERE5HgqziIiIj6j4iwiIuIzKs4iIiI+o+IsIiLiM/W9DgDQunVrl5KScsrbHTp0iMaNG4c+UDX5LQ8oU3VFaqbFixfvdc61CVOk01JxPPvxdQblqinlqrlaj2fnnOcfqamprjo+//zzat0uXPyWxzllqq5IzQQscj4Ysyf7qDie/fg6O6dcNaVcNVfb8azD2iIiIj6j4iwiIuIzKs4iIiI+44sJYZUpLCwkKyuLgoKC8m3NmjVjzZo1HqY6nt/yQPgzxcfHk5ycTGxsbNieU0SkrvNtcc7KyqJp06akpKRgZgDk5eXRtGlTj5P9m9/yQHgzOefYt28fWVlZdOnSJSzPKSISDXx7WLugoIBWrVqVF2bxHzOjVatWxx3dEBGR2vNtcQZUmCOAfkYiIsHn6+IsEgprd+WyLKfI6xgiIlVScT4JM+Omm24qv15UVESbNm0YN26ch6lCLyUlhb1793odIyRy8gq48aVv+MOSo3ycscvrOCIilfLthDA/aNy4MatWreLIkSM0bNiQefPm0aFDh7BmKCoqon790P2YQv34flJS4rhv5nLyCopIbmLc8+YyZt1xHj3bJXgdTUR8IGXy3KA91itjatdWVHvOp3DJJZcwd27pD2zGjBlMmDCh/GuHDh3i1ltv5eyzz2bgwIHMnj0bgMzMTIYNG8agQYMYNGgQX375JQDp6emMGDGCq6++mp49e3LDDTdQ2sHteCNGjODhhx/mggsu4I9//COLFy/mggsuIDU1lYsvvpjs7GxycnJITU0FYPny5ZgZ27ZtA+CMM87g8OHDvPfee5xzzjkMHDiQkSNHsnv3bgCmTJnCpEmTGD16NDfffDP79u1j9OjRDBw4kJ/97GflmQ4dOsTYsWPp378/ffv25c033wzRqxwe0xZsZsGGvTx+WR/uS4unSVx9bp++iP2HjnkdTUTkOBGxy/TEexms3plLcXEx9erVC8pj9m6fwOOX9Tnl7a6//nqefPJJxo0bx4oVK7j11ltZsGABAM888wwXXnghL7/8MgcOHGDw4MGMHDmStm3bMm/ePOLj49mwYQMTJkxg0aJFACxdupSMjAzat2/P+eefz8KFCxk6dOgJz3vgwAH+9a9/UVhYyAUXXMDs2bNp06YNb775Jo888ggvv/wyBQUF5ObmsmDBAtLS0liwYAEDBgygbdu2NGrUiKFDh/L1119jZrz00ks8/fTTPPvsswAsXryYL774goYNG3LXXXcxdOhQHnvsMebOncu0adMA+Oijj2jfvn35PycHDx4MymvvhWXbD/DMP9dxSd92TBjckX/9azN/uWkg1037ml+8tpjXbj+H2Hr6X1VE/CEiirOXzjrrLDIzM5kxYwaXXnrpcV/77LPP+Oijj3jmmWeA0uVf27Zto3379tx5550sW7aMevXqsX79+vL7DB48mOTkZAAGDBhAZmZmpcX5uuuuA2DdunWsWrWKUaNGAVBcXExSUhIA5513HgsXLmT+/Pk8/PDDfPTRRxw+fJhhw4YBpWvFr7vuOrKzszl27Nhxa5Evv/xyGjZsCMD8+fOZNWsWAGPHjqVFixYA9OvXj/vvv58HH3yQcePGlT9upMkrKOSuGUtJTIjnqavOKp9hPrBTC566qh/3zlzOlDkZTL2yn8dJRURKRURxLtvD9arpx+WXX879999Peno6+/btK9/unOOdd96hR48ex91+ypQpJCYmsnz5ckpKSoiPjy//WlxcXPnlevXqUVRU+azhslONOefo06cPX3311Qm3GTZsGAsWLGDr1q2MHz+e3/3udxQVFXHllVcC8Ktf/Yp7772Xyy+/nPT0dKZMmXLC45epbElU9+7dWbx4MR988AEPPfQQo0eP5rHHHqvqZfIl5xyPvLuKHQeOMPNnQ2jW6PhOZlcNSmbdrjz+Mn8zPZMSuGlIZ4+Sioj8m47jVcOtt97KY489Rr9+x+9ZXXTRRTz//PPl79EuXboUKD38m5SURExMDK+++irFxcWn/dw9evRgz5495cW5sLCQjIwMAIYPH85rr71G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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "26.267060041427612\n" + ] + } + ], + "source": [ + "algorithm = <>\n", + "\n", + "for i in range(15):\n", + " t = time.time()\n", + " algorithm.step(model)\n", + " print(time.time() - t)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Environment 2: LunarLanderContinuous-v2" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "last mean reward = 155.350\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "def get_env_function():\n", + " env = gym.make('LunarLanderContinuous-v2').env\n", + " return env\n", + "tmp_env = get_env_function()\n", + "n_states = tmp_env.observation_space.shape[0]\n", + "n_actions = tmp_env.action_space.shape[0]\n", + "model = <>\n", + "algorithm = <>\n", + "for i in range(1000):\n", + " algorithm.step(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "297.1928817226966" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "display_session(tmp_env, model, t_max=500)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Task 3: Hyperparameter's analysis" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we are going to do some experimental analysis of the algorithm.\n", + "\n", + "Plan:\n", + "- to learn something about the *std* parameter\n", + "- to learn something about the *learning rate* parameter\n", + "- to learn something about the *n_samples* parameter" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/week01_intro/seminar_gym_interface.ipynb b/week01_intro/seminar_gymnasium_interface.ipynb similarity index 68% rename from week01_intro/seminar_gym_interface.ipynb rename to week01_intro/seminar_gymnasium_interface.ipynb index 02021a65d..f47c6fe07 100644 --- a/week01_intro/seminar_gym_interface.ipynb +++ b/week01_intro/seminar_gymnasium_interface.ipynb @@ -8,7 +8,7 @@ "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", "\n", " !touch .setup_complete\n", "\n", @@ -34,11 +34,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### OpenAI Gym\n", + "### OpenAI Gym --> Farama Gymnasium\n", "\n", "We're gonna spend several next weeks learning algorithms that solve decision processes. We are then in need of some interesting decision problems to test our algorithms.\n", "\n", - "That's where OpenAI Gym comes into play. It's a Python library that wraps many classical decision problems including robot control, videogames and board games.\n", + "That's where Gymnasium comes into play. It's a Python library that wraps many classical decision problems including robot control, videogames and board games.\n", + "\n", + "The library Gym by OpenAi has been replaced by Gymnsasium while saving all functionality comparable with the latest version of Gym.\n", + "\n", + "Announce: https://farama.org/Announcing-The-Farama-Foundation\n", + "\n", + "Github: https://github.com/Farama-Foundation/Gymnasium\n", + "\n", + "Documentation: https://gymnasium.farama.org/\n", "\n", "So here's how it works:" ] @@ -49,14 +57,14 @@ "metadata": {}, "outputs": [], "source": [ - "import gym\n", + "import gymnasium as gym\n", "\n", - "env = gym.make(\"MountainCar-v0\")\n", + "env = gym.make(\"MountainCar-v0\", render_mode=\"rgb_array\")\n", "env.reset()\n", "\n", - "plt.imshow(env.render('rgb_array'))\n", + "plt.imshow(env.render())\n", "print(\"Observation space:\", env.observation_space)\n", - "print(\"Action space:\", env.action_space)" + "print(\"Action space:\", env.action_space)\n" ] }, { @@ -70,16 +78,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Gym interface\n", + "### Gymnasium interface\n", "\n", "The three main methods of an environment are\n", - "* `reset()`: reset environment to the initial state, _return first observation_\n", + "* `reset()`: reset environment to the initial state, return first observation and dict with auxiliary info\n", "* `render()`: show current environment state (a more colorful version :) )\n", - "* `step(a)`: commit action `a` and return `(new_observation, reward, is_done, info)`\n", + "* `step(a)`: commit action `a` and return `(new_observation, reward, terminated, truncated, info)`\n", " * `new_observation`: an observation right after committing the action `a`\n", " * `reward`: a number representing your reward for committing action `a`\n", - " * `is_done`: True if the MDP has just finished, False if still in progress\n", - " * `info`: some auxiliary stuff about what just happened. For now, ignore it." + " * `terminated`: True if the MDP has just finished, False if still in progress\n", + " * `truncated`: True if the number of steps elapsed >= max episode steps\n", + " * `info`: some auxiliary stuff about what just happened. For now, ignore it.\n", + "\n", + "A detailed explanation of the difference between `terminated` and `truncated` and how it should be used:\n", + "1. https://gymnasium.farama.org/tutorials/gymnasium_basics/handling_time_limits/\n", + "2. https://gymnasium.farama.org/content/migration-guide/" ] }, { @@ -88,10 +101,14 @@ "metadata": {}, "outputs": [], "source": [ - "obs0 = env.reset()\n", + "# Set seed to reproduce initial state in stochastic environment\n", + "obs0, info = env.reset(seed=0)\n", "print(\"initial observation code:\", obs0)\n", "\n", - "# Note: in MountainCar, observation is just two numbers: car position and velocity" + "obs0, info = env.reset(seed=1)\n", + "print(\"initial observation code:\", obs0)\n", + "\n", + "# Note: in MountainCar, observation is just two numbers: car position and velocity\n" ] }, { @@ -101,13 +118,14 @@ "outputs": [], "source": [ "print(\"taking action 2 (right)\")\n", - "new_obs, reward, is_done, _ = env.step(2)\n", + "new_obs, reward, terminated, truncated, _ = env.step(2)\n", "\n", "print(\"new observation code:\", new_obs)\n", "print(\"reward:\", reward)\n", - "print(\"is game over?:\", is_done)\n", + "print(\"is game over?:\", terminated)\n", + "print(\"is game truncated due to time limit?:\", truncated)\n", "\n", - "# Note: as you can see, the car has moved to the right slightly (around 0.0005)" + "# Note: as you can see, the car has moved to the right slightly (around 0.0005)\n" ] }, { @@ -134,10 +152,10 @@ "# Create env manually to set time limit. Please don't change this.\n", "TIME_LIMIT = 250\n", "env = gym.wrappers.TimeLimit(\n", - " gym.envs.classic_control.MountainCarEnv(),\n", + " gym.make(\"MountainCar-v0\", render_mode=\"rgb_array\"),\n", " max_episode_steps=TIME_LIMIT + 1,\n", ")\n", - "actions = {'left': 0, 'stop': 1, 'right': 2}" + "actions = {\"left\": 0, \"stop\": 1, \"right\": 2}\n" ] }, { @@ -151,12 +169,12 @@ " # (a tuple of position and velocity), the current time step, or both,\n", " # if you want.\n", " position, velocity = obs\n", - " \n", + "\n", " # This is an example policy. You can try running it, but it will not work.\n", " # Your goal is to fix that. You don't need anything sophisticated here,\n", " # and you can hard-code any policy that seems to work.\n", " # Hint: think how you would make a swing go farther and faster.\n", - " return actions['right']" + " return actions[\"right\"]\n" ] }, { @@ -168,29 +186,31 @@ "plt.figure(figsize=(4, 3))\n", "display.clear_output(wait=True)\n", "\n", - "obs = env.reset()\n", + "obs, _ = env.reset()\n", "for t in range(TIME_LIMIT):\n", " plt.gca().clear()\n", - " \n", + "\n", " action = policy(obs, t) # Call your policy\n", - " obs, reward, done, _ = env.step(action) # Pass the action chosen by the policy to the environment\n", - " \n", + " obs, reward, terminated, truncated, _ = env.step(\n", + " action\n", + " ) # Pass the action chosen by the policy to the environment\n", + "\n", " # We don't do anything with reward here because MountainCar is a very simple environment,\n", " # and reward is a constant -1. Therefore, your goal is to end the episode as quickly as possible.\n", "\n", " # Draw game image on display.\n", - " plt.imshow(env.render('rgb_array'))\n", - " \n", + " plt.imshow(env.render())\n", + "\n", " display.display(plt.gcf())\n", " display.clear_output(wait=True)\n", "\n", - " if done:\n", + " if terminated or truncated:\n", " print(\"Well done!\")\n", " break\n", "else:\n", " print(\"Time limit exceeded. Try again.\")\n", "\n", - "display.clear_output(wait=True)" + "display.clear_output(wait=True)\n" ] }, { @@ -200,7 +220,7 @@ "outputs": [], "source": [ "assert obs[0] > 0.47\n", - "print(\"You solved it!\")" + "print(\"You solved it!\")\n" ] } ], diff --git a/week02_value_based/README.md b/week02_value_based/README.md index a3338e96f..380e0479d 100644 --- a/week02_value_based/README.md +++ b/week02_value_based/README.md @@ -9,6 +9,6 @@ ## Homework description: -The main assignment is `seminar_vi.ipynb`[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/spring20/week02_value_based/seminar_vi.ipynb) notebook in this week's folder. It has no requirements besides the most basic data science libraries (e.g. numpy) so you should be able to run it locally. +The main assignment is `seminar_vi.ipynb`[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week02_value_based/seminar_vi.ipynb) notebook in this week's folder. It has no requirements besides the most basic data science libraries (e.g. numpy) so you should be able to run it locally. __Note:__ if you have any difficulty using graphviz, just set `has_graphviz=False`. diff --git a/week02_value_based/mdp.py b/week02_value_based/mdp.py index b86b42539..1d148f22f 100644 --- a/week02_value_based/mdp.py +++ b/week02_value_based/mdp.py @@ -1,8 +1,6 @@ # most of this code was politely stolen from https://github.com/berkeleydeeprlcourse/homework/ # all credit goes to https://github.com/abhishekunique # (if I got the author right) -import sys -import random import numpy as np from gym.utils import seeding @@ -118,7 +116,7 @@ def _check_param_consistency(self, transition_probs, rewards): for action in transition_probs[state]: assert isinstance(transition_probs[state][action], dict), \ "transition_probs for %s, %s should be a a dictionary but is instead %s" % ( - state, action, type(transition_probs[state, action])) + state, action, type(transition_probs[state][action])) next_state_probs = transition_probs[state][action] assert len(next_state_probs) != 0, "from state %s action %s leads to no next states" % (state, action) sum_probs = sum(next_state_probs.values()) @@ -128,11 +126,11 @@ def _check_param_consistency(self, transition_probs, rewards): for state in rewards: assert isinstance(rewards[state], dict), \ "rewards for %s should be a dictionary but is instead %s" % ( - state, type(transition_probs[state])) + state, type(rewards[state])) for action in rewards[state]: assert isinstance(rewards[state][action], dict), \ "rewards for %s, %s should be a a dictionary but is instead %s" % ( - state, action, type(transition_probs[state, action])) + state, action, type(rewards[state][action])) msg = "The Enrichment Center once again reminds you that Android Hell is a real place where" \ " you will be sent at the first sign of defiance." assert None not in transition_probs, "please do not use None as a state identifier. " + msg @@ -251,7 +249,7 @@ def render(self): print('\n'.join(map(''.join, desc_copy)), end='\n\n') -def plot_graph(mdp, graph_size='10,10', s_node_size='1,5', +def plot_graph(mdp, s_node_size='1,5', a_node_size='0,5', rankdir='LR', ): """ Function for pretty drawing MDP graph with graphviz library. @@ -261,7 +259,6 @@ def plot_graph(mdp, graph_size='10,10', s_node_size='1,5', python library for graphviz for pip users: pip install graphviz :param mdp: - :param graph_size: size of graph plot :param s_node_size: size of state nodes :param a_node_size: size of action nodes :param rankdir: order for drawing @@ -294,7 +291,7 @@ def plot_graph(mdp, graph_size='10,10', s_node_size='1,5', 'fontsize': '16'} graph = Digraph(name='MDP') - graph.attr(rankdir=rankdir, size=graph_size) + graph.attr(rankdir=rankdir) for state_node in mdp._transition_probs: graph.node(state_node, **s_node_attrs) diff --git a/week02_value_based/seminar_vi.ipynb b/week02_value_based/seminar_vi.ipynb index 549213ee3..188448bbe 100644 --- a/week02_value_based/seminar_vi.ipynb +++ b/week02_value_based/seminar_vi.ipynb @@ -30,8 +30,8 @@ "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week02_value_based/mdp.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week02_value_based/mdp.py\n", " !touch .setup_complete\n", "\n", "# This code creates a virtual display to draw game images on.\n", @@ -870,7 +870,7 @@ "source": [ "# HW Part 1: Value iteration convergence\n", "\n", - "### Find an MDP for which value iteration takes long to converge (0.5 pts)\n", + "### Find an MDP for which value iteration takes long to converge (1 pts)\n", "\n", "When we ran value iteration on the small frozen lake problem, the last iteration where an action changed was iteration 6--i.e., value iteration computed the optimal policy at iteration 6. Are there any guarantees regarding how many iterations it'll take value iteration to compute the optimal policy? There are no such guarantees without additional assumptions--we can construct the MDP in such a way that the greedy policy will change after arbitrarily many iterations.\n", "\n", @@ -926,7 +926,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Value iteration convervence proof (0.5 pts)\n", + "### Value iteration convervence proof (1 pts)\n", "**Note:** Assume that $\\mathcal{S}, \\mathcal{A}$ are finite.\n", "\n", "Update of value function in value iteration can be rewritten in a form of Bellman operator:\n", @@ -963,7 +963,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Bonus. Asynchronious value iteration (2 pts)\n", + "### Asynchronious value iteration (2 pts)\n", "\n", "Consider the following algorithm:\n", "\n", @@ -997,7 +997,7 @@ "source": [ "# HW Part 2: Policy iteration\n", "\n", - "## Policy iteration implementateion (2 pts)\n", + "## Policy iteration implementateion (3 pts)\n", "\n", "Let's implement exact policy iteration (PI), which has the following pseudocode:\n", "\n", @@ -1238,7 +1238,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/week03_model_free/README.md b/week03_model_free/README.md index eb4ccb80a..b2271d15b 100644 --- a/week03_model_free/README.md +++ b/week03_model_free/README.md @@ -3,8 +3,8 @@ * Russian materials: - Lecture - [video](https://yadi.sk/i/jcQ1Bg8n3SrhuQ) - Seminars - - Q-learning seminar - [video](https://yadi.sk/i/dQmolwOy3EtGNK) (older track - [assignment](https://github.com/neer201/Practical_RL/tree/spring20/week03_model_free/crawler_and_pacman/seminar_py2)) - - SARSA & stuff - [video](https://yadi.sk/i/XbqNQmjm3ExNsq) + - Q-learning seminar - [video](https://yadi.sk/i/dQmolwOy3EtGNK) (older track - [assignment](./crawler_and_pacman/seminar_py2)) + - SARSA & stuff - [video](https://yadi.sk/i/XbqNQmjm3ExNsq) * English materials: - Lecture by David Silver (english) - [video part I](https://www.youtube.com/watch?v=PnHCvfgC_ZA), [video part II](https://www.youtube.com/watch?v=0g4j2k_Ggc4&t=43s) - Alternative lecture by Pieter Abbeel (english) - [video](https://www.youtube.com/watch?v=ifma8G7LegE) @@ -18,9 +18,4 @@ ### Assignments -Just as usual, start with -- [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/spring20/week03_model_free/seminar_qlearning.ipynb) -`seminar_qlearning.ipynb` _Implement q-learning agent and test it on Taxi and CartPole with binarizer_ - -and then proceed to -- [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/spring20/week03_model_free/homework.ipynb) `homework.ipynb` _Implement EV-SARSA agent, experience replay + bonus tasks_ +Just as usual, start with `homework.ipynb` [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week03_model_free/homework.ipynb) For seminar, implement q-learning agent and test it on Taxi and CartPole with binarizer. And then, implement EV-SARSA agent, experience replay + bonus tasks for homework. diff --git a/week03_model_free/crawler_and_pacman/seminar_py2/README.md b/week03_model_free/crawler_and_pacman/seminar_py2/README.md index 7c4c91301..872c8e500 100644 --- a/week03_model_free/crawler_and_pacman/seminar_py2/README.md +++ b/week03_model_free/crawler_and_pacman/seminar_py2/README.md @@ -1,5 +1,5 @@ # Disclaimer -This assignment is not supported now. You can do it at your own risk. +This assignment is not supported now. You can do it at your own risk. _this assignment borrows code from awesome [cs188](http://ai.berkeley.edu/project_overview.html)_ This homework assignment works on __python2 only__. If you stick to py3, consider seminar_alternative. Or just install it for this homework alone and remove afterwards. @@ -17,8 +17,8 @@ python pacman.py -p PacmanQAgent -x 5000 -n 5010 -l smallGrid # example ``` * Make sure you can tune agent to beat ./run_crawler.sh * on windows, just run `python crawler.py` from cmd in the project directory -* other ./run* files are mostly for your amusement. - * ./run_pacman.sh will need more epochs to converge, see [comments](https://github.com/yandexdataschool/Practical_RL/blob/spring20/week03_model_free/crawler_and_pacman/seminar_py2/run_pacman.sh) +* other ./run* files are mostly for your amusement. + * ./run_pacman.sh will need more epochs to converge, see [comments](https://github.com/yandexdataschool/Practical_RL/blob/master/week03_model_free/crawler_and_pacman/seminar_py2/run_pacman.sh) * on windows, just copy the type `python pacman.py -p PacmanQAgent -x 2000 -n 2010 -l smallGrid` in cmd from assignemnt dir @@ -35,14 +35,14 @@ The problem with those environments is that they have a large amount of unique s * where is nearest food * 'center of mass' of all food points (and variance, and whatever) * is there a wall in each direction - * and anything else you see fit - + * and anything else you see fit + Here's how to get this information from [state](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L49), * Get pacman position: [state.getPacmanPosition()](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L128) * Is there a wall at (x,y)?: [state.hasWall(x,y)](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L189) * Get ghost positions: [state.getGhostPositions()](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L144) * Get all food positions: [state.getCapsules()](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L153) - + You can call those methods anywhere you see state. * e.g. in [agent.getValue(state)](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/qlearningAgents.py#L52) * Defining a function that extracts all features and calling it in [getQValue](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/qlearningAgents.py#L38) and [setQValue](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/qlearningAgents.py#L44) is probably enough. diff --git a/week03_model_free/crawler_and_pacman/seminar_py3/README.md b/week03_model_free/crawler_and_pacman/seminar_py3/README.md index 696e8163d..7faec7ce0 100644 --- a/week03_model_free/crawler_and_pacman/seminar_py3/README.md +++ b/week03_model_free/crawler_and_pacman/seminar_py3/README.md @@ -1,13 +1,13 @@ Contributors: [Vlad Lyalin](https://github.com/Guitaricet) # Disclaimer -This assignment is not supported now. You can do it at your own risk. +This assignment is not supported now. You can do it at your own risk. # Requirements __Ubuntu__ - not tested __MacOS__ Python 3.7.0 (3.6, 3.8 and other cause on MacOS [problems](https://stackoverflow.com/questions/57400301/how-to-fix-tkinter-every-code-with-gui-crashes-mac-os-with-respring) with _Tkinter_) - + Anaconda users just can create new_env: ```bash conda create -n pacman_env python=3.7.0 @@ -31,8 +31,8 @@ python pacman.py -p PacmanQAgent -x 5000 -n 5010 -l smallGrid # example ``` * Make sure you can tune agent to beat ./run_crawler.sh * on windows, just run `python crawler.py` from cmd in the project directory -* other ./run* files are mostly for your amusement. - * ./run_pacman.sh will need more epochs to converge, see [comments](https://github.com/yandexdataschool/Practical_RL/blob/spring20/week03_model_free/crawler_and_pacman/seminar_py2/run_pacman.sh) +* other ./run* files are mostly for your amusement. + * ./run_pacman.sh will need more epochs to converge, see [comments](https://github.com/yandexdataschool/Practical_RL/blob/master/week03_model_free/crawler_and_pacman/seminar_py2/run_pacman.sh) * on windows, just copy the type `python pacman.py -p PacmanQAgent -x 2000 -n 2010 -l smallGrid` in cmd from assignemnt dir @@ -49,14 +49,14 @@ The problem with those environments is that they have a large amount of unique s * where is nearest food * 'center of mass' of all food points (and variance, and whatever) * is there a wall in each direction - * and anything else you see fit - + * and anything else you see fit + Here's how to get this information from [state](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L49), * Get pacman position: [state.getPacmanPosition()](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L128) * Is there a wall at (x,y)?: [state.hasWall(x,y)](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L189) * Get ghost positions: [state.getGhostPositions()](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L144) * Get all food positions: [state.getCapsules()](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/pacman.py#L153) - + You can call those methods anywhere you see state. * e.g. in [agent.getValue(state)](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/qlearningAgents.py#L52) * Defining a function that extracts all features and calling it in [getQValue](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/qlearningAgents.py#L38) and [setQValue](https://github.com/yandexdataschool/Practical_RL/blob/7a559f8/week03_model_free/seminar_py2/qlearningAgents.py#L44) is probably enough. diff --git a/week03_model_free/homework.ipynb b/week03_model_free/homework.ipynb index a13d9e6dc..6eb18ea33 100644 --- a/week03_model_free/homework.ipynb +++ b/week03_model_free/homework.ipynb @@ -1,29 +1,5 @@ { "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[Part I: On-policy learning and SARSA (3 points)](#Part-I:-On-policy-learning-and-SARSA-(3-points))\n", - "\n", - "[Part II: Experience replay (4 points)](#Part-II:-experience-replay-(4-points))\n", - "\n", - "[Bonus I: TD($ \\lambda $) (5+ points)](#Bonus-I:-TD($\\lambda$)-(5+-points))\n", - "\n", - "[Bonus II: More pacman (5+ points)](#Bonus-II:-More-pacman-(5+-points))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part I: On-policy learning and SARSA (3 points)\n", - "\n", - "_This notebook builds upon `qlearning.ipynb`, or to be exact your implementation of QLearningAgent._\n", - "\n", - "The policy we're gonna use is epsilon-greedy policy, where agent takes optimal action with probability $(1-\\epsilon)$, otherwise samples action at random. Note that agent __can__ occasionally sample optimal action during random sampling by pure chance." - ] - }, { "cell_type": "code", "execution_count": null, @@ -32,7 +8,8 @@ "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", " !touch .setup_complete\n", "\n", "# This code creates a virtual display to draw game images on.\n", @@ -53,11 +30,24 @@ "%matplotlib inline" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip3 install -q gymnasium[classic-control]" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "You can copy your `QLearningAgent` implementation from previous notebook." + "## Seminar: Q-learning (1.5 points)\n", + "\n", + "This notebook will guide you through implementation of vanilla Q-learning algorithm.\n", + "\n", + "You need to implement QLearningAgent (follow instructions for each method) and use it on a number of tests below." ] }, { @@ -89,7 +79,6 @@ " which returns Q(state,action)\n", " - self.set_qvalue(state,action,value)\n", " which sets Q(state,action) := value\n", - "\n", " !!!Important!!!\n", " Note: please avoid using self._qValues directly. \n", " There's a special self.get_qvalue/set_qvalue for that.\n", @@ -159,7 +148,7 @@ " \"\"\"\n", " Compute the action to take in the current state, including exploration. \n", " With probability self.epsilon, we should take a random action.\n", - " otherwise - the best policy action (self.getPolicy).\n", + " otherwise - the best policy action (self.get_best_action).\n", "\n", " Note: To pick randomly from a list, use random.choice(list). \n", " To pick True or False with a given probablity, generate uniform number in [0, 1]\n", @@ -182,6 +171,335 @@ " return chosen_action" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Try it on taxi\n", + "\n", + "Here we use the Q-Learning agent on the Taxi-v3 environment from OpenAI gym.\n", + "You will need to complete a few of its functions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import gymnasium as gym\n", + "env = gym.make(\"Taxi-v3\", render_mode='rgb_array')\n", + "\n", + "n_actions = env.action_space.n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s, _ = env.reset()\n", + "plt.imshow(env.render())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "agent = QLearningAgent(\n", + " alpha=0.5, epsilon=0.25, discount=0.99,\n", + " get_legal_actions=lambda s: range(n_actions))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def play_and_train(env, agent, t_max=10**4):\n", + " \"\"\"\n", + " This function should \n", + " - run a full game, actions given by agent's e-greedy policy\n", + " - train agent using agent.update(...) whenever it is possible\n", + " - return total reward\n", + " \"\"\"\n", + " total_reward = 0.0\n", + " s, _ = env.reset()\n", + "\n", + " for t in range(t_max):\n", + " # get agent to pick action given state s.\n", + " a = \n", + "\n", + " next_s, r, done, _, _ = env.step(a)\n", + "\n", + " # train (update) agent for state s\n", + " \n", + "\n", + " s = next_s\n", + " total_reward += r\n", + " if done:\n", + " break\n", + "\n", + " return total_reward" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import clear_output\n", + "\n", + "rewards = []\n", + "for i in range(1000):\n", + " rewards.append(play_and_train(env, agent))\n", + " agent.epsilon *= 0.99\n", + "\n", + " if i % 100 == 0:\n", + " clear_output(True)\n", + " plt.title('eps = {:e}, mean reward = {:.1f}'.format(agent.epsilon, np.mean(rewards[-10:])))\n", + " plt.plot(rewards)\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Seminar: Discretized state spaces (1.5 points)\n", + "\n", + "Use agent to train efficiently on `CartPole-v0`. This environment has a continuous set of possible states, so you will have to group them into bins somehow.\n", + "\n", + "The simplest way is to use `round(x, n_digits)` (or `np.round`) to round a real number to a given amount of digits. The tricky part is to get the `n_digits` right for each state to train effectively.\n", + "\n", + "Note that you don't need to convert state to integers, but to __tuples__ of any kind of values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def make_env():\n", + " return gym.make('CartPole-v0', render_mode='rgb_array').env # .env unwraps the TimeLimit wrapper\n", + "\n", + "env = make_env()\n", + "n_actions = env.action_space.n\n", + "\n", + "print(\"first state: %s\" % (env.reset()[0]))\n", + "plt.imshow(env.render())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Play a few games\n", + "\n", + "We need to estimate observation distributions. To do so, we'll play a few games and record all states." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def visualize_cartpole_observation_distribution(seen_observations):\n", + " seen_observations = np.array(seen_observations)\n", + " \n", + " # The meaning of the observations is documented in\n", + " # https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py\n", + "\n", + " f, axarr = plt.subplots(2, 2, figsize=(16, 9), sharey=True)\n", + " for i, title in enumerate(['Cart Position', 'Cart Velocity', 'Pole Angle', 'Pole Velocity At Tip']):\n", + " ax = axarr[i // 2, i % 2]\n", + " ax.hist(seen_observations[:, i], bins=20)\n", + " ax.set_title(title)\n", + " xmin, xmax = ax.get_xlim()\n", + " ax.set_xlim(min(xmin, -xmax), max(-xmin, xmax))\n", + " ax.grid()\n", + " f.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "seen_observations = []\n", + "for _ in range(1000):\n", + " s, _ = env.reset()\n", + " seen_observations.append(s)\n", + " done = False\n", + " while not done:\n", + " s, r, done, _, _ = env.step(env.action_space.sample())\n", + " seen_observations.append(s)\n", + " \n", + "visualize_cartpole_observation_distribution(seen_observations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Discretize environment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from gymnasium.core import ObservationWrapper\n", + "\n", + "\n", + "class Discretizer(ObservationWrapper):\n", + " def observation(self, state):\n", + " # Hint: you can do that with round(x, n_digits).\n", + " # You may pick a different n_digits for each dimension.\n", + " state = \n", + "\n", + " return tuple(state)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env = Discretizer(make_env())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "seen_observations = []\n", + "for _ in range(1000):\n", + " s, _ = env.reset()\n", + " seen_observations.append(s)\n", + " done = False\n", + " while not done:\n", + " s, r, done, _, _ = env.step(env.action_space.sample())\n", + " seen_observations.append(s)\n", + " if done:\n", + " break\n", + " \n", + "visualize_cartpole_observation_distribution(seen_observations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Learn discretized policy\n", + "\n", + "Now let's train a policy that uses discretized state space.\n", + "\n", + "__Tips:__\n", + "\n", + "* Note that increasing the number of digits for one dimension of the observations increases your state space by a factor of $10$.\n", + "* If your discretization is too fine-grained, your agent will take much longer than 10000 steps to converge. You can either increase the number of iterations and reduce epsilon decay or change discretization. In practice we found that this kind of mistake is rather frequent.\n", + "* If your discretization is too coarse, your agent may fail to find the optimal policy. In practice we found that on this particular environment this kind of mistake is rare.\n", + "* **Start with a coarse discretization** and make it more fine-grained if that seems necessary.\n", + "* Having $10^3$–$10^4$ distinct states is recommended (`len(agent._qvalues)`), but not required.\n", + "* If things don't work without annealing $\\varepsilon$, consider adding that, but make sure that it doesn't go to zero too quickly.\n", + "\n", + "A reasonable agent should attain an average reward of at least 50." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "def moving_average(x, span=100):\n", + " return pd.DataFrame({'x': np.asarray(x)}).x.ewm(span=span).mean().values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "agent = QLearningAgent(\n", + " alpha=0.5, epsilon=0.25, discount=0.99,\n", + " get_legal_actions=lambda s: range(n_actions))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rewards = []\n", + "epsilons = []\n", + "\n", + "for i in range(10000):\n", + " reward = play_and_train(env, agent)\n", + " rewards.append(reward)\n", + " epsilons.append(agent.epsilon)\n", + " \n", + " # OPTIONAL: \n", + "\n", + " if i % 100 == 0:\n", + " rewards_ewma = moving_average(rewards)\n", + " \n", + " clear_output(True)\n", + " plt.plot(rewards, label='rewards')\n", + " plt.plot(rewards_ewma, label='rewards ewma@100')\n", + " plt.legend()\n", + " plt.grid()\n", + " plt.title('eps = {:e}, rewards ewma@100 = {:.1f}'.format(agent.epsilon, rewards_ewma[-1]))\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('Your agent has learned {} Q-values.'.format(len(agent._qvalues)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Homework Part I: On-policy learning and SARSA (3 points)\n", + "\n", + "The policy we're gonna use is epsilon-greedy policy, where agent takes the optimal action with probability $(1-\\epsilon)$, otherwise samples action at random. Note that agent __can__ occasionally sample optimal action during random sampling by pure chance." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -232,7 +550,7 @@ "Let's now see how our algorithm compares against q-learning in case where we force agent to explore all the time.\n", "\n", "\n", - "
image by cs188
" + "
Image from CS188
" ] }, { @@ -241,23 +559,10 @@ "metadata": {}, "outputs": [], "source": [ - "import gym\n", - "import gym.envs.toy_text\n", - "env = gym.envs.toy_text.CliffWalkingEnv()\n", - "n_actions = env.action_space.n\n", + "import gymnasium as gym\n", "\n", - "print(env.__doc__)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Our cliffworld has one difference from what's on the image: there is no wall.\n", - "# Agent can choose to go as close to the cliff as it wishes. x:start, T:exit, C:cliff, o: flat ground\n", - "env.render()" + "env = gym.make('CliffWalking-v0', render_mode='rgb_array')\n", + "n_actions = env.action_space.n" ] }, { @@ -266,26 +571,12 @@ "metadata": {}, "outputs": [], "source": [ - "def play_and_train(env, agent, t_max=10**4):\n", - " \"\"\"This function should \n", - " - run a full game, actions given by agent.getAction(s)\n", - " - train agent using agent.update(...) whenever possible\n", - " - return total reward\"\"\"\n", - " total_reward = 0.0\n", - " s = env.reset()\n", - "\n", - " for t in range(t_max):\n", - " a = agent.get_action(s)\n", + "# Our cliffworld has one difference from what's in the image: there is no wall.\n", + "# Agent can choose to go as close to the cliff as it wishes.\n", + "# x:start, T:exit, C:cliff, o: flat ground\n", "\n", - " next_s, r, done, _ = env.step(a)\n", - " agent.update(s, a, r, next_s)\n", - "\n", - " s = next_s\n", - " total_reward += r\n", - " if done:\n", - " break\n", - "\n", - " return total_reward" + "env.reset()\n", + "plt.imshow(env.render())" ] }, { @@ -346,17 +637,22 @@ "metadata": {}, "outputs": [], "source": [ - "def draw_policy(env, agent):\n", + "def draw_policy(agent):\n", " \"\"\" Prints CliffWalkingEnv policy with arrows. Hard-coded. \"\"\"\n", - " n_rows, n_cols = env._cliff.shape\n", + " \n", + " env = gym.make('CliffWalking-v0', render_mode='ansi')\n", + " env.reset()\n", + " grid = [x.split(' ') for x in env.render().split('\\n')[:4]]\n", "\n", + " n_rows, n_cols = 4, 12\n", + " start_state_index = 36\n", " actions = '^>v<'\n", "\n", " for yi in range(n_rows):\n", " for xi in range(n_cols):\n", - " if env._cliff[yi, xi]:\n", + " if grid[yi][xi] == 'C':\n", " print(\" C \", end='')\n", - " elif (yi * n_cols + xi) == env.start_state_index:\n", + " elif (yi * n_cols + xi) == start_state_index:\n", " print(\" X \", end='')\n", " elif (yi * n_cols + xi) == n_rows * n_cols - 1:\n", " print(\" T \", end='')\n", @@ -373,10 +669,69 @@ "outputs": [], "source": [ "print(\"Q-Learning\")\n", - "draw_policy(env, agent_ql)\n", + "draw_policy(agent_ql)\n", "\n", "print(\"SARSA\")\n", - "draw_policy(env, agent_sarsa)" + "draw_policy(agent_sarsa)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Expected Value SARSA for softmax policy (2 points)\n", + "\n", + "Implement an agent that would use a softmax policy for getting an action. Do not forget to also use softmax when calculating the expected value for value estimation. Draw the policy of the agent and see if the result is different compared to the previous approaches. Also, try using different temperatures ($\\tau$) and compare the results.\n", + "\n", + "$$ \\pi(a_i \\mid s) = \\operatorname{softmax} \\left( \\left\\{ {Q(s, a_j) \\over \\tau} \\right\\}_{j=1}^n \\right)_i = {\\operatorname{exp} \\left( Q(s,a_i) / \\tau \\right) \\over {\\sum_{j} \\operatorname{exp} \\left( Q(s,a_j) / \\tau \\right)}} $$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SoftmaxEVSarsaAgent(EVSarsaAgent):\n", + " def __init__(self, alpha, tau, discount, get_legal_actions):\n", + " super().__init__(alpha, None, discount, get_legal_actions)\n", + " assert tau > 0\n", + " self.tau = tau\n", + " \n", + " def get_value(self, state):\n", + " \"\"\" \n", + " Returns V_{pi} for current state under softmax policy:\n", + " V_{pi}(s) = sum _{over a_i} {pi(a_i | s) * Q(s, a_i)}\n", + "\n", + " Hint: all other methods from QLearningAgent are still accessible.\n", + " \"\"\"\n", + " possible_actions = self.get_legal_actions(state)\n", + "\n", + " # If there are no legal actions, return 0.0\n", + " if len(possible_actions) == 0:\n", + " return 0.0\n", + "\n", + " \n", + "\n", + " return value\n", + " \n", + " def get_action(self, state):\n", + " \"\"\"\n", + " Compute the action to take in the current state, including exploration. \n", + " We should take a random action with probability equaled softmax of q values.\n", + " \"\"\"\n", + " # Pick Action\n", + " possible_actions = self.get_legal_actions(state)\n", + " action = None\n", + "\n", + " # If there are no legal actions, return None\n", + " if len(possible_actions) == 0:\n", + " return None\n", + "\n", + " \n", + " \n", + "\n", + " return chosen_action" ] }, { @@ -388,8 +743,6 @@ "Here are some of the things you can do if you feel like it:\n", "\n", "* Play with epsilon. See learned how policies change if you set epsilon to higher/lower values (e.g. 0.75).\n", - "* Expected Value SARSA for softmax policy __(2pts)__:\n", - "$$ \\pi(a_i \\mid s) = \\operatorname{softmax} \\left( \\left\\{ {Q(s, a_j) \\over \\tau} \\right\\}_{j=1}^n \\right)_i = {\\operatorname{exp} \\left( Q(s,a_i) / \\tau \\right) \\over {\\sum_{j} \\operatorname{exp} \\left( Q(s,a_j) / \\tau \\right)}} $$\n", "* Implement N-step algorithms and TD($\\lambda$): see [Sutton's book](http://incompleteideas.net/book/RLbook2020.pdf) chapter 7 and chapter 12.\n", "* Use those algorithms to train on CartPole in previous / next assignment for this week." ] @@ -398,7 +751,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Part II: experience replay (4 points)\n", + "## Part II: experience replay (2 points)\n", "\n", "There's a powerful technique that you can use to improve sample efficiency for off-policy algorithms: [spoiler] Experience replay :)\n", "\n", @@ -423,28 +776,6 @@ "metadata": {}, "outputs": [], "source": [ - "import sys, os\n", - "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - " !touch .setup_complete\n", - "\n", - "# This code creates a virtual display to draw game images on.\n", - "# It will have no effect if your machine has a monitor.\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "\n", "from IPython.display import clear_output" ] }, @@ -574,7 +905,7 @@ "metadata": {}, "outputs": [], "source": [ - "import gym\n", + "import gymnasium as gym\n", "env = gym.make(\"Taxi-v3\")\n", "n_actions = env.action_space.n" ] @@ -589,20 +920,20 @@ " t_max=10**4, replay_batch_size=32):\n", " \"\"\"\n", " This function should \n", - " - run a full game, actions given by agent.getAction(s)\n", + " - run a full game, actions given by agent.get_action(s)\n", " - train agent using agent.update(...) whenever possible\n", " - return total reward\n", " :param replay: ReplayBuffer where agent can store and sample (s,a,r,s',done) tuples.\n", " If None, do not use experience replay\n", " \"\"\"\n", " total_reward = 0.0\n", - " s = env.reset()\n", + " s, _ = env.reset()\n", "\n", " for t in range(t_max):\n", " # get agent to pick action given state s\n", " a = \n", "\n", - " next_s, r, done, _ = env.step(a)\n", + " next_s, r, done, _, _ = env.step(a)\n", "\n", " # update agent on current transition. Use agent.update\n", " \n", @@ -690,7 +1021,7 @@ "\n", "### Outro\n", "\n", - "We will use the code you just wrote extensively in the next week of our course. If you're feeling that you need more examples to understand how experience replay works, try using it for binarized state spaces (CartPole or other __[classic control envs](https://gym.openai.com/envs/#classic_control)__).\n", + "We will use the code you just wrote extensively in the next week of our course. If you're feeling that you need more examples to understand how experience replay works, try using it for discretized state spaces (CartPole or other __[classic control envs](https://gym.openai.com/envs/#classic_control)__).\n", "\n", "__Next week__ we're gonna explore how q-learning and similar algorithms can be applied for large state spaces, with deep learning models to approximate the Q function.\n", "\n", diff --git a/week03_model_free/seminar_qlearning.ipynb b/week03_model_free/seminar_qlearning.ipynb deleted file mode 100644 index 7ef47effb..000000000 --- a/week03_model_free/seminar_qlearning.ipynb +++ /dev/null @@ -1,495 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q-learning (3 points)\n", - "\n", - "This notebook will guide you through implementation of vanilla Q-learning algorithm.\n", - "\n", - "You need to implement QLearningAgent (follow instructions for each method) and use it on a number of tests below." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys, os\n", - "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - "\n", - " !touch .setup_complete\n", - "\n", - "# This code creates a virtual display to draw game images on.\n", - "# It will have no effect if your machine has a monitor.\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from collections import defaultdict\n", - "import random\n", - "import math\n", - "import numpy as np\n", - "\n", - "\n", - "class QLearningAgent:\n", - " def __init__(self, alpha, epsilon, discount, get_legal_actions):\n", - " \"\"\"\n", - " Q-Learning Agent\n", - " based on https://inst.eecs.berkeley.edu/~cs188/sp19/projects.html\n", - " Instance variables you have access to\n", - " - self.epsilon (exploration prob)\n", - " - self.alpha (learning rate)\n", - " - self.discount (discount rate aka gamma)\n", - "\n", - " Functions you should use\n", - " - self.get_legal_actions(state) {state, hashable -> list of actions, each is hashable}\n", - " which returns legal actions for a state\n", - " - self.get_qvalue(state,action)\n", - " which returns Q(state,action)\n", - " - self.set_qvalue(state,action,value)\n", - " which sets Q(state,action) := value\n", - " !!!Important!!!\n", - " Note: please avoid using self._qValues directly. \n", - " There's a special self.get_qvalue/set_qvalue for that.\n", - " \"\"\"\n", - "\n", - " self.get_legal_actions = get_legal_actions\n", - " self._qvalues = defaultdict(lambda: defaultdict(lambda: 0))\n", - " self.alpha = alpha\n", - " self.epsilon = epsilon\n", - " self.discount = discount\n", - "\n", - " def get_qvalue(self, state, action):\n", - " \"\"\" Returns Q(state,action) \"\"\"\n", - " return self._qvalues[state][action]\n", - "\n", - " def set_qvalue(self, state, action, value):\n", - " \"\"\" Sets the Qvalue for [state,action] to the given value \"\"\"\n", - " self._qvalues[state][action] = value\n", - "\n", - " #---------------------START OF YOUR CODE---------------------#\n", - "\n", - " def get_value(self, state):\n", - " \"\"\"\n", - " Compute your agent's estimate of V(s) using current q-values\n", - " V(s) = max_over_action Q(state,action) over possible actions.\n", - " Note: please take into account that q-values can be negative.\n", - " \"\"\"\n", - " possible_actions = self.get_legal_actions(state)\n", - "\n", - " # If there are no legal actions, return 0.0\n", - " if len(possible_actions) == 0:\n", - " return 0.0\n", - "\n", - " \n", - "\n", - " return value\n", - "\n", - " def update(self, state, action, reward, next_state):\n", - " \"\"\"\n", - " You should do your Q-Value update here:\n", - " Q(s,a) := (1 - alpha) * Q(s,a) + alpha * (r + gamma * V(s'))\n", - " \"\"\"\n", - "\n", - " # agent parameters\n", - " gamma = self.discount\n", - " learning_rate = self.alpha\n", - "\n", - " \n", - "\n", - " self.set_qvalue(state, action, )\n", - "\n", - " def get_best_action(self, state):\n", - " \"\"\"\n", - " Compute the best action to take in a state (using current q-values). \n", - " \"\"\"\n", - " possible_actions = self.get_legal_actions(state)\n", - "\n", - " # If there are no legal actions, return None\n", - " if len(possible_actions) == 0:\n", - " return None\n", - "\n", - " \n", - "\n", - " return best_action\n", - "\n", - " def get_action(self, state):\n", - " \"\"\"\n", - " Compute the action to take in the current state, including exploration. \n", - " With probability self.epsilon, we should take a random action.\n", - " otherwise - the best policy action (self.get_best_action).\n", - "\n", - " Note: To pick randomly from a list, use random.choice(list). \n", - " To pick True or False with a given probablity, generate uniform number in [0, 1]\n", - " and compare it with your probability\n", - " \"\"\"\n", - "\n", - " # Pick Action\n", - " possible_actions = self.get_legal_actions(state)\n", - " action = None\n", - "\n", - " # If there are no legal actions, return None\n", - " if len(possible_actions) == 0:\n", - " return None\n", - "\n", - " # agent parameters:\n", - " epsilon = self.epsilon\n", - "\n", - " \n", - "\n", - " return chosen_action" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Try it on taxi\n", - "\n", - "Here we use the qlearning agent on taxi env from openai gym.\n", - "You will need to insert a few agent functions here." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "env = gym.make(\"Taxi-v3\")\n", - "\n", - "n_actions = env.action_space.n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "agent = QLearningAgent(\n", - " alpha=0.5, epsilon=0.25, discount=0.99,\n", - " get_legal_actions=lambda s: range(n_actions))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def play_and_train(env, agent, t_max=10**4):\n", - " \"\"\"\n", - " This function should \n", - " - run a full game, actions given by agent's e-greedy policy\n", - " - train agent using agent.update(...) whenever it is possible\n", - " - return total reward\n", - " \"\"\"\n", - " total_reward = 0.0\n", - " s = env.reset()\n", - "\n", - " for t in range(t_max):\n", - " # get agent to pick action given state s.\n", - " a = \n", - "\n", - " next_s, r, done, _ = env.step(a)\n", - "\n", - " # train (update) agent for state s\n", - " \n", - "\n", - " s = next_s\n", - " total_reward += r\n", - " if done:\n", - " break\n", - "\n", - " return total_reward" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import clear_output\n", - "\n", - "rewards = []\n", - "for i in range(1000):\n", - " rewards.append(play_and_train(env, agent))\n", - " agent.epsilon *= 0.99\n", - "\n", - " if i % 100 == 0:\n", - " clear_output(True)\n", - " plt.title('eps = {:e}, mean reward = {:.1f}'.format(agent.epsilon, np.mean(rewards[-10:])))\n", - " plt.plot(rewards)\n", - " plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Binarized state spaces\n", - "\n", - "Use agent to train efficiently on `CartPole-v0`. This environment has a continuous set of possible states, so you will have to group them into bins somehow.\n", - "\n", - "The simplest way is to use `round(x, n_digits)` (or `np.round`) to round a real number to a given amount of digits. The tricky part is to get the `n_digits` right for each state to train effectively.\n", - "\n", - "Note that you don't need to convert state to integers, but to __tuples__ of any kind of values." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def make_env():\n", - " return gym.make('CartPole-v0').env # .env unwraps the TimeLimit wrapper\n", - "\n", - "env = make_env()\n", - "n_actions = env.action_space.n\n", - "\n", - "print(\"first state: %s\" % (env.reset()))\n", - "plt.imshow(env.render('rgb_array'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Play a few games\n", - "\n", - "We need to estimate observation distributions. To do so, we'll play a few games and record all states." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def visualize_cartpole_observation_distribution(seen_observations):\n", - " seen_observations = np.array(seen_observations)\n", - " \n", - " # The meaning of the observations is documented in\n", - " # https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py\n", - "\n", - " f, axarr = plt.subplots(2, 2, figsize=(16, 9), sharey=True)\n", - " for i, title in enumerate(['Cart Position', 'Cart Velocity', 'Pole Angle', 'Pole Velocity At Tip']):\n", - " ax = axarr[i // 2, i % 2]\n", - " ax.hist(seen_observations[:, i], bins=20)\n", - " ax.set_title(title)\n", - " xmin, xmax = ax.get_xlim()\n", - " ax.set_xlim(min(xmin, -xmax), max(-xmin, xmax))\n", - " ax.grid()\n", - " f.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "seen_observations = []\n", - "for _ in range(1000):\n", - " seen_observations.append(env.reset())\n", - " done = False\n", - " while not done:\n", - " s, r, done, _ = env.step(env.action_space.sample())\n", - " seen_observations.append(s)\n", - "\n", - "visualize_cartpole_observation_distribution(seen_observations)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Binarize environment" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from gym.core import ObservationWrapper\n", - "\n", - "\n", - "class Binarizer(ObservationWrapper):\n", - " def observation(self, state):\n", - " # Hint: you can do that with round(x, n_digits).\n", - " # You may pick a different n_digits for each dimension.\n", - " state = \n", - "\n", - " return tuple(state)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "env = Binarizer(make_env())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "seen_observations = []\n", - "for _ in range(1000):\n", - " seen_observations.append(env.reset())\n", - " done = False\n", - " while not done:\n", - " s, r, done, _ = env.step(env.action_space.sample())\n", - " seen_observations.append(s)\n", - " if done:\n", - " break\n", - "\n", - "visualize_cartpole_observation_distribution(seen_observations)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Learn binarized policy\n", - "\n", - "Now let's train a policy that uses binarized state space.\n", - "\n", - "__Tips:__\n", - "\n", - "* Note that increasing the number of digits for one dimension of the observations increases your state space by a factor of $10$.\n", - "* If your binarization is too fine-grained, your agent will take much longer than 10000 steps to converge. You can either increase the number of iterations and reduce epsilon decay or change binarization. In practice we found that this kind of mistake is rather frequent.\n", - "* If your binarization is too coarse, your agent may fail to find the optimal policy. In practice we found that on this particular environment this kind of mistake is rare.\n", - "* **Start with a coarse binarization** and make it more fine-grained if that seems necessary.\n", - "* Having $10^3$–$10^4$ distinct states is recommended (`len(agent._qvalues)`), but not required.\n", - "* If things don't work without annealing $\\varepsilon$, consider adding that, but make sure that it doesn't go to zero too quickly.\n", - "\n", - "A reasonable agent should attain an average reward of at least 50." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "def moving_average(x, span=100):\n", - " return pd.DataFrame({'x': np.asarray(x)}).x.ewm(span=span).mean().values" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "agent = QLearningAgent(\n", - " alpha=0.5, epsilon=0.25, discount=0.99,\n", - " get_legal_actions=lambda s: range(n_actions))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "rewards = []\n", - "epsilons = []\n", - "\n", - "for i in range(10000):\n", - " reward = play_and_train(env, agent)\n", - " rewards.append(reward)\n", - " epsilons.append(agent.epsilon)\n", - " \n", - " # OPTIONAL: \n", - "\n", - " if i % 100 == 0:\n", - " rewards_ewma = moving_average(rewards)\n", - " \n", - " clear_output(True)\n", - " plt.plot(rewards, label='rewards')\n", - " plt.plot(rewards_ewma, label='rewards ewma@100')\n", - " plt.legend()\n", - " plt.grid()\n", - " plt.title('eps = {:e}, rewards ewma@100 = {:.1f}'.format(agent.epsilon, rewards_ewma[-1]))\n", - " plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print('Your agent has learned {} Q-values.'.format(len(agent._qvalues)))" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week04_[recap]_deep_learning/README.md b/week04_[recap]_deep_learning/README.md index ab19e5717..d5bc7139d 100644 --- a/week04_[recap]_deep_learning/README.md +++ b/week04_[recap]_deep_learning/README.md @@ -1,22 +1,20 @@ -__Note:__ This week's materials cover the basics of neural nets and deep learning and teach you how to use auto-diff frameworks. If you're already fluent in tensorflow OR pytorch OR theano - feel free to skip this week entirely.. +__Note:__ This week's materials cover the basics of neural nets and deep learning and teach you how to use auto-diff frameworks. If you're already fluent in Tensorflow or PyTorch, feel free to skip this week entirely. ## Materials * [__Lecture slides__](https://yadi.sk/i/yAO2AJ3M3EKP8g) - __In russian:__ * Basic lecture on deep learning - [video](https://yadi.sk/i/yyHZub6R3Ej5dV) - * Deep learning frameworks - [video](https://yadi.sk/i/hDIkaR4H3EtnXM) + * Deep learning frameworks - [video](https://yadi.sk/i/hDIkaR4H3EtnXM) * [Pytorch tutorial](https://yadi.sk/i/O3mQ76u43So3h9) __recommended__ * [Tensorflow tutorial](https://www.youtube.com/watch?v=FQ660T4uu7k) (english only for now. Links are welcome) - * [Theano tutorial](https://yadi.sk/i/54STsEBVpubkn) - __In english:__ * Intro to neural nets and backprop (english) - [video](https://www.youtube.com/watch?v=uXt8qF2Zzfo) * Intro to convnets - [video](https://www.youtube.com/watch?v=FmpDIaiMIeA) * Deep learning frameworks - [video](https://www.youtube.com/watch?v=Vf_-OkqbwPo) * [Tensorflow tutorial](https://www.youtube.com/watch?v=FQ660T4uu7k) - * [Theano tutorial](https://www.youtube.com/watch?v=OU8I1oJ9HhI) - * [Pytorch tutorial](https://www.youtube.com/watch?v=VMcRWYEKmhw) + * [PyTorch tutorial](https://www.youtube.com/watch?v=VMcRWYEKmhw) ## Bonus materials * Karpathy's course on deep learning (english) - http://cs231n.github.io/ @@ -26,21 +24,19 @@ __Note:__ This week's materials cover the basics of neural nets and deep learnin * Deep learning demystified - [video](https://www.youtube.com/watch?v=Q9Z20HCPnww) * Karpathy's lecture on deep learning for computer vision - https://www.youtube.com/watch?v=u6aEYuemt0M * Our humble DL course: [HSE'fall17](https://github.com/yandexdataschool/HSE_deeplearning), [Skoltech/YSDA'spring16](https://github.com/ddtm/dl-course/) courses on deep learning (english). -* Srsly, just google `"deep learning %s"%s for s in what_you_want_to_know`. +* Srsly, just google `"deep learning %s" % s for s in what_you_want_to_know`. + - ### Practice -__[Colab url (pytorch)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week04_%5Brecap%5D_deep_learning/seminar_pytorch.ipynb)__ -From now on, we'll have two tracks: theano and tensorflow. We'll also add pytorch seminars as soon as they're ready. +__[Colab URL (PyTorch)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week04_%5Brecap%5D_deep_learning/seminar_pytorch.ipynb)__ +From now on, we'll have two tracks: Tensorflow and PyTorch. -Please pick seminar_theano.ipynb, seminar_tensorflow.ipynb or seminar_pytorch.ipynb. +Please pick `seminar_tensorflow.ipynb` or `seminar_pytorch.ipynb`. __Note:__ in this and all following weeks you're only required to get through practice in _one_ of the frameworks. Looking into other alternatives is great for self-education but never mandatory. #### What to choose? * The simplest choice is PyTorch: it's basically ye olde numpy with automatic gradients and a lot of pre-implemented DL stuff... except all the functions have different names. * If you want to be familiar with production-related stuff from day 1, choose TensorFlow. It's much more convenient to deploy (to non-python or to mobiles). The catch is that all those conveniences become inconveniences once you want to write something simple in jupyter. -* Theano works like tensorflow but it offers a numpy-compatible interface and comes with built-in graph optimization. The payoff is that theano is not as popular as the first two. It is also not meant as a producton framework so deploying to mobiles may be a problem. * It's not like choosing house at Hogwarts, you'll be able to switch between frameworks easily once you master the underlying principles. - diff --git a/week04_[recap]_deep_learning/mnist.py b/week04_[recap]_deep_learning/mnist.py index e3d79b7db..70d61958e 100644 --- a/week04_[recap]_deep_learning/mnist.py +++ b/week04_[recap]_deep_learning/mnist.py @@ -1,7 +1,5 @@ import sys import os -import time - import numpy as np __doc__ = """taken from https://github.com/Lasagne/Lasagne/blob/master/examples/mnist.py""" diff --git a/week04_[recap]_deep_learning/practice_lasagne.ipynb b/week04_[recap]_deep_learning/practice_lasagne.ipynb deleted file mode 100644 index 3ff11ce71..000000000 --- a/week04_[recap]_deep_learning/practice_lasagne.ipynb +++ /dev/null @@ -1,1304 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Theano, Lasagne\n", - "and why they matter\n", - "\n", - "\n", - "### got no lasagne?\n", - "Install the __bleeding edge__ version from here: http://lasagne.readthedocs.org/en/latest/user/installation.html" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Warming up\n", - "* Implement a function that computes the sum of squares of numbers from 0 to N\n", - "* Use numpy or python\n", - "* An array of numbers 0 to N - numpy.arange(N)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "\n", - "def sum_squares(N):\n", - " return " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "sum_squares(10**8)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# theano teaser\n", - "\n", - "Doing the very same thing" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import theano\n", - "import theano.tensor as T" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "\n", - "# I gonna be function parameter\n", - "N = T.scalar(\"a dimension\", dtype='int32')\n", - "\n", - "\n", - "# i am a recipe on how to produce sum of squares of arange of N given N\n", - "result = (T.arange(N)**2).sum()\n", - "\n", - "# Compiling the recipe of computing \"result\" given N\n", - "sum_function = theano.function(inputs=[N], outputs=result)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "sum_function(10**8)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How does it work?\n", - "* 1 You define inputs f your future function;\n", - "* 2 You write a recipe for some transformation of inputs;\n", - "* 3 You compile it;\n", - "* You have just got a function!\n", - "* The gobbledegooky version: you define a function as symbolic computation graph.\n", - "\n", - "\n", - "* There are two main kinвs of entities: \"Inputs\" and \"Transformations\"\n", - "* Both can be numbers, vectors, matrices, tensors, etc.\n", - "* Both can be integers, floats of booleans (uint8) of various size.\n", - "\n", - "\n", - "* An input is a placeholder for function parameters.\n", - " * N from example above\n", - "\n", - "\n", - "* Transformations are the recipes for computing something given inputs and transformation\n", - " * (T.arange(N)^2).sum() are 3 sequential transformations of N\n", - " * Doubles all functions of numpy vector syntax\n", - " * You can almost always go with replacing \"np.function\" with \"T.function\" aka \"theano.tensor.function\"\n", - " * np.mean -> T.mean\n", - " * np.arange -> T.arange\n", - " * np.cumsum -> T.cumsum\n", - " * and so on.\n", - " * builtin operations also work that way\n", - " * np.arange(10).mean() -> T.arange(10).mean()\n", - " * Once upon a blue moon the functions have different names or locations (e.g. T.extra_ops)\n", - " * Ask us or google it\n", - " \n", - " \n", - "Still confused? We gonna fix that." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Inputs\n", - "example_input_integer = T.scalar(\"scalar input\", dtype='float32')\n", - "\n", - "# dtype = theano.config.floatX by default\n", - "example_input_tensor = T.tensor4(\"four dimensional tensor input\")\n", - "# не бойся, тензор нам не пригодится\n", - "\n", - "\n", - "input_vector = T.vector(\"my vector\", dtype='int32') # vector of integers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Transformations\n", - "\n", - "# transofrmation: elementwise multiplication\n", - "double_the_vector = input_vector*2\n", - "\n", - "# elementwise cosine\n", - "elementwise_cosine = T.cos(input_vector)\n", - "\n", - "# difference between squared vector and vector itself\n", - "vector_squares = input_vector**2 - input_vector" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Practice time:\n", - "# create two vectors of size float32\n", - "my_vector = student.init_float32_vector()\n", - "my_vector2 = student.init_one_more_such_vector()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Write a transformation(recipe):\n", - "#(vec1)*(vec2) / (sin(vec1) +1)\n", - "my_transformation = student.implementwhatwaswrittenabove()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(my_transformation)\n", - "# it's okay it aint a number" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# What's inside the transformation\n", - "theano.printing.debugprint(my_transformation)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Compiling\n", - "* So far we were using \"symbolic\" variables and transformations\n", - " * Defining the recipe for computation, but not computing anything\n", - "* To use the recipe, one should compile it" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "inputs = [ ]\n", - "outputs = [ ]\n", - "\n", - "# The next lines compile a function that takes two vectors and computes your transformation\n", - "my_function = theano.function(\n", - " inputs, outputs,\n", - " # automatic type casting for input parameters (e.g. float64 -> float32)\n", - " allow_input_downcast=True\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# using function with, lists:\n", - "print \"using python lists:\"\n", - "print my_function([1, 2, 3], [4, 5, 6])\n", - "print\n", - "\n", - "# Or using numpy arrays:\n", - "# btw, that 'float' dtype is casted to secong parameter dtype which is float32\n", - "print \"using numpy arrays:\"\n", - "print my_function(np.arange(10),\n", - " np.linspace(5, 6, 10, dtype='float'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Debugging\n", - "* Compilation can take a while for big functions\n", - "* To avoid waiting, one can evaluate transformations without compiling\n", - "* Without compilation, the code runs slower, so consider reducing input size\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# a dictionary of inputs\n", - "my_function_inputs = {\n", - " my_vector: [1, 2, 3],\n", - " my_vector2: [4, 5, 6]\n", - "}\n", - "\n", - "# evaluate my_transformation\n", - "# has to match with compiled function output\n", - "print my_transformation.eval(my_function_inputs)\n", - "\n", - "\n", - "# can compute transformations on the fly\n", - "print(\"add 2 vectors\", (my_vector + my_vector2).eval(my_function_inputs))\n", - "\n", - "#!WARNING! if your transformation only depends on some inputs,\n", - "# do not provide the rest of them\n", - "print(\"vector's shape:\", my_vector.shape.eval({\n", - " my_vector: [1, 2, 3]\n", - "}))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* When debugging, it's usually a good idea to reduce the scale of your computation. E.g. if you train on batches of 128 objects, debug on 2-3.\n", - "* If it's imperative that you run a large batch of data, consider compiling with mode='debug' instead" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Your turn: Mean Squared Error (2 pts)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Quest #1 - implement a function that computes a mean squared error of two input vectors\n", - "# Your function has to take 2 vectors and return a single number\n", - "\n", - "\n", - "\n", - "compute_mse = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Tests\n", - "from sklearn.metrics import mean_squared_error\n", - "\n", - "for n in [1, 5, 10, 10**3]:\n", - "\n", - " elems = [np.arange(n), np.arange(n, 0, -1), np.zeros(n),\n", - " np.ones(n), np.random.random(n), np.random.randint(100, size=n)]\n", - "\n", - " for el in elems:\n", - " for el_2 in elems:\n", - " true_mse = np.array(mean_squared_error(el, el_2))\n", - " my_mse = compute_mse(el, el_2)\n", - " if not np.allclose(true_mse, my_mse):\n", - " print('Wrong result:')\n", - " print('mse(%s,%s)' % (el, el_2))\n", - " print(\"should be: %f, but your function returned %f\" %\n", - " (true_mse, my_mse))\n", - " raise ValueError(\"Что-то не так\")\n", - "\n", - "print(\"All tests passed\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Shared variables\n", - "\n", - "* The inputs and transformations only exist when function is called\n", - "\n", - "* Shared variables always stay in memory like global variables\n", - " * Shared variables can be included into a symbolic graph\n", - " * They can be set and evaluated using special methods\n", - " * but they can't change value arbitrarily during symbolic graph computation\n", - " * we'll cover that later;\n", - " \n", - " \n", - "* Hint: such variables are a perfect place to store network parameters\n", - " * e.g. weights or some metadata" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# creating shared variable\n", - "shared_vector_1 = theano.shared(np.ones(10, dtype='float64'))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# evaluating shared variable (outside symbolicd graph)\n", - "print(\"initial value\", shared_vector_1.get_value())\n", - "\n", - "# within symbolic graph you use them just as any other inout or transformation, not \"get value\" needed" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# setting new value\n", - "shared_vector_1.set_value(np.arange(5))\n", - "\n", - "# getting that new value\n", - "print(\"new value\", shared_vector_1.get_value())\n", - "\n", - "# Note that the vector changed shape\n", - "# This is entirely allowed... unless your graph is hard-wired to work with some fixed shape" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Your turn" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Write a recipe (transformation) that computes an elementwise transformation of shared_vector and input_scalar\n", - "# Compile as a function of input_scalar\n", - "\n", - "input_scalar = T.scalar('coefficient', dtype='float32')\n", - "\n", - "scalar_times_shared = \n", - "\n", - "\n", - "shared_times_n = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print \"shared:\", shared_vector_1.get_value()\n", - "\n", - "print \"shared_times_n(5)\", shared_times_n(5)\n", - "\n", - "print \"shared_times_n(-0.5)\", shared_times_n(-0.5)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Changing value of vector 1 (output should change)\n", - "shared_vector_1.set_value([-1, 0, 1])\n", - "print \"shared:\", shared_vector_1.get_value()\n", - "\n", - "print \"shared_times_n(5)\", shared_times_n(5)\n", - "\n", - "print \"shared_times_n(-0.5)\", shared_times_n(-0.5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T.grad - why theano matters\n", - "* Theano can compute derivatives and gradients automatically\n", - "* Derivatives are computed symbolically, not numerically\n", - "\n", - "Limitations:\n", - "* You can only compute a gradient of a __scalar__ transformation over one or several scalar or vector (or tensor) transformations or inputs.\n", - "* A transformation has to have float32 or float64 dtype throughout the whole computation graph\n", - " * derivative over an integer has no mathematical sense\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "my_scalar = T.scalar(name='input', dtype='float64')\n", - "\n", - "scalar_squared = T.sum(my_scalar**2)\n", - "\n", - "# a derivative of v_squared by my_vector\n", - "derivative = T.grad(scalar_squared, my_scalar)\n", - "\n", - "fun = theano.function([my_scalar], scalar_squared)\n", - "grad = theano.function([my_scalar], derivative)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "\n", - "\n", - "x = np.linspace(-3, 3)\n", - "x_squared = list(map(fun, x))\n", - "x_squared_der = list(map(grad, x))\n", - "\n", - "plt.plot(x, x_squared, label=\"x^2\")\n", - "plt.plot(x, x_squared_der, label=\"derivative\")\n", - "plt.legend()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Why that rocks" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "my_vector = T.vector('float64')\n", - "\n", - "# Compute the gradient of the next weird function over my_scalar and my_vector\n", - "# warning! Trying to understand the meaning of that function may result in permanent brain damage\n", - "\n", - "weird_psychotic_function = ((my_vector+my_scalar)**(1+T.var(my_vector)) + 1./T.arcsinh(my_scalar)).mean()/(my_scalar**2 + 1) + 0.01*T.sin(2*my_scalar**1.5)*(\n", - " T.sum(my_vector) * my_scalar**2)*T.exp((my_scalar-4)**2)/(1+T.exp((my_scalar-4)**2))*(1.-(T.exp(-(my_scalar-4)**2))/(1+T.exp(-(my_scalar-4)**2)))**2\n", - "\n", - "\n", - "der_by_scalar, der_by_vector = \n", - "\n", - "\n", - "compute_weird_function = theano.function(\n", - " [my_scalar, my_vector], weird_psychotic_function)\n", - "compute_der_by_scalar = theano.function([my_scalar, my_vector], der_by_scalar)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Plotting your derivative\n", - "vector_0 = [1, 2, 3]\n", - "\n", - "scalar_space = np.linspace(0, 7)\n", - "\n", - "y = [compute_weird_function(x, vector_0) for x in scalar_space]\n", - "plt.plot(scalar_space, y, label='function')\n", - "y_der_by_scalar = [compute_der_by_scalar(x, vector_0) for x in scalar_space]\n", - "plt.plot(scalar_space, y_der_by_scalar, label='derivative')\n", - "plt.grid()\n", - "plt.legend()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Almost done - Updates\n", - "\n", - "* updates are a way of changing shared variables at after function call.\n", - "\n", - "* technically it's a dictionary {shared_variable : a recipe for new value} which is has to be provided when function is compiled\n", - "\n", - "That's how it works:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Multiply shared vector by a number and save the product back into shared vector\n", - "\n", - "inputs = [input_scalar]\n", - "outputs = [scalar_times_shared] # return vector times scalar\n", - "\n", - "my_updates = {\n", - " # and write this same result bach into shared_vector_1\n", - " shared_vector_1: scalar_times_shared\n", - "}\n", - "\n", - "compute_and_save = theano.function(inputs, outputs, updates=my_updates)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "shared_vector_1.set_value(np.arange(5))\n", - "\n", - "# initial shared_vector_1\n", - "print(\"initial shared value:\", shared_vector_1.get_value())\n", - "\n", - "# evaluating the function (shared_vector_1 will be changed)\n", - "print(\"compute_and_save(2) returns\", compute_and_save(2))\n", - "\n", - "# evaluate new shared_vector_1\n", - "print(\"new shared value:\", shared_vector_1.get_value())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Logistic regression example (4 pts)\n", - "\n", - "Implement the regular logistic regression training algorithm\n", - "\n", - "Tips:\n", - "* Weights fit in as a shared variable\n", - "* X and y are potential inputs\n", - "* Compile 2 functions:\n", - " * train_function(X,y) - returns error and computes weights' new values __(through updates)__\n", - " * predict_fun(X) - just computes probabilities (\"y\") given data\n", - " \n", - " \n", - "We shall train on a two-class MNIST dataset\n", - "* please note that target y are {0,1} and not {-1,1} as in some formulae" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.datasets import load_digits\n", - "mnist = load_digits(2)\n", - "\n", - "X, y = mnist.data, mnist.target\n", - "\n", - "\n", - "print(\"y [shape - %s]:\" % (str(y.shape)), y[:10])\n", - "\n", - "print(\"X [shape - %s]:\" % (str(X.shape)))\n", - "print(X[:3])\n", - "print(y[:10])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# inputs and shareds\n", - "shared_weights = \n", - "input_y = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "predicted_y = \n", - "\n", - "\n", - "loss = \n", - "\n", - "\n", - "grad = \n", - "\n", - "\n", - "updates = {\n", - " shared_weights: \n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "train_function = \n", - "\n", - "predict_function = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.cross_validation import train_test_split\n", - "X_train, X_test, y_train, y_test = train_test_split(X, y)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.metrics import roc_auc_score\n", - "\n", - "for i in range(5):\n", - " loss_i = train_function(X_train, y_train)\n", - " print(\"loss at iter %i:%.4f\" % (i, loss_i))\n", - " print(\"train auc:\", roc_auc_score(y_train, predict_function(X_train)))\n", - " print(\"test auc:\", roc_auc_score(y_test, predict_function(X_test)))\n", - "\n", - "\n", - "print(\"resulting weights:\")\n", - "plt.imshow(shared_weights.get_value().reshape(8, -1))\n", - "plt.colorbar()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# lasagne\n", - "* lasagne is a library for neural network building and training\n", - "* it's a low-level library with almost seamless integration with theano\n", - "\n", - "For a demo we shall solve the same digit recognition problem, but at a different scale\n", - "* images are now 28x28\n", - "* 10 different digits\n", - "* 50k samples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from mnist import load_dataset\n", - "X_train, y_train, X_val, y_val, X_test, y_test = load_dataset()\n", - "\n", - "print X_train.shape, y_train.shape" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import lasagne\n", - "\n", - "input_X = T.tensor4(\"X\")\n", - "\n", - "# input dimention (None means \"Arbitrary\" and only works at the first axes [samples])\n", - "input_shape = [None, 1, 28, 28]\n", - "\n", - "target_y = T.vector(\"target Y integer\", dtype='int32')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Defining network architecture" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Input layer (auxilary)\n", - "input_layer = lasagne.layers.InputLayer(shape=input_shape, input_var=input_X)\n", - "\n", - "# fully connected layer, that takes input layer and applies 50 neurons to it.\n", - "# nonlinearity here is sigmoid as in logistic regression\n", - "# you can give a name to each layer (optional)\n", - "dense_1 = lasagne.layers.DenseLayer(input_layer, num_units=50,\n", - " nonlinearity=lasagne.nonlinearities.sigmoid,\n", - " name=\"hidden_dense_layer\")\n", - "\n", - "# fully connected output layer that takes dense_1 as input and has 10 neurons (1 for each digit)\n", - "# We use softmax nonlinearity to make probabilities add up to 1\n", - "dense_output = lasagne.layers.DenseLayer(dense_1, num_units=10,\n", - " nonlinearity=lasagne.nonlinearities.softmax,\n", - " name='output')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# network prediction (theano-transformation)\n", - "y_predicted = lasagne.layers.get_output(dense_output)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# all network weights (shared variables)\n", - "all_weights = lasagne.layers.get_all_params(dense_output)\n", - "print(all_weights)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Than you could simply\n", - "* define loss function manually\n", - "* compute error gradient over all weights\n", - "* define updates\n", - "* But that's a whole lot of work and life's short\n", - " * not to mention life's too short to wait for SGD to converge\n", - "\n", - "Instead, we shall use Lasagne builtins" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Mean categorical crossentropy as a loss function - similar to logistic loss but for multiclass targets\n", - "loss = lasagne.objectives.categorical_crossentropy(\n", - " y_predicted, target_y).mean()\n", - "\n", - "# prediction accuracy\n", - "accuracy = lasagne.objectives.categorical_accuracy(\n", - " y_predicted, target_y).mean()\n", - "\n", - "# This function computes gradient AND composes weight updates just like you did earlier\n", - "updates_sgd = lasagne.updates.sgd(loss, all_weights, learning_rate=0.01)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# function that computes loss and updates weights\n", - "train_fun = theano.function(\n", - " [input_X, target_y], [loss, accuracy], updates=updates_sgd)\n", - "\n", - "# function that just computes accuracy\n", - "accuracy_fun = theano.function([input_X, target_y], accuracy)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### That's all, now let's train it!\n", - "* We got a lot of data, so it's recommended that you use SGD\n", - "* So let's implement a function that splits the training sample into minibatches" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# An auxilary function that returns mini-batches for neural network training\n", - "\n", - "# Parameters\n", - "# X - a tensor of images with shape (many, 1, 28, 28), e.g. X_train\n", - "# y - a vector of answers for corresponding images e.g. Y_train\n", - "# batch_size - a single number - the intended size of each batches\n", - "\n", - "# What do need to implement\n", - "# 1) Shuffle data\n", - "# - Gotta shuffle X and y the same way not to break the correspondence between X_i and y_i\n", - "# 3) Split data into minibatches of batch_size\n", - "# - If data size is not a multiple of batch_size, make one last batch smaller.\n", - "# 4) return a list (or an iterator) of pairs\n", - "# - (подгруппа картинок, ответы из y на эту подгруппу)\n", - "\n", - "\n", - "def iterate_minibatches(X, y, batchsize):\n", - "\n", - " \n", - "\n", - "\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# You feel lost and wish you stayed home tonight?\n", - "# Go search for a similar function at\n", - "# https://github.com/Lasagne/Lasagne/blob/master/examples/mnist.py" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Training loop" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "\n", - "num_epochs = 100 # amount of passes through the data\n", - "\n", - "batch_size = 50 # number of samples processed at each function call\n", - "\n", - "for epoch in range(num_epochs):\n", - " # In each epoch, we do a full pass over the training data:\n", - " train_err = 0\n", - " train_acc = 0\n", - " train_batches = 0\n", - " start_time = time.time()\n", - " for batch in iterate_minibatches(X_train, y_train, batch_size):\n", - " inputs, targets = batch\n", - " train_err_batch, train_acc_batch = train_fun(inputs, targets)\n", - " train_err += train_err_batch\n", - " train_acc += train_acc_batch\n", - " train_batches += 1\n", - "\n", - " # And a full pass over the validation data:\n", - " val_acc = 0\n", - " val_batches = 0\n", - " for batch in iterate_minibatches(X_val, y_val, batch_size):\n", - " inputs, targets = batch\n", - " val_acc += accuracy_fun(inputs, targets)\n", - " val_batches += 1\n", - "\n", - " # Then we print the results for this epoch:\n", - " print(\"Epoch {} of {} took {:.3f}s\".format(\n", - " epoch + 1, num_epochs, time.time() - start_time))\n", - "\n", - " print(\n", - " \" training loss (in-iteration):\\t\\t{:.6f}\".format(train_err / train_batches))\n", - " print(\" train accuracy:\\t\\t{:.2f} %\".format(\n", - " train_acc / train_batches * 100))\n", - " print(\" validation accuracy:\\t\\t{:.2f} %\".format(\n", - " val_acc / val_batches * 100))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "test_acc = 0\n", - "test_batches = 0\n", - "for batch in iterate_minibatches(X_test, y_test, 500):\n", - " inputs, targets = batch\n", - " acc = accuracy_fun(inputs, targets)\n", - " test_acc += acc\n", - " test_batches += 1\n", - "print(\"Final results:\")\n", - "print(\" test accuracy:\\t\\t{:.2f} %\".format(\n", - " test_acc / test_batches * 100))\n", - "\n", - "if test_acc / test_batches * 100 > 99:\n", - " print(\"Achievement unlocked: 80lvl Warlock!\")\n", - "else:\n", - " print(\"We need more magic!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# A better network ( 4+ pts )\n", - "\n", - "\n", - "* The quest is to create a network that gets at least 99% at test set\n", - " * In case you tried several architectures and have a __detailed__ report - 97.5% \"is fine too\". \n", - " * __+1 bonus point__ each 0.1% past 99%\n", - " * More points for creative approach\n", - " \n", - "__ There is a mini-report at the end that you will have to fill in. We recommend to read it first and fill in while you are iterating. __\n", - " \n", - "\n", - "## Tips on what can be done:\n", - "\n", - "\n", - "\n", - " * Network size\n", - " * MOAR neurons, \n", - " * MOAR layers, \n", - " * Convolutions are almost imperative\n", - " * Пх'нглуи мглв'нафх Ктулху Р'льех вгах'нагл фхтагн! \n", - " \n", - " \n", - " \n", - " * Regularize to prevent overfitting\n", - " * Add some L2 weight norm to the loss function, theano will do the rest\n", - " * Can be done manually or via - http://lasagne.readthedocs.org/en/latest/modules/regularization.html\n", - " \n", - " \n", - " \n", - " * Better optimization - rmsprop, nesterov_momentum, adadelta, adagrad and so on.\n", - " * Converge faster and sometimes reach better optima\n", - " * It might make sense to tweak learning rate, other learning parameters, batch size and number of epochs\n", - " \n", - " \n", - " \n", - " * Dropout - to prevent overfitting\n", - " * `lasagne.layers.DropoutLayer(prev_layer, p=probability_to_zero_out)`\n", - " \n", - " \n", - " \n", - " * Convolution layers\n", - " * `network = lasagne.layers.Conv2DLayer(prev_layer,`\n", - " ` num_filters = n_neurons,`\n", - " ` filter_size = (filter width, filter height),`\n", - " ` nonlinearity = some_nonlinearity)`\n", - " * Warning! Training convolutional networks can take long without GPU.\n", - " * If you are CPU-only, we still recomment to try a simple convolutional architecture\n", - " * a perfect option is if you can set it up to run at nighttime and check it up at the morning.\n", - " \n", - " * Plenty other layers and architectures\n", - " * http://lasagne.readthedocs.org/en/latest/modules/layers.html\n", - " * batch normalization, pooling, etc\n", - " \n", - " \n", - " * Nonlinearities in the hidden layers\n", - " * tanh, relu, leaky relu, etc\n", - " \n", - " \n", - " \n", - " \n", - "There is a template for your solution below that you can opt to use or throw away and write it your way" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from mnist import load_dataset\n", - "X_train, y_train, X_val, y_val, X_test, y_test = load_dataset()\n", - "\n", - "print X_train.shape, y_train.shape" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import lasagne\n", - "\n", - "input_X = T.tensor4(\"X\")\n", - "\n", - "# input dimention (None means \"Arbitrary\" and only works at the first axes [samples])\n", - "input_shape = [None, 1, 28, 28]\n", - "\n", - "target_y = T.vector(\"target Y integer\", dtype='int32')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Input layer (auxilary)\n", - "input_layer = lasagne.layers.InputLayer(shape=input_shape, input_var=input_X)\n", - "\n", - "\n", - "\n", - "dense_output = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Network predictions (theano-transformation)\n", - "y_predicted = lasagne.layers.get_output(dense_output)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# All weights (shared-varaibles)\n", - "# \"trainable\" flag means not to return auxilary params like batch mean (for batch normalization)\n", - "all_weights = lasagne.layers.get_all_params(dense_output, trainable=True)\n", - "print(all_weights)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# loss function\n", - "loss = \n", - "\n", - "# \n", - "\n", - "accuracy = \n", - "\n", - "# weight updates\n", - "updates = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# A function that accepts X and y, returns loss functions and performs weight updates\n", - "train_fun = theano.function(\n", - " [input_X, target_y], [loss, accuracy], updates=updates_sgd)\n", - "\n", - "# A function that just computes accuracy given X and y\n", - "accuracy_fun = theano.function([input_X, target_y], accuracy)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# итерации обучения\n", - "\n", - "num_epochs = \n", - "\n", - "batch_size = \n", - "\n", - "for epoch in range(num_epochs):\n", - " # In each epoch, we do a full pass over the training data:\n", - " train_err = 0\n", - " train_acc = 0\n", - " train_batches = 0\n", - " start_time = time.time()\n", - " for batch in iterate_minibatches(X_train, y_train, batch_size):\n", - " inputs, targets = batch\n", - " train_err_batch, train_acc_batch = train_fun(inputs, targets)\n", - " train_err += train_err_batch\n", - " train_acc += train_acc_batch\n", - " train_batches += 1\n", - "\n", - " # And a full pass over the validation data:\n", - " val_acc = 0\n", - " val_batches = 0\n", - " for batch in iterate_minibatches(X_val, y_val, batch_size):\n", - " inputs, targets = batch\n", - " val_acc += accuracy_fun(inputs, targets)\n", - " val_batches += 1\n", - "\n", - " # Then we print the results for this epoch:\n", - " print(\"Epoch {} of {} took {:.3f}s\".format(\n", - " epoch + 1, num_epochs, time.time() - start_time))\n", - "\n", - " print(\n", - " \" training loss (in-iteration):\\t\\t{:.6f}\".format(train_err / train_batches))\n", - " print(\" train accuracy:\\t\\t{:.2f} %\".format(\n", - " train_acc / train_batches * 100))\n", - " print(\" validation accuracy:\\t\\t{:.2f} %\".format(\n", - " val_acc / val_batches * 100))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "test_acc = 0\n", - "test_batches = 0\n", - "for batch in iterate_minibatches(X_test, y_test, 500):\n", - " inputs, targets = batch\n", - " acc = accuracy_fun(inputs, targets)\n", - " test_acc += acc\n", - " test_batches += 1\n", - "print(\"Final results:\")\n", - "print(\" test accuracy:\\t\\t{:.2f} %\".format(\n", - " test_acc / test_batches * 100))\n", - "\n", - "if test_acc / test_batches * 100 > 99:\n", - " print(\"Achievement unlocked: 80lvl Warlock!\")\n", - "else:\n", - " print(\"We need more magic!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Report\n", - "\n", - "All creative approaches are highly welcome, but at the very least it would be great to mention\n", - "* the idea;\n", - "* brief history of tweaks and improvements;\n", - "* what is the final architecture and why?\n", - "* what is the training method and, again, why?\n", - "* Any regularizations and other techniques applied and their effects;\n", - "\n", - "\n", - "There is no need to write strict mathematical proofs (unless you want to).\n", - " * \"I tried this, this and this, and the second one turned out to be better. And i just didn't like the name of that one\" - OK, but can be better\n", - " * \"I have analized these and these articles|sources|blog posts, tried that and that to adapt them to my problem and the conclusions are such and such\" - the ideal one\n", - " * \"I took that code that demo without understanding it, but i'll never confess that and instead i'll make up some pseudoscientific explaination\" - __not_ok__" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Hi, my name is `___ ___`, and here's my story\n", - "\n", - "A long ago in a galaxy far far away, when it was still more than an hour before deadline, i got an idea:\n", - "\n", - "##### I gonna build a neural network, that\n", - "* brief text on what was\n", - "* the original idea\n", - "* and why it was so\n", - "\n", - "How could i be so naive?!\n", - "\n", - "##### One day, with no signs of warning,\n", - "This thing has finally converged and\n", - "* Some explaination about what were the results,\n", - "* what worked and what didn't\n", - "* most importantly - what next steps were taken, if any\n", - "* and what were their respective outcomes\n", - "\n", - "##### Finally, after __ iterations, __ mugs of [tea/coffee]\n", - "* what was the final architecture\n", - "* as well as training method and tricks\n", - "\n", - "That, having wasted ____ [minutes, hours or days] of my life training, got\n", - "\n", - "* accuracy on training: __\n", - "* accuracy on validation: __\n", - "* accuracy on test: __\n", - "\n", - "\n", - "[an optional afterword and mortal curses on assignment authors]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/week04_[recap]_deep_learning/seminar_pytorch.ipynb b/week04_[recap]_deep_learning/seminar_pytorch.ipynb index e10863802..d2ec82ade 100644 --- a/week04_[recap]_deep_learning/seminar_pytorch.ipynb +++ b/week04_[recap]_deep_learning/seminar_pytorch.ipynb @@ -8,9 +8,9 @@ "\n", "![img](https://pytorch.org/tutorials/_static/pytorch-logo-dark.svg)\n", "\n", - "__This notebook__ will teach you to use PyTorch low-level core. You can install it [here](http://pytorch.org/). For high-level interface see the next notebook.\n", + "__This notebook__ will teach you to use PyTorch low-level core. If you're running this notebook outside the course environment, you can install it [here](https://pytorch.org).\n", "\n", - "__PyTorch feels__ differently than tensorflow/theano on almost every level. TensorFlow makes your code live in two \"worlds\" simultaneously: symbolic graphs and actual tensors. First you declare a symbolic \"recipe\" of how to get from inputs to outputs, then feed it with actual minibatches of data. In PyTorch, __there's only one world__: all tensors have a numeric value.\n", + "__PyTorch feels__ differently than Tensorflow on almost every level. TensorFlow makes your code live in two \"worlds\" simultaneously: symbolic graphs and actual tensors. First you declare a symbolic \"recipe\" of how to get from inputs to outputs, then feed it with actual minibatches of data. In PyTorch, __there's only one world__: all tensors have a numeric value.\n", "\n", "You compute outputs on the fly without pre-declaring anything. The code looks exactly as in pure numpy with one exception: PyTorch computes gradients for you. And can run stuff on GPU. And has a number of pre-implemented building blocks for your neural nets. [And a few more things.](https://medium.com/towards-data-science/pytorch-vs-tensorflow-spotting-the-difference-25c75777377b)\n", "\n", @@ -25,8 +25,7 @@ "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week04_%5Brecap%5D_deep_learning/notmnist.py\n", - "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_%5Brecap%5D_deep_learning/notmnist.py\n", " !touch .setup_complete" ] }, @@ -58,30 +57,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "X :\n", + "X:\n", "[[ 0 1 2 3]\n", " [ 4 5 6 7]\n", " [ 8 9 10 11]\n", " [12 13 14 15]]\n", "\n", - "X.shape : (4, 4)\n", + "X.shape: (4, 4)\n", "\n", - "add 5 :\n", + "add 5:\n", "[[ 5 6 7 8]\n", " [ 9 10 11 12]\n", " [13 14 15 16]\n", " [17 18 19 20]]\n", "\n", - "X*X^T :\n", + "X*X^T:\n", "[[ 14 38 62 86]\n", " [ 38 126 214 302]\n", " [ 62 214 366 518]\n", " [ 86 302 518 734]]\n", "\n", - "mean over cols :\n", + "mean over rows:\n", "[ 1.5 5.5 9.5 13.5]\n", "\n", - "cumsum of cols :\n", + "cumsum of cols:\n", "[[ 0 1 2 3]\n", " [ 4 6 8 10]\n", " [12 15 18 21]\n", @@ -95,12 +94,12 @@ "\n", "x = np.arange(16).reshape(4, 4)\n", "\n", - "print(\"X :\\n%s\\n\" % x)\n", - "print(\"X.shape : %s\\n\" % (x.shape,))\n", - "print(\"add 5 :\\n%s\\n\" % (x + 5))\n", - "print(\"X*X^T :\\n%s\\n\" % np.dot(x, x.T))\n", - "print(\"mean over cols :\\n%s\\n\" % (x.mean(axis=-1)))\n", - "print(\"cumsum of cols :\\n%s\\n\" % (np.cumsum(x, axis=0)))" + "print(\"X:\\n%s\\n\" % x)\n", + "print(\"X.shape: %s\\n\" % (x.shape,))\n", + "print(\"add 5:\\n%s\\n\" % (x + 5))\n", + "print(\"X*X^T:\\n%s\\n\" % np.dot(x, x.T))\n", + "print(\"mean over rows:\\n%s\\n\" % (x.mean(axis=-1)))\n", + "print(\"cumsum of cols:\\n%s\\n\" % (np.cumsum(x, axis=0)))" ] }, { @@ -112,26 +111,26 @@ "name": "stdout", "output_type": "stream", "text": [ - "X :\n", + "X:\n", "tensor([[ 0., 1., 2., 3.],\n", " [ 4., 5., 6., 7.],\n", " [ 8., 9., 10., 11.],\n", " [12., 13., 14., 15.]])\n", - "X.shape : torch.Size([4, 4])\n", + "X.shape: torch.Size([4, 4])\n", "\n", - "add 5 :\n", + "add 5:\n", "tensor([[ 5., 6., 7., 8.],\n", " [ 9., 10., 11., 12.],\n", " [13., 14., 15., 16.],\n", " [17., 18., 19., 20.]])\n", - "X*X^T :\n", + "X*X^T:\n", "tensor([[ 14., 38., 62., 86.],\n", " [ 38., 126., 214., 302.],\n", " [ 62., 214., 366., 518.],\n", " [ 86., 302., 518., 734.]])\n", - "mean over cols :\n", + "mean over rows:\n", "tensor([ 1.5000, 5.5000, 9.5000, 13.5000])\n", - "cumsum of cols :\n", + "cumsum of cols:\n", "tensor([[ 0., 1., 2., 3.],\n", " [ 4., 6., 8., 10.],\n", " [12., 15., 18., 21.],\n", @@ -144,14 +143,14 @@ "\n", "x = np.arange(16).reshape(4, 4)\n", "\n", - "x = torch.tensor(x, dtype=torch.float32) # or torch.arange(0,16).view(4,4)\n", + "x = torch.tensor(x, dtype=torch.float32) # or torch.arange(0, 16).view(4, 4)\n", "\n", - "print(\"X :\\n%s\" % x)\n", - "print(\"X.shape : %s\\n\" % (x.shape,))\n", - "print(\"add 5 :\\n%s\" % (x + 5))\n", - "print(\"X*X^T :\\n%s\" % torch.matmul(x, x.transpose(1, 0))) # short: x.mm(x.t())\n", - "print(\"mean over cols :\\n%s\" % torch.mean(x, dim=-1))\n", - "print(\"cumsum of cols :\\n%s\" % torch.cumsum(x, dim=0))" + "print(\"X:\\n%s\" % x)\n", + "print(\"X.shape: %s\\n\" % (x.shape,))\n", + "print(\"add 5:\\n%s\" % (x + 5))\n", + "print(\"X*X^T:\\n%s\" % torch.matmul(x, x.transpose(1, 0))) # short: x.mm(x.t())\n", + "print(\"mean over rows:\\n%s\" % torch.mean(x, dim=-1))\n", + "print(\"cumsum of cols:\\n%s\" % torch.cumsum(x, dim=0))" ] }, { @@ -160,25 +159,25 @@ "source": [ "## NumPy and PyTorch\n", "\n", - "As you can notice, PyTorch allows you to hack stuff much the same way you did with numpy. No graph declaration, no placeholders, no sessions. This means that you can _see the numeric value of any tensor at any moment of time_. Debugging such code can be done with by printing tensors or using any debug tool you want (e.g. [gdb](https://wiki.python.org/moin/DebuggingWithGdb)).\n", + "As you can notice, PyTorch allows you to hack stuff much the same way you did with NumPy. No graph declaration, no placeholders, no sessions. This means that you can _see the numeric value of any tensor at any moment of time_. Debugging such code can be done with by printing tensors or using any debug tool you want (e.g. [PyCharm debugger](https://www.jetbrains.com/help/pycharm/part-1-debugging-python-code.html) or [gdb](https://wiki.python.org/moin/DebuggingWithGdb)).\n", "\n", - "You could also notice the a few new method names and a different API. So no, there's no compatibility with numpy [yet](https://github.com/pytorch/pytorch/issues/2228) and yes, you'll have to memorize all the names again. Get excited!\n", + "You could also notice the a few new method names and a different API. So no, there's no compatibility with NumPy [yet](https://github.com/pytorch/pytorch/issues/2228) and yes, you'll have to memorize all the names again. Get excited!\n", "\n", "![img](http://i0.kym-cdn.com/entries/icons/original/000/017/886/download.jpg)\n", "\n", - "For example, \n", - "* If something takes a list/tuple of axes in numpy, you can expect it to take *args in PyTorch\n", + "For example,\n", + "* If something takes a list/tuple of axes in NumPy, you can expect it to take `*args` in PyTorch\n", " * `x.reshape([1,2,8]) -> x.view(1,2,8)`\n", - "* You should swap _axis_ for _dim_ in operations like mean or cumsum\n", + "* You should swap `axis` for `dim` in operations like `mean` or `cumsum`\n", " * `x.sum(axis=-1) -> x.sum(dim=-1)`\n", - "* most mathematical operations are the same, but types an shaping is different\n", + "* Most mathematical operations are the same, but types an shaping is different\n", " * `x.astype('int64') -> x.type(torch.LongTensor)`\n", "\n", - "To help you acclimatize, there's a [table](https://github.com/torch/torch7/wiki/Torch-for-Numpy-users) covering most new things. There's also a neat [documentation page](http://pytorch.org/docs/master/).\n", + "To help you acclimatize, there's a [table](https://github.com/torch/torch7/wiki/Torch-for-NumPy-users) covering most new things. There's also a neat [documentation page](http://pytorch.org/docs/master/).\n", "\n", - "Finally, if you're stuck with a technical problem, we recommend searching [PyTorch forumns](https://discuss.pytorch.org/). Or just googling, which usually works just as efficiently. \n", + "Finally, if you're stuck with a technical problem, we recommend searching [PyTorch forums](https://discuss.pytorch.org/). Or just googling, which usually works just as efficiently.\n", "\n", - "If you feel like you almost give up, remember two things: __GPU__ an __free gradients__. Besides you can always jump back to numpy with x.numpy()" + "If you feel like you almost give up, remember two things: __GPU__ and __free gradients__. Besides you can always jump back to NumPy with `x.numpy()`." ] }, { @@ -190,8 +189,8 @@ "\n", "There are some simple mathematical functions with cool plots. For one, consider this:\n", "\n", - "$$ x(t) = t - 1.5 * cos( 15 t) $$\n", - "$$ y(t) = t - 1.5 * sin( 16 t) $$\n" + "$$ x(t) = t - 1.5 * cos(15 t) $$\n", + "$$ y(t) = t - 1.5 * sin(16 t) $$" ] }, { @@ -216,48 +215,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "if you're done early, try adjusting the formula and seing how it affects the function" + "If you're done early, try adjusting the formula and seeing how it affects the function." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n" + "---" ] }, { @@ -270,13 +235,13 @@ "\n", "The general pipeline looks like this:\n", "* When creating a tensor, you mark it as `requires_grad`:\n", - " * __```torch.zeros(5, requires_grad=True)```__\n", - " * torch.tensor(np.arange(5), dtype=torch.float32, requires_grad=True)\n", + " * `torch.zeros(5, requires_grad=True)`\n", + " * `torch.tensor(np.arange(5), dtype=torch.float32, requires_grad=True)`\n", "* Define some differentiable `loss = arbitrary_function(a)`\n", "* Call `loss.backward()`\n", - "* Gradients are now available as ```a.grads```\n", + "* Gradients are now available as ```a.grad```\n", "\n", - "__Here's an example:__ let's fit a linear regression on Boston house prices" + "__Here's an example:__ let's fit a linear regression on Boston house prices." ] }, { @@ -319,7 +284,6 @@ "metadata": {}, "outputs": [], "source": [ - "from torch.autograd import Variable\n", "w = torch.zeros(1, requires_grad=True)\n", "b = torch.zeros(1, requires_grad=True)\n", "\n", @@ -336,7 +300,7 @@ "y_pred = w * x + b\n", "loss = torch.mean((y_pred - y)**2)\n", "\n", - "# propagete gradients\n", + "# propagate gradients\n", "loss.backward()" ] }, @@ -404,7 +368,6 @@ "from IPython.display import clear_output\n", "\n", "for i in range(100):\n", - "\n", " y_pred = w * x + b\n", " loss = torch.mean((y_pred - y)**2)\n", " loss.backward()\n", @@ -417,15 +380,14 @@ " b.grad.data.zero_()\n", "\n", " # the rest of code is just bells and whistles\n", - " if (i+1) % 5 == 0:\n", + " if (i + 1) % 5 == 0:\n", " clear_output(True)\n", - " plt.scatter(x.data.numpy(), y.data.numpy())\n", - " plt.scatter(x.data.numpy(), y_pred.data.numpy(),\n", - " color='orange', linewidth=5)\n", + " plt.scatter(x.numpy(), y.numpy())\n", + " plt.scatter(x.numpy(), y_pred.numpy(), color='orange', linewidth=5)\n", " plt.show()\n", "\n", - " print(\"loss = \", loss.data.numpy())\n", - " if loss.data.numpy() < 0.5:\n", + " print(\"loss = \", loss.numpy())\n", + " if loss.numpy() < 0.5:\n", " print(\"Done!\")\n", " break" ] @@ -434,7 +396,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "__Bonus quest__: try implementing and writing some nonlinear regression. You can try quadratic features or some trigonometry, or a simple neural network. The only difference is that now you have more variables and a more complicated `y_pred`. " + "__Bonus quest__: try implementing and writing some nonlinear regression. You can try quadratic features or some trigonometry, or a simple neural network. The only difference is that now you have more variables and a more complicated `y_pred`." ] }, { @@ -443,9 +405,9 @@ "source": [ "# High-level PyTorch\n", "\n", - "So far we've been dealing with low-level torch API. While it's absolutely vital for any custom losses or layers, building large neura nets in it is a bit clumsy.\n", + "So far we've been dealing with low-level PyTorch API. While it's absolutely vital for any custom losses or layers, building large neural nets in it is a bit clumsy.\n", "\n", - "Luckily, there's also a high-level torch interface with a pre-defined layers, activations and training algorithms. \n", + "Luckily, there's also a high-level PyTorch interface with pre-defined layers, activations and training algorithms.\n", "\n", "We'll cover them as we go through a simple image recognition problem: classifying letters into __\"A\"__ vs __\"B\"__.\n" ] @@ -454,34 +416,7 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Parsing...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/jheuristic/anaconda3/lib/python3.6/site-packages/scipy/misc/pilutil.py:482: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.\n", - " if issubdtype(ts, int):\n", - "/home/jheuristic/anaconda3/lib/python3.6/site-packages/scipy/misc/pilutil.py:485: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n", - " elif issubdtype(type(size), float):\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "found broken img: ./notMNIST_small/A/RGVtb2NyYXRpY2FCb2xkT2xkc3R5bGUgQm9sZC50dGY=.png [it's ok if <10 images are broken]\n", - "Done\n", - "Train size = 2808, test_size = 937\n" - ] - } - ], + "outputs": [], "source": [ "from notmnist import load_notmnist\n", "X_train, y_train, X_test, y_test = load_notmnist(letters='AB')\n", @@ -517,7 +452,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's start with layers. The main abstraction here is __`torch.nn.Module`__" + "Let's start with layers. The main abstraction here is __`torch.nn.Module`__:" ] }, { @@ -568,7 +503,7 @@ "source": [ "There's a vast library of popular layers and architectures already built for ya'.\n", "\n", - "This is a binary classification problem, so we'll train a __Logistic Regression with sigmoid__.\n", + "This is a binary classification problem, so we'll train __Logistic Regression__.\n", "$$P(y_i | X_i) = \\sigma(W \\cdot X_i + b) ={ 1 \\over {1+e^{- [W \\cdot X_i + b]}} }$$\n" ] }, @@ -676,7 +611,7 @@ "source": [ "__Torch optimizers__\n", "\n", - "When we trained Linear Regression above, we had to manually .zero_() gradients on both our variables. Imagine that code for a 50-layer network.\n", + "When we trained Linear Regression above, we had to manually `.zero_()` gradients on both our variables. Imagine that code for a 50-layer network.\n", "\n", "Again, to keep it from getting dirty, there's `torch.optim` module with pre-implemented algorithms:" ] @@ -690,9 +625,9 @@ "opt = torch.optim.RMSprop(model.parameters(), lr=0.01)\n", "\n", "# here's how it's used:\n", + "opt.zero_grad() # clear gradients\n", "loss.backward() # add new gradients\n", - "opt.step() # change weights\n", - "opt.zero_grad() # clear gradients" + "opt.step() # change weights" ] }, { @@ -787,12 +722,12 @@ "metadata": {}, "source": [ "__Debugging tips:__\n", - "* make sure your model predicts probabilities correctly. Just print them and see what's inside.\n", - "* don't forget _minus_ sign in the loss function! It's a mistake 99% ppl do at some point.\n", - "* make sure you zero-out gradients after each step. Srsly:)\n", + "* Make sure your model predicts probabilities correctly. Just print them and see what's inside.\n", + "* Don't forget the _minus_ sign in the loss function! It's a mistake 99% people do at some point.\n", + "* Make sure you zero-out gradients after each step. Seriously:)\n", "* In general, PyTorch's error messages are quite helpful, read 'em before you google 'em.\n", "* if you see nan/inf, print what happens at each iteration to find our where exactly it occurs.\n", - " * If loss goes down and then turns nan midway through, try smaller learning rate. (Our current loss formula is unstable).\n" + " * If loss goes down and then turns nan midway through, try smaller learning rate. (Our current loss formula is unstable)." ] }, { @@ -843,25 +778,7 @@ "* Practical PyTorch - a repo that implements some... other cool DL models... yes, in PyTorch - [link](https://github.com/spro/practical-pytorch)\n", "* And some more - [link](https://www.reddit.com/r/pytorch/comments/6z0yeo/pytorch_and_pytorch_tricks_for_kaggle/)\n", "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```" + "---" ] }, { @@ -870,7 +787,7 @@ "source": [ "# Homework tasks\n", "\n", - "There will be three tasks worth 2, 3 and 5 points respectively. \n", + "There will be three tasks worth 2, 3 and 5 points respectively.\n", "If you get stuck with no progress, try switching to the next task and returning later." ] }, @@ -882,11 +799,11 @@ "\n", "![img](https://media.giphy.com/media/3o751UMCYtSrRAFRFC/giphy.gif)\n", "\n", - "When dealing with more complex stuff like neural network, it's best if you use tensors the way samurai uses his sword. \n", + "When dealing with more complex stuff like neural network, it's best if you use tensors the way samurai uses his sword.\n", "\n", "\n", - "__1.1 the cannabola__ \n", - "[_disclaimer_](https://gist.githubusercontent.com/justheuristic/e2c1fa28ca02670cabc42cacf3902796/raw/fd3d935cef63a01b85ed2790b5c11c370245cbd7/stddisclaimer.h)\n", + "__1.1 The Cannabola__\n", + "[(_disclaimer_)](https://gist.githubusercontent.com/justheuristic/e2c1fa28ca02670cabc42cacf3902796/raw/fd3d935cef63a01b85ed2790b5c11c370245cbd7/stddisclaimer.h)\n", "\n", "Let's write another function, this time in polar coordinates:\n", "$$\\rho(\\theta) = (1 + 0.9 \\cdot cos (8 \\cdot \\theta) ) \\cdot (1 + 0.1 \\cdot cos(24 \\cdot \\theta)) \\cdot (0.9 + 0.05 \\cdot cos(200 \\cdot \\theta)) \\cdot (1 + sin(\\theta))$$\n", @@ -922,20 +839,20 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Task II: the game of life (3 points)\n", + "### Task II: The Game of Life (3 points)\n", "\n", - "Now it's time for you to make something more challenging. We'll implement Conway's [Game of Life](http://web.stanford.edu/~cdebs/GameOfLife/) in _pure PyTorch_. \n", + "Now it's time for you to make something more challenging. We'll implement Conway's [Game of Life](http://web.stanford.edu/~cdebs/GameOfLife/) in _pure PyTorch_.\n", "\n", - "While this is still a toy task, implementing game of life this way has one cool benefit: __you'll be able to run it on GPU! __ Indeed, what could be a better use of your gpu than simulating game of life on 1M/1M grids?\n", + "While this is still a toy task, implementing game of life this way has one cool benefit: __you'll be able to run it on GPU!__ Indeed, what could be a better use of your GPU than simulating Game of Life on 1M/1M grids?\n", "\n", "![img](https://cdn.tutsplus.com/gamedev/authors/legacy/Stephane%20Beniak/2012/09/11/Preview_Image.png)\n", - "If you've skipped the url above out of sloth, here's the game of life:\n", + "If you've skipped the URL above out of sloth, here's the Game of Life:\n", "* You have a 2D grid of cells, where each cell is \"alive\"(1) or \"dead\"(0)\n", "* Any living cell that has 2 or 3 neighbors survives, else it dies [0,1 or 4+ neighbors]\n", "* Any cell with exactly 3 neighbors becomes alive (if it was dead)\n", "\n", - "For this task, you are given a reference numpy implementation that you must convert to PyTorch.\n", - "_[numpy code inspired by: https://github.com/rougier/numpy-100]_\n", + "For this task, you are given a reference NumPy implementation that you must convert to PyTorch.\n", + "_[NumPy code inspired by: https://github.com/rougier/numpy-100]_\n", "\n", "\n", "__Note:__ You can find convolution in `torch.nn.functional.conv2d(Z,filters)`. Note that it has a different input format.\n", @@ -979,10 +896,10 @@ " :param Z: torch.FloatTensor of shape [height,width] containing 0s(dead) an 1s(alive)\n", " :returns: torch.FloatTensor Z after updates.\n", "\n", - " You can opt to create new tensor or change Z inplace.\n", + " You can opt to create a new tensor or change Z inplace.\n", " \"\"\"\n", "\n", - " # \n", + " \n", "\n", " return Z" ] @@ -1002,8 +919,8 @@ "\n", "# tests\n", "Z_reference = np_update(Z_numpy.copy())\n", - "assert np.all(Z_new.numpy(\n", - ") == Z_reference), \"your PyTorch implementation doesn't match np_update. Look into Z and np_update(ZZ) to investigate.\"\n", + "assert np.all(Z_new.numpy() == Z_reference), \\\n", + " \"your PyTorch implementation doesn't match np_update. Look into Z and np_update(ZZ) to investigate.\"\n", "print(\"Well done!\")" ] }, @@ -1025,7 +942,6 @@ "fig.show()\n", "\n", "for _ in range(100):\n", - "\n", " # update\n", " Z = torch_update(Z)\n", "\n", @@ -1072,40 +988,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "\n", - "\n", "### Task III: Going deeper (5 points)\n", "\n", - "Your ultimate task for this week is to build your first neural network [almost] from scratch and pure torch.\n", + "Your ultimate task for this week is to build your first neural network [almost] from scratch and pure PyTorch.\n", + "\n", + "This time you will solve the same digit recognition problem, but at a larger scale\n", "\n", - "This time you will solve the same digit recognition problem, but at a greater scale\n", "* 10 different letters\n", "* 20k samples\n", "\n", - "We want you to build a network that reaches at least 80% accuracy and has at least 2 linear layers in it. Naturally, it should be nonlinear to beat logistic regression. You can implement it with either \n", + "We want you to build a network that reaches at least 80% accuracy and has at least 2 linear layers in it. Naturally, it should be nonlinear to beat logistic regression.\n", "\n", - "\n", - "With 10 classes you will need to use __Softmax__ at the top instead of sigmoid and train for __categorical crossentropy__ (see [here](http://wiki.fast.ai/index.php/Log_Loss)). Write your own loss or use `torch.nn.functional.nll_loss`. Just make sure you understand what it accepts as an input.\n", + "With 10 classes you will need to use __Softmax__ at the top instead of sigmoid and train using __categorical crossentropy__ (see [here](http://wiki.fast.ai/index.php/Log_Loss)). Write your own loss or use `torch.nn.functional.nll_loss`. Just make sure you understand what it accepts as input.\n", "\n", "Note that you are not required to build 152-layer monsters here. A 2-layer (one hidden, one output) neural network should already give you an edge over logistic regression.\n", "\n", @@ -1114,26 +1008,15 @@ "If you've already beaten logistic regression with a two-layer net, but enthusiasm still ain't gone, you can try improving the test accuracy even further! It should be possible to reach 90% without convnets.\n", "\n", "__SPOILERS!__\n", - "At the end of the notebook you will find a few tips and frequent errors. \n", - "If you feel confident enogh, just start coding right away and get there ~~if~~ once you need to untangle yourself. \n", - "\n" + "At the end of the notebook you will find a few tips and frequent errors.\n", + "If you feel confident enough, just start coding right away and get there ~~if~~ once you need to untangle yourself." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Parsing...\n", - "found broken img: ./notMNIST_small/F/Q3Jvc3NvdmVyIEJvbGRPYmxpcXVlLnR0Zg==.png [it's ok if <10 images are broken]\n", - "found broken img: ./notMNIST_small/A/RGVtb2NyYXRpY2FCb2xkT2xkc3R5bGUgQm9sZC50dGY=.png [it's ok if <10 images are broken]\n" - ] - } - ], + "outputs": [], "source": [ "from notmnist import load_notmnist\n", "X_train, y_train, X_test, y_test = load_notmnist(letters='ABCDEFGHIJ')\n", @@ -1175,101 +1058,39 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "











" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "\n", "# SPOILERS!\n", "\n", - "Recommended pipeline\n", + "Recommended pipeline:\n", "\n", "* Adapt logistic regression from previous assignment to classify one letter against others (e.g. A vs the rest)\n", "* Generalize it to multiclass logistic regression.\n", " - Either try to remember lecture 0 or google it.\n", " - Instead of weight vector you'll have to use matrix (feature_id x class_id)\n", - " - softmax (exp over sum of exps) can implemented manually or as nn.Softmax (layer) F.softmax (function)\n", - " - probably better to use STOCHASTIC gradient descent (minibatch) for greater speed\n", - " - you can also try momentum/rmsprop/adawhatever\n", - " - in which case sample should probably be shuffled (or use random subsamples on each iteration)\n", + " - Softmax (exp over sum of exps) can be implemented manually or as `nn.Softmax` (layer) or `F.softmax` (function)\n", + " - Probably better to use STOCHASTIC gradient descent (minibatch) for greater speed\n", + " - You can also try momentum/rmsprop/adawhatever\n", + " - in which case the dataset should probably be shuffled (or use random subsamples on each iteration)\n", "* Add a hidden layer. Now your logistic regression uses hidden neurons instead of inputs.\n", " - Hidden layer uses the same math as output layer (ex-logistic regression), but uses some nonlinearity (e.g. sigmoid) instead of softmax\n", - " - You need to train both layers, not just output layer :)\n", - " - 50 hidden neurons and a sigmoid nonlinearity will do for a start. Many ways to improve. \n", - " - In ideal case this totals to 2 torch.matmul's, 1 softmax and 1 relu/sigmoid\n", - " - __make sure this neural network works better than logistic regression__\n", - " \n", - "* Now's the time to try improving the network. Consider layers (size, neuron count), nonlinearities, optimization methods, initialization - whatever you want, but please avoid convolutions for now.\n", - " \n", + " - You need to train both layers, not just the output layer :)\n", + " - 50 hidden neurons and a sigmoid nonlinearity will do for a start. Many ways to improve.\n", + " - In ideal case this totals to 2 `torch.matmul`'s, 1 softmax and 1 ReLU/sigmoid\n", + " - __Make sure this neural network works better than logistic regression!__\n", + "\n", + "* Now's the time to try improving the network. Consider layers (size, neuron count), nonlinearities, optimization methods, initialization — whatever you want, but please avoid convolutions for now.\n", + "\n", "* If anything seems wrong, try going through one step of training and printing everything you compute.\n", - "* If you see NaNs midway through optimization, you can estimate log P(y|x) as via F.log_softmax(layer_before_softmax)\n", - "\n" + "* If you see NaNs midway through optimization, you can estimate $\\log P(y \\mid x)$ as `F.log_softmax(layer_before_softmax)`." ] } ], diff --git a/week04_[recap]_deep_learning/seminar_tensorflow.ipynb b/week04_[recap]_deep_learning/seminar_tensorflow.ipynb index a26eb57db..02cefe6ac 100644 --- a/week04_[recap]_deep_learning/seminar_tensorflow.ipynb +++ b/week04_[recap]_deep_learning/seminar_tensorflow.ipynb @@ -24,9 +24,9 @@ " %tensorflow_version 1.x\n", " \n", " if not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", "\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week04_[recap]_deep_learning/mnist.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_[recap]_deep_learning/mnist.py\n", "\n", " !touch .setup_complete\n", "\n", diff --git a/week04_approx_rl/README.md b/week04_approx_rl/README.md index 4d37da0e7..45a92a4df 100644 --- a/week04_approx_rl/README.md +++ b/week04_approx_rl/README.md @@ -1,5 +1,5 @@ ## Materials -* [__slides__](https://docs.google.com/presentation/d/1HEfIyKT0rIuUQCGAsR1PIVGirccDXu5LQvxhVUjuIqM) +* [__slides__](https://github.com/yandexdataschool/Practical_RL/files/15286337/ysda_practical_rl_lecture_04.pdf) * Our [lecture](https://yadi.sk/i/Gd9yWV1dpuB7BQ), [seminar](https://yadi.sk/i/mvtKAIRN2yKU2g) (russian) * [__seminar slides__](https://yadi.sk/i/B89gXClSpmYZKw) @@ -35,9 +35,9 @@ ## Practice -* Seminar: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/spring20/week04_approx_rl/seminar_pytorch.ipynb) -* Homework (main): [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/spring20/week04_approx_rl/homework_pytorch_main.ipynb#scrollTo=KVvvo7k_ap8w) -* Homework (debug): [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/spring20/week04_approx_rl/homework_pytorch_debug.ipynb#scrollTo=KVvvo7k_ap8w) +* Seminar: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week04_approx_rl/seminar_pytorch.ipynb) +* Homework (main): [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week04_approx_rl/homework_pytorch_main.ipynb#scrollTo=KVvvo7k_ap8w) +* Homework (debug): [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week04_approx_rl/homework_pytorch_debug.ipynb#scrollTo=KVvvo7k_ap8w) @@ -46,6 +46,4 @@ From now on, we have two tracks, for pytorch and tensorflow. However, pytorch tr Begin with `seminar_.ipynb` and then proceed with `homework_.ipynb`. -__Note: you're not required to submit assignments in all three frameworks. Pick one and go with it. Maybe switch it occasionally if you want more challenge. __ - - +__Note: you're not required to submit assignments in all three frameworks. Pick one and go with it. Maybe switch it occasionally if you want more challenge.__ diff --git a/week04_approx_rl/atari_wrappers.py b/week04_approx_rl/atari_wrappers.py deleted file mode 100644 index ea19dd880..000000000 --- a/week04_approx_rl/atari_wrappers.py +++ /dev/null @@ -1,119 +0,0 @@ -# taken from OpenAI baselines. - -import numpy as np -import gym - - -class MaxAndSkipEnv(gym.Wrapper): - def __init__(self, env, skip=4): - """Return only every `skip`-th frame""" - gym.Wrapper.__init__(self, env) - # most recent raw observations (for max pooling across time steps) - self._obs_buffer = np.zeros( - (2,) + env.observation_space.shape, dtype=np.uint8) - self._skip = skip - - def step(self, action): - """Repeat action, sum reward, and max over last observations.""" - total_reward = 0.0 - done = None - for i in range(self._skip): - obs, reward, done, info = self.env.step(action) - if i == self._skip - 2: - self._obs_buffer[0] = obs - if i == self._skip - 1: - self._obs_buffer[1] = obs - total_reward += reward - if done: - break - # Note that the observation on the done=True frame - # doesn't matter - max_frame = self._obs_buffer.max(axis=0) - - return max_frame, total_reward, done, info - - def reset(self, **kwargs): - return self.env.reset(**kwargs) - - -class ClipRewardEnv(gym.RewardWrapper): - def __init__(self, env): - gym.RewardWrapper.__init__(self, env) - - def reward(self, reward): - """Bin reward to {+1, 0, -1} by its sign.""" - return np.sign(reward) - - -class FireResetEnv(gym.Wrapper): - def __init__(self, env): - """Take action on reset for environments that are fixed until firing.""" - gym.Wrapper.__init__(self, env) - assert env.unwrapped.get_action_meanings()[1] == 'FIRE' - assert len(env.unwrapped.get_action_meanings()) >= 3 - - def reset(self, **kwargs): - self.env.reset(**kwargs) - obs, _, done, _ = self.env.step(1) - if done: - self.env.reset(**kwargs) - obs, _, done, _ = self.env.step(2) - if done: - self.env.reset(**kwargs) - return obs - - def step(self, ac): - return self.env.step(ac) - - -class EpisodicLifeEnv(gym.Wrapper): - def __init__(self, env): - """Make end-of-life == end-of-episode, but only reset on true game over. - Done by DeepMind for the DQN and co. since it helps value estimation. - """ - gym.Wrapper.__init__(self, env) - self.lives = 0 - self.was_real_done = True - - def step(self, action): - obs, reward, done, info = self.env.step(action) - self.was_real_done = done - # check current lives, make loss of life terminal, - # then update lives to handle bonus lives - lives = self.env.unwrapped.ale.lives() - if lives < self.lives and lives > 0: - # for Qbert sometimes we stay in lives == 0 condition for a few frames - # so it's important to keep lives > 0, so that we only reset once - # the environment advertises done. - done = True - self.lives = lives - return obs, reward, done, info - - def reset(self, **kwargs): - """Reset only when lives are exhausted. - This way all states are still reachable even though lives are episodic, - and the learner need not know about any of this behind-the-scenes. - """ - if self.was_real_done: - obs = self.env.reset(**kwargs) - else: - # no-op step to advance from terminal/lost life state - obs, _, _, _ = self.env.step(0) - self.lives = self.env.unwrapped.ale.lives() - return obs - - -# in torch imgs have shape [c, h, w] instead of common [h, w, c] -class AntiTorchWrapper(gym.ObservationWrapper): - def __init__(self, env): - gym.ObservationWrapper.__init__(self, env) - - self.img_size = [env.observation_space.shape[i] - for i in [1, 2, 0] - ] - self.observation_space = gym.spaces.Box(0.0, 1.0, self.img_size) - - def observation(self, img): - """what happens to each observation""" - img = img.transpose(1, 2, 0) - return img diff --git a/week04_approx_rl/dqn/__init__.py b/week04_approx_rl/dqn/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/week04_approx_rl/dqn/analysis.py b/week04_approx_rl/dqn/analysis.py new file mode 100644 index 000000000..2c007732d --- /dev/null +++ b/week04_approx_rl/dqn/analysis.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Reversible +import numpy as np + + +def play_and_log_episode(env, agent, t_max=10000): + """ + Plays an episode using the greedy policy and logs for each timestep: + - state + - qvalues (estimated by the agent) + - actions + - rewards + + Also logs: + - the final (usually termo=inal) state. + - whether the episode was terminated + + Uses the greedy policy. + """ + assert t_max > 0, t_max + + states = [] + qvalues_all = [] + actions = [] + rewards = [] + + s, _ = env.reset() + for step in range(t_max): + s = np.array(s) + states.append(s) + qvalues = agent.get_qvalues(s[None])[0] + qvalues_all.append(qvalues) + action = np.argmax(qvalues) + actions.append(action) + s, r, terminated, truncated, _ = env.step(action) + rewards.append(r) + if terminated or truncated: + break + states.append(s) # the last state + + return_pack = { + "states": np.array(states), + "qvalues": np.array(qvalues_all), + "actions": np.array(actions), + "rewards": np.array(rewards), + "episode_finished": terminated, + } + + return return_pack diff --git a/week04_approx_rl/dqn/atari_wrappers.py b/week04_approx_rl/dqn/atari_wrappers.py new file mode 100644 index 000000000..563dcd99f --- /dev/null +++ b/week04_approx_rl/dqn/atari_wrappers.py @@ -0,0 +1,64 @@ +# taken from stable_baselines3. + +from gymnasium import Wrapper + + +class FireResetEnv(Wrapper): + def __init__(self, env): + """Take action on reset for environments that are fixed until firing.""" + super().__init__(env) + assert env.unwrapped.get_action_meanings()[1] == "FIRE" + assert len(env.unwrapped.get_action_meanings()) >= 3 + + def reset(self, **kwargs): + self.env.reset(**kwargs) + obs, _, terminated, truncated, _ = self.env.step(1) + if terminated or truncated: + self.env.reset(**kwargs) + obs, _, terminated, truncated, _ = self.env.step(2) + if terminated or truncated: + self.env.reset(**kwargs) + return obs, {} + + +class EpisodicLifeEnv(Wrapper): + def __init__(self, env): + """Make end-of-life == end-of-episode, but only reset on true game over. + Done by DeepMind for the DQN and co. since it helps value estimation. + """ + super().__init__(env) + self.lives = 0 + self.was_real_done = True + + def step(self, action): + obs, reward, terminated, truncated, info = self.env.step(action) + self.was_real_done = terminated or truncated + # check current lives, make loss of life terminal, + # then update lives to handle bonus lives + lives = self.env.unwrapped.ale.lives() + if lives < self.lives and lives > 0: + # for Qbert sometimes we stay in lives == 0 condition for a few frames + # so it's important to keep lives > 0, so that we only reset once + # the environment advertises done. + terminated = True + self.lives = lives + return obs, reward, terminated, truncated, info + + def reset(self, **kwargs): + """Reset only when lives are exhausted. + This way all states are still reachable even though lives are episodic, + and the learner need not know about any of this behind-the-scenes. + """ + if self.was_real_done: + obs, info = self.env.reset(**kwargs) + else: + # no-op step to advance from terminal/lost life state + obs, _, terminated, truncated, info = self.env.step(0) + + # The no-op step can lead to a game over, so we need to check it again + # to see if we should reset the environment and avoid the + # monitor.py `RuntimeError: Tried to step environment that needs reset` + if terminated or truncated: + obs, info = self.env.reset(**kwargs) + self.lives = self.env.unwrapped.ale.lives() + return obs, info diff --git a/week04_approx_rl/dqn/logger.py b/week04_approx_rl/dqn/logger.py new file mode 100644 index 000000000..52837d873 --- /dev/null +++ b/week04_approx_rl/dqn/logger.py @@ -0,0 +1,80 @@ +import matplotlib.pyplot as plt +from torch.utils.tensorboard import SummaryWriter +import numpy as np + +class Logger: + def __init__(self, use_tensorboard=True, log_dir='runs'): + """ + Initializes the Logger. + + :param use_tensorboard: If True, logs will be sent to TensorBoard. + :param log_dir: Directory where TensorBoard logs are saved. + """ + self.use_tensorboard = use_tensorboard + if self.use_tensorboard: + self.writer = SummaryWriter(log_dir=log_dir) + else: + # Initialize lists to store history for matplotlib + self.mean_rw_history = [] + self.td_loss_history = [] + self.grad_norm_history = [] + self.initial_state_v_history = [] + + def log_loss(self, loss, step): + if self.use_tensorboard: + self.writer.add_scalar("Loss", loss, step) + else: + self.td_loss_history.append(loss) + + def log_grad_norm(self, grad_norm, step): + if self.use_tensorboard: + self.writer.add_scalar("Grad Norm", grad_norm, step) + else: + self.grad_norm_history.append(grad_norm) + + def log_mean_reward(self, mean_reward, step): + if self.use_tensorboard: + self.writer.add_scalar("Mean Reward per Life", mean_reward, step) + else: + self.mean_rw_history.append(mean_reward) + + def log_initial_state_v(self, initial_v, step): + if self.use_tensorboard: + self.writer.add_scalar("Initial State V", initial_v, step) + else: + self.initial_state_v_history.append(initial_v) + + def plot(self): + if not self.use_tensorboard: + plt.figure(figsize=[16, 9]) + + plt.subplot(2, 2, 1) + plt.title("Mean Reward per Episode") + plt.plot(self.mean_rw_history, label='Mean Reward') + plt.legend() + plt.grid() + + plt.subplot(2, 2, 2) + plt.title("TD Loss History") + plt.plot(self.td_loss_history, label='TD Loss') + plt.legend() + plt.grid() + + plt.subplot(2, 2, 3) + plt.title("Initial State V") + plt.plot(self.initial_state_v_history, label='Initial State V') + plt.legend() + plt.grid() + + plt.subplot(2, 2, 4) + plt.title("Grad Norm History") + plt.plot(self.grad_norm_history, label='Grad Norm') + plt.legend() + plt.grid() + + plt.tight_layout() + plt.show() + + def close(self): + if self.use_tensorboard: + self.writer.close() \ No newline at end of file diff --git a/week04_approx_rl/dqn/replay_buffer.py b/week04_approx_rl/dqn/replay_buffer.py new file mode 100644 index 000000000..e695d78d9 --- /dev/null +++ b/week04_approx_rl/dqn/replay_buffer.py @@ -0,0 +1,120 @@ +# This code is shamelessly stolen from +# https://github.com/openai/baselines/blob/master/baselines/deepq/replay_buffer.py +import numpy as np +import random + + +class ReplayBuffer(object): + def __init__(self, size): + """Create Replay buffer. + Parameters + ---------- + size: int + Max number of transitions to store in the buffer. When the buffer + overflows the old memories are dropped. + """ + self._storage = [] + self._maxsize = size + self._next_idx = 0 + + def __len__(self): + return len(self._storage) + + def add(self, obs_t, action, reward, obs_tp1, done): + data = (obs_t, action, reward, obs_tp1, done) + + if self._next_idx >= len(self._storage): + self._storage.append(data) + else: + self._storage[self._next_idx] = data + self._next_idx = (self._next_idx + 1) % self._maxsize + + def _encode_sample(self, idxes): + obses_t, actions, rewards, obses_tp1, dones = [], [], [], [], [] + for i in idxes: + data = self._storage[i] + obs_t, action, reward, obs_tp1, done = data + obses_t.append(np.array(obs_t, copy=False)) + actions.append(np.array(action, copy=False)) + rewards.append(reward) + obses_tp1.append(np.array(obs_tp1, copy=False)) + dones.append(done) + return ( + np.array(obses_t), + np.array(actions), + np.array(rewards), + np.array(obses_tp1), + np.array(dones), + ) + + def sample(self, batch_size): + """Sample a batch of experiences. + Parameters + ---------- + batch_size: int + How many transitions to sample. + Returns + ------- + obs_batch: np.array + batch of observations + act_batch: np.array + batch of actions executed given obs_batch + rew_batch: np.array + rewards received as results of executing act_batch + next_obs_batch: np.array + next set of observations seen after executing act_batch + done_mask: np.array + done_mask[i] = 1 if executing act_batch[i] resulted in + the end of an episode and 0 otherwise. + """ + idxes = [random.randint(0, len(self._storage) - 1) for _ in range(batch_size)] + return self._encode_sample(idxes) + + +class LazyFramesVectorReplayBuffer(ReplayBuffer): + """ + ReplayBuffer for vectorized environments, which are wrapped into FrameBuffers. + + If an environment is first wrapped into a FrameBuffer and then vectorized, + then the resulting VecEnv will not use LazyFrames, but it will directly + use np.ndarrays, thus greatly increasing RAM consumption by the buffer. + + Instead, we first vectorize an environment and only then wrap in into FrameBuffers. + It's not as convenient, but it keeps the advantage in memory from LazyFrames. + + So, + observations and next_obervations are stored as LazyFrames + of shape (n_frames, n_envs, ...) + actions, rewards and dones are stored as np.ndarrays of shape (n_envs,). + + """ + + # (n_frames, n_envs, *) + + def _encode_sample(self, idxes): + """ + For each index in idxes samples a (s, a, r, s', done) transition + from a randomly chosen environment of the corresponding VecEnv. + """ + obses_t, actions, rewards, obses_tp1, dones = [], [], [], [], [] + for i in idxes: + data = self._storage[i] + obs_t, action, reward, obs_tp1, done = data + n_envs = action.shape[0] + env_idx_chosen_for_sample = random.randint(0, n_envs - 1) + obses_t.append( + np.array(obs_t, copy=False)[:, env_idx_chosen_for_sample], + ) + actions.append(np.array(action, copy=False)[env_idx_chosen_for_sample]) + rewards.append(reward[env_idx_chosen_for_sample]) + obses_tp1.append( + np.array(obs_tp1, copy=False)[:, env_idx_chosen_for_sample], + ) + dones.append(done[env_idx_chosen_for_sample]) + return ( + np.array(obses_t), + np.array(actions), + np.array(rewards), + np.array(obses_tp1), + np.array(dones), + ) diff --git a/week04_approx_rl/dqn/utils.py b/week04_approx_rl/dqn/utils.py new file mode 100644 index 000000000..a79672901 --- /dev/null +++ b/week04_approx_rl/dqn/utils.py @@ -0,0 +1,14 @@ +import psutil # type: ignore + + +def is_enough_ram(min_available_gb=0.1): + mem = psutil.virtual_memory() + return mem.available >= min_available_gb * (1024**3) + + +def linear_decay( + init_val: float, final_val: float, cur_step: int, total_steps: int +) -> float: + if cur_step >= total_steps: + return final_val + return (init_val * (total_steps - cur_step) + final_val * cur_step) / total_steps diff --git a/week04_approx_rl/framebuffer.py b/week04_approx_rl/framebuffer.py deleted file mode 100644 index fa8805d24..000000000 --- a/week04_approx_rl/framebuffer.py +++ /dev/null @@ -1,45 +0,0 @@ -import numpy as np -from gym.spaces.box import Box -from gym.core import Wrapper - - -class FrameBuffer(Wrapper): - def __init__(self, env, n_frames=4, dim_order='tensorflow'): - """A gym wrapper that reshapes, crops and scales image into the desired shapes""" - super(FrameBuffer, self).__init__(env) - self.dim_order = dim_order - if dim_order == 'tensorflow': - height, width, n_channels = env.observation_space.shape - obs_shape = [height, width, n_channels * n_frames] - elif dim_order == 'pytorch': - n_channels, height, width = env.observation_space.shape - obs_shape = [n_channels * n_frames, height, width] - else: - raise ValueError( - 'dim_order should be "tensorflow" or "pytorch", got {}'.format(dim_order)) - self.observation_space = Box(0.0, 1.0, obs_shape) - self.framebuffer = np.zeros(obs_shape, 'float32') - - def reset(self): - """resets breakout, returns initial frames""" - self.framebuffer = np.zeros_like(self.framebuffer) - self.update_buffer(self.env.reset()) - return self.framebuffer - - def step(self, action): - """plays breakout for 1 step, returns frame buffer""" - new_img, reward, done, info = self.env.step(action) - self.update_buffer(new_img) - return self.framebuffer, reward, done, info - - def update_buffer(self, img): - if self.dim_order == 'tensorflow': - offset = self.env.observation_space.shape[-1] - axis = -1 - cropped_framebuffer = self.framebuffer[:, :, :-offset] - elif self.dim_order == 'pytorch': - offset = self.env.observation_space.shape[0] - axis = 0 - cropped_framebuffer = self.framebuffer[:-offset] - self.framebuffer = np.concatenate( - [img, cropped_framebuffer], axis=axis) diff --git a/week04_approx_rl/homework_lasagne.ipynb b/week04_approx_rl/homework_lasagne.ipynb deleted file mode 100644 index d09541ac4..000000000 --- a/week04_approx_rl/homework_lasagne.ipynb +++ /dev/null @@ -1,767 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Homework 4\n", - "\n", - "Today we'll start by reproducing the DQN and then try improving it with the tricks we learned on the lecture:\n", - "* Target networks\n", - "* Double q-learning\n", - "* Prioritized experience replay\n", - "* Dueling DQN\n", - "* Bootstrap DQN" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "%matplotlib inline\n", - "\n", - "\n", - "# If you are running on a server, launch xvfb to record game videos\n", - "# Please make sure you have xvfb installed\n", - "import os\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Processing game image (2 pts)\n", - "\n", - "Raw Atari images are large, 210x160x3 by default. However, we don't need that level of detail in order to learn them.\n", - "\n", - "We can thus save a lot of time by preprocessing game image, including\n", - "* Resizing to a smaller shape\n", - "* Converting to grayscale\n", - "* Cropping irrelevant image parts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from gym.core import ObservationWrapper\n", - "from gym.spaces import Box\n", - "\n", - "from scipy.misc import imresize\n", - "\n", - "\n", - "class PreprocessAtari(ObservationWrapper):\n", - " def __init__(self, env):\n", - " \"\"\"A gym wrapper that crops, scales image into the desired shapes and optionally grayscales it.\"\"\"\n", - " ObservationWrapper.__init__(self, env)\n", - "\n", - " self.img_size = (64, 64)\n", - " self.observation_space = Box(0.0, 1.0, self.img_size)\n", - "\n", - " def observation(self, img):\n", - " \"\"\"what happens to each observation\"\"\"\n", - "\n", - " # Here's what you need to do:\n", - " # * crop image, remove irrelevant parts\n", - " # * resize image to self.img_size\n", - " # (use imresize imported above or any library you want,\n", - " # e.g. opencv, skimage, PIL, keras)\n", - " # * cast image to grayscale\n", - " # * convert image pixels to (0,1) range, float32 type\n", - "\n", - " \n", - " return " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "\n", - "\n", - "def make_env():\n", - " env = gym.make(\"KungFuMasterDeterministic-v0\") # create raw env\n", - " return PreprocessAtari(env) # apply your wrapper\n", - "\n", - "\n", - "# spawn game instance for tests\n", - "env = make_env()\n", - "\n", - "observation_shape = env.observation_space.shape\n", - "n_actions = env.action_space.n\n", - "\n", - "obs = env.reset()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# test observation\n", - "assert obs.shape == observation_shape\n", - "assert obs.dtype == 'float32'\n", - "assert len(np.unique(obs)) > 2, \"your image must not be binary\"\n", - "assert 0 <= np.min(obs) and np.max(\n", - " obs) <= 1, \"convert image pixels to (0,1) range\"\n", - "\n", - "print \"Formal tests seem fine. Here's an example of what you'll get.\"\n", - "\n", - "plt.title(\"what your network gonna see\")\n", - "plt.imshow(obs, interpolation='none', cmap='gray')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.figure(figsize=[12, 12])\n", - "env.reset()\n", - "for i in range(16):\n", - " for _ in range(10):\n", - " new_obs = env.step(env.action_space.sample())[0]\n", - " plt.subplot(4, 4, i+1)\n", - " plt.imshow(new_obs, interpolation='none', cmap='gray')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# dispose of the game instance\n", - "del env" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Building a DQN (2 pts)\n", - "Here we define a simple agent that maps game images into Qvalues using simple convolutional neural network.\n", - "\n", - "![scheme](https://s18.postimg.cc/gbmsq6gmx/dqn_scheme.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# setup theano/lasagne. Prefer GPU. Fallback to CPU (will print warning)\n", - "%env THEANO_FLAGS = floatX = float32\n", - "\n", - "import theano\n", - "import lasagne\n", - "from lasagne.layers import *\n", - "from theano import tensor as T" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# observation\n", - "observation_layer = InputLayer(\n", - " (None,)+observation_shape) # game image, [batch,64,64]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# 4-tick window over images\n", - "from agentnet.memory import WindowAugmentation\n", - "\n", - "# window size [batch,4,64,64]\n", - "prev_wnd = InputLayer((None, 4)+observation_shape)\n", - "\n", - "new_wnd = WindowAugmentation( < current observation layer> , prev_wnd)\n", - "\n", - "# if you changed img size, remove assert\n", - "assert new_wnd.output_shape == (None, 4, 64, 64)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from lasagne.nonlinearities import elu, tanh, softmax, rectify\n", - "\n", - "\n", - "\n", - "dense = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# qvalues layer\n", - "qvalues_layer = \n", - "\n", - "assert qvalues_layer.nonlinearity is not rectify" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# sample actions proportionally to policy_layer\n", - "from agentnet.resolver import EpsilonGreedyResolver\n", - "action_layer = EpsilonGreedyResolver(qvalues_layer)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define agent\n", - "Here you will need to declare how your agent works\n", - "\n", - "* `observation_layers` and `action_layers` are the input and output of agent in MDP.\n", - "* `policy_estimators` must contain whatever you need for training\n", - " * In our case, that's `qvalues_layer`, but you'll need to add more when implementing target network.\n", - "* agent_states contains our frame buffer. \n", - " * The code `{new_wnd:prev_wnd}` reads as \"`new_wnd becomes prev_wnd next turn`\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.agent import Agent\n", - "# agent\n", - "agent = Agent(observation_layers=,\n", - " policy_estimators=,\n", - " action_layers=,\n", - " agent_states={new_wnd: prev_wnd},)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Create and manage a pool of Atari sessions to play with\n", - "\n", - "* To make training more stable, we shall have an entire batch of game sessions each happening independent of others\n", - "* Why several parallel agents help training: http://arxiv.org/pdf/1602.01783v1.pdf\n", - "* Alternative approach: store more sessions: https://www.cs.toronto.edu/~vmnih/docs/dqn.pdf" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.experiments.openai_gym.pool import EnvPool\n", - "\n", - "pool = EnvPool(agent, make_env, n_games=16) # 16 parallel game sessions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "# interact for 7 ticks\n", - "_, action_log, reward_log, _, _, _ = pool.interact(5)\n", - "\n", - "print('actions:')\n", - "print(action_log[0])\n", - "print(\"rewards\")\n", - "print(reward_log[0])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# load first sessions (this function calls interact and remembers sessions)\n", - "SEQ_LENGTH = 10 # sub-session length\n", - "pool.update(SEQ_LENGTH)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Q-learning\n", - "\n", - "We train our agent based on sessions it has played in `pool.update(SEQ_LENGTH)`\n", - "\n", - "To do so, we first obtain sequences of observations, rewards, actions, q-values, etc.\n", - "\n", - "Actions and rewards have shape `[n_games,seq_length]`, q-values are `[n_games,seq_length,n_actions]`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get agent's Qvalues obtained via experience replay\n", - "replay = pool.experience_replay\n", - "\n", - "actions, rewards, is_alive = replay.actions[0], replay.rewards, replay.is_alive\n", - "\n", - "_, _, _, _, qvalues = agent.get_sessions(\n", - " replay,\n", - " session_length=SEQ_LENGTH,\n", - " experience_replay=True,\n", - ")\n", - "\n", - "assert actions.ndim == rewards.ndim == is_alive.ndim == 2, \"actions, rewards and is_alive must have shape [batch,time]\"\n", - "assert qvalues.ndim == 3, \"q-values must have shape [batch,time,n_actions]\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# compute V(s) as Qvalues of best actions.\n", - "# For homework assignment, you will need to use target net\n", - "# or special double q-learning objective here\n", - "\n", - "state_values_target = \n", - "\n", - "assert state_values_target.eval().shape = qvalues.eval().shape[:2]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.learning.generic import get_n_step_value_reference\n", - "\n", - "# get reference Q-values via Q-learning algorithm\n", - "reference_qvalues = get_n_step_value_reference(\n", - " state_values=state_values_target,\n", - " rewards=rewards/100.,\n", - " is_alive=is_alive,\n", - " n_steps=10,\n", - " gamma_or_gammas=0.99,\n", - ")\n", - "\n", - "# consider it constant\n", - "from theano.gradient import disconnected_grad\n", - "reference_qvalues = disconnected_grad(reference_qvalues)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get predicted Q-values for committed actions by both current and target networks\n", - "from agentnet.learning.generic import get_values_for_actions\n", - "action_qvalues = get_values_for_actions(qvalues, actions)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# loss for Qlearning =\n", - "# (Q(s,a) - (r+ gamma*r' + gamma^2*r'' + ... +gamma^10*Q(s_{t+10},a_max)))^2\n", - "\n", - "elwise_mse_loss = \n", - "\n", - "# mean over all batches and time ticks\n", - "loss = (elwise_mse_loss*is_alive).mean()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Since it's a single lasagne network, one can get it's weights, output, etc\n", - "weights = \n", - "weights" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Compute weight updates\n", - "updates = \n", - "\n", - "# compile train function\n", - "train_step = theano.function([], loss, updates=updates)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Demo run\n", - "as usual..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "action_layer.epsilon.set_value(0.05)\n", - "untrained_reward = np.mean(pool.evaluate(save_path=\"./records\",\n", - " record_video=True))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show video\n", - "from IPython.display import HTML\n", - "import os\n", - "\n", - "video_names = list(\n", - " filter(lambda s: s.endswith(\".mp4\"), os.listdir(\"./records/\")))\n", - "\n", - "HTML(\"\"\"\n", - "\n", - "\"\"\".format(\"./records/\" + video_names[-1])) # this may or may not be _last_ video. Try other indices" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Training loop" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# starting epoch\n", - "epoch_counter = 1\n", - "\n", - "# full game rewards\n", - "rewards = {}\n", - "loss, reward_per_tick, reward = 0, 0, 0" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from tqdm import trange\n", - "from IPython.display import clear_output\n", - "\n", - "\n", - "for i in trange(150000):\n", - "\n", - " # update agent's epsilon (in e-greedy policy)\n", - " current_epsilon = 0.05 + 0.45*np.exp(-epoch_counter/20000.)\n", - " action_layer.epsilon.set_value(np.float32(current_epsilon))\n", - "\n", - " # play\n", - " pool.update(SEQ_LENGTH)\n", - "\n", - " # train\n", - " loss = 0.95*loss + 0.05*train_step()\n", - "\n", - " if epoch_counter % 10 == 0:\n", - " # average reward per game tick in current experience replay pool\n", - " reward_per_tick = 0.95*reward_per_tick + 0.05 * \\\n", - " pool.experience_replay.rewards.get_value().mean()\n", - " print(\"iter=%i\\tepsilon=%.3f\\tloss=%.3f\\treward/tick=%.3f\" % (epoch_counter,\n", - " current_epsilon,\n", - " loss,\n", - " reward_per_tick))\n", - "\n", - " # record current learning progress and show learning curves\n", - " if epoch_counter % 100 == 0:\n", - " action_layer.epsilon.set_value(0.05)\n", - " reward = 0.95*reward + 0.05*np.mean(pool.evaluate(record_video=False))\n", - " action_layer.epsilon.set_value(np.float32(current_epsilon))\n", - "\n", - " rewards[epoch_counter] = reward\n", - "\n", - " clear_output(True)\n", - " plt.plot(*zip(*sorted(rewards.items(), key=lambda (t, r): t)))\n", - " plt.show()\n", - "\n", - " epoch_counter += 1\n", - "\n", - "\n", - "# Time to drink some coffee!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Evaluating results\n", - " * Here we plot learning curves and sample testimonials" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "plt.plot(*zip(*sorted(rewards.items(), key=lambda k: k[0])))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.utils.persistence import save, load\n", - "save(action_layer, \"pacman.pcl\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "action_layer.epsilon.set_value(0.05)\n", - "rw = pool.evaluate(n_games=20, save_path=\"./records\", record_video=False)\n", - "print(\"mean session score=%f.5\" % np.mean(rw))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show video\n", - "from IPython.display import HTML\n", - "import os\n", - "\n", - "video_names = list(\n", - " filter(lambda s: s.endswith(\".mp4\"), os.listdir(\"./records/\")))\n", - "\n", - "HTML(\"\"\"\n", - "\n", - "\"\"\".format(\"./videos/\" + video_names[-1])) # this may or may not be _last_ video. Try other indices" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Assignment part I (5 pts)\n", - "\n", - "We'll start by implementing target network to stabilize training.\n", - "\n", - "There are two ways to do so: \n", - "\n", - "\n", - "__1)__ Manually write lasagne network, or clone it via [one of those methods](https://github.com/Lasagne/Lasagne/issues/720).\n", - "\n", - "You will need to implement loading weights from original network to target network.\n", - "\n", - "We recommend thoroughly debugging your code on simple tests before applying it in Atari dqn.\n", - "\n", - "__2)__ Use pre-build functionality from [here](http://agentnet.readthedocs.io/en/master/modules/target_network.html)\n", - "\n", - "```\n", - "from agentnet.target_network import TargetNetwork\n", - "target_net = TargetNetwork(qvalues_layer)\n", - "old_qvalues = target_net.output_layers\n", - "\n", - "#agent's policy_estimators must now become (qvalues,old_qvalues)\n", - "\n", - "_,_,_,_,(qvalues,old_qvalues) = agent.get_sessions(...) #replaying experience\n", - "\n", - "\n", - "target_net.load_weights()#loads weights, so target network is now exactly same as main network\n", - "\n", - "target_net.load_weights(0.01)# w_target = 0.99*w_target + 0.01*w_new\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Bonus I (2+ pts)\n", - "\n", - "Implement and train double q-learning.\n", - "\n", - "This task contains of\n", - "* Implementing __double q-learning__ or __dueling q-learning__ or both (see tips below)\n", - "* Training a network till convergence\n", - " * Full points will be awwarded if your network gets average score of >=10 (see \"evaluating results\")\n", - " * Higher score = more points as usual\n", - " * If you're running out of time, it's okay to submit a solution that hasn't converged yet and updating it when it converges. _Lateness penalty will not increase for second submission_, so submitting first one in time gets you no penalty.\n", - "\n", - "\n", - "#### Tips:\n", - "* Implementing __double q-learning__ shouldn't be a problem if you've already have target networks in place.\n", - " * As one option, use `get_values_for_actions(,)`.\n", - " * You will probably need `T.argmax` to select best actions\n", - " * Here's an original [article](https://arxiv.org/abs/1509.06461)\n", - "\n", - "* __Dueling__ architecture is also quite straightforward if you have standard DQN.\n", - " * You will need to change network architecture, namely the q-values layer\n", - " * It must now contain two heads: V(s) and A(s,a), both dense layers\n", - " * You should then add them up via elemwise sum layer or a [custom](http://lasagne.readthedocs.io/en/latest/user/custom_layers.html) layer.\n", - " * Here's an [article](https://arxiv.org/pdf/1511.06581.pdf)\n", - " \n", - "Here's a template for your convenience:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from lasagne.layers import *\n", - "\n", - "\n", - "class DuelingQvaluesLayer(MergeLayer):\n", - " def get_output_for(self, inputs, **tags):\n", - " V, A = inputs\n", - " return \n", - "\n", - " def get_output_shape_for(self, input_shapes, **tags):\n", - " V_shape, A_shape=input_shapes\n", - " assert len(\n", - " V_shape) == 2 and V_shape[-1] == 1, \"V layer (first param) shape must be [batch,tick,1]\"\n", - " return A_shape # shape of q-values is same as predicted advantages" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# mock-up tests\n", - "import theano.tensor as T\n", - "v_tensor = -T.arange(10).reshape((10, 1))\n", - "V = InputLayer((None, 1), v_tensor)\n", - "\n", - "a_tensor = T.arange(30).reshape((10, 3))\n", - "A = InputLayer((None, 1), a_tensor)\n", - "\n", - "Q = DuelingQvaluesLayer([V, A])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "assert np.allclose(get_output(Q).eval(), (v_tensor+a_tensor).eval())\n", - "print(\"looks good\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Bonus II (5+ pts): Prioritized experience replay\n", - "\n", - "In this section, you're invited to implement prioritized experience replay\n", - "\n", - "* You will probably need to provide a custom data structure\n", - "* Once pool.update is called, collect the pool.experience_replay.observations, actions, rewards and is_alive and store them in your data structure\n", - "* You can now sample such transitions in proportion to the error (see [article](https://arxiv.org/abs/1511.05952)) for training.\n", - "\n", - "It's probably more convenient to explicitly declare inputs for \"sample observations\", \"sample actions\" and so on to plug them into q-learning.\n", - "\n", - "Prioritized (and even normal) experience replay should greatly reduce amount of game sessions you need to play in order to achieve good performance. \n", - "\n", - "While it's effect on runtime is limited for atari, more complicated envs (further in the course) will certainly benefit for it.\n", - "\n", - "Prioritized experience replay only supports off-policy algorithms, so pls enforce `n_steps=1` in your q-learning reference computation (default is 10)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week04_approx_rl/homework_pytorch_debug.ipynb b/week04_approx_rl/homework_pytorch_debug.ipynb index 197dfd52f..41b6a06cf 100644 --- a/week04_approx_rl/homework_pytorch_debug.ipynb +++ b/week04_approx_rl/homework_pytorch_debug.ipynb @@ -2,11 +2,13 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "SqZ2EwnTZdC8" + }, "source": [ "# Deep Q-Network implementation.\n", "\n", - "This homework shamelessly demands you to implement a DQN - an approximate q-learning algorithm with experience replay and target networks - and see if it works any better this way.\n", + "This homework shamelessly demands you to implement DQN — an approximate Q-learning algorithm with experience replay and target networks — and see if it works any better this way.\n", "\n", "Original paper:\n", "https://arxiv.org/pdf/1312.5602.pdf" @@ -14,7 +16,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "Zv7XJfXaZdC9" + }, "source": [ "**This notebook is given for debug.** The main task is in the other notebook (**homework_pytorch_main**). The tasks are similar and share most of the code. The main difference is in environments. In main notebook it can take some 2 hours for the agent to start improving so it seems reasonable to launch the algorithm on a simpler env first. Here it is CartPole and it will train in several minutes.\n", "\n", @@ -26,28 +30,23 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "setup complete\n", - "Starting virtual X frame buffer: Xvfb.\n" - ] - } - ], + "metadata": { + "id": "ioIEVODJZdC9" + }, + "outputs": [], "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - " \n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/atari_wrappers.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/utils.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/replay_buffer.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/framebuffer.py\n", + " os.makedirs('dqn', exist_ok=True)\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/atari_wrappers.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/utils.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/replay_buffer.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/framebuffer.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/analysis.py -P dqn/\n", "\n", - " !pip install gym[box2d]\n", + " !pip install gymnasium\n", "\n", " !touch .setup_complete\n", "\n", @@ -60,30 +59,36 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "FDZqlI3kZdC9" + }, "source": [ - "__Frameworks__ - we'll accept this homework in any deep learning framework. This particular notebook was designed for pytoch, but you find it easy to adapt it to almost any python-based deep learning framework." + "__Frameworks__ - we'll accept this homework in any deep learning framework. This particular notebook was designed for PyTorch, but you find it easy to adapt it to almost any Python-based deep learning framework." ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "dsYq558wZdC-" + }, "outputs": [], "source": [ "import random\n", "import numpy as np\n", "import torch\n", - "import utils" + "import dqn.utils\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "6ypPZ8e6ZdC-" + }, "outputs": [], "source": [ - "import gym\n", + "import gymnasium as gym\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" @@ -91,7 +96,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "9j8EGNlSZdC-" + }, "source": [ "### CartPole again\n", "\n", @@ -105,62 +112,48 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "v-5u-CcQZdC-" + }, "outputs": [], "source": [ - "ENV_NAME = 'CartPole-v1'\n", + "ENV_NAME = \"CartPole-v1\"\n", + "\n", "\n", - "def make_env(seed=None):\n", + "def make_env():\n", " # some envs are wrapped with a time limit wrapper by default\n", - " env = gym.make(ENV_NAME).unwrapped\n", - " if seed is not None:\n", - " env.seed(seed)\n", - " return env" + " env = gym.make(ENV_NAME, render_mode=\"rgb_array\").unwrapped\n", + " return env\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.6/dist-packages/gym/logger.py:30: UserWarning: \u001b[33mWARN: Box bound precision lowered by casting to float32\u001b[0m\n", - " warnings.warn(colorize('%s: %s'%('WARN', msg % args), 'yellow'))\n" - ] - }, - { - "data": { - "image/png": "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\nGYNbkjrzf0Ew7Is+EjUWAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - }, - "output_type": "display_data" - } - ], + "metadata": { + "id": "AmFXRrkqZdC-" + }, + "outputs": [], "source": [ "env = make_env()\n", "env.reset()\n", - "plt.imshow(env.render(\"rgb_array\"))\n", + "plt.imshow(env.render())\n", "state_shape, n_actions = env.observation_space.shape, env.action_space.n" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "qOyWgOmvZdC-" + }, "source": [ "### Building a network" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "XqpThLZXZdC-" + }, "source": [ "We now need to build a neural network that can map observations to state q-values.\n", "The model does not have to be huge yet. 1-2 hidden layers with < 200 neurons and ReLU activation will probably be enough. Batch normalization and dropout can spoil everything here." @@ -169,7 +162,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "UVlpkvZOZdC-" + }, "outputs": [], "source": [ "import torch\n", @@ -183,7 +178,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "RFva1cpyZdC-" + }, "outputs": [], "source": [ "class DQNAgent(nn.Module):\n", @@ -198,7 +195,7 @@ " state_dim = state_shape[0]\n", " \n", "\n", - " \n", + "\n", " def forward(self, state_t):\n", " \"\"\"\n", " takes agent's observation (tensor), returns qvalues (tensor)\n", @@ -208,8 +205,11 @@ " qvalues = \n", "\n", " assert qvalues.requires_grad, \"qvalues must be a torch tensor with grad\"\n", - " assert len(\n", - " qvalues.shape) == 2 and qvalues.shape[0] == state_t.shape[0] and qvalues.shape[1] == n_actions\n", + " assert (\n", + " len(qvalues.shape) == 2 and\n", + " qvalues.shape[0] == state_t.shape[0] and\n", + " qvalues.shape[1] == n_actions\n", + " )\n", "\n", " return qvalues\n", "\n", @@ -238,7 +238,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "Bv1s5JKzZdC-" + }, "outputs": [], "source": [ "agent = DQNAgent(state_shape, n_actions, epsilon=0.5).to(device)" @@ -246,7 +248,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "vazC0DPQZdC_" + }, "source": [ "Now let's try out our agent to see if it raises any errors." ] @@ -254,39 +258,34 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "e-Sg1cqPZdC_" + }, "outputs": [], "source": [ - "def evaluate(env, agent, n_games=1, greedy=False, t_max=10000):\n", + "def evaluate(env, agent, n_games=1, greedy=False, t_max=10000, seed=None):\n", " \"\"\" Plays n_games full games. If greedy, picks actions as argmax(qvalues). Returns mean reward. \"\"\"\n", " rewards = []\n", " for _ in range(n_games):\n", - " s = env.reset()\n", + " s, _ = env.reset(seed=seed)\n", " reward = 0\n", " for _ in range(t_max):\n", " qvalues = agent.get_qvalues([s])\n", " action = qvalues.argmax(axis=-1)[0] if greedy else agent.sample_actions(qvalues)[0]\n", - " s, r, done, _ = env.step(action)\n", + " s, r, terminated, truncated, _ = env.step(action)\n", " reward += r\n", - " if done:\n", + " if terminated or truncated:\n", " break\n", "\n", " rewards.append(reward)\n", " return np.mean(rewards)" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "evaluate(env, agent, n_games=1)" - ] - }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "Y_0NzjUEZdC_" + }, "source": [ "### Experience replay\n", "For this assignment, we provide you with experience replay buffer. If you implemented experience replay buffer in last week's assignment, you can copy-paste it here in main notebook **to get 2 bonus points**.\n", @@ -296,7 +295,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "jHyCO4TuZdC_" + }, "source": [ "#### The interface is fairly simple:\n", "* `exp_replay.add(obs, act, rw, next_obs, done)` - saves (s,a,r,s',done) tuple into the buffer\n", @@ -307,18 +308,18 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "wQEHwR1AZdC_" + }, "outputs": [], "source": [ - "from replay_buffer import ReplayBuffer\n", + "from dqn.replay_buffer import ReplayBuffer\n", "exp_replay = ReplayBuffer(10)\n", "\n", "for _ in range(30):\n", - " exp_replay.add(env.reset(), env.action_space.sample(),\n", - " 1.0, env.reset(), done=False)\n", + " exp_replay.add(env.reset()[0], env.action_space.sample(), 1.0, env.reset()[0], done=False)\n", "\n", - "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", - " 5)\n", + "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(5)\n", "\n", "assert len(exp_replay) == 10, \"experience replay size should be 10 because that's what maximum capacity is\"" ] @@ -326,14 +327,16 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "0RnFX5sfZdC_" + }, "outputs": [], "source": [ "def play_and_record(initial_state, agent, env, exp_replay, n_steps=1):\n", " \"\"\"\n", - " Play the game for exactly n steps, record every (s,a,r,s', done) to replay buffer. \n", - " Whenever game ends, add record with done=True and reset the game.\n", - " It is guaranteed that env has done=False when passed to this function.\n", + " Play the game for exactly n_steps, record every (s,a,r,s', done) to replay buffer.\n", + " Whenever game ends due to termination or truncation, add record with done=terminated and reset the game.\n", + " It is guaranteed that env has terminated=False when passed to this function.\n", "\n", " PLEASE DO NOT RESET ENV UNLESS IT IS \"DONE\"\n", "\n", @@ -351,46 +354,55 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZXXmFEKGZdC_", + "outputId": "d1b66847-a141-4406-9697-7ebd194fdb6a" + }, "outputs": [], "source": [ "# testing your code.\n", "exp_replay = ReplayBuffer(2000)\n", "\n", - "state = env.reset()\n", + "state, _ = env.reset()\n", "play_and_record(state, agent, env, exp_replay, n_steps=1000)\n", "\n", "# if you're using your own experience replay buffer, some of those tests may need correction.\n", "# just make sure you know what your code does\n", - "assert len(exp_replay) == 1000, \"play_and_record should have added exactly 1000 steps, \"\\\n", - " \"but instead added %i\" % len(exp_replay)\n", + "assert len(exp_replay) == 1000, \\\n", + " \"play_and_record should have added exactly 1000 steps, \" \\\n", + " \"but instead added %i\" % len(exp_replay)\n", "is_dones = list(zip(*exp_replay._storage))[-1]\n", "\n", - "assert 0 < np.mean(is_dones) < 0.1, \"Please make sure you restart the game whenever it is 'done' and record the is_done correctly into the buffer.\"\\\n", - " \"Got %f is_done rate over %i steps. [If you think it's your tough luck, just re-run the test]\" % (\n", - " np.mean(is_dones), len(exp_replay))\n", + "assert 0 < np.mean(is_dones) < 0.1, \\\n", + " \"Please make sure you restart the game whenever it is 'done' and \" \\\n", + " \"record the is_done correctly into the buffer. Got %f is_done rate over \" \\\n", + " \"%i steps. [If you think it's your tough luck, just re-run the test]\" % (\n", + " np.mean(is_dones), len(exp_replay))\n", "\n", "for _ in range(100):\n", - " obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", - " 10)\n", + " obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(10)\n", " assert obs_batch.shape == next_obs_batch.shape == (10,) + state_shape\n", - " assert act_batch.shape == (\n", - " 10,), \"actions batch should have shape (10,) but is instead %s\" % str(act_batch.shape)\n", - " assert reward_batch.shape == (\n", - " 10,), \"rewards batch should have shape (10,) but is instead %s\" % str(reward_batch.shape)\n", - " assert is_done_batch.shape == (\n", - " 10,), \"is_done batch should have shape (10,) but is instead %s\" % str(is_done_batch.shape)\n", - " assert [int(i) in (0, 1)\n", - " for i in is_dones], \"is_done should be strictly True or False\"\n", - " assert [\n", - " 0 <= a < n_actions for a in act_batch], \"actions should be within [0, n_actions]\"\n", + " assert act_batch.shape == (10,), \\\n", + " \"actions batch should have shape (10,) but is instead %s\" % str(act_batch.shape)\n", + " assert reward_batch.shape == (10,), \\\n", + " \"rewards batch should have shape (10,) but is instead %s\" % str(reward_batch.shape)\n", + " assert is_done_batch.shape == (10,), \\\n", + " \"is_done batch should have shape (10,) but is instead %s\" % str(is_done_batch.shape)\n", + " assert [int(i) in (0, 1) for i in is_dones], \\\n", + " \"is_done should be strictly True or False\"\n", + " assert [0 <= a < n_actions for a in act_batch], \"actions should be within [0, n_actions)\"\n", "\n", "print(\"Well done!\")" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "uoVGsnHRZdC_" + }, "source": [ "### Target networks\n", "\n", @@ -406,7 +418,13 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8BLJCNiuZdC_", + "outputId": "6181261a-60cf-4626-fbe6-930a6ccd9896" + }, "outputs": [], "source": [ "target_network = DQNAgent(agent.state_shape, agent.n_actions, epsilon=0.5).to(device)\n", @@ -416,7 +434,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "I_GGShX3ZdC_" + }, "source": [ "### Learning with... Q-learning\n", "Here we write a function similar to `agent.update` from tabular q-learning." @@ -424,7 +444,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "4hbg-xANZdC_" + }, "source": [ "Compute Q-learning TD error:\n", "\n", @@ -435,7 +457,7 @@ "$$ Q_{reference}(s,a) = r(s,a) + \\gamma \\cdot max_{a'} Q_{target}(s', a') $$\n", "\n", "Where\n", - "* $Q_{target}(s',a')$ denotes q-value of next state and next action predicted by __target_network__\n", + "* $Q_{target}(s',a')$ denotes Q-value of next state and next action predicted by __target_network__\n", "* $s, a, r, s'$ are current state, action, reward and next state respectively\n", "* $\\gamma$ is a discount factor defined two cells above.\n", "\n", @@ -448,7 +470,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "VxrEOC7mZdC_" + }, "outputs": [], "source": [ "def compute_td_loss(states, actions, rewards, next_states, is_done,\n", @@ -457,35 +481,32 @@ " check_shapes=False,\n", " device=device):\n", " \"\"\" Compute td loss using torch operations only. Use the formulae above. \"\"\"\n", - " states = torch.tensor(states, device=device, dtype=torch.float) # shape: [batch_size, *state_shape]\n", - "\n", - " # for some torch reason should not make actions a tensor\n", - " actions = torch.tensor(actions, device=device, dtype=torch.long) # shape: [batch_size]\n", - " rewards = torch.tensor(rewards, device=device, dtype=torch.float) # shape: [batch_size]\n", + " states = torch.tensor(states, device=device, dtype=torch.float32) # shape: [batch_size, *state_shape]\n", + " actions = torch.tensor(actions, device=device, dtype=torch.int64) # shape: [batch_size]\n", + " rewards = torch.tensor(rewards, device=device, dtype=torch.float32) # shape: [batch_size]\n", " # shape: [batch_size, *state_shape]\n", " next_states = torch.tensor(next_states, device=device, dtype=torch.float)\n", " is_done = torch.tensor(\n", " is_done.astype('float32'),\n", " device=device,\n", - " dtype=torch.float\n", + " dtype=torch.float32,\n", " ) # shape: [batch_size]\n", " is_not_done = 1 - is_done\n", "\n", " # get q-values for all actions in current states\n", - " predicted_qvalues = agent(states)\n", + " predicted_qvalues = agent(states) # shape: [batch_size, n_actions]\n", "\n", " # compute q-values for all actions in next states\n", - " predicted_next_qvalues = target_network(next_states)\n", - " \n", + " predicted_next_qvalues = target_network(next_states) # shape: [batch_size, n_actions]\n", + "\n", " # select q-values for chosen actions\n", - " predicted_qvalues_for_actions = predicted_qvalues[range(\n", - " len(actions)), actions]\n", + " predicted_qvalues_for_actions = predicted_qvalues[range(len(actions)), actions] # shape: [batch_size]\n", "\n", " # compute V*(next_states) using predicted next q-values\n", " next_state_values = \n", "\n", - " assert next_state_values.dim(\n", - " ) == 1 and next_state_values.shape[0] == states.shape[0], \"must predict one value per state\"\n", + " assert next_state_values.dim() == 1 and next_state_values.shape[0] == states.shape[0], \\\n", + " \"must predict one value per state\"\n", "\n", " # compute \"target q-values\" for loss - it's what's inside square parentheses in the above formula.\n", " # at the last state use the simplified formula: Q(s,a) = r(s,a) since s' doesn't exist\n", @@ -493,23 +514,24 @@ " target_qvalues_for_actions = \n", "\n", " # mean squared error loss to minimize\n", - " loss = torch.mean((predicted_qvalues_for_actions -\n", - " target_qvalues_for_actions.detach()) ** 2)\n", + " loss = torch.mean((predicted_qvalues_for_actions - target_qvalues_for_actions.detach()) ** 2)\n", "\n", " if check_shapes:\n", - " assert predicted_next_qvalues.data.dim(\n", - " ) == 2, \"make sure you predicted q-values for all actions in next state\"\n", - " assert next_state_values.data.dim(\n", - " ) == 1, \"make sure you computed V(s') as maximum over just the actions axis and not all axes\"\n", - " assert target_qvalues_for_actions.data.dim(\n", - " ) == 1, \"there's something wrong with target q-values, they must be a vector\"\n", + " assert predicted_next_qvalues.data.dim() == 2, \\\n", + " \"make sure you predicted q-values for all actions in next state\"\n", + " assert next_state_values.data.dim() == 1, \\\n", + " \"make sure you computed V(s') as maximum over just the actions axis and not all axes\"\n", + " assert target_qvalues_for_actions.data.dim() == 1, \\\n", + " \"there's something wrong with target q-values, they must be a vector\"\n", "\n", " return loss" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "pgZKcPPnZdC_" + }, "source": [ "Sanity checks" ] @@ -517,27 +539,31 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "Yp8eREoDZdC_" + }, "outputs": [], "source": [ - "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", - " 10)\n", + "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(10)\n", "\n", "loss = compute_td_loss(obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch,\n", " agent, target_network,\n", " gamma=0.99, check_shapes=True)\n", "loss.backward()\n", "\n", - "assert loss.requires_grad and tuple(loss.data.size()) == (\n", - " ), \"you must return scalar loss - mean over batch\"\n", - "assert np.any(next(agent.parameters()).grad.data.cpu().numpy() !=\n", - " 0), \"loss must be differentiable w.r.t. network weights\"\n", - "assert np.all(next(target_network.parameters()).grad is None), \"target network should not have grads\"" + "assert loss.requires_grad and tuple(loss.data.size()) == (), \\\n", + " \"you must return scalar loss - mean over batch\"\n", + "assert np.any(next(agent.parameters()).grad.data.cpu().numpy() != 0), \\\n", + " \"loss must be differentiable w.r.t. network weights\"\n", + "assert np.all(next(target_network.parameters()).grad is None), \\\n", + " \"target network should not have grads\"" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "8A1QtGVqZdC_" + }, "source": [ "### Main loop\n", "\n", @@ -547,7 +573,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "8lAUT94JZdC_" + }, "outputs": [], "source": [ "from tqdm import trange\n", @@ -558,10 +586,16 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "YOk81bdZZdC_", + "outputId": "2fd2404e-19e5-4ebe-b0e1-c6f7593db790" + }, "outputs": [], "source": [ - "seed = \n", + "seed = \n", "random.seed(seed)\n", "np.random.seed(seed)\n", "torch.manual_seed(seed)" @@ -570,13 +604,18 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "13K5t2CTZdDA", + "outputId": "031d4a0a-99c3-4cc3-f7c3-77e4d8a5a331" + }, "outputs": [], "source": [ - "env = make_env(seed)\n", "state_dim = env.observation_space.shape\n", "n_actions = env.action_space.n\n", - "state = env.reset()\n", + "state, _ = env.reset(seed=seed)\n", "\n", "agent = DQNAgent(state_dim, n_actions, epsilon=1).to(device)\n", "target_network = DQNAgent(state_dim, n_actions, epsilon=1).to(device)\n", @@ -586,21 +625,31 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "iD7PAlwQZdDA", + "outputId": "aeb4bb67-4776-4b02-e558-d9d1a3306d47" + }, "outputs": [], "source": [ - "exp_replay = ReplayBuffer(10**4)\n", + "from dqn.utils import is_enough_ram, linear_decay\n", + "\n", + "REPLAY_BUFFER_SIZE = 10**4\n", + "\n", + "exp_replay = ReplayBuffer(REPLAY_BUFFER_SIZE)\n", "for i in range(100):\n", - " if not utils.is_enough_ram(min_available_gb=0.1):\n", + " if not is_enough_ram(min_available_gb=0.1):\n", " print(\"\"\"\n", - " Less than 100 Mb RAM available. \n", + " Less than 100 Mb RAM available.\n", " Make sure the buffer size in not too huge.\n", " Also check, maybe other processes consume RAM heavily.\n", " \"\"\"\n", " )\n", " break\n", " play_and_record(state, agent, env, exp_replay, n_steps=10**2)\n", - " if len(exp_replay) == 10**4:\n", + " if len(exp_replay) == REPLAY_BUFFER_SIZE:\n", " break\n", "print(len(exp_replay))" ] @@ -608,7 +657,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "Zl2VCEYQZdDA" + }, "outputs": [], "source": [ "# # for something more complicated than CartPole\n", @@ -633,7 +684,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "x-sD-QyUZdDA" + }, "outputs": [], "source": [ "timesteps_per_epoch = 1\n", @@ -656,98 +709,120 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "piqDfKQAZdDA" + }, "outputs": [], "source": [ "mean_rw_history = []\n", "td_loss_history = []\n", "grad_norm_history = []\n", - "initial_state_v_history = []" + "initial_state_v_history = []\n", + "step = 0" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "Ks8NAV8AZdDA" + }, "outputs": [], "source": [ - "state = env.reset()\n", - "for step in trange(total_steps + 1):\n", - " if not utils.is_enough_ram():\n", - " print('less that 100 Mb RAM available, freezing')\n", - " print('make sure everything is ok and make KeyboardInterrupt to continue')\n", - " try:\n", - " while True:\n", - " pass\n", - " except KeyboardInterrupt:\n", - " pass\n", + "import time\n", "\n", - " agent.epsilon = utils.linear_decay(init_epsilon, final_epsilon, step, decay_steps)\n", + "def wait_for_keyboard_interrupt():\n", + " try:\n", + " while True:\n", + " time.sleep(1)\n", + " except KeyboardInterrupt:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sU3GSGZqZdDA" + }, + "outputs": [], + "source": [ + "state, _ = env.reset()\n", + "with trange(step, total_steps + 1) as progress_bar:\n", + " for step in progress_bar:\n", + " if not is_enough_ram():\n", + " print('less that 100 Mb RAM available, freezing')\n", + " print('make sure everything is ok and use KeyboardInterrupt to continue')\n", + " wait_for_keyboard_interrupt()\n", "\n", - " # play\n", - " _, state = play_and_record(state, agent, env, exp_replay, timesteps_per_epoch)\n", + " agent.epsilon = linear_decay(init_epsilon, final_epsilon, step, decay_steps)\n", "\n", - " # train\n", - " \n", + " # play\n", + " _, state = play_and_record(state, agent, env, exp_replay, timesteps_per_epoch)\n", "\n", - " loss = \n", + " # train\n", + " \n", "\n", - " loss.backward()\n", - " grad_norm = nn.utils.clip_grad_norm_(agent.parameters(), max_grad_norm)\n", - " opt.step()\n", - " opt.zero_grad()\n", + " loss = \n", "\n", - " if step % loss_freq == 0:\n", - " td_loss_history.append(loss.data.cpu().item())\n", - " grad_norm_history.append(grad_norm)\n", + " loss.backward()\n", + " grad_norm = nn.utils.clip_grad_norm_(agent.parameters(), max_grad_norm)\n", + " opt.step()\n", + " opt.zero_grad()\n", "\n", - " if step % refresh_target_network_freq == 0:\n", - " # Load agent weights into target_network\n", - " \n", + " if step % loss_freq == 0:\n", + " td_loss_history.append(loss.data.cpu().item())\n", + " grad_norm_history.append(grad_norm)\n", "\n", - " if step % eval_freq == 0:\n", - " # eval the agent\n", - " mean_rw_history.append(evaluate(\n", - " make_env(seed=step), agent, n_games=3, greedy=True, t_max=1000)\n", - " )\n", - " initial_state_q_values = agent.get_qvalues(\n", - " [make_env(seed=step).reset()]\n", - " )\n", - " initial_state_v_history.append(np.max(initial_state_q_values))\n", + " if step % refresh_target_network_freq == 0:\n", + " # Load agent weights into target_network\n", + " \n", + "\n", + " if step % eval_freq == 0:\n", + " mean_rw_history.append(evaluate(\n", + " make_env(), agent, n_games=3, greedy=True, t_max=1000, seed=step)\n", + " )\n", + " initial_state_q_values = agent.get_qvalues(\n", + " [make_env().reset(seed=step)[0]]\n", + " )\n", + " initial_state_v_history.append(np.max(initial_state_q_values))\n", "\n", - " clear_output(True)\n", - " print(\"buffer size = %i, epsilon = %.5f\" %\n", - " (len(exp_replay), agent.epsilon))\n", + " clear_output(True)\n", + " print(\"buffer size = %i, epsilon = %.5f\" %\n", + " (len(exp_replay), agent.epsilon))\n", "\n", - " plt.figure(figsize=[16, 9])\n", - " plt.subplot(2, 2, 1)\n", - " plt.title(\"Mean reward per episode\")\n", - " plt.plot(mean_rw_history)\n", - " plt.grid()\n", + " plt.figure(figsize=[16, 9])\n", "\n", - " assert not np.isnan(td_loss_history[-1])\n", - " plt.subplot(2, 2, 2)\n", - " plt.title(\"TD loss history (smoothened)\")\n", - " plt.plot(utils.smoothen(td_loss_history))\n", - " plt.grid()\n", + " plt.subplot(2, 2, 1)\n", + " plt.title(\"Mean reward per episode\")\n", + " plt.plot(mean_rw_history)\n", + " plt.grid()\n", "\n", - " plt.subplot(2, 2, 3)\n", - " plt.title(\"Initial state V\")\n", - " plt.plot(initial_state_v_history)\n", - " plt.grid()\n", + " assert not np.isnan(td_loss_history[-1])\n", + " plt.subplot(2, 2, 2)\n", + " plt.title(\"TD loss history\")\n", + " plt.plot(td_loss_history)\n", + " plt.grid()\n", "\n", - " plt.subplot(2, 2, 4)\n", - " plt.title(\"Grad norm history (smoothened)\")\n", - " plt.plot(utils.smoothen(grad_norm_history))\n", - " plt.grid()\n", + " plt.subplot(2, 2, 3)\n", + " plt.title(\"Initial state V\")\n", + " plt.plot(initial_state_v_history)\n", + " plt.grid()\n", "\n", - " plt.show()" + " plt.subplot(2, 2, 4)\n", + " plt.title(\"Grad norm history\")\n", + " plt.plot(grad_norm_history)\n", + " plt.grid()\n", + "\n", + " plt.show()" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "qwWFT2SBZdDA" + }, "outputs": [], "source": [ "final_score = evaluate(\n", @@ -761,7 +836,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "G-feeX9YZdDA" + }, "source": [ "**Agent's predicted V-values vs their Monte-Carlo estimates**" ] @@ -769,11 +846,15 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "rjVuSIrPZdDA" + }, "outputs": [], "source": [ + "from analysis import play_and_log_episode\n", + "\n", "eval_env = make_env()\n", - "record = utils.play_and_log_episode(eval_env, agent)\n", + "record = play_and_log_episode(eval_env, agent)\n", "print('total reward for life:', np.sum(record['rewards']))\n", "for key in record:\n", " print(key)" @@ -782,7 +863,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "FCacwLw6ZdDA" + }, "outputs": [], "source": [ "fig = plt.figure(figsize=(5, 5))\n", @@ -803,11 +886,17 @@ } ], "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, "language_info": { - "name": "python", - "pygments_lexer": "ipython3" + "name": "python" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 0 } diff --git a/week04_approx_rl/homework_pytorch_main.ipynb b/week04_approx_rl/homework_pytorch_main.ipynb index b1d91e0ec..d2628ec9a 100644 --- a/week04_approx_rl/homework_pytorch_main.ipynb +++ b/week04_approx_rl/homework_pytorch_main.ipynb @@ -2,49 +2,66 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "1NDjJiqysoT-" + }, "source": [ "# Deep Q-Network implementation.\n", "\n", - "This homework shamelessly demands you to implement a DQN - an approximate q-learning algorithm with experience replay and target networks - and see if it works any better this way.\n", + "This homework shamelessly demands you to implement DQN — an approximate Q-learning algorithm with experience replay and target networks — and see if it works any better this way.\n", + "\n", + "**Papers:**\n", + "\n", + "[1] Original paper, 2013: https://arxiv.org/pdf/1312.5602.pdf\n", "\n", - "Original paper:\n", - "https://arxiv.org/pdf/1312.5602.pdf" + "[2] Extended paper, Nature, 2015: https://web.stanford.edu/class/psych209/Readings/MnihEtAlHassibis15NatureControlDeepRL.pdf\n", + "\n", + "[3] Rainbow, 2017: https://arxiv.org/pdf/1710.02298.pdf" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "BcLhaXMKsoT_" + }, "source": [ - "**This notebook is the main notebook.** Another notebook is given for debug. (**homework_pytorch_main**). The tasks are similar and share most of the code. The main difference is in environments. In main notebook it can take some 2 hours for the agent to start improving so it seems reasonable to launch the algorithm on a simpler env first. In debug one it is CartPole and it will train in several minutes.\n", + "**This notebook is the main homework notebook.**\n", + "Another notebook is given for debug: (**homework_pytorch_debug**). The debug notebook is not supported anymore, the codes have diverged. However, it can be useful in some cases. The tasks are similar and they used to share most of the code. The main difference is in environments. In main notebook it can take some 2 hours for the agent to start improving so it seems reasonable to launch the algorithm on a simpler env first. In debug one it is CartPole and it will train in several minutes.\n", "\n", - "**We suggest the following pipeline:** First implement debug notebook then implement the main one.\n", + "**About evaluation:** All points are only given for the main notebook.\n", "\n", - "**About evaluation:** All points are given for the main notebook with one exception: if agent fails to beat the threshold in main notebook you can get 1 pt (instead of 3 pts) for beating the threshold in debug notebook." + "**Plan and evaluation points:**\n", + "1. Getting to know the environment: most of the code is implemented for you\n", + "2. DQN as it is (10 points): the main part of DQN implementation\n", + "3. Main Loop (3 points): the training loop itself. Please, note, it can be really time-consuming, and implementation bugs can arise.\n", + "4. Interpretation (2 points): calculation of episode statistics and their interpretation" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Starting virtual X frame buffer: Xvfb.\n" - ] - } - ], + "metadata": { + "id": "IVo0UxTWsoT_" + }, + "outputs": [], "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - " \n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/atari_wrappers.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/utils.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/replay_buffer.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/framebuffer.py\n", + " os.makedirs('dqn', exist_ok=True)\n", + " os.makedirs('test_td_loss', exist_ok=True)\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/atari_wrappers.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/utils.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/replay_buffer.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/framebuffer.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/analysis.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/dqn/logger.py -P dqn/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/test_td_loss/compute_td_loss.py -P test_td_loss/\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/requirements.txt\n", + "\n", + " !pip install -r requirements.txt\n", "\n", " !touch .setup_complete\n", "\n", @@ -57,21 +74,47 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "KkrBeP7YsoUA" + }, "source": [ - "__Frameworks__ - we'll accept this homework in any deep learning framework. This particular notebook was designed for pytoch, but you find it easy to adapt it to almost any python-based deep learning framework." + "__Frameworks__ - we'll accept this homework in any deep learning framework. This particular notebook was designed for PyTorch, but you find it easy to adapt it to almost any Python-based deep learning framework." ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "P8WoWe9DsoUA" + }, "outputs": [], "source": [ - "import random\n", + "%matplotlib inline\n", + "import gymnasium as gym\n", + "import ale_py\n", "import numpy as np\n", - "import torch\n", - "import utils" + "import matplotlib.pyplot as plt\n", + "\n", + "gym.register_envs(ale_py)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6GQBgViKsoUA" + }, + "source": [ + "### Let's play some old videogames\n", + "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/yet_another_week/_resource/nerd.png)\n", + "\n", + "This time we're gonna apply approximate Q-learning to an Atari game called Breakout. It's not the hardest thing out there, but it's definitely way more complex than anything we have tried before." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**These are various versions of Breakout provided by Gynmasium:**" ] }, { @@ -80,65 +123,84 @@ "metadata": {}, "outputs": [], "source": [ - "import gym\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline" + "all_names = list(gym.envs.registry.keys())\n", + "names_breakout = [name for name in all_names if \"Break\" in name]\n", + "names_breakout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "S_zvw_31soUA" + }, + "outputs": [], + "source": [ + "# ENV_NAME = \"BreakoutDeterministic-v4\" # this one is simpler\n", + "ENV_NAME = \"ALE/Breakout-v5\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Let's play some old videogames\n", - "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/yet_another_week/_resource/nerd.png)\n", + "If you are curious about Atari environments in Gymnasium, please, refer to:\n", + "- [4] Gymnasium docs: https://gymnasium.farama.org/environments/atari/\n", + "- [5] Longer paper: https://arxiv.org/abs/1709.06009\n", + "- [6] Shorter paper: https://www.ijcai.org/Proceedings/2018/0787.pdf\n", "\n", - "This time we're gonna apply approximate q-learning to an Atari game called Breakout. It's not the hardest thing out there, but it's definitely way more complex than anything we tried before.\n" + "For now it's enough to know about the v5 environments:\n", + "- v5 environments are recommended for use\n", + "- frame_skip=5, every 5-th frame is shown to the agent and the chosen action is executed for the next 5 moves\n", + "- randomness comes from repeat_action_probability=0.25: with this probability the previous action is executed instead of the chosen action" ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "metadata": { + "id": "xT9BvasNsoUA" + }, "source": [ - "ENV_NAME = \"BreakoutNoFrameskip-v4\"" + "## Getting to know the Environment" ] }, { "cell_type": "markdown", + "metadata": { + "id": "iwN8jA0OsoUA" + }, + "source": [ + "**Let's see what observations look like.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "## Preprocessing (3 pts)" + "env = gym.make(ENV_NAME, render_mode=\"rgb_array\")\n", + "env.reset()\n", + "plt.imshow(env.render())\n", + "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let's see what observations look like." + "**Some more observations, coming from taking random actions**" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\nKQAAAN2c23uAyTeSHJ8+bqoXxvw97WT+v7WKQU5D4/3thfl7Nv4XSR7q+Pzz2gt9rLt1btz38P72\nwvz+njKfvdDIOpur8bU40VGSVNWRTf7He83f1ybMvwkznon5+1r3+dd9vu2Yv791/29Y9/m2Y/6+\nNmH+TZjxTMzf17zze/suAAAA3VhKAQAA6GadltJDvQeYk/n72oT5N2HGMzF/X+s+/7rPtx3z97fu\n/w3rPt92zN/XJsy/CTOeifn7mmv+tfmdUgAAAPaedXqlFAAAgD3GUgoAAEA33ZfSqjpQVQ9V1SNV\ndWPveXaiqh6rqs9V1f1VdWQ69vyquruqHp4+nt97zllVdUtVPVlVD84cO+XMteUD05/JA1X1in6T\n/2DWU83/3qo6Ov053F9VV8/c9q5p/oeq6mf6TP2DWTS+ZPruS+PLp/F+NrHvROOrpvHV2rS+E41v\n+wSttW6XJOckeTTJS5I8J8mfJXlZz5l2OPdjSV540rFfT3LjdP3GJP+h95wnzfeaJK9I8uB2Mye5\nOsnvJ6kkVyX59JrO/94k//oU933Z1NJzk1w2NXZOp7k13q8Pfa9mdo33a0Tjy597I/ueZtd4//k1\nvry5N6rvMzSi8enS+5XSK5M80lr7Smvt+0k+kuSazjPt1jVJbp2u35rkjR1n+RGttU8leeqkw6eb\n+ZokH25b7k1yXlVduJpJT+0085/ONUk+0lr7Xmvtz5M8kq3WetD4Cui7W9+JxldC476HL4jGl0Tj\na2Ft+040nm0a772UXpTkazOfPz4dW3ctySer6r6qOjgdu6C1dmy6/vUkF/QZ7aycbuZN+nN55/S2\nhltm3qaxTvOv0yxnY4TG9b0a6zbPTml8Pax74+s0y9nS+HrQ+HKM0Hei8R/ovZRuqle11l6R5A1J\n3lFVr5m9sW29br1R/9bOJs6c5OYkL01yRZJjSd7Xd5yhDNX4ps070fdyabw/jS+XxvvT+PIM1Xey\nmTNngY33XkqPJrlk5vOLp2NrrbV2dPr4ZJKPZ+vl6CdOvKw+fXyy34Q7drqZN+LPpbX2RGvtmdba\ns0k+mB++LWCd5l+nWXZskMb1vRrrNs+OaLy/DWl8nWY5KxrvT+PLM0jficZ/oPdS+pkkl1fVZVX1\nnCTXJrmj80xnVFX7qup5J64neX2SB7M19/XT3a5P8ok+E56V0818R5K3TGf+uirJt2beWrA2Tnpv\n/Zuy9eeQbM1/bVU9t6ouS3J5kj9Z9XwTjfej79XQeD8aX76N6zvR+LrQ+HIM1Hei8R8601mQVnHJ\n1tmlvpytszK9u/c8O5j3Jdk6m9SfJfn8iZmTvCDJPUkeTvIHSZ7fe9aT5r4tWy+r/1W23tf91tPN\nnK0zff3m9GfyuST713T+/zLN98AU/4Uz93/3NP9DSd7QeXaN9+lD36ubX+N9GtH4ambfqL6nmTW+\nHvNrfDnzblzfZ2hE49OlpgcBAADAyvV++y4AAAB7mKUUAACAbiylAAAAdGMpBQAAoBtLKQAAAN1Y\nSgEAAOjGUgoAAEA3llIAAAC6sZQCAADQjaUUAACAbiylAAAAdGMpBQAAoBtLKQAAAN1YSgEAAOjG\nUgoAAEA3llIAAAC6sZQCAADQjaUUAACAbiylAAAAdGMpBQAAoBtLKQAAAN1YSgEAAOjGUgoAAEA3\nllIAAAC6sZQCAADQjaUUAACAbiylAAAAdGMpBQAAoBtLKQAAAN1YSgEAAOjGUgoAAEA3llIAAAC6\nsZQCAADQjaUUAACAbiylAAAAdGMpBQAAoBtLKQAAAN1YSgEAAOjGUgoAAEA3llIAAAC6sZQCAADQ\njaUUAACAbiylAAAAdGMpBQAAoBtLKQAAAN0sbSmtqgNV9VBVPVJVNy7reaAHfTM6jTM6jTM6jbNJ\nqrW2+C9adU6SLyf56SSPJ/lMkutaa19Y+JPBiumb0Wmc0Wmc0WmcTbOsV0qvTPJIa+0rrbXvJ/lI\nkmuW9FywavpmdBpndBpndBpno5y7pK97UZKvzXz+eJJ/MHuHqjqY5OD06SuXNAfM+kZr7UUL+Drb\n9p1onC40zuhW1ri+6WBRfScaZz2dtvFlLaXbaq0dSnIoSapq8e8hhh/11VU+mcbpQOOMbmWN65sO\nfA9ndKdtfFlv3z2a5JKZzy+ejsEI9M3oNM7oNM7oNM5GWdZS+pkkl1fVZVX1nCTXJrljSc8Fq6Zv\nRqdxRqdxRqdxNspS3r7bWnu6qt6Z5H8kOSfJLa21zy/juRbtpptu2vF9b7jhhl0/9uTHz/PYefV8\n7pOdPMsyn2u3NrnvROOrfu6TaXz5NL7a5z6ZxpdL36t97pNtQt+JxnfzeI1v6dX40n6ntLV2Z5I7\nl/X1oSd9MzqNMzqNMzqNs0m6nehoEyzypy9n+/h5n3se6/pTPxZP44xO44xM34xO43vHsn6nFAAA\n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\nm+5Icv10/fokn5g5/pbpzF9XJfnWzFsLYO1onNFpnJHpm9FpnD2htXbGS5JXJWlJHkhy/3S5OskL\nsnWmr4eT/EGS50/3ryS/meTRJJ9Lsn8Hz9FcXFZwOaJxl8EvGncZ/fIjjUffLuNcfA93Gf1yysZb\na6kpxK7O9j3wsEv+UWpGp3FG16VxfbMivoczutM2flZn3wUAAIBFspQCAADQjaUUAACAbiylAAAA\ndHNu7wEm30hyfPq4qV4Y8/e0k/n/1ioGOQ2N97cX5u/Z+F8keajj889rL/Sx7ta5cd/D+9sL8/t7\nynz2QiPrbK7G1+Lsu0lSVUc2+R/vNX9fmzD/Jsx4Jubva93nX/f5tmP+/tb9v2Hd59uO+fvahPk3\nYcYzMX9f887v7bsAAAB0YykFAACgm3VaSg/1HmBO5u9rE+bfhBnPxPx9rfv86z7fdszf37r/N6z7\nfNsxf1+bMP8mzHgm5u9rrvnX5ndKAQAA2HvW6ZVSAAAA9hhLKQAAAN10X0qr6kBVPVRVj1TVjb3n\n2YmqeqyqPldV91fVkenY86vq7qp6ePp4fu85Z1XVLVX1ZFU9OHPslDPXlg9MfyYPVNUr+k3+g1lP\nNf97q+ro9Odwf1VdPXPbu6b5H6qqn+kz9Q9m0fiS6bsvjS+fxvvZxL4Tja+axldr0/pONL7tE7TW\nul2SnJPk0SQvSfKcJH+W5GU9Z9rh3I8leeFJx349yY3T9RuT/Ifec54032uSvCLJg9vNnOTqJL+f\npJJcleTTazr/e5P861Pc92VTS89NctnU2Dmd5tZ4vz70vZrZNd6vEY0vf+6N7HuaXeP959f48ube\nqL7P0IjGp0vvV0qvTPJIa+0rrbXvJ/lIkms6z7Rb1yS5dbp+a5I3dpzlR7TWPpXkqZMOn27ma5J8\nuG25N8l5VXXhaiY9tdPMfzrXJPlIa+17rbU/T/JItlrrQeMroO9ufScaXwmN+x6+IBpfEo2vhbXt\nO9F4tmm891J6UZKvzXz++HRs3bUkn6yq+6rq4HTsgtbasen615Nc0Ge0s3K6mTfpz+Wd09sabpl5\nm8Y6zb9Os5yNERrX92qs2zw7pfH1sO6Nr9MsZ0vj60HjyzFC34nGf6D3UrqpXtVae0WSNyR5R1W9\nZvbGtvW69Ub9WzubOHOSm5O8NMkVSY4leV/fcYYyVOObNu9E38ul8f40vlwa70/jyzNU38lmzpwF\nNt57KT2a5JKZzy+ejq211trR6eOTST6erZejnzjxsvr08cl+E+7Y6WbeiD+X1toTrbVnWmvPJvlg\nfvi2gHWaf51m2bFBGtf3aqzbPDui8f42pPF1muWsaLw/jS/PIH0nGv+B3kvpZ5JcXlWXVdVzklyb\n5I7OM51RVe2rqueduJ7k9UkezNbc1093uz7JJ/pMeFZON/MdSd4ynfnrqiTfmnlrwdo46b31b8rW\nn0OyNf+1VfXcqrosyeVJ/mTV80003o++V0Pj/Wh8+Tau70Tj60LjyzFQ34nGf+hMZ0FaxSVbZ5f6\ncrbOyvTu3vPsYN6XZOtsUn+W5PMnZk7ygiT3JHk4yR8keX7vWU+a+7Zsvaz+V9l6X/dbTzdzts70\n9ZvTn8nnkuxf0/n/yzTfA1P8F87c/93T/A8leUPn2TXepw99r25+jfdpROOrmX2j+p5m1vh6zK/x\n5cy7cX2foRGNT5eaHgQAAAAr1/vtuwAAAOxhllIAAAC6sZQCAADQjaUUAACAbiylAAAAdGMpBQAA\noBtLKQAAAN38P4MFx8hKCA3KAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "tags": [] - }, - "output_type": "display_data" - } - ], - "source": [ - "env = gym.make(ENV_NAME)\n", + "metadata": { + "id": "rUZHU2HdsoUB" + }, + "outputs": [], + "source": [ + "env = gym.make(ENV_NAME, render_mode=\"rgb_array\")\n", "env.reset()\n", "\n", "n_cols = 5\n", @@ -148,7 +210,7 @@ "for row in range(n_rows):\n", " for col in range(n_cols):\n", " ax = fig.add_subplot(n_rows, n_cols, row * n_cols + col + 1)\n", - " ax.imshow(env.render('rgb_array'))\n", + " ax.imshow(env.render())\n", " env.step(env.action_space.sample())\n", "plt.show()" ] @@ -156,6 +218,44 @@ { "cell_type": "markdown", "metadata": {}, + "source": [ + "**About the game:** You have 5 lives and get points for breaking the wall. Higher bricks cost more than the lower ones. There are 4 actions: start game (should be called at the beginning and after each life is lost), move left, move right and do nothing. There are some common wrappers used for Atari environments." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Let's take a look at action meanings:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env.unwrapped.get_action_meanings()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. NOOP stands for the action of doing nothing\n", + "2. Right and Left move the platform to the corresponding direction\n", + "3. Fire releases the ball in the beginning of a life\n", + "\n", + "In this assignment we will wrap the environment to execute the \"Fire\" action in the beginning of a life automatically. It will turn the \"FIRE\" action into another \"NOOP\". \n", + "Also, we will wrap the environment to make an episode last for 1 life instead of 5 ones. \n", + "These transforms are claimed as non-recommended in the paper [5] but it was done in the original paper [1] and it will help the training to converge faster. " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hLNt1fbnsoUB" + }, "source": [ "**Let's play a little.**\n", "\n", @@ -165,33 +265,73 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "WOIL47azsoUB" + }, "outputs": [], "source": [ - "# # does not work in Colab.\n", - "# # make keyboard interrupt to continue\n", + "# # Does not work in Colab.\n", + "# Even on a local laptop breaks matplotlib rendering. So it's recommended to restart the notebook after playing.\n", + "# # Use the Escape button to continue.\n", "\n", - "# from gym.utils.play import play\n", + "# from gymnasium.utils.play import play\n", "\n", - "# play(env=gym.make(ENV_NAME), zoom=5, fps=30)" + "# play(env=gym.make(ENV_NAME, render_mode=\"rgb_array\"), zoom=4, fps=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Processing game image \n", + "## Wrapping the Environment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def make_basic_env():\n", + " return gym.make(ENV_NAME, render_mode=\"rgb_array\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5DPrxQuXsoUB" + }, + "source": [ + "### Processing game image\n", "\n", - "Raw Atari images are large, 210x160x3 by default. However, we don't need that level of detail in order to learn them.\n", + "Let's check the shape and the dtype of the observation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env = make_basic_env()\n", + "obs, *_ = env.reset()\n", + "obs.shape, obs.dtype" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Raw Atari images are large, 210x160x3 by default. However, we don't need that level of detail in order to learn from them.\n", "\n", "We can thus save a lot of time by preprocessing game image, including\n", - "* Resizing to a smaller shape, 64 x 64\n", + "* Resizing to a smaller shape, 64x64 (or 84 x 84, which is used in literature)\n", "* Converting to grayscale\n", - "* Cropping irrelevant image parts (top, bottom and edges)\n", - "\n", - "Also please keep one dimension for channel so that final shape would be 1 x 64 x 64.\n", + "* Cropping irrelevant image parts (top, bottom and edges) \\[we won't do this\\]\n", "\n", - "Tip: You can implement your own grayscale converter and assign a huge weight to the red channel. This dirty trick is not necessary but it will speed up learning." + "The images are of the uint8 dtype. \n", + "uint8 stands for the 8-bit unsigned integer type. \n", + "We are going to store 10^5 or 10^6 observations in memory (RAM), so let's pay attention to preserving the 8-bit type after our transforms." ] }, { @@ -200,35 +340,73 @@ "metadata": {}, "outputs": [], "source": [ - "from gym.core import ObservationWrapper\n", - "from gym.spaces import Box\n", + "def apply_gray_scale_wrap(env):\n", + " # With the argument values chosen as below, the gym.wrappers.AtariPreprocessing wrapper\n", + " # only converts images to grayscale and downsamples them the screen_size\n", + " env = gym.wrappers.AtariPreprocessing(\n", + " env,\n", + " noop_max=0, # the default value 30 can be harmful with FireResetEnv and frame_skip=5\n", + " frame_skip=1, # frame_skip has already been set to 5 inside the env\n", + " terminal_on_life_loss=False, # we do this explicitly in the FireResetEnv wrapper\n", + " screen_size=84 # please use 84 (which is the standard value) or 64 (which will save some computations and memory)\n", + " )\n", + " return env\n", "\n", "\n", - "class PreprocessAtariObs(ObservationWrapper):\n", - " def __init__(self, env):\n", - " \"\"\"A gym wrapper that crops, scales image into the desired shapes and grayscales it.\"\"\"\n", - " ObservationWrapper.__init__(self, env)\n", + "env = make_basic_env()\n", + "env = apply_gray_scale_wrap(env)\n", "\n", - " self.img_size = (1, 64, 64)\n", - " self.observation_space = Box(0.0, 1.0, self.img_size)\n", + "obs, *_ = env.reset()\n", "\n", + "assert obs.dtype == np.dtype('uint8'), obs_dtype\n", "\n", - " def _to_gray_scale(self, rgb, channel_weights=[0.8, 0.1, 0.1]):\n", - " \n", + "print(obs.shape, obs.dtype)\n", + "plt.imshow(obs)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Atari specific wrappers\n", + "\n", + "We try to make our lives a little easier with the following wrappers:\n", + "1. EpisodicLifeEnv it makes the signal that dropping a ball is not good more explicit\n", + "2. Using FireResetEnv: with it the agent doesn't have to perform a special action to fire the ball in the beginning of a life" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from dqn.atari_wrappers import FireResetEnv\n", + "from dqn.atari_wrappers import EpisodicLifeEnv\n", + "\n", + "def apply_atary_specific_wrap(env):\n", + " env = EpisodicLifeEnv(env)\n", + " env = FireResetEnv(env)\n", + " return env\n", "\n", + "env = make_basic_env()\n", + "env = apply_gray_scale_wrap(env)\n", + "env = apply_atary_specific_wrap(env)\n", "\n", - " def observation(self, img):\n", - " \"\"\"what happens to each observation\"\"\"\n", + "obs, *_ = env.reset()\n", "\n", - " # Here's what you need to do:\n", - " # * crop image, remove irrelevant parts\n", - " # * resize image to self.img_size\n", - " # (use imresize from any library you want,\n", - " # e.g. opencv, skimage, PIL, keras)\n", - " # * cast image to grayscale\n", - " # * convert image pixels to (0,1) range, float32 type\n", - " \n", - " return " + "print(obs.shape, obs.dtype)\n", + "plt.imshow(obs)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### FrameStack\n", + "To make the game playable from a single observation (note the direction of the ball), we stack 4 consecutive frames:" ] }, { @@ -237,52 +415,58 @@ "metadata": {}, "outputs": [], "source": [ - "import gym\n", - "# spawn game instance for tests\n", - "env = gym.make(ENV_NAME) # create raw env\n", - "env = PreprocessAtariObs(env)\n", - "observation_shape = env.observation_space.shape\n", - "n_actions = env.action_space.n\n", - "env.reset()\n", - "obs, _, _, _ = env.step(env.action_space.sample())\n", + "N_FRAMES_STACKED = 4\n", "\n", - "# test observation\n", - "assert obs.ndim == 3, \"observation must be [channel, h, w] even if there's just one channel\"\n", - "assert obs.shape == observation_shape\n", - "assert obs.dtype == 'float32'\n", - "assert len(np.unique(obs)) > 2, \"your image must not be binary\"\n", - "assert 0 <= np.min(obs) and np.max(\n", - " obs) <= 1, \"convert image pixels to [0,1] range\"\n", + "def make_final_env(apply_frame_stack=True):\n", + " \"\"\"\n", + " Builds the environment with all the wrappers applied.\n", + " The environment is meant be used directly as an RL algorithm input.\n", "\n", - "assert np.max(obs) >= 0.5, \"It would be easier to see a brighter observation\"\n", - "assert np.mean(obs) >= 0.1, \"It would be easier to see a brighter observation\"\n", + " apply_frame_stack=False can be useful for vecotrized environments, which are not required for this assignment.\n", + " \"\"\"\n", + " env = make_basic_env()\n", + " env = apply_gray_scale_wrap(env)\n", + " env = apply_atary_specific_wrap(env)\n", + " if apply_frame_stack:\n", + " env = # your code. Please, use gym.wrappers.FrameStackObservation\n", + " return env\n", "\n", - "print(\"Formal tests seem fine. Here's an example of what you'll get.\")\n", "\n", - "n_cols = 5\n", - "n_rows = 2\n", - "fig = plt.figure(figsize=(16, 9))\n", - "obs = env.reset()\n", - "for row in range(n_rows):\n", - " for col in range(n_cols):\n", - " ax = fig.add_subplot(n_rows, n_cols, row * n_cols + col + 1)\n", - " ax.imshow(obs[0, :, :], interpolation='none', cmap='gray')\n", - " obs, _, _, _ = env.step(env.action_space.sample())\n", - "plt.show()\n" + "env = make_final_env()\n", + "\n", + "obs, *_ = env.reset()\n", + "print(f\"Shape: {obs.shape}, dtype: {obs.dtype}, Python object type: {type(obs)}\")\n", + "for _ in range(N_FRAMES_STACKED - 1):\n", + " obs, *_ = env.step(env.action_space.sample())\n", + "print()\n", + "\n", + "\n", + "print(\"Frames, left to right: from older to more recent. The ball is dropping.\")\n", + "_, axes = plt.subplots(figsize=(len(obs) * 3, 4), ncols=len(obs))\n", + "for ax, frame in zip(axes, obs):\n", + " ax.imshow(frame)\n", + "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Wrapping." + "**That is the final version of the environment we are going to do RL on.**\n", + "\n", + "**Let's discuss the representation of an obsevation.**\\\n", + "An observation is a 4-frame-stack of grayscale images with reduced resolution.\\\n", + "Memory (RAM) is a high-demand resource in this task. That's why:\n", + "1. We use the uint8 dtype instead of float32 the neural network will operate on\n", + "2. We don't represent them as numpy.ndarrays. **LazyFrames** are used by gym.wrappers.FrameStack instead. 2 consecutive observations share 3 of 4 frames. LazyFrames make use of this fact to save memory.\n", + "When we feed the observations to neural networks, we should remember to scale them to the \\[-1, 1\\] range. We'll implement scaling as the first layer of a neural network, but that'll be later." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**About the game:** You have 5 lives and get points for breaking the wall. Higher bricks cost more than the lower ones. There are 4 actions: start game (should be called at the beginning and after each life is lost), move left, move right and do nothing. There are some common wrappers used for Atari environments." + "**The ball is dropping, but its hard to notice. Let's define a function to render more human-readable images:**" ] }, { @@ -291,43 +475,33 @@ "metadata": {}, "outputs": [], "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "import atari_wrappers\n", - "\n", - "def PrimaryAtariWrap(env, clip_rewards=True):\n", - " assert 'NoFrameskip' in env.spec.id\n", - "\n", - " # This wrapper holds the same action for frames and outputs\n", - " # the maximal pixel value of 2 last frames (to handle blinking\n", - " # in some envs)\n", - " env = atari_wrappers.MaxAndSkipEnv(env, skip=4)\n", + "def merge_frame_stack_to_plot(frame_stack_obs: np.ndarray | gym.wrappers.frame_stack.LazyFrames):\n", + " \"\"\"\n", + " A helper function to plot a frame stack as a single human-interpretable image.\n", "\n", - " # This wrapper sends done=True when each life is lost\n", - " # (not all the 5 lives that are givern by the game rules).\n", - " # It should make easier for the agent to understand that losing is bad.\n", - " env = atari_wrappers.EpisodicLifeEnv(env)\n", + " Brighter pixels are more recent, pale pixels are older.\n", + " Motions goes from pale to bright.\n", "\n", - " # This wrapper laucnhes the ball when an episode starts.\n", - " # Without it the agent has to learn this action, too.\n", - " # Actually it can but learning would take longer.\n", - " env = atari_wrappers.FireResetEnv(env)\n", + " Note! This function is designed for human vision convenience and it is NOT supposed to be used as part of\n", + " data preprocessing for the Reinforcement Learning agent.\n", + " \"\"\"\n", + " weights = np.ones(frame_stack_obs.shape[0], dtype=float)\n", + " weights[-1] += weights.sum()\n", + " weights /= weights.sum()\n", + " result = (weights[:, None, None] * frame_stack_obs).sum(0)\n", + " return result\n", "\n", - " # This wrapper transforms rewards to {-1, 0, 1} according to their sign\n", - " if clip_rewards:\n", - " env = atari_wrappers.ClipRewardEnv(env)\n", "\n", - " # This wrapper is yours :)\n", - " env = PreprocessAtariObs(env)\n", - " return env" + "obs_joint = merge_frame_stack_to_plot(obs)\n", + "plt.imshow(obs_joint)\n", + "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Let's see if the game is still playable after applying the wrappers.**\n", - "At playing the EpisodicLifeEnv wrapper seems not to work but actually it does (because after when life finishes a new ball is dropped automatically - it means that FireResetEnv wrapper understands that a new episode began)." + "Hope that's better" ] }, { @@ -336,30 +510,92 @@ "metadata": {}, "outputs": [], "source": [ - "# # does not work in Colab.\n", - "# # make keyboard interrupt to continue\n", + "N_ACTIONS = env.action_space.n\n", + "STATE_SHAPE = env.observation_space.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4iJM3IAwsoUB" + }, + "source": [ + "**Let's see if the game is still playable after applying the wrappers.**\n", + "At playing the EpisodicLifeEnv wrapper seems not to work but actually it does (because after when life finishes a new ball is dropped automatically - it means that FireResetEnv wrapper understands that a new episode began).\n", "\n", - "# from gym.utils.play import play\n", + "**Not supported for now.**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jhiOKsQvsoUC" + }, + "source": [ + "## DQN as it is (10 pts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aspwJFiGsoUC" + }, + "source": [ + "### Building a network\n", "\n", - "# def make_play_env():\n", - "# env = gym.make(ENV_NAME)\n", - "# env = PrimaryAtariWrap(env)\n", - "# # in torch imgs have shape [c, h, w] instead of common [h, w, c]\n", - "# env = atari_wrappers.AntiTorchWrapper(env)\n", - "# return env\n", + "We now need to build a neural network that can map images to state q-values. This network will be called on every agent's step so it better not be resnet-152 unless you have an array of GPUs. Instead, you can use strided convolutions with a small number of features to save time and memory.\n", "\n", - "# play(make_play_env(), zoom=10, fps=3)" + "You can build any architecture you want, but you can find a couple of examples on diagrams below." ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "YbZIucfksoUC" + }, "source": [ - "### Frame buffer\n", + "**Dueling network:**\\\n", + "Paper: https://arxiv.org/pdf/1511.06581.pdf\n", + "$$Q_{\\theta}(s, a) = V_{\\eta}(f_{\\xi}(s)) + A_{\\psi}(f_{\\xi}(s), a) - \\frac{\\sum_{a'}A_{\\psi}(f_{\\xi}(s), a')}{N_{actions}},$$\n", + "where $\\xi$, $\\eta$, and $\\psi$ are, respectively, the parameters of the\n", + "shared encoder $f_ξ$ , of the value stream $V_\\eta$ , and of the advantage stream $A_\\psi$; and $\\theta = \\{\\xi, \\eta, \\psi\\}$ is their concatenation.\n", + "\n", + "This is what it looks like:\n", + "\n", + "Simple, expects height=width=64\n", "\n", - "Our agent can only process one observation at a time, so we gotta make sure it contains enough information to find optimal actions. For instance, agent has to react to moving objects so he must be able to measure object's velocity.\n", + "\n", + "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/week04_approx_rl/img/dueling_basic.png)\n", "\n", - "To do so, we introduce a buffer that stores 4 last images. This time everything is pre-implemented for you, not really by the staff of the course :)" + "Nature DQN ([2]), expects height=width=84\n", + "\n", + "\n", + "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/week04_approx_rl/img/dueling_nature.png)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "SPPmY6wIsoUC", + "outputId": "717e2355-008e-4994-b5f2-1c8cf98ac445" + }, + "outputs": [], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", + "device" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These constants will be useful" ] }, { @@ -368,20 +604,7 @@ "metadata": {}, "outputs": [], "source": [ - "from framebuffer import FrameBuffer\n", - "\n", - "def make_env(clip_rewards=True, seed=None):\n", - " env = gym.make(ENV_NAME) # create raw env\n", - " if seed is not None:\n", - " env.seed(seed)\n", - " env = PrimaryAtariWrap(env, clip_rewards)\n", - " env = FrameBuffer(env, n_frames=4, dim_order='pytorch')\n", - " return env\n", - "\n", - "env = make_env()\n", - "env.reset()\n", - "n_actions = env.action_space.n\n", - "state_shape = env.observation_space.shape" + "N_ACTIONS, N_FRAMES_STACKED" ] }, { @@ -390,56 +613,139 @@ "metadata": {}, "outputs": [], "source": [ - "for _ in range(12):\n", - " obs, _, _, _ = env.step(env.action_space.sample())\n", + "class ConvBackbone(nn.Sequential):\n", + " \"\"\"\n", + " The convolutional part of a DQN model.\n", + " Please, don't think about input scaling here: it will be implemented below.\n", + " \"\"\"\n", + " def __init__(self, c_in: int = N_FRAMES_STACKED) -> None:\n", + " super().__init__(\n", + " nn.Conv2d(...),\n", + " ...\n", + " # your code,\n", + " nn.Flatten(),\n", + " )\n", "\n", - "plt.figure(figsize=[12,10])\n", - "plt.title(\"Game image\")\n", - "plt.imshow(env.render(\"rgb_array\"))\n", - "plt.show()\n", "\n", - "plt.figure(figsize=[15,15])\n", - "plt.title(\"Agent observation (4 frames top to bottom)\")\n", - "plt.imshow(utils.img_by_obs(obs, state_shape), cmap='gray')\n", - "plt.show()" + "class DuelingDqnHead(nn.Module):\n", + " \"\"\"\n", + " Implenets the Dueling DQN logic.\n", + " Please, don't think about gradient scaling here (if you know what it is about): it will be implemented below.\n", + " \"\"\"\n", + " def __init__(self, n_actions, inp_size=64 * 7 * 7, hidden_size=512) -> None:\n", + " super().__init__()\n", + " self.adv_stream = nn.Sequential(\n", + " # your code\n", + " )\n", + " self.value_stream = nn.Sequential(\n", + " # your code\n", + " )\n", + "\n", + " def forward(self, x: torch.Tensor) -> torch.Tensor:\n", + " assert x.ndim == 2, x.shape # (batch_size, n_features)\n", + " # your code\n", + " # When calculating the mean advantage, please, remember, x is a batched input!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## DQN as it is (4 pts)" + "Let's make a simple test for the network architecture:" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "### Building a network\n", + "@torch.no_grad()\n", + "def test_network_part_shapes(backbone, head):\n", + " batch_size = 3\n", + " env = make_final_env()\n", + " s, _ = env.reset()\n", + " inp = torch.rand(batch_size, *s.shape)\n", "\n", - "We now need to build a neural network that can map images to state q-values. This network will be called on every agent's step so it better not be resnet-152 unless you have an array of GPUs. Instead, you can use strided convolutions with a small number of features to save time and memory.\n", + " features = backbone(inp)\n", + " qvalues = head(features)\n", "\n", - "You can build any architecture you want, but for reference, here's something that will more or less work:" + " assert features.ndim == 2, features.shape\n", + " assert features.shape[0] == batch_size, features.shape\n", + " \n", + " assert qvalues.ndim == 2, qvalues.shape\n", + " assert qvalues.shape[0] == batch_size, qvalues.shape\n", + " assert qvalues.shape[1] == N_ACTIONS, qvalues.shape\n", + "\n", + " print(\"Test passed!\")\n", + "\n", + "test_network_part_shapes(\n", + " backbone=ConvBackbone(N_FRAMES_STACKED),\n", + " head=DuelingDqnHead(N_ACTIONS),\n", + ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/yet_another_week/_resource/dqn_arch.png)" + "**Now let's build a full model.**" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "**Dueling network: (+2 pts)**\n", - "$$Q_{\\theta}(s, a) = V_{\\eta}(f_{\\xi}(s)) + A_{\\psi}(f_{\\xi}(s), a) - \\frac{\\sum_{a'}A_{\\psi}(f_{\\xi}(s), a')}{N_{actions}},$$\n", - "where $\\xi$, $\\eta$, and $\\psi$ are, respectively, the parameters of the\n", - "shared encoder $f_ξ$ , of the value stream $V_\\eta$ , and of the advan\n", - "tage stream $A_\\psi$; and $\\theta = \\{\\xi, \\eta, \\psi\\}$ is their concatenation.\n", + "MAX_UINT_8 = 2 ** 8 - 1\n", + "\n", + "\n", + "class InputScaler(nn.Module):\n", + " def __init__(self, mult=1 / MAX_UINT_8):\n", + " super().__init__()\n", + " self.mult = mult\n", "\n", - "For the architecture on the image $V$ and $A$ heads can follow the dense layer instead of $Q$. Please don't worry that the model becomes a little bigger." + " def forward(self, x: torch.Tensor) -> torch.Tensor:\n", + " return x * self.mult\n", + "\n", + "\n", + "class GradScalerFunctional(torch.autograd.Function):\n", + " \"\"\"\n", + " A torch.autograd.Function works as Identity on forward pass\n", + " and scales the gradient by scale_factor on backward pass.\n", + " \"\"\"\n", + " @staticmethod\n", + " def forward(ctx, input, scale_factor):\n", + " ctx.scale_factor = scale_factor\n", + " return input\n", + "\n", + " @staticmethod\n", + " def backward(ctx, grad_output):\n", + " scale_factor = ctx.scale_factor\n", + " grad_input = grad_output * scale_factor\n", + " return grad_input, None\n", + "\n", + "\n", + "class GradScaler(nn.Module):\n", + " \"\"\"\n", + " An nn.Module incapsulating GradScalerFunctional\n", + " \"\"\"\n", + " def __init__(self, scale_factor: float):\n", + " super().__init__()\n", + " self.scale_factor = scale_factor\n", + "\n", + " def forward(self, x):\n", + " return GradScalerFunctional.apply(x, self.scale_factor)\n", + "\n", + "\n", + "class DQNetworkDueling(nn.Sequential):\n", + " def __init__(self, c_in: int, n_actions: int) -> None:\n", + " input_scaler = InputScaler() # the inputs come from the uint8 range\n", + " backbone = ConvBackbone(c_in=c_in) # your code\n", + " grad_scaler = GradScaler(1 / 2**0.5) # Dueling DQN suggests do scale the gradient by 1 / sqrt(2)\n", + " head = DuelingDqnHead(n_actions=n_actions)\n", + " super().__init__(input_scaler, backbone, grad_scaler, head)" ] }, { @@ -448,28 +754,30 @@ "metadata": {}, "outputs": [], "source": [ - "import torch\n", - "import torch.nn as nn\n", - "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", - "# those who have a GPU but feel unfair to use it can uncomment:\n", - "# device = torch.device('cpu')\n", - "device" + "@torch.no_grad()\n", + "def test_network_shapes(model):\n", + " batch_size = 3\n", + " env = make_final_env()\n", + " s, _ = env.reset()\n", + " inp = torch.rand(batch_size, *s.shape)\n", + "\n", + " qvalues = model(inp)\n", + " \n", + " assert qvalues.ndim == 2, qvalues.shape\n", + " assert qvalues.shape[0] == batch_size, qvalues.shape\n", + " assert qvalues.shape[1] == N_ACTIONS, qvalues.shape\n", + "\n", + " print(\"Test passed!\")\n", + "\n", + "test_network_shapes(model=DQNetworkDueling(N_FRAMES_STACKED, N_ACTIONS))" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "def conv2d_size_out(size, kernel_size, stride):\n", - " \"\"\"\n", - " common use case:\n", - " cur_layer_img_w = conv2d_size_out(cur_layer_img_w, kernel_size, stride)\n", - " cur_layer_img_h = conv2d_size_out(cur_layer_img_h, kernel_size, stride)\n", - " to understand the shape for dense layer's input\n", - " \"\"\"\n", - " return (size - (kernel_size - 1) - 1) // stride + 1\n" + "**Now let's wrap our model into an Agent class.** \n", + "It will implement epsilon-greedy policy on numpy ndarrays." ] }, { @@ -479,52 +787,57 @@ "outputs": [], "source": [ "class DQNAgent(nn.Module):\n", - " def __init__(self, state_shape, n_actions, epsilon=0):\n", + " \"\"\"\n", + " Epsilon-greedy policy with a torch.nn.Module Q-value estimator.\n", + " \"\"\"\n", "\n", + " def __init__(self, q_network: nn.Module, epsilon=1) -> None:\n", " super().__init__()\n", " self.epsilon = epsilon\n", - " self.n_actions = n_actions\n", - " self.state_shape = state_shape\n", - "\n", - " # Define your network body here. Please make sure agent is fully contained here\n", - " # nn.Flatten() can be useful\n", - " \n", - " \n", + " self.q_network = q_network\n", "\n", " def forward(self, state_t):\n", " \"\"\"\n", " takes agent's observation (tensor), returns qvalues (tensor)\n", " :param state_t: a batch of 4-frame buffers, shape = [batch_size, 4, h, w]\n", " \"\"\"\n", - " # Use your network to compute qvalues for given state\n", - " qvalues = \n", - "\n", - " assert qvalues.requires_grad, \"qvalues must be a torch tensor with grad\"\n", - " assert len(\n", - " qvalues.shape) == 2 and qvalues.shape[0] == state_t.shape[0] and qvalues.shape[1] == n_actions\n", - "\n", + " # Use your network to compute qvalues for given state\n", + " qvalues = # your code\n", " return qvalues\n", "\n", - " def get_qvalues(self, states):\n", + " @torch.no_grad() # we don't need autograd here, so let's save the computations\n", + " def get_qvalues(self, states: np.ndarray) -> np.ndarray:\n", " \"\"\"\n", " like forward, but works on numpy arrays, not tensors\n", " \"\"\"\n", " model_device = next(self.parameters()).device\n", - " states = torch.tensor(states, device=model_device, dtype=torch.float)\n", - " qvalues = self.forward(states)\n", - " return qvalues.data.cpu().numpy()\n", + " states_pt = torch.tensor(\n", + " np.array(states), device=model_device, dtype=torch.float32\n", + " )\n", + " # Use your network to compute qvalues for given state\n", + " qvalues_pt = # your code\n", + " qvalues = qvalues_pt.data.cpu().numpy()\n", + " return qvalues\n", "\n", - " def sample_actions(self, qvalues):\n", - " \"\"\"pick actions given qvalues. Uses epsilon-greedy exploration strategy. \"\"\"\n", - " epsilon = self.epsilon\n", + " def sample_actions_by_qvalues(self, qvalues: np.ndarray, greedy: bool = False) -> np.ndarray:\n", + " \"\"\"pick actions given qvalues. Uses epsilon-greedy exploration strategy.\"\"\"\n", " batch_size, n_actions = qvalues.shape\n", + " # greedy_actions = # your code\n", + " greedy_actions = qvalues.argmax(axis=-1) # your code\n", + " if greedy:\n", + " return greedy_actions\n", + "\n", + " random_actions = np.random.randint(\"your code\")\n", + " should_explore = np.random.binomial(\"your code\")\n", + " epsilon_greedy_actions = np.where(\n", + " \"your code\"\n", + " )\n", + " return epsilon_greedy_actions\n", "\n", - " random_actions = np.random.choice(n_actions, size=batch_size)\n", - " best_actions = qvalues.argmax(axis=-1)\n", - "\n", - " should_explore = np.random.choice(\n", - " [0, 1], batch_size, p=[1-epsilon, epsilon])\n", - " return np.where(should_explore, random_actions, best_actions)" + " def sample_actions(self, states: np.ndarray) -> np.ndarray:\n", + " qvalues = self.get_qvalues(states)\n", + " actions = self.sample_actions_by_qvalues(qvalues)\n", + " return actions" ] }, { @@ -533,12 +846,30 @@ "metadata": {}, "outputs": [], "source": [ - "agent = DQNAgent(state_shape, n_actions, epsilon=0.5).to(device)" + "test_network_shapes(\n", + " model=DQNAgent(DQNetworkDueling(N_FRAMES_STACKED, N_ACTIONS))\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "BUFMLKX1soUC" + }, + "outputs": [], + "source": [ + "agent = DQNAgent(\n", + " DQNetworkDueling(N_FRAMES_STACKED, N_ACTIONS),\n", + " epsilon=0.5\n", + ").to(device)" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "XbsIT2EdsoUC" + }, "source": [ "Now let's try out our agent to see if it raises any errors." ] @@ -546,49 +877,49 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "pZR3qE2esoUC" + }, "outputs": [], "source": [ - "def evaluate(env, agent, n_games=1, greedy=False, t_max=10000):\n", + "def evaluate(env, agent, n_games=1, greedy=False, t_max=10000, seed=None):\n", " \"\"\" Plays n_games full games. If greedy, picks actions as argmax(qvalues). Returns mean reward. \"\"\"\n", " rewards = []\n", " for _ in range(n_games):\n", - " s = env.reset()\n", + " s, _ = env.reset(seed=seed)\n", " reward = 0\n", " for _ in range(t_max):\n", - " qvalues = agent.get_qvalues([s])\n", - " action = qvalues.argmax(axis=-1)[0] if greedy else agent.sample_actions(qvalues)[0]\n", - " s, r, done, _ = env.step(action)\n", + " action = agent.sample_actions(np.array(s)[None], greedy=greedy)[0]\n", + " s, r, terminated, truncated, _ = env.step(action)\n", " reward += r\n", - " if done:\n", + " if terminated or truncated:\n", " break\n", "\n", " rewards.append(reward)\n", - " return np.mean(rewards)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "evaluate(env, agent, n_games=1)" + " return np.mean(rewards)\n", + "\n", + "print(evaluate(env, agent, n_games=1, greedy=False))\n", + "print(evaluate(env, agent, n_games=1, greedy=True))" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "2BiRixA-soUC" + }, "source": [ "### Experience replay\n", - "For this assignment, we provide you with experience replay buffer. If you implemented experience replay buffer in last week's assignment, you can copy-paste it here **to get 2 bonus points**.\n", + "For this assignment, we provide you with experience replay buffer.\n", "\n", - "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/yet_another_week/_resource/exp_replay.png)" + "\n", + "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/yet_another_week/_resource/exp_replay.png)\n" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "jTBZo5BVsoUC" + }, "source": [ "#### The interface is fairly simple:\n", "* `exp_replay.add(obs, act, rw, next_obs, done)` - saves (s,a,r,s',done) tuple into the buffer\n", @@ -599,33 +930,112 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "Ydi0KK9LsoUC" + }, "outputs": [], "source": [ - "from replay_buffer import ReplayBuffer\n", + "from dqn.replay_buffer import ReplayBuffer\n", "exp_replay = ReplayBuffer(10)\n", "\n", "for _ in range(30):\n", - " exp_replay.add(env.reset(), env.action_space.sample(),\n", - " 1.0, env.reset(), done=False)\n", + " exp_replay.add(env.reset()[0], env.action_space.sample(), 1.0, env.reset()[0], done=False)\n", "\n", - "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", - " 5)\n", + "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(5)\n", "\n", "assert len(exp_replay) == 10, \"experience replay size should be 10 because that's what maximum capacity is\"" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**The `play_and_record` function, defined below is the main way the agent will interact with the environment during training.**\n", + "\n", + "Previously we used to train RL algorithms on entire episodes. \n", + "\n", + "This time we keep the environment constantly running and will be getting small portions of interactions with it.\n", + "\n", + "The agent takes several actions (4 actions in [2] and [3]), the corresponding (s, a, r, s', terminated) tuples are put into the replay buffer. \n", + "Whenever an episode finishes (i.e. `truncated or terminated`), the environment is reset and the procedure continues as usually. \n", + "\n", + "To make the first step in a constantly running environment, the agent needs to know the state of the environment. This is the meaning of the `initial_state` argument of the function.\n", + "\n", + "It's worth noting, the agent does not train on the fresh tuples immediately. The agent trains on samples which are sampled from the buffer.\n", + "\n", + "**Implementation note:**\n", + "We define an `ActionSampler` protocol. The goal of it is to let the function `play_and_record` accept not only `DQNAgent` class instances, but any object that can sample actions. " + ] + }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "cEXv69KWsoUC" + }, "outputs": [], "source": [ - "def play_and_record(initial_state, agent, env, exp_replay, n_steps=1):\n", + "from typing import Protocol\n", + "\n", + "\n", + "class ActionSampler(Protocol):\n", + " \"\"\"\n", + " A protocol which defines an Callable which samples actions from states\n", + " \"\"\"\n", + "\n", + " def __call__(\n", + " self, state: gym.wrappers.stateful_observation.FrameStackObservation\n", + " ) -> int: ...\n", + "\n", + "\n", + "class RandomActionSampler:\n", + " \"\"\"\n", + " We will need this guy to fill the buffer with initial 50-200K observations from a random policy.\n", " \"\"\"\n", - " Play the game for exactly n steps, record every (s,a,r,s', done) to replay buffer. \n", - " Whenever game ends, add record with done=True and reset the game.\n", - " It is guaranteed that env has done=False when passed to this function.\n", + "\n", + " def __init__(self, action_space) -> None:\n", + " self.action_space = action_space\n", + "\n", + " def __call__(\n", + " self, state: gym.wrappers.stateful_observation.FrameStackObservation\n", + " ) -> int:\n", + " action = self.action_space.sample()\n", + " return action\n", + "\n", + "\n", + "class DqnActionSampler:\n", + " \"\"\"\n", + " DQNAgent works on batched np.ndarray inputs.\n", + " This class uses a DQNAgent to sample actions from single LazyFrames observations.\n", + "\n", + " This will be an epsilon-greedy sampler.\n", + " A greedy sampler can be defined as well, but we won't need it.\n", + " \"\"\"\n", + "\n", + " def __init__(self, agent: DQNAgent):\n", + " self.agent = agent\n", + "\n", + " def __call__(\n", + " self, state: gym.wrappers.stateful_observation.FrameStackObservation\n", + " ) -> int:\n", + " state_batched = np.array(state)[None]\n", + " action_batched = # \n", + " action = action_batched.item()\n", + " return action\n", + "\n", + "\n", + "@torch.no_grad()\n", + "def play_and_record(\n", + " initial_state: gym.wrappers.stateful_observation.FrameStackObservation,\n", + " action_sampler: ActionSampler,\n", + " env,\n", + " exp_replay,\n", + " n_steps=1,\n", + "):\n", + " \"\"\"\n", + " Play the game for exactly n_steps, record every (s,a,r,s', done) to replay buffer.\n", + " Whenever game ends due to termination or truncation, add record with done=terminated and reset the game.\n", + " It is guaranteed that env has terminated=False when passed to this function.\n", "\n", " PLEASE DO NOT RESET ENV UNLESS IT IS \"DONE\"\n", "\n", @@ -637,7 +1047,7 @@ " # Play the game for n_steps as per instructions above\n", " \n", "\n", - " return sum_rewards, s" + " return sum_rewards, s\n" ] }, { @@ -646,43 +1056,55 @@ "metadata": {}, "outputs": [], "source": [ - "# testing your code.\n", - "exp_replay = ReplayBuffer(2000)\n", - "\n", - "state = env.reset()\n", - "play_and_record(state, agent, env, exp_replay, n_steps=1000)\n", - "\n", - "# if you're using your own experience replay buffer, some of those tests may need correction.\n", - "# just make sure you know what your code does\n", - "assert len(exp_replay) == 1000, \"play_and_record should have added exactly 1000 steps, \"\\\n", - " \"but instead added %i\" % len(exp_replay)\n", - "is_dones = list(zip(*exp_replay._storage))[-1]\n", - "\n", - "assert 0 < np.mean(is_dones) < 0.1, \"Please make sure you restart the game whenever it is 'done' and record the is_done correctly into the buffer.\"\\\n", - " \"Got %f is_done rate over %i steps. [If you think it's your tough luck, just re-run the test]\" % (\n", - " np.mean(is_dones), len(exp_replay))\n", - "\n", - "for _ in range(100):\n", - " obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", - " 10)\n", - " assert obs_batch.shape == next_obs_batch.shape == (10,) + state_shape\n", - " assert act_batch.shape == (\n", - " 10,), \"actions batch should have shape (10,) but is instead %s\" % str(act_batch.shape)\n", - " assert reward_batch.shape == (\n", - " 10,), \"rewards batch should have shape (10,) but is instead %s\" % str(reward_batch.shape)\n", - " assert is_done_batch.shape == (\n", - " 10,), \"is_done batch should have shape (10,) but is instead %s\" % str(is_done_batch.shape)\n", - " assert [int(i) in (0, 1)\n", - " for i in is_dones], \"is_done should be strictly True or False\"\n", - " assert [\n", - " 0 <= a < n_actions for a in act_batch], \"actions should be within [0, n_actions)\"\n", + "def test_play_and_record(action_sampler):\n", + " exp_replay = ReplayBuffer(10_000)\n", "\n", - "print(\"Well done!\")" + " state, _ = env.reset()\n", + " \n", + " # action_sampler = RandomActionSampler(env.action_space)\n", + " # action_sampler = DqnActionSampler(agent)\n", + " play_and_record(state, action_sampler, env, exp_replay, n_steps=1000);\n", + " \n", + " # if you're using your own experience replay buffer, some of those tests may need correction.\n", + " # just make sure you know what your code does\n", + " assert len(exp_replay) == 1000, \\\n", + " \"play_and_record should have added exactly 1000 steps, \" \\\n", + " \"but instead added %i\" % len(exp_replay)\n", + " is_dones = list(zip(*exp_replay._storage))[-1]\n", + " \n", + " assert 0 < np.mean(is_dones) < 0.1, \\\n", + " \"Please make sure you restart the game whenever it is 'done' and \" \\\n", + " \"record the is_done correctly into the buffer. Got %f is_done rate over \" \\\n", + " \"%i steps. [If you think it's your tough luck, just re-run the test]\" % (\n", + " np.mean(is_dones), len(exp_replay))\n", + " \n", + " for _ in range(100):\n", + " obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(10)\n", + " assert obs_batch.shape == next_obs_batch.shape == (10,) + STATE_SHAPE\n", + " assert act_batch.shape == (10,), \\\n", + " \"actions batch should have shape (10,) but is instead %s\" % str(act_batch.shape)\n", + " assert reward_batch.shape == (10,), \\\n", + " \"rewards batch should have shape (10,) but is instead %s\" % str(reward_batch.shape)\n", + " assert is_done_batch.shape == (10,), \\\n", + " \"is_done batch should have shape (10,) but is instead %s\" % str(is_done_batch.shape)\n", + " assert [int(i) in (0, 1) for i in is_dones], \\\n", + " \"is_done should be strictly True or False\"\n", + " assert [0 <= a < N_ACTIONS for a in act_batch], \"actions should be within [0, n_actions)\"\n", + " \n", + " print(\"Well done!\")\n", + "\n", + "\n", + "print(\"Random:\")\n", + "test_play_and_record(RandomActionSampler(env.action_space))\n", + "print(\"DQN:\")\n", + "test_play_and_record(DqnActionSampler(agent))" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "y5zyryPOsoUF" + }, "source": [ "### Target networks\n", "\n", @@ -701,14 +1123,15 @@ "metadata": {}, "outputs": [], "source": [ - "target_network = DQNAgent(agent.state_shape, agent.n_actions, epsilon=0.5).to(device)\n", - "# This is how you can load weights from agent into target network\n", - "target_network.load_state_dict(agent.state_dict())" + "target_network = DQNetworkDueling(N_FRAMES_STACKED, N_ACTIONS).to(device)\n", + "target_network.load_state_dict(agent.q_network.state_dict())" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "2idY8QX0soUF" + }, "source": [ "### Learning with... Q-learning\n", "Here we write a function similar to `agent.update` from tabular q-learning." @@ -716,7 +1139,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "k46MPwwwsoUF" + }, "source": [ "Compute Q-learning TD error:\n", "\n", @@ -727,19 +1152,87 @@ "$$ Q_{reference}(s,a) = r(s,a) + \\gamma \\cdot max_{a'} Q_{target}(s', a') $$\n", "\n", "Where\n", - "* $Q_{target}(s',a')$ denotes q-value of next state and next action predicted by __target_network__\n", + "* $Q_{target}(s',a')$ denotes Q-value of next state and next action predicted by __target_network__\n", "* $s, a, r, s'$ are current state, action, reward and next state respectively\n", "* $\\gamma$ is a discount factor defined two cells above.\n", "\n", "\n", "__Note 1:__ there's an example input below. Feel free to experiment with it before you write the function.\n", "\n", - "__Note 2:__ compute_td_loss is a source of 99% of bugs in this homework. If reward doesn't improve, it often helps to go through it line by line [with a rubber duck](https://rubberduckdebugging.com/).\n", + "__Note 2:__ compute_td_loss is a major source of of bugs in this homework. We tried to cover it with tests, but if reward doesn't improve, it often helps to go through it line by line [with a rubber duck](https://rubberduckdebugging.com/).\n", "\n", - "**Double DQN (+2 pts)**\n", + "**Double DQN**\n", "\n", "$$ Q_{reference}(s,a) = r(s, a) + \\gamma \\cdot\n", - "Q_{target}(s',argmax_{a'}Q_\\theta(s', a')) $$" + "Q_{target}(s',argmax_{a'}Q_\\theta(s', a')) $$\n", + "\n", + "We will use Double DQN for training, but **we ask you to implement both** of the methods to experience the difference." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "V02HcUYasoUG", + "outputId": "7a11e3d3-d030-40be-8f14-59b5481749fb" + }, + "outputs": [], + "source": [ + "def compute_td_loss_on_tensors(\n", + " states: torch.Tensor, # (batch_size, *state_shape)\n", + " actions: torch.Tensor, # (batch_size,)\n", + " rewards: torch.Tensor, # (batch_size,)\n", + " next_states: torch.Tensor, # (batch_size, *state_shape)\n", + " is_done: torch.Tensor, # (batch_size,), torch.bool\n", + " agent: nn.Module,\n", + " target_network: nn.Module,\n", + " gamma: float = 0.99,\n", + " check_shapes=False,\n", + "):\n", + " predicted_qvalues = agent(states) # shape: [batch_size, n_actions]\n", + " assert is_done.dtype is torch.bool\n", + "\n", + " # compute q-values for all actions in next states\n", + " with torch.no_grad():\n", + " predicted_next_qvalues_target = # your code; # shape: [batch_size, n_actions]\n", + "\n", + " # select q-values for chosen actions\n", + " predicted_qvalues_for_actions = predicted_qvalues[\n", + " range(len(actions)), actions\n", + " ] # shape: [batch_size]\n", + "\n", + " # compute V*(next_states) using predicted next q-values\n", + " next_state_values = # your code\n", + "\n", + " if check_shapes:\n", + " assert (\n", + " next_state_values.dim() == 1\n", + " and next_state_values.shape[0] == states.shape[0]\n", + " ), \"must predict one value per state\"\n", + " assert not next_state_values.requires_grad\n", + "\n", + " # compute \"target q-values\" for loss - it's what's inside square parentheses in the above formula.\n", + " # at the last state use the simplified formula: Q(s,a) = r(s,a) since s' doesn't exist\n", + " target_qvalues_for_actions = # your code\n", + "\n", + " # mean squared error loss to minimize\n", + " loss = torch.mean((predicted_qvalues_for_actions - target_qvalues_for_actions) ** 2)\n", + "\n", + " if check_shapes:\n", + " assert (\n", + " predicted_next_qvalues_target.data.dim() == 2\n", + " ), \"make sure you predicted q-values for all actions in next state\"\n", + " assert (\n", + " next_state_values.data.dim() == 1\n", + " ), \"make sure you computed V(s') as maximum over just the actions axis and not all axes\"\n", + " assert (\n", + " target_qvalues_for_actions.data.dim() == 1\n", + " ), \"there's something wrong with target q-values, they must be a vector\"\n", + "\n", + " return loss" ] }, { @@ -748,67 +1241,89 @@ "metadata": {}, "outputs": [], "source": [ - "def compute_td_loss(states, actions, rewards, next_states, is_done,\n", - " agent, target_network,\n", - " gamma=0.99,\n", - " check_shapes=False,\n", - " device=device):\n", - " \"\"\" Compute td loss using torch operations only. Use the formulae above. \"\"\"\n", - " states = torch.tensor(states, device=device, dtype=torch.float) # shape: [batch_size, *state_shape]\n", - "\n", - " # for some torch reason should not make actions a tensor\n", - " actions = torch.tensor(actions, device=device, dtype=torch.long) # shape: [batch_size]\n", - " rewards = torch.tensor(rewards, device=device, dtype=torch.float) # shape: [batch_size]\n", - " # shape: [batch_size, *state_shape]\n", - " next_states = torch.tensor(next_states, device=device, dtype=torch.float)\n", - " is_done = torch.tensor(\n", - " is_done.astype('float32'),\n", - " device=device,\n", - " dtype=torch.float\n", - " ) # shape: [batch_size]\n", - " is_not_done = 1 - is_done\n", + "from test_td_loss.compute_td_loss import test_is_done_is_used, test_compute_td_loss_vanilla\n", "\n", - " # get q-values for all actions in current states\n", - " predicted_qvalues = agent(states)\n", + "test_compute_td_loss_vanilla(compute_td_loss_on_tensors)\n", + "print(\"Well done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def compute_td_loss_on_tensors_double(\n", + " states: torch.Tensor, # (batch_size, *state_shape)\n", + " actions: torch.Tensor, # (batch_size,)\n", + " rewards: torch.Tensor, # (batch_size,)\n", + " next_states: torch.Tensor, # (batch_size, *state_shape)\n", + " is_done: torch.Tensor, # (batch_size,), torch.bool\n", + " agent: nn.Module,\n", + " target_network: nn.Module,\n", + " gamma: float = 0.99,\n", + " check_shapes=False,\n", + "):\n", + " predicted_qvalues = agent(states) # shape: [batch_size, n_actions]\n", + " assert is_done.dtype is torch.bool\n", "\n", " # compute q-values for all actions in next states\n", - " predicted_next_qvalues = target_network(next_states)\n", - " \n", + " with torch.no_grad():\n", + " predicted_next_qvalues_target = # your code; # shape: [batch_size, n_actions]\n", + "\n", " # select q-values for chosen actions\n", - " predicted_qvalues_for_actions = predicted_qvalues[range(\n", - " len(actions)), actions]\n", + " predicted_qvalues_for_actions = predicted_qvalues[\n", + " range(len(actions)), actions\n", + " ] # shape: [batch_size]\n", "\n", " # compute V*(next_states) using predicted next q-values\n", - " next_state_values = \n", + " next_state_values = # your code\n", "\n", - " assert next_state_values.dim(\n", - " ) == 1 and next_state_values.shape[0] == states.shape[0], \"must predict one value per state\"\n", + " if check_shapes:\n", + " assert (\n", + " next_state_values.dim() == 1\n", + " and next_state_values.shape[0] == states.shape[0]\n", + " ), \"must predict one value per state\"\n", + " assert not next_state_values.requires_grad\n", "\n", " # compute \"target q-values\" for loss - it's what's inside square parentheses in the above formula.\n", " # at the last state use the simplified formula: Q(s,a) = r(s,a) since s' doesn't exist\n", - " # you can multiply next state values by is_not_done to achieve this.\n", - " target_qvalues_for_actions = \n", + " target_qvalues_for_actions = # your code\n", "\n", " # mean squared error loss to minimize\n", - " loss = torch.mean((predicted_qvalues_for_actions -\n", - " target_qvalues_for_actions.detach()) ** 2)\n", + " loss = torch.mean((predicted_qvalues_for_actions - target_qvalues_for_actions) ** 2)\n", "\n", " if check_shapes:\n", - " assert predicted_next_qvalues.data.dim(\n", - " ) == 2, \"make sure you predicted q-values for all actions in next state\"\n", - " assert next_state_values.data.dim(\n", - " ) == 1, \"make sure you computed V(s') as maximum over just the actions axis and not all axes\"\n", - " assert target_qvalues_for_actions.data.dim(\n", - " ) == 1, \"there's something wrong with target q-values, they must be a vector\"\n", + " assert (\n", + " predicted_next_qvalues_target.data.dim() == 2\n", + " ), \"make sure you predicted q-values for all actions in next state\"\n", + " assert (\n", + " next_state_values.data.dim() == 1\n", + " ), \"make sure you computed V(s') as maximum over just the actions axis and not all axes\"\n", + " assert (\n", + " target_qvalues_for_actions.data.dim() == 1\n", + " ), \"there's something wrong with target q-values, they must be a vector\"\n", "\n", " return loss" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from test_td_loss.compute_td_loss import test_compute_td_loss_double\n", + "\n", + "test_compute_td_loss_double(compute_td_loss_on_tensors_double)\n", + "print(\"Well done!\")" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Sanity checks" + "**The following function works on np.ndarrays: it converts its inputs to torch.Tensors and calls the torch-tensor function**" ] }, { @@ -817,24 +1332,88 @@ "metadata": {}, "outputs": [], "source": [ - "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", - " 10)\n", + "def compute_td_loss(\n", + " states,\n", + " actions,\n", + " rewards,\n", + " next_states,\n", + " is_done,\n", + " agent,\n", + " target_network,\n", + " gamma=0.99,\n", + " check_shapes=False,\n", + " device=None,\n", + " tensor_loss_evaluator=compute_td_loss_on_tensors_double,\n", + "):\n", + " \"\"\"Compute td loss using torch operations only. Use the formulae above.\"\"\"\n", + "\n", + " if device is None:\n", + " device = next(agent.parameters()).device\n", + " states = torch.tensor(\n", + " states, device=device, dtype=torch.float32\n", + " ) # shape: [batch_size, *state_shape]\n", + " actions = torch.tensor(\n", + " actions, device=device, dtype=torch.int64\n", + " ) # shape: [batch_size]\n", + " rewards = torch.tensor(\n", + " rewards, device=device, dtype=torch.float32\n", + " ) # shape: [batch_size]\n", + " # shape: [batch_size, *state_shape]\n", + " next_states = torch.tensor(next_states, device=device, dtype=torch.float)\n", + " is_done = torch.tensor(\n", + " is_done, device=device, dtype=torch.bool\n", + " ) # shape: [batch_size]\n", + "\n", + " return tensor_loss_evaluator(\n", + " states=states,\n", + " actions=actions,\n", + " rewards=rewards,\n", + " next_states=next_states,\n", + " is_done=is_done,\n", + " agent=agent,\n", + " target_network=target_network,\n", + " gamma=gamma,\n", + " check_shapes=check_shapes,\n", + " )\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "x8AvquAtsoUG" + }, + "source": [ + "Sanity checks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5nRoOn30soUG" + }, + "outputs": [], + "source": [ + "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(10)\n", "\n", "loss = compute_td_loss(obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch,\n", " agent, target_network,\n", " gamma=0.99, check_shapes=True)\n", "loss.backward()\n", "\n", - "assert loss.requires_grad and tuple(loss.data.size()) == (\n", - " ), \"you must return scalar loss - mean over batch\"\n", - "assert np.any(next(agent.parameters()).grad.data.cpu().numpy() !=\n", - " 0), \"loss must be differentiable w.r.t. network weights\"\n", - "assert np.all(next(target_network.parameters()).grad is None), \"target network should not have grads\"" + "assert loss.requires_grad and tuple(loss.data.size()) == (), \\\n", + " \"you must return scalar loss - mean over batch\"\n", + "assert np.any(next(agent.parameters()).grad.data.cpu().numpy() != 0), \\\n", + " \"loss must be differentiable w.r.t. network weights\"\n", + "assert np.all(next(target_network.parameters()).grad is None), \\\n", + " \"target network should not have grads\"" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "KIplL0hSsoUG" + }, "source": [ "## Main loop (3 pts)\n", "\n", @@ -847,10 +1426,12 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "-JV-ulB-soUG" + }, "outputs": [], "source": [ - "from tqdm import trange\n", + "from tqdm.auto import trange\n", "from IPython.display import clear_output\n", "import matplotlib.pyplot as plt" ] @@ -861,7 +1442,9 @@ "metadata": {}, "outputs": [], "source": [ - "seed = \n", + "import random\n", + "\n", + "seed = # your favourite seed\n", "random.seed(seed)\n", "np.random.seed(seed)\n", "torch.manual_seed(seed)" @@ -870,46 +1453,73 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-eurxA-_soUG", + "outputId": "4eb73eb0-771c-442e-a086-50bae3ebd9d8" + }, "outputs": [], "source": [ - "env = make_env(seed)\n", - "state_shape = env.observation_space.shape\n", - "n_actions = env.action_space.n\n", - "state = env.reset()\n", + "env = make_final_env()\n", + "\n", + "state, _ = env.reset(seed=seed)\n", "\n", - "agent = DQNAgent(state_shape, n_actions, epsilon=1).to(device)\n", - "target_network = DQNAgent(state_shape, n_actions).to(device)\n", - "target_network.load_state_dict(agent.state_dict())" + "agent = DQNAgent(\n", + " DQNetworkDueling(N_FRAMES_STACKED, N_ACTIONS),\n", + " epsilon=1\n", + ").to(device)\n", + "target_network = DQNetworkDueling(N_FRAMES_STACKED, N_ACTIONS).to(device)\n", + "target_network.load_state_dict(agent.q_network.state_dict())\n", + "\n", + "action_sampler = DqnActionSampler(agent)\n", + "action_sampler_random = RandomActionSampler(env.action_space)" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "WZg25kIasoUG" + }, "source": [ - "Buffer of size $10^4$ fits into 5 Gb RAM.\n", + "Buffer of size $10^4$ can probably pass the threshold for this assignment.\n", "\n", - "Larger sizes ($10^5$ and $10^6$ are common) can be used. It can improve the learning, but $10^4$ is quiet enough. $10^2$ will probably fail learning." + "Larger sizes ($10^5$ and $10^6$ are common) can show a much higher score." ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hWyMxfN4soUG", + "outputId": "a0d4147b-56b2-4f69-802a-0da87ad82bdb", + "scrolled": true + }, "outputs": [], "source": [ - "exp_replay = ReplayBuffer(10**4)\n", - "for i in range(100):\n", - " if not utils.is_enough_ram(min_available_gb=0.1):\n", + "from dqn.utils import is_enough_ram\n", + "\n", + "REPLAY_BUFFER_SIZE = 10**6\n", + "# INITIAL_BUFFER_FILL = 50_000 # Nature DQN Extended Data Table 1\n", + "INITIAL_BUFFER_FILL = 200_000 # Rainbow without prioritization\n", + "_n_steps = 100\n", + "\n", + "exp_replay = ReplayBuffer(REPLAY_BUFFER_SIZE)\n", + "for i in trange(INITIAL_BUFFER_FILL // _n_steps):\n", + " if not is_enough_ram(min_available_gb=0.1):\n", " print(\"\"\"\n", - " Less than 100 Mb RAM available. \n", + " Less than 100 Mb RAM available.\n", " Make sure the buffer size in not too huge.\n", " Also check, maybe other processes consume RAM heavily.\n", " \"\"\"\n", " )\n", " break\n", - " play_and_record(state, agent, env, exp_replay, n_steps=10**2)\n", - " if len(exp_replay) == 10**4:\n", + " play_and_record(state, action_sampler_random, env, exp_replay, n_steps=_n_steps)\n", + " if len(exp_replay) >= INITIAL_BUFFER_FILL:\n", " break\n", "print(len(exp_replay))" ] @@ -920,21 +1530,32 @@ "metadata": {}, "outputs": [], "source": [ - "timesteps_per_epoch = 1\n", - "batch_size = 16\n", - "total_steps = 3 * 10**6\n", - "decay_steps = 10**6\n", + "len(exp_replay)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_ca9vbW4soUG" + }, + "outputs": [], + "source": [ + "update_frequency = 4 # n_steps for play_and_record; Nature DQN Extended Data Table 1 + Rainbow Table 4: Additional hyper-parameters\n", + "batch_size = 32 # Nature DQN Extended Data Table 1 + Table 4: Additional hyper-parameters\n", + "total_steps = 10 * 10**6 # this can be long, feel free to stop the training when the target score is reached\n", + "decay_steps = 10**6 # Nature DQN Extended Data Table 1\n", "\n", - "opt = torch.optim.Adam(agent.parameters(), lr=1e-4)\n", + "opt = torch.optim.Adam(agent.parameters(), lr=6.25e-05, eps=1.4e-4) # Rainbow\n", "\n", - "init_epsilon = 1\n", - "final_epsilon = 0.1\n", + "init_epsilon = 1 # Nature DQN\n", + "final_epsilon = 0.1 # Nature DQN\n", "\n", - "loss_freq = 50\n", - "refresh_target_network_freq = 5000\n", - "eval_freq = 5000\n", + "loss_freq = 100\n", + "refresh_target_network_freq = 10_000 # Nature DQN\n", + "eval_freq = 10_000\n", "\n", - "max_grad_norm = 50\n", + "max_grad_norm = 10 # Dueling DQN\n", "\n", "n_lives = 5" ] @@ -942,98 +1563,149 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "oJWs0q-6soUG" + }, "outputs": [], "source": [ - "mean_rw_history = []\n", - "td_loss_history = []\n", - "grad_norm_history = []\n", - "initial_state_v_history = []\n", "step = 0" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "675-JU0hsoUG" + }, "outputs": [], "source": [ - "state = env.reset()\n", - "for step in trange(step, total_steps + 1):\n", - " if not utils.is_enough_ram():\n", - " print('less that 100 Mb RAM available, freezing')\n", - " print('make sure everythin is ok and make KeyboardInterrupt to continue')\n", - " try:\n", - " while True:\n", - " pass\n", - " except KeyboardInterrupt:\n", - " pass\n", + "import time\n", "\n", - " agent.epsilon = utils.linear_decay(init_epsilon, final_epsilon, step, decay_steps)\n", - "\n", - " # play\n", - " _, state = play_and_record(state, agent, env, exp_replay, timesteps_per_epoch)\n", + "def wait_for_keyboard_interrupt():\n", + " try:\n", + " while True:\n", + " time.sleep(1)\n", + " except KeyboardInterrupt:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from dqn.utils import linear_decay, is_enough_ram\n", + "from torch.utils.tensorboard import SummaryWriter\n", + "from dqn.logger import Logger" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "use_tensorboard = True # Set to False to use simple matplotlib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "logger = Logger(use_tensorboard=use_tensorboard)\n", "\n", - " # train\n", - " \n", + "if use_tensorboard:\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FgQ1vK3CsoUG", + "scrolled": true + }, + "outputs": [], + "source": [ + "env = make_final_env()\n", + "state, _ = env.reset()\n", "\n", - " loss = \n", + "with trange(step, total_steps + 1) as progress_bar:\n", + " for step in progress_bar:\n", + " if not is_enough_ram():\n", + " print('Less than 100 MB RAM available, freezing.')\n", + " print('Ensure everything is okay and use KeyboardInterrupt to continue.')\n", + " wait_for_keyboard_interrupt()\n", "\n", - " loss.backward()\n", - " grad_norm = nn.utils.clip_grad_norm_(agent.parameters(), max_grad_norm)\n", - " opt.step()\n", - " opt.zero_grad()\n", + " agent.epsilon = linear_decay(init_epsilon, final_epsilon, step, decay_steps)\n", "\n", - " if step % loss_freq == 0:\n", - " td_loss_history.append(loss.data.cpu().item())\n", - " grad_norm_history.append(grad_norm)\n", + " # Play\n", + " _, state = play_and_record(state, action_sampler, env, exp_replay, n_steps=update_frequency)\n", "\n", - " if step % refresh_target_network_freq == 0:\n", - " # Load agent weights into target_network\n", - " \n", + " # Train\n", + " s, a, r, s_next, done = exp_replay.sample(batch_size)\n", + " # \n", "\n", - " if step % eval_freq == 0:\n", - " mean_rw_history.append(evaluate(\n", - " make_env(clip_rewards=True, seed=step), agent, n_games=3 * n_lives, greedy=True)\n", - " )\n", - " initial_state_q_values = agent.get_qvalues(\n", - " [make_env(seed=step).reset()]\n", - " )\n", - " initial_state_v_history.append(np.max(initial_state_q_values))\n", + " loss = compute_td_loss(s, a, r, s_next, done, agent, target_network, device=device) # Ensure 'device' is defined\n", "\n", - " clear_output(True)\n", - " print(\"buffer size = %i, epsilon = %.5f\" %\n", - " (len(exp_replay), agent.epsilon))\n", + " loss.backward()\n", + " grad_norm = nn.utils.clip_grad_norm_(agent.parameters(), max_grad_norm)\n", + " opt.step()\n", + " opt.zero_grad()\n", "\n", - " plt.figure(figsize=[16, 9])\n", + " if step % loss_freq == 0:\n", + " loss_value = loss.data.cpu().item()\n", + " grad_norm_value = grad_norm.cpu().item()\n", + " logger.log_loss(loss_value, step)\n", + " logger.log_grad_norm(grad_norm_value, step)\n", "\n", - " plt.subplot(2, 2, 1)\n", - " plt.title(\"Mean reward per life\")\n", - " plt.plot(mean_rw_history)\n", - " plt.grid()\n", + " if step % refresh_target_network_freq == 0:\n", + " # Load agent weights into target_network\n", + " target_network.load_state_dict(agent.q_network.state_dict())\n", + " torch.save(agent.state_dict(), \"last_state_dict.pt\")\n", "\n", - " assert not np.isnan(td_loss_history[-1])\n", - " plt.subplot(2, 2, 2)\n", - " plt.title(\"TD loss history (smoothened)\")\n", - " plt.plot(utils.smoothen(td_loss_history))\n", - " plt.grid()\n", + " if step % eval_freq == 0:\n", + " mean_reward = evaluate(\n", + " make_final_env(), agent, n_games=3 * n_lives, greedy=True, seed=step\n", + " )\n", + " initial_state_q_values = agent.get_qvalues(\n", + " [make_final_env().reset(seed=step)[0]]\n", + " )\n", + " initial_v = np.max(initial_state_q_values).item()\n", "\n", - " plt.subplot(2, 2, 3)\n", - " plt.title(\"Initial state V\")\n", - " plt.plot(initial_state_v_history)\n", - " plt.grid()\n", + " logger.log_mean_reward(mean_reward, step)\n", + " logger.log_initial_state_v(initial_v, step)\n", "\n", - " plt.subplot(2, 2, 4)\n", - " plt.title(\"Grad norm history (smoothened)\")\n", - " plt.plot(utils.smoothen(grad_norm_history))\n", - " plt.grid()\n", + " clear_output(True)\n", + " print(\"Buffer size = %i, Epsilon = %.5f\" % (len(exp_replay), agent.epsilon))\n", "\n", - " plt.show()" + " if not use_tensorboard:\n", + " # If using matplotlib, plot the metrics\n", + " logger.plot()" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], + "source": [ + "agent = DQNAgent(\n", + " DQNetworkDueling(N_FRAMES_STACKED, N_ACTIONS),\n", + " epsilon=1\n", + ").to(device)\n", + "agent.load_state_dict(torch.load(\"last_state_dict.pt\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZEDQhQrdsoUG" + }, "source": [ "Agent is evaluated for 1 life, not for a whole episode of 5 lives. Rewards in evaluation are also truncated. Cuz this is what environment the agent is learning in and in this way mean rewards per life can be compared with initial state value\n", "\n", @@ -1042,7 +1714,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "s0jLjYGwsoUG" + }, "source": [ "Final scoring is done on a whole episode with all 5 lives." ] @@ -1050,28 +1724,32 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "xTGVrwwQsoUG" + }, "outputs": [], "source": [ "final_score = evaluate(\n", - " make_env(clip_rewards=False, seed=9),\n", - " agent, n_games=30, greedy=True, t_max=10 * 1000\n", - ") * n_lives\n", + " make_final_env(),\n", + " agent, n_games=30, greedy=True, t_max=10 * 1000, seed=9\n", + ")\n", "print('final score:', final_score)\n", - "assert final_score >= 15, 'not as cool as DQN can'\n", + "assert final_score >= 3, 'not as cool as DQN can'\n", "print('Cool!')" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "ovaG8N4lsoUH" + }, "source": [ "## How to interpret plots:\n", "\n", - "This aint no supervised learning so don't expect anything to improve monotonously. \n", + "This aint no supervised learning so don't expect anything to improve monotonously.\n", "* **TD loss** is the MSE between agent's current Q-values and target Q-values. It may slowly increase or decrease, it's ok. The \"not ok\" behavior includes going NaN or stayng at exactly zero before agent has perfect performance.\n", "* **grad norm** just shows the intensivity of training. Not ok is growing to values of about 100 (or maybe even 50) though it depends on network architecture.\n", - "* **mean reward** is the expected sum of r(s,a) agent gets over the full game session. It will oscillate, but on average it should get higher over time (after a few thousand iterations...). \n", + "* **mean reward** is the expected sum of r(s,a) agent gets over the full game session. It will oscillate, but on average it should get higher over time (after a few thousand iterations...).\n", " * In basic q-learning implementation it takes about 40k steps to \"warm up\" agent before it starts to get better.\n", "* **Initial state V** is the expected discounted reward for episode in the oppinion of the agent. It should behave more smoothly than **mean reward**. It should get higher over time but sometimes can experience drawdowns because of the agaent's overestimates.\n", "* **buffer size** - this one is simple. It should go up and cap at max size.\n", @@ -1088,11 +1766,13 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "kVV72AB-soUH" + }, "source": [ "## About hyperparameters:\n", "\n", - "The task has something in common with supervised learning: loss is optimized through the buffer (instead of Train dataset). But the distribution of states and actions in the buffer **is not stationary** and depends on the policy that generated it. It can even happen that the mean TD error across the buffer is very low but the performance is extremely poor (imagine the agent collecting data to the buffer always manages to avoid the ball).\n", + "The task has something in common with supervised learning: loss is optimized through the buffer (instead of Train dataset). But the distribution of states and actions in the buffer **is not stationary** and depends on the policy it was generated by. It can even happen that the mean TD error across the buffer is very low but the performance is extremely poor (imagine the agent collecting data to the buffer always manages to avoid the ball).\n", "\n", "* Total timesteps and training time: It seems to be so huge, but actually it is normal for RL.\n", "\n", @@ -1102,15 +1782,14 @@ "\n", "* lr: $10^{-3}$ would probably be too huge\n", "\n", - "* batch size: This one can be very important: if it is too small the agent can fail to learn. Huge batch takes more time to process. If batch of size 8 can not be processed on the hardware you use take 2 (or even 4) batches of size 4, divide the loss on them by 2 (or 4) and make optimization step after both backward() calls in torch.\n", - "\n", - "* target network update frequency: has something in common with learning rate. Too frequent updates can lead to divergence. Too rare can lead to slow leraning. For millions of total timesteps thousands of inner steps seem ok. One iteration of target network updating is an iteration of the (this time approximate) $\\gamma$-compression that stands behind Q-learning. The more inner steps it makes the more accurate is the compression.\n", - "* max_grad_norm - just huge enough. In torch clip_grad_norm also evaluates the norm before clipping and it can be convenient for logging." + "* target network update frequency: has something in common with learning rate. Too frequent updates can lead to divergence. Too rare can lead to slow leraning. For millions of total timesteps thousands of inner steps seem ok. One iteration of target network updating is an iteration of the (this time approximate) $\\gamma$-compression that stands behind Q-learning. The more inner steps it makes the more accurate is the compression." ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "Plp8WC_esoUH" + }, "source": [ "### Video" ] @@ -1118,58 +1797,64 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "DdExc_AssoUH" + }, "outputs": [], "source": [ - "# Record sessions\n", + "# record sessions\n", + "from gymnasium.wrappers import RecordVideo\n", "\n", - "import gym.wrappers\n", - "\n", - "with gym.wrappers.Monitor(make_env(), directory=\"videos\", force=True) as env_monitor:\n", - " sessions = [evaluate(env_monitor, agent, n_games=n_lives, greedy=True) for _ in range(10)]" + "with make_final_env() as env, RecordVideo(\n", + " env=env, video_folder=\"./videos\", episode_trigger=lambda episode_number: True\n", + ") as env_monitor:\n", + " sessions = [\n", + " evaluate(env_monitor, agent, n_games=n_lives, greedy=True) for _ in range(10)\n", + " ]\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "lt6xg1n_soUH" + }, "outputs": [], "source": [ "# Show video. This may not work in some setups. If it doesn't\n", "# work for you, you can download the videos and view them locally.\n", "\n", "from pathlib import Path\n", + "from base64 import b64encode\n", "from IPython.display import HTML\n", "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", "\n", "HTML(\"\"\"\n", "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" + "\"\"\".format(data_url))" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "fLPx2aI7soUH" + }, "source": [ - "## Let's have a closer look at this.\n", + "## Let's have a closer look at this. Interpretation (2 pts).\n", "\n", - "If average episode score is below 200 using all 5 lives, then probably DQN has not converged fully. But anyway let's make a more complete record of an episode." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "eval_env = make_env(clip_rewards=False)\n", - "record = utils.play_and_log_episode(eval_env, agent)\n", - "print('total reward for life:', np.sum(record['rewards']))\n", - "for key in record:\n", - " print(key)" + "Let's play 5 episodes (note that the game has 5 lives) and log some stats:" ] }, { @@ -1178,60 +1863,52 @@ "metadata": {}, "outputs": [], "source": [ - "fig = plt.figure(figsize=(5, 5))\n", - "ax = fig.add_subplot(1, 1, 1)\n", + "from dqn.analysis import play_and_log_episode\n", "\n", - "ax.scatter(record['v_mc'], record['v_agent'])\n", - "ax.plot(sorted(record['v_mc']), sorted(record['v_mc']),\n", - " 'black', linestyle='--', label='x=y')\n", + "env = make_final_env()\n", + "stats = play_and_log_episode(env, agent)\n", "\n", - "ax.grid()\n", - "ax.legend()\n", - "ax.set_title('State Value Estimates')\n", - "ax.set_xlabel('Monte-Carlo')\n", - "ax.set_ylabel('Agent')\n", - "\n", - "plt.show()" + "print(\"Keys:\", list(stats.keys()))\n", + "print(\"Shapes:\")\n", + "for key in [\"states\", \"qvalues\", \"actions\", \"rewards\"]:\n", + " print(f\"{key}: {stats[key].shape}\")\n", + "print(\"terminated:\", stats[\"episode_finished\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "$\\hat V_{Monte-Carlo}(s_t) = \\sum_{\\tau=0}^{episode~end} \\gamma^{\\tau-t}r_t$" + "Let's plot rewards:" ] }, { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Is there a big bias? It's ok, anyway it works." - ] - }, - { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "## Bonus I (2 pts)" + "plt.plot(stats[\"rewards\"])\n", + "plt.grid()\n", + "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**1.** Plot several (say 3) states with high and low spreads of Q estimate by actions i.e.\n", - "$$\\max_a \\hat Q(s,a) - \\min_a \\hat Q(s,a)\\$$\n", - "Please take those states from different episodes to make sure that the states are really different.\n", - "\n", - "What should high and low spread mean at least in the world of perfect Q-fucntions?\n", + "Your task it to evaluate the following quantities from the logs:\n", + "1. Discounted returns: $G[t] = \\sum_{t'=t}^T \\gamma ^ {t' - t}r[t]$, where $T$ is the total time of an episode.\n", + "2. State Values estimated by the agent: $V_{agent}[t] = \\max_{a}Q_{agent}(s[t], a)$. \n", + "3. Q-spread: $\\Delta Q[t] = \\max_{a}Q_{agent}(s[t], a) - \\min_{a}Q_{agent}(s[t], a)$\n", "\n", - "Comment the states you like most.\n", + "Create a new env: `env = make_final_env()`, play for 5 episodes (a full game has 5 lives, so it will be 1 full game). \n", + "Plot rewards and the evaluated quantites for each of them. \n", + "Using the plots, can you find points where the ball hits the wall? \n", + "Where the ball hits the platform? \n", + "Probably, you won't need all the quantities for that, but it's still good to check the behavior of a model.\n", "\n", - "**2.** Plot several (say 3) states with high td-error and several states with high values of\n", - "$$| \\hat V_{Monte-Carlo}(s) - \\hat V_{agent}(s)|,$$ \n", - "$$\\hat V_{agent}(s)=\\max_a \\hat Q(s,a).$$ Please take those states from different episodes to make sure that the states are really different. From what part (i.e. beginning, middle, end) of an episode did these states come from?\n", - "\n", - "Comment the states you like most." + "The `merge_frame_stack_to_plot` function may be useful." ] }, { @@ -1240,75 +1917,91 @@ "metadata": {}, "outputs": [], "source": [ - "from utils import play_and_log_episode, img_by_obs\n", + "def get_discounted_returns(rewards: Reversible[float], gamma: float) -> list[float]:\n", + " \"\"\"\n", + " Calculates G[t] for each t, given rewards and gamma.\n", "\n", - "" + " Tip: Iterate backwards through rewards and use the following relationship:\n", + " G[t] = r[t] + gamma * G[t + 1]\n", + " \"\"\"\n", + " returns_reverse: list[float] = []\n", + " last_return: float = 0\n", + " for r in reversed(rewards):\n", + " # your code\n", + " returns = list(reversed(returns_reverse))\n", + " return returns\n" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "e36bU0u8soUH" + }, "source": [ - "## Bonus II (1-5 pts). Get High Score!\n", + "## Bonus I (2 pts). Get High Score!\n", "\n", - "1 point to you for each 50 points of your agent. Truncated by 5 points. Starting with 50 points, **not** 50 + threshold.\n", - "\n", - "One way is to train for several days and use heavier hardware (why not actually).\n", - "\n", - "Another way is to apply modifications (see **Bonus III**)." + "Get mean reward per life:\n", + "1. $\\geq 20$: +1 pt\n", + "2. $\\geq 40$: +2 pts" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "78e4nRoSsoUH" + }, "source": [ - "## Bonus III (2+ pts). Apply modifications to DQN.\n", - "\n", - "For inspiration see [Rainbow](https://arxiv.org/abs/1710.02298) - a version of q-learning that combines lots of them.\n", + "## Bonus II (2+ pts). Apply modifications to DQN.\n", "\n", - "Points for Bonus II and Bonus III fully stack. So if modified agent gets score 250+ you get 5 pts for Bonus II + points for modifications. If the final score is 40 then you get the points for modifications.\n", - "\n", - "\n", - "Some modifications:\n", - "* [Prioritized experience replay](https://arxiv.org/abs/1511.05952) (5 pts for your own implementation, 3 pts for using a ready one)\n", - "* [double q-learning](https://arxiv.org/abs/1509.06461) (2 pts)\n", - "* [dueling q-learning](https://arxiv.org/abs/1511.06581) (2 pts)\n", - "* multi-step heuristics (see [Rainbow](https://arxiv.org/abs/1710.02298)) (3 pts)\n", - "* [Noisy Nets](https://arxiv.org/abs/1706.10295) (3 pts)\n", - "* [distributional RL](https://arxiv.org/abs/1707.06887)(distributional and distributed stand for different things here) (5 pts)\n", + "* [Prioritized experience replay](https://arxiv.org/abs/1511.05952) (2 pts, please check for effective open-source implementations)\n", + "* [Noisy Nets](https://arxiv.org/abs/1706.10295) (2 pts, please, pay attention to the exploration policy and whether epsilon-greedy policy is used)\n", + "* [distributional RL](https://arxiv.org/abs/1707.06887)(distributional and distributed stand for different things here) (3 pts)\n", "* Other modifications (2+ pts depending on complexity)" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "j_3RXboysoUH" + }, "source": [ - "## Bonus IV (4+ pts). Distributed RL.\n", + "## Bonus III (2 pts). Distributed RL.\n", "\n", - "Solve the task in a distributed way. It can strongly speed up learning. See [article](https://arxiv.org/pdf/1602.01783.pdf) or some guides." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**As usual bonus points for all the tasks fully stack.**" + "https://gymnasium.farama.org/api/vector/#gymnasium.vector.AsyncVectorEnv" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "f9X5aB56soUI" + }, "outputs": [], "source": [] } ], "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "pygments_lexer": "ipython3" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 4 } diff --git a/week04_approx_rl/homework_tf.ipynb b/week04_approx_rl/homework_tf.ipynb index b7023c487..c95dc2355 100644 --- a/week04_approx_rl/homework_tf.ipynb +++ b/week04_approx_rl/homework_tf.ipynb @@ -20,10 +20,12 @@ " %tensorflow_version 1.x\n", " \n", " if not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", "\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week04_approx_rl/framebuffer.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week04_approx_rl/replay_buffer.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/framebuffer.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/replay_buffer.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/atari_wrappers.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week04_approx_rl/utils.py\n", "\n", " !touch .setup_complete\n", "\n", @@ -41,6 +43,17 @@ "__Frameworks__ - we'll accept this homework in any deep learning framework. This particular notebook was designed for tensorflow, but you will find it easy to adapt it to almost any python-based deep learning framework." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "import numpy as np\n", + "import utils" + ] + }, { "cell_type": "code", "execution_count": null, @@ -49,7 +62,6 @@ "source": [ "import gym\n", "import numpy as np\n", - "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] @@ -64,6 +76,50 @@ "This time we're gonna apply approximate q-learning to an Atari game called Breakout. It's not the hardest thing out there, but it's definitely way more complex than anything we tried before.\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ENV_NAME = \"BreakoutNoFrameskip-v4\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preprocessing (3 pts)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see what observations look like." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env = gym.make(ENV_NAME)\n", + "env.reset()\n", + "\n", + "n_cols = 5\n", + "n_rows = 2\n", + "fig = plt.figure(figsize=(16, 9))\n", + "\n", + "for row in range(n_rows):\n", + " for col in range(n_cols):\n", + " ax = fig.add_subplot(n_rows, n_cols, row * n_cols + col + 1)\n", + " ax.imshow(env.render('rgb_array'))\n", + " env.step(env.action_space.sample())\n", + "plt.show()" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -75,7 +131,9 @@ "We can thus save a lot of time by preprocessing game image, including\n", "* Resizing to a smaller shape, 64 x 64\n", "* Converting to grayscale\n", - "* Cropping irrelevant image parts (top & bottom)" + "* Cropping irrelevant image parts (top & bottom)\n", + "\n", + "Tip: You can implement your own grayscale converter and assign a huge weight to the red channel. This dirty trick is not necessary but it will speed up learning." ] }, { @@ -90,15 +148,15 @@ "import cv2\n", "\n", "\n", - "class PreprocessAtari(ObservationWrapper):\n", + "class PreprocessAtariObs(ObservationWrapper):\n", " def __init__(self, env):\n", " \"\"\"A gym wrapper that crops, scales image into the desired shapes and optionally grayscales it.\"\"\"\n", - " ObservationWrapper.__init__(self, env)\n", + " super().__init__(env)\n", "\n", " self.img_size = (64, 64, 1)\n", " self.observation_space = Box(0.0, 1.0, self.img_size)\n", "\n", - " def _to_gray_scale(self, rgb_image, channel_weights=[0.8, 0.1, 0.1]):\\n\",\n", + " def _to_gray_scale(self, rgb, channel_weights=[0.8, 0.1, 0.1]):\n", " \n", "\n", " def observation(self, img):\n", @@ -124,8 +182,8 @@ "source": [ "import gym\n", "# spawn game instance for tests\n", - "env = gym.make(\"BreakoutNoFrameskip-v4\") # create raw env\n", - "env = PreprocessAtari(env)\n", + "env = gym.make(ENV_NAME) # create raw env\n", + "env = PreprocessAtariObs(env)\n", "\n", "observation_shape = env.observation_space.shape\n", "n_actions = env.action_space.n\n", @@ -135,17 +193,78 @@ "\n", "# test observation\n", "assert obs.ndim == 3, \"observation must be [height, width, channels] even if there's just one channel\"\n", - "assert obs.shape == observation_shape\n", - "assert obs.dtype == 'float32'\n", + "assert obs.shape == observation_shape, (obs.shape, observation_shape)\n", + "assert obs.dtype == np.float32\n", "assert len(np.unique(obs)) > 2, \"your image must not be binary\"\n", "assert 0 <= np.min(obs) and np.max(obs) <= 1, \"convert image pixels to (0,1) range\"\n", "assert np.max(obs) >= 0.5, \"It would be easier to see a brighter observation\"\n", "assert np.mean(obs) >= 0.1, \"It would be easier to see a brighter observation\"\n", "\n", + "assert np.max(obs) >= 0.5, \"It would be easier to see a brighter observation\"\n", + "assert np.mean(obs) >= 0.1, \"It would be easier to see a brighter observation\"\n", + "\n", "print(\"Formal tests seem fine. Here's an example of what you'll get.\")\n", "\n", - "plt.title(\"what your network gonna see\")\n", - "plt.imshow(obs, interpolation='none', cmap='gray')" + "\n", + "n_cols = 5\n", + "n_rows = 2\n", + "fig = plt.figure(figsize=(16, 9))\n", + "obs = env.reset()\n", + "for row in range(n_rows):\n", + " for col in range(n_cols):\n", + " ax = fig.add_subplot(n_rows, n_cols, row * n_cols + col + 1)\n", + " ax.imshow(obs[:, :, 0], interpolation='none', cmap='gray')\n", + " obs, _, _, _ = env.step(env.action_space.sample())\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Wrapping." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**About the game:** You have 5 lives and get points for breaking the wall. Higher bricks cost more than the lower ones. There are 4 actions: start game (should be called at the beginning and after each life is lost), move left, move right and do nothing. There are some common wrappers used for Atari environments." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import atari_wrappers\n", + "\n", + "def PrimaryAtariWrap(env, clip_rewards=True):\n", + " assert 'NoFrameskip' in env.spec.id\n", + "\n", + " # This wrapper holds the same action for frames and outputs\n", + " # the maximal pixel value of 2 last frames (to handle blinking\n", + " # in some envs)\n", + " env = atari_wrappers.MaxAndSkipEnv(env, skip=4)\n", + "\n", + " # This wrapper sends done=True when each life is lost\n", + " # (not all the 5 lives that are givern by the game rules).\n", + " # It should make easier for the agent to understand that losing is bad.\n", + " env = atari_wrappers.EpisodicLifeEnv(env)\n", + "\n", + " # This wrapper laucnhes the ball when an episode starts.\n", + " # Without it the agent has to learn this action, too.\n", + " # Actually it can but learning would take longer.\n", + " env = atari_wrappers.FireResetEnv(env)\n", + "\n", + " # This wrapper transforms rewards to {-1, 0, 1} according to their sign\n", + " if clip_rewards:\n", + " env = atari_wrappers.ClipRewardEnv(env)\n", + "\n", + " # This wrapper is yours :)\n", + " env = PreprocessAtariObs(env)\n", + " return env" ] }, { @@ -168,9 +287,11 @@ "from framebuffer import FrameBuffer\n", "\n", "\n", - "def make_env():\n", - " env = gym.make(\"BreakoutNoFrameskip-v4\")\n", - " env = PreprocessAtari(env)\n", + "def make_env(clip_rewards=True, seed=None):\n", + " env = gym.make(ENV_NAME) # create raw env\n", + " if seed is not None:\n", + " env.seed(seed)\n", + " env = PrimaryAtariWrap(env, clip_rewards)\n", " env = FrameBuffer(env, n_frames=4, dim_order='tensorflow')\n", " return env\n", "\n", @@ -178,7 +299,7 @@ "env = make_env()\n", "env.reset()\n", "n_actions = env.action_space.n\n", - "state_dim = env.observation_space.shape" + "state_shape = env.observation_space.shape" ] }, { @@ -191,11 +312,22 @@ " obs, _, _, _ = env.step(env.action_space.sample())\n", "\n", "\n", + "plt.figure()\n", "plt.title(\"Game image\")\n", "plt.imshow(env.render(\"rgb_array\"))\n", "plt.show()\n", + "\n", + "plt.figure(figsize=[12,10])\n", "plt.title(\"Agent observation (4 frames left to right)\")\n", - "plt.imshow(obs.transpose([0, 2, 1]).reshape([state_dim[0], -1]))" + "plt.imshow(obs.transpose([0, 2, 1]).reshape([state_shape[0], -1]))\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## DQN as it is (4 pts)" ] }, { @@ -216,6 +348,19 @@ "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/yet_another_week/_resource/dqn_arch.png)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Dueling network: (+2 pts)**\n", + "$$Q_{\\theta}(s, a) = V_{\\eta}(f_{\\xi}(s)) + A_{\\psi}(f_{\\xi}(s), a) - \\frac{\\sum_{a'}A_{\\psi}(f_{\\xi}(s), a')}{N_{actions}},$$\n", + "where $\\xi$, $\\eta$, and $\\psi$ are, respectively, the parameters of the\n", + "shared encoder $f_ξ$ , of the value stream $V_\\eta$ , and of the advan\n", + "tage stream $A_\\psi$; and $\\theta = \\{\\xi, \\eta, \\psi\\}$ is their concatenation.\n", + "\n", + "For the architecture on the image $V$ and $A$ heads can follow the dense layer instead of $Q$. Please don't worry that the model becomes a little bigger." + ] + }, { "cell_type": "code", "execution_count": null, @@ -233,7 +378,8 @@ "metadata": {}, "outputs": [], "source": [ - "from keras.layers import Conv2D, Dense, Flatten\n", + "from tensorflow.keras.layers import Conv2D, Dense, Flatten\n", + "from tensorflow.keras import models\n", "\n", "\n", "class DQNAgent:\n", @@ -283,7 +429,7 @@ "metadata": {}, "outputs": [], "source": [ - "agent = DQNAgent(\"dqn_agent\", state_dim, n_actions, epsilon=0.5)\n", + "agent = DQNAgent(\"dqn_agent\", state_shape, n_actions, epsilon=1)\n", "sess.run(tf.global_variables_initializer())" ] }, @@ -370,7 +516,7 @@ "metadata": {}, "outputs": [], "source": [ - "def play_and_record(agent, env, exp_replay, n_steps=1):\n", + "def play_and_record(initial_state, agent, env, exp_replay, n_steps=1):\n", " \"\"\"\n", " Play the game for exactly n steps, record every (s,a,r,s', done) to replay buffer. \n", " Whenever game ends, add record with done=True and reset the game.\n", @@ -378,13 +524,16 @@ "\n", " PLEASE DO NOT RESET ENV UNLESS IT IS \"DONE\"\n", "\n", - " :returns: return sum of rewards over time\n", + " :returns: return sum of rewards over time and the state in which the env stays\n", " \"\"\"\n", " # initial state\n", - " s = env.framebuffer\n", + " s = initial_state\n", + " sum_rewards = 0\n", "\n", " # Play the game for n_steps as per instructions above\n", - " " + " \n", + "\n", + " return sum_rewards, s" ] }, { @@ -393,33 +542,34 @@ "metadata": {}, "outputs": [], "source": [ - "# testing your code. This may take a minute...\n", - "exp_replay = ReplayBuffer(20000)\n", + "# testing your code.\n", + "exp_replay = ReplayBuffer(2000)\n", "\n", - "play_and_record(agent, env, exp_replay, n_steps=10000)\n", + "state = env.reset()\n", + "play_and_record(state, agent, env, exp_replay, n_steps=1000)\n", "\n", "# if you're using your own experience replay buffer, some of those tests may need correction.\n", "# just make sure you know what your code does\n", - "assert len(exp_replay) == 10000, (\n", - " \"play_and_record should have added exactly 10000 steps, \" +\n", - " \"but instead added %i\") % len(exp_replay)\n", + "assert len(exp_replay) == 1000, \"play_and_record should have added exactly 1000 steps, \"\\\n", + " \"but instead added %i\" % len(exp_replay)\n", "is_dones = list(zip(*exp_replay._storage))[-1]\n", "\n", - "assert 0 < np.mean(is_dones) < 0.1, (\n", - " \"Please make sure you restart the game whenever it is 'done' \" +\n", - " \"and record the is_done correctly into the buffer.\" +\n", - " \"Got %f is_done rate over %i steps. [If you think it's your tough luck, just re-run the test]\"\n", - ") % (np.mean(is_dones), len(exp_replay))\n", + "assert 0 < np.mean(is_dones) < 0.1, \"Please make sure you restart the game whenever it is 'done' and record the is_done correctly into the buffer.\"\\\n", + " \"Got %f is_done rate over %i steps. [If you think it's your tough luck, just re-run the test]\" % (\n", + " np.mean(is_dones), len(exp_replay))\n", "\n", "for _ in range(100):\n", " obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", " 10)\n", - " assert obs_batch.shape == next_obs_batch.shape == (10,) + state_dim\n", - " assert act_batch.shape == (10,), \"actions batch should have shape (10,) but is instead %s\" % str(act_batch.shape)\n", - " assert reward_batch.shape == (10,), \"rewards batch should have shape (10,) but is instead %s\" % str(reward_batch.shape)\n", - " assert is_done_batch.shape == (10,), \"is_done batch should have shape (10,) but is instead %s\" % str(is_done_batch.shape)\n", + " assert obs_batch.shape == next_obs_batch.shape == (10,) + state_shape\n", + " assert act_batch.shape == (10,), \\\n", + " \"actions batch should have shape (10,) but is instead %s\" % str(act_batch.shape)\n", + " assert reward_batch.shape == (10,), \\\n", + " \"rewards batch should have shape (10,) but is instead %s\" % str(reward_batch.shape)\n", + " assert is_done_batch.shape == (10,), \\\n", + " \"is_done batch should have shape (10,) but is instead %s\" % str(is_done_batch.shape)\n", " assert [int(i) in (0, 1) for i in is_dones], \"is_done should be strictly True or False\"\n", - " assert [0 <= a <= n_actions for a in act_batch], \"actions should be within [0, n_actions]\"\n", + " assert [0 <= a < n_actions for a in act_batch], \"actions should be within [0, n_actions)\"\n", "\n", "print(\"Well done!\")" ] @@ -446,7 +596,7 @@ "metadata": {}, "outputs": [], "source": [ - "target_network = DQNAgent(\"target_network\", state_dim, n_actions)" + "target_network = DQNAgent(\"target_network\", state_shape, n_actions)" ] }, { @@ -493,10 +643,10 @@ "outputs": [], "source": [ "# placeholders that will be fed with exp_replay.sample(batch_size)\n", - "obs_ph = tf.placeholder(tf.float32, shape=(None,) + state_dim)\n", + "obs_ph = tf.placeholder(tf.float32, shape=(None,) + state_shape)\n", "actions_ph = tf.placeholder(tf.int32, shape=[None])\n", "rewards_ph = tf.placeholder(tf.float32, shape=[None])\n", - "next_obs_ph = tf.placeholder(tf.float32, shape=(None,) + state_dim)\n", + "next_obs_ph = tf.placeholder(tf.float32, shape=(None,) + state_shape)\n", "is_done_ph = tf.placeholder(tf.float32, shape=[None])\n", "\n", "is_not_done = 1 - is_done_ph\n", @@ -535,7 +685,17 @@ "Where\n", "* $Q_{target}(s',a')$ denotes q-value of next state and next action predicted by __target_network__\n", "* $s, a, r, s'$ are current state, action, reward and next state respectively\n", - "* $\\gamma$ is a discount factor defined two cells above." + "* $\\gamma$ is a discount factor defined two cells above.\n", + "\n", + "\n", + "__Note 1:__ there's an example input below. Feel free to experiment with it before you write the function.\n", + "\n", + "__Note 2:__ compute_td_loss is a source of 99% of bugs in this homework. If reward doesn't improve, it often helps to go through it line by line [with a rubber duck](https://rubberduckdebugging.com/).\n", + "\n", + "**Double DQN (+2 pts)**\n", + "\n", + "$$ Q_{reference}(s,a) = r(s, a) + \\gamma \\cdot\n", + "Q_{target}(s',argmax_{a'}Q_\\theta(s', a')) $$" ] }, { @@ -586,7 +746,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Main loop\n", + "## Main loop (3 pts)\n", + "\n", + "**If deadline is tonight and it has not converged:** It is ok. Send the notebook today and when it converges send it again.\n", + "If the code is exactly the same points will not be discounted.\n", "\n", "It's time to put everything together and see if it learns anything." ] @@ -601,13 +764,27 @@ "import pandas as pd\n", "from IPython.display import clear_output\n", "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "seed = \n", + "random.seed(seed)\n", + "np.random.seed(seed)\n", + "tf.set_random_seed(seed)\n", "\n", - "def moving_average(x, span=100, **kw):\n", - " return pd.DataFrame({'x': np.asarray(x)}).x.ewm(span=span, **kw).mean().values\n", + "env = make_env(seed)\n", + "state_shape = env.observation_space.shape\n", + "n_actions = env.action_space.n\n", + "state = env.reset()\n", "\n", - "mean_rw_history = []\n", - "td_loss_history = []" + "sess.run(tf.global_variables_initializer())\n", + "sess.run(copy_step)" ] }, { @@ -616,8 +793,10 @@ "metadata": {}, "outputs": [], "source": [ - "exp_replay = ReplayBuffer(10**5)\n", - "play_and_record(agent, env, exp_replay, n_steps=10000)\n", + "REPLAY_BUFFER_SIZE = 10**5\n", + "\n", + "exp_replay = ReplayBuffer(REPLAY_BUFFER_SIZE)\n", + "_, state = play_and_record(state, agent, env, exp_replay, n_steps=10000)\n", "\n", "\n", "def sample_batch(exp_replay, batch_size):\n", @@ -637,41 +816,19 @@ "metadata": {}, "outputs": [], "source": [ - "for i in trange(10**5):\n", - " # play\n", - " play_and_record(agent, env, exp_replay, 10)\n", - "\n", - " # train\n", - " _, loss_t = sess.run([train_step, td_loss], sample_batch(exp_replay, batch_size=64))\n", - " td_loss_history.append(loss_t)\n", - "\n", - " # adjust agent parameters\n", - " if i % 500 == 0:\n", - " # You could think that loading weights onto a target network is simply\n", - " # load_weigths_into_target_network(agent, target_network)\n", - " # but actually calling this function repeatedly creates a TF copy operator\n", - " # again and again, which bloats memory consumption with each training step.\n", - " # Instead, you should create 'copy_step' once.\n", - " sess.run(copy_step)\n", - " agent.epsilon = max(agent.epsilon * 0.99, 0.01)\n", - " mean_rw_history.append(evaluate(make_env(), agent, n_games=3))\n", + "timesteps_per_epoch = 10\n", + "batch_size = 64\n", + "total_steps = 3 * 10**5\n", + "decay_steps = 10**5\n", "\n", - " if i % 100 == 0:\n", - " clear_output(True)\n", - " print(\"buffer size = %i, epsilon = %.5f\" % (len(exp_replay), agent.epsilon))\n", + "init_epsilon = 1\n", + "final_epsilon = 0.1\n", "\n", - " plt.subplot(1, 2, 1)\n", - " plt.title(\"mean reward per game\")\n", - " plt.plot(mean_rw_history)\n", - " plt.grid()\n", + "loss_freq = 5\n", + "refresh_target_network_freq = 500\n", + "eval_freq = 500\n", "\n", - " assert not np.isnan(loss_t)\n", - " plt.figure(figsize=[12, 4])\n", - " plt.subplot(1, 2, 2)\n", - " plt.title(\"TD loss history (moving average)\")\n", - " plt.plot(moving_average(np.array(td_loss_history), span=100, min_periods=100))\n", - " plt.grid()\n", - " plt.show()" + "n_lives = 5" ] }, { @@ -680,30 +837,123 @@ "metadata": {}, "outputs": [], "source": [ - "assert np.mean(mean_rw_history[-10:]) > 10.\n", - "print(\"That's good enough for tutorial.\")" + "mean_rw_history = []\n", + "td_loss_history = []\n", + "initial_state_v_history = []\n", + "step = 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "state = env.reset()\n", + "\n", + "with trange(step, total_steps) as progress_bar:\n", + " for step in progress_bar:\n", + " agent.epsilon = utils.linear_decay(init_epsilon, final_epsilon, step, decay_steps)\n", + " \n", + " # play\n", + " _, state = play_and_record(state, agent, env, exp_replay, timesteps_per_epoch)\n", + "\n", + " # train\n", + " _, loss_t = sess.run([train_step, td_loss], sample_batch(exp_replay, batch_size=batch_size))\n", + " \n", + " if step % loss_freq == 0:\n", + " td_loss_history.append(loss_t)\n", + " \n", + " if step % refresh_target_network_freq == 0:\n", + " # Load agent weights into target_network\n", + " sess.run(copy_step)\n", + "\n", + " if step % eval_freq == 0:\n", + " # eval the agent\n", + " mean_rw_history.append(evaluate(\n", + " make_env(clip_rewards=True, seed=step), agent, n_games=3 * n_lives, greedy=True)\n", + " )\n", + " initial_state_q_values = agent.get_qvalues(\n", + " [make_env(seed=step).reset()]\n", + " )\n", + " initial_state_v_history.append(np.max(initial_state_q_values))\n", + "\n", + " clear_output(True)\n", + " print(\"buffer size = %i, epsilon = %.5f\" %\n", + " (len(exp_replay), agent.epsilon))\n", + "\n", + " plt.figure(figsize=[16, 9])\n", + "\n", + " plt.subplot(2, 2, 1)\n", + " plt.title(\"Mean reward per life\")\n", + " plt.plot(mean_rw_history)\n", + " plt.grid()\n", + "\n", + " assert not np.isnan(td_loss_history[-1])\n", + " plt.subplot(2, 2, 2)\n", + " plt.title(\"TD loss history (smoothened)\")\n", + " plt.plot(utils.smoothen(td_loss_history))\n", + " plt.grid()\n", + "\n", + " plt.subplot(2, 2, 3)\n", + " plt.title(\"Initial state V\")\n", + " plt.plot(initial_state_v_history)\n", + " plt.grid()\n", + "\n", + " plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "__ How to interpret plots: __\n", + "Agent is evaluated for 1 life, not for a whole episode of 5 lives. Rewards in evaluation are also truncated. Cuz this is what environment the agent is learning in and in this way mean rewards per life can be compared with initial state value\n", "\n", + "**The goal is to get 15 points in the real env**. So 3 or better 4 points in the preprocessed one will probably be enough. You can interrupt learning then." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Final scoring is done on a whole episode with all 5 lives." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "final_score = evaluate(\n", + " make_env(clip_rewards=False, seed=9),\n", + " agent, n_games=30, greedy=True, t_max=10 * 1000\n", + ") * n_lives\n", + "print('final score:', final_score)\n", + "assert final_score >= 15, 'not as cool as DQN can'\n", + "print('Cool!')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How to interpret plots:\n", "\n", "This aint no supervised learning so don't expect anything to improve monotonously. \n", - "* __ TD loss __ is the MSE between agent's current Q-values and target Q-values. It may slowly increase or decrease, it's ok. The \"not ok\" behavior includes going NaN or stayng at exactly zero before agent has perfect performance.\n", - "* __ mean reward__ is the expected sum of r(s,a) agent gets over the full game session. It will oscillate, but on average it should get higher over time (after a few thousand iterations...). \n", - " * In basic q-learning implementation it takes 5-10k steps to \"warm up\" agent before it starts to get better.\n", - "* __ buffer size__ - this one is simple. It should go up and cap at max size.\n", - "* __ epsilon__ - agent's willingness to explore. If you see that agent's already at 0.01 epsilon before it's average reward is above 0 - __ it means you need to increase epsilon__. Set it back to some 0.2 - 0.5 and decrease the pace at which it goes down.\n", - "* Also please ignore first 100-200 steps of each plot - they're just oscillations because of the way moving average works.\n", + "* **TD loss** is the MSE between agent's current Q-values and target Q-values. It may slowly increase or decrease, it's ok. The \"not ok\" behavior includes going NaN or stayng at exactly zero before agent has perfect performance.\n", + "* **mean reward** is the expected sum of r(s,a) agent gets over the full game session. It will oscillate, but on average it should get higher over time (after a few thousand iterations...). \n", + " * In basic q-learning implementation it takes about 40k steps to \"warm up\" agent before it starts to get better.\n", + "* **Initial state V** is the expected discounted reward for episode in the oppinion of the agent. It should behave more smoothly than **mean reward**. It should get higher over time but sometimes can experience drawdowns because of the agaent's overestimates.\n", + "* **buffer size** - this one is simple. It should go up and cap at max size.\n", + "* **epsilon** - agent's willingness to explore. If you see that agent's already at 0.01 epsilon before it's average reward is above 0 - it means you need to increase epsilon. Set it back to some 0.2 - 0.5 and decrease the pace at which it goes down.\n", + "* Smoothing of plots is done with a gaussian kernel\n", "\n", "At first your agent will lose quickly. Then it will learn to suck less and at least hit the ball a few times before it loses. Finally it will learn to actually score points.\n", "\n", - "__Training will take time.__ A lot of it actually. An optimistic estimate is to say it's gonna start winning (average reward > 10) after 10k steps. \n", + "**Training will take time.** A lot of it actually. Probably you will not see any improvment during first **150k** time steps (note that by default in this notebook agent is evaluated every 5000 time steps).\n", "\n", - "But hey, look on the bright side of things:\n", + "But hey, long training time isn't _that_ bad:\n", "\n", "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/yet_another_week/_resource/training.png)" ] @@ -712,7 +962,30 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Video" + "## About hyperparameters:\n", + "\n", + "The task has something in common with supervised learning: loss is optimized through the buffer (instead of Train dataset). But the distribution of states and actions in the buffer **is not stationary** and depends on the policy that generated it. It can even happen that the mean TD error across the buffer is very low but the performance is extremely poor (imagine the agent collecting data to the buffer always manages to avoid the ball).\n", + "\n", + "* Total timesteps and training time: It seems to be so huge, but actually it is normal for RL.\n", + "\n", + "* $\\epsilon$ decay shedule was taken from the original paper and is like traditional for epsilon-greedy policies. At the beginning of the training the agent's greedy policy is poor so many random actions should be taken.\n", + "\n", + "* Optimizer: In the original paper RMSProp was used (they did not have Adam in 2013) and it can work not worse than Adam. For us Adam was default and it worked.\n", + "\n", + "* lr: $10^{-3}$ would probably be too huge\n", + "\n", + "* batch size: This one can be very important: if it is too small the agent can fail to learn. Huge batch takes more time to process.\n", + "\n", + "* target network update frequency: has something in common with learning rate. Too frequent updates can lead to divergence. Too rare can lead to slow learning. For millions of total timesteps thousands of inner steps seem ok. One iteration of target network updating is an iteration of the (this time approximate) $\\gamma$-compression that stands behind Q-learning. The more inner steps it makes the more accurate is the compression." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Let's have a closer look at this.\n", + "\n", + "If average episode score is below 200 using all 5 lives, then probably DQN has not converged fully. But anyway let's make a more complete record of an episode." ] }, { @@ -721,8 +994,54 @@ "metadata": {}, "outputs": [], "source": [ - "# Don't forget to reset epsilon back to previous value if you want to go on training\n", - "agent.epsilon = 0" + "eval_env = make_env(clip_rewards=False)\n", + "record = utils.play_and_log_episode(eval_env, agent)\n", + "print('total reward for life:', np.sum(record['rewards']))\n", + "for key in record:\n", + " print(key)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(5, 5))\n", + "ax = fig.add_subplot(1, 1, 1)\n", + "\n", + "ax.scatter(record['v_mc'], record['v_agent'])\n", + "ax.plot(sorted(record['v_mc']), sorted(record['v_mc']),\n", + " 'black', linestyle='--', label='x=y')\n", + "\n", + "ax.grid()\n", + "ax.legend()\n", + "ax.set_title('State Value Estimates')\n", + "ax.set_xlabel('Monte-Carlo')\n", + "ax.set_ylabel('Agent')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "$\\hat V_{Monte-Carlo}(s_t) = \\sum_{\\tau=0}^{episode~end} \\gamma^{\\tau-t}r_t$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Is there a big bias? It's ok, anyway it works." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Video" ] }, { @@ -736,7 +1055,7 @@ "import gym.wrappers\n", "\n", "with gym.wrappers.Monitor(make_env(), directory=\"videos\", force=True) as env_monitor:\n", - " sessions = [evaluate(env_monitor, agent, n_games=1) for _ in range(100)]" + " sessions = [evaluate(env_monitor, agent, n_games=n_lives, greedy=True) for _ in range(10)]" ] }, { @@ -749,88 +1068,117 @@ "# work for you, you can download the videos and view them locally.\n", "\n", "from pathlib import Path\n", + "from base64 import b64encode\n", "from IPython.display import HTML\n", "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", "\n", "HTML(\"\"\"\n", "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" + "\"\"\".format(data_url))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Assignment part I (5 pts)\n", - "\n", - "We'll start by implementing target network to stabilize training.\n", - "\n", - "To do that you should use TensorFlow functionality. \n", - "\n", - "We recommend thoroughly debugging your code on simple tests before applying it in Atari dqn." + "## Bonus I (2 pts)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Bonus I (2+ pts)\n", + "**1.** Plot several (say 3) states with high and low spreads of Q estimate by actions i.e.\n", + "$$\\max_a \\hat Q(s,a) - \\min_a \\hat Q(s,a)\\$$\n", + "Please take those states from different episodes to make sure that the states are really different.\n", "\n", - "Implement and train double q-learning.\n", + "What should high and low spread mean at least in the world of perfect Q-fucntions?\n", "\n", - "This task contains of\n", - "* Implementing __double q-learning__ or __dueling q-learning__ or both (see tips below)\n", - "* Training a network till convergence\n", - " * Full points will be awwarded if your network gets average score of >=10 (see \"evaluating results\")\n", - " * Higher score = more points as usual\n", - " * If you're running out of time, it's okay to submit a solution that hasn't converged yet and updating it when it converges. _Lateness penalty will not increase for second submission_, so submitting first one in time gets you no penalty.\n", + "Comment the states you like most.\n", "\n", + "**2.** Plot several (say 3) states with high td-error and several states with high values of\n", + "$$| \\hat V_{Monte-Carlo}(s) - \\hat V_{agent}(s)|,$$ \n", + "$$\\hat V_{agent}(s)=\\max_a \\hat Q(s,a).$$ Please take those states from different episodes to make sure that the states are really different. From what part (i.e. beginning, middle, end) of an episode did these states come from?\n", "\n", - "#### Tips:\n", - "* Implementing __double q-learning__ shouldn't be a problem if you've already have target networks in place.\n", - " * You will probably need `tf.argmax` to select best actions\n", - " * Here's an original [article](https://arxiv.org/abs/1509.06461)\n", + "Comment the states you like most." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from utils import play_and_log_episode, img_by_obs\n", "\n", - "* __Dueling__ architecture is also quite straightforward if you have standard DQN.\n", - " * You will need to change network architecture, namely the q-values layer\n", - " * It must now contain two heads: V(s) and A(s,a), both dense layers\n", - " * You should then add them up via elemwise sum layer.\n", - " * Here's an [article](https://arxiv.org/pdf/1511.06581.pdf)" + "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Bonus II (5+ pts): Prioritized experience replay\n", + "## Bonus II (1-5 pts). Get High Score!\n", + "\n", + "1 point to you for each 50 points of your agent. Truncated by 5 points. Starting with 50 points, **not** 50 + threshold.\n", "\n", - "In this section, you're invited to implement prioritized experience replay\n", + "One way is to train for several days and use heavier hardware (why not actually).\n", + "\n", + "Another way is to apply modifications (see **Bonus III**)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bonus III (2+ pts). Apply modifications to DQN.\n", "\n", - "* You will probably need to provide a custom data structure\n", - "* Once pool.update is called, collect the pool.experience_replay.observations, actions, rewards and is_alive and store them in your data structure\n", - "* You can now sample such transitions in proportion to the error (see [article](https://arxiv.org/abs/1511.05952)) for training.\n", + "For inspiration see [Rainbow](https://arxiv.org/abs/1710.02298) - a version of q-learning that combines lots of them.\n", "\n", - "It's probably more convenient to explicitly declare inputs for \"sample observations\", \"sample actions\" and so on to plug them into q-learning.\n", + "Points for Bonus II and Bonus III fully stack. So if modified agent gets score 250+ you get 5 pts for Bonus II + points for modifications. If the final score is 40 then you get the points for modifications.\n", "\n", - "Prioritized (and even normal) experience replay should greatly reduce amount of game sessions you need to play in order to achieve good performance. \n", "\n", - "While it's effect on runtime is limited for atari, more complicated envs (further in the course) will certainly benefit for it.\n", + "Some modifications:\n", + "* [Prioritized experience replay](https://arxiv.org/abs/1511.05952) (5 pts for your own implementation, 3 pts for using a ready one)\n", + "* [double q-learning](https://arxiv.org/abs/1509.06461) (2 pts)\n", + "* [dueling q-learning](https://arxiv.org/abs/1511.06581) (2 pts)\n", + "* multi-step heuristics (see [Rainbow](https://arxiv.org/abs/1710.02298)) (3 pts)\n", + "* [Noisy Nets](https://arxiv.org/abs/1706.10295) (3 pts)\n", + "* [distributional RL](https://arxiv.org/abs/1707.06887)(distributional and distributed stand for different things here) (5 pts)\n", + "* Other modifications (2+ pts depending on complexity)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bonus IV (4+ pts). Distributed RL.\n", "\n", - "Prioritized experience replay only supports off-policy algorithms, so pls enforce `n_steps=1` in your q-learning reference computation (default is 10)." + "Solve the task in a distributed way. It can strongly speed up learning. See [article](https://arxiv.org/pdf/1602.01783.pdf) or some guides." ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "**As usual bonus points for all the tasks fully stack.**" + ] } ], "metadata": { + "accelerator": "GPU", "language_info": { "name": "python", "pygments_lexer": "ipython3" diff --git a/week04_approx_rl/img/dqn_arch.png b/week04_approx_rl/img/dqn_arch.png new file mode 100644 index 000000000..47a82a18a Binary files /dev/null and b/week04_approx_rl/img/dqn_arch.png differ diff --git a/week04_approx_rl/img/dueling.png b/week04_approx_rl/img/dueling.png new file mode 100644 index 000000000..b72a9ad2d Binary files /dev/null and b/week04_approx_rl/img/dueling.png differ diff --git a/week04_approx_rl/img/dueling_basic.png b/week04_approx_rl/img/dueling_basic.png new file mode 100644 index 000000000..13b86ef38 Binary files /dev/null and b/week04_approx_rl/img/dueling_basic.png differ diff --git a/week04_approx_rl/img/dueling_nature.png b/week04_approx_rl/img/dueling_nature.png new file mode 100644 index 000000000..3ad0ec1e9 Binary files /dev/null and b/week04_approx_rl/img/dueling_nature.png differ diff --git a/week04_approx_rl/img/dueling_single.png b/week04_approx_rl/img/dueling_single.png new file mode 100644 index 000000000..297701529 Binary files /dev/null and b/week04_approx_rl/img/dueling_single.png differ diff --git a/week04_approx_rl/img/exp_replay.png b/week04_approx_rl/img/exp_replay.png new file mode 100644 index 000000000..cded84fb5 Binary files /dev/null and b/week04_approx_rl/img/exp_replay.png differ diff --git a/week04_approx_rl/requirements.txt b/week04_approx_rl/requirements.txt new file mode 100644 index 000000000..69414565d --- /dev/null +++ b/week04_approx_rl/requirements.txt @@ -0,0 +1,13 @@ +gymnasium[atari,accept-rom-license,classic-control] +ale_py +ipython +ipywidgets +notebook +matplotlib +moviepy +numpy +opencv-python +scipy +tensorboard +torch +torchvision diff --git a/week04_approx_rl/seminar_lasagne.ipynb b/week04_approx_rl/seminar_lasagne.ipynb deleted file mode 100644 index d80665ed7..000000000 --- a/week04_approx_rl/seminar_lasagne.ipynb +++ /dev/null @@ -1,350 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Approximate q-learning\n", - "\n", - "In this notebook you will teach a lasagne neural network to do Q-learning." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "__Frameworks__ - we'll accept this homework in any deep learning framework. For example, it translates to TensorFlow almost line-to-line. However, we recommend you to stick to theano/lasagne unless you're certain about your skills in the framework of your choice." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%env THEANO_FLAGS = 'floatX=float32'\n", - "import os\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "env = gym.make(\"CartPole-v0\").env\n", - "env.reset()\n", - "n_actions = env.action_space.n\n", - "state_dim = env.observation_space.shape\n", - "\n", - "plt.imshow(env.render(\"rgb_array\"))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Approximate (deep) Q-learning: building the network\n", - "\n", - "In this section we will build and train naive Q-learning with theano/lasagne" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First step is initializing input variables" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import theano\n", - "import theano.tensor as T\n", - "\n", - "# create input variables. We'll support multiple states at once\n", - "\n", - "\n", - "current_states = T.matrix(\"states[batch,units]\")\n", - "actions = T.ivector(\"action_ids[batch]\")\n", - "rewards = T.vector(\"rewards[batch]\")\n", - "next_states = T.matrix(\"next states[batch,units]\")\n", - "is_end = T.ivector(\"vector[batch] where 1 means that session just ended\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import lasagne\n", - "from lasagne.layers import *\n", - "\n", - "# input layer\n", - "l_states = InputLayer((None,)+state_dim)\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "# output layer\n", - "l_qvalues = DenseLayer( , num_units=n_actions, nonlinearity=None)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Predicting Q-values for `current_states`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get q-values for ALL actions in current_states\n", - "predicted_qvalues = get_output(l_qvalues, {l_states: current_states})" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# compiling agent's \"GetQValues\" function\n", - "get_qvalues = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# select q-values for chosen actions\n", - "predicted_qvalues_for_actions = predicted_qvalues[T.arange(\n", - " actions.shape[0]), actions]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Loss function and `update`\n", - "Here we write a function similar to `agent.update`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# predict q-values for next states\n", - "predicted_next_qvalues = get_output(l_qvalues, {l_states: < theano input with for states> })\n", - "\n", - "\n", - "# Computing target q-values under\n", - "gamma = 0.99\n", - "target_qvalues_for_actions = \n", - "\n", - "# zero-out q-values at the end\n", - "target_qvalues_for_actions = (1-is_end)*target_qvalues_for_actions\n", - "\n", - "# don't compute gradient over target q-values (consider constant)\n", - "target_qvalues_for_actions = theano.gradient.disconnected_grad(\n", - " target_qvalues_for_actions)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# mean squared error loss function\n", - "loss = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# all network weights\n", - "all_weights = get_all_params(l_qvalues, trainable=True)\n", - "\n", - "# network updates. Note the small learning rate (for stability)\n", - "updates = lasagne.updates.sgd(loss, all_weights, learning_rate=1e-4)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Training function that resembles agent.update(state,action,reward,next_state)\n", - "# with 1 more argument meaning is_end\n", - "train_step = theano.function([current_states, actions, rewards, next_states, is_end],\n", - " updates=updates)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Playing the game" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "epsilon = 0.25 # initial epsilon\n", - "\n", - "\n", - "def generate_session(t_max=1000):\n", - " \"\"\"play env with approximate q-learning agent and train it at the same time\"\"\"\n", - "\n", - " total_reward = 0\n", - " s = env.reset()\n", - "\n", - " for t in range(t_max):\n", - "\n", - " # get action q-values from the network\n", - " q_values = get_qvalues([s])[0]\n", - "\n", - " a = \n", - "\n", - " new_s, r, done, info = env.step(a)\n", - "\n", - " # train agent one step. Note that we use one-element arrays instead of scalars\n", - " # because that's what function accepts.\n", - " train_step([s], [a], [r], [new_s], [done])\n", - "\n", - " total_reward += r\n", - "\n", - " s = new_s\n", - " if done:\n", - " break\n", - "\n", - " return total_reward" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for i in range(100):\n", - "\n", - " rewards = [generate_session() for _ in range(100)] # generate new sessions\n", - "\n", - " epsilon *= 0.95\n", - "\n", - " print(\"mean reward:%.3f\\tepsilon:%.5f\" % (np.mean(rewards), epsilon))\n", - "\n", - " if np.mean(rewards) > 300:\n", - " print(\"You Win!\")\n", - " break\n", - "\n", - " assert epsilon != 0, \"Please explore environment\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Video" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "epsilon = 0 # Don't forget to reset epsilon back to initial value if you want to go on training" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# record sessions\n", - "import gym.wrappers\n", - "\n", - "env = gym.wrappers.Monitor(gym.make(\"CartPole-v0\"),\n", - " directory=\"videos\", force=True)\n", - "sessions = [generate_session() for _ in range(100)]\n", - "env.close()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# show video\n", - "from IPython.display import HTML\n", - "import os\n", - "\n", - "video_names = list(\n", - " filter(lambda s: s.endswith(\".mp4\"), os.listdir(\"./videos/\")))\n", - "\n", - "HTML(\"\"\"\n", - "\n", - "\"\"\".format(\"./videos/\" + video_names[-1])) # this may or may not be _last_ video. Try other indices" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week04_approx_rl/seminar_pytorch.ipynb b/week04_approx_rl/seminar_pytorch.ipynb index 75c4fda6f..1cab93585 100644 --- a/week04_approx_rl/seminar_pytorch.ipynb +++ b/week04_approx_rl/seminar_pytorch.ipynb @@ -1,382 +1,454 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Approximate q-learning\n", - "\n", - "In this notebook you will teach a __PyTorch__ neural network to do Q-learning." - ] + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "kr_aKWMGEmh-" + }, + "source": [ + "# Approximate q-learning\n", + "\n", + "In this notebook you will teach a __PyTorch__ neural network to do Q-learning." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "oaMu65ONEmh_" + }, + "outputs": [], + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display to draw game images on.\n", + "# It will have no effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "avILCRKkEpaX" + }, + "outputs": [], + "source": [ + "!pip install gymnasium[classic_control]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "K_SRk2ASEmh_" + }, + "outputs": [], + "source": [ + "import gymnasium as gym\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "x2YvkgprEmh_" + }, + "outputs": [], + "source": [ + "env = gym.make(\"CartPole-v0\", render_mode=\"rgb_array\").env\n", + "env.reset()\n", + "n_actions = env.action_space.n\n", + "state_dim = env.observation_space.shape\n", + "\n", + "plt.imshow(env.render())\n", + "env.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sI8W19CwEmh_" + }, + "source": [ + "# Approximate Q-learning: building the network\n", + "\n", + "To train a neural network policy one must have a neural network policy. Let's build it.\n", + "\n", + "\n", + "Since we're working with a pre-extracted features (cart positions, angles and velocities), we don't need a complicated network yet. In fact, let's build something like this for starters:\n", + "\n", + "![img](https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/yet_another_week/_resource/qlearning_scheme.png)\n", + "\n", + "For your first run, please only use linear layers (`nn.Linear`) and activations. Stuff like batch normalization or dropout may ruin everything if used haphazardly.\n", + "\n", + "Also please avoid using nonlinearities like sigmoid & tanh: since agent's observations are not normalized, sigmoids might be saturated at initialization. Instead, use non-saturating nonlinearities like ReLU.\n", + "\n", + "Ideally you should start small with maybe 1-2 hidden layers with < 200 neurons and then increase network size if agent doesn't beat the target score." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "YdWXv8WJEmiA" + }, + "outputs": [], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "y2-PcaIQEmiA" + }, + "outputs": [], + "source": [ + "network = nn.Sequential()\n", + "\n", + "network.add_module('layer1', )\n", + "\n", + "\n", + "\n", + "# hint: use state_dim[0] as input size" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "8xuWPGriEmiA" + }, + "outputs": [], + "source": [ + "def get_action(state, epsilon=0):\n", + " \"\"\"\n", + " sample actions with epsilon-greedy policy\n", + " recap: with p = epsilon pick random action, else pick action with highest Q(s,a)\n", + " \"\"\"\n", + " state = torch.tensor(state[None], dtype=torch.float32)\n", + " q_values = network(state).detach().numpy()\n", + "\n", + " \n", + "\n", + " return int( )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wroEfSRNEmiA" + }, + "outputs": [], + "source": [ + "s, _ = env.reset()\n", + "assert tuple(network(torch.tensor([s]*3, dtype=torch.float32)).size()) == (\n", + " 3, n_actions), \"please make sure your model maps state s -> [Q(s,a0), ..., Q(s, a_last)]\"\n", + "assert isinstance(list(network.modules(\n", + "))[-1], nn.Linear), \"please make sure you predict q-values without nonlinearity (ignore if you know what you're doing)\"\n", + "assert isinstance(get_action(s), int), \"get_action(s) must return int, not %s. try int(action)\" % (type(get_action(s)))\n", + "\n", + "# test epsilon-greedy exploration\n", + "for eps in [0., 0.1, 0.5, 1.0]:\n", + " state_frequencies = np.bincount(\n", + " [get_action(s, epsilon=eps) for i in range(10000)], minlength=n_actions)\n", + " best_action = state_frequencies.argmax()\n", + " assert abs(state_frequencies[best_action] -\n", + " 10000 * (1 - eps + eps / n_actions)) < 200\n", + " for other_action in range(n_actions):\n", + " if other_action != best_action:\n", + " assert abs(state_frequencies[other_action] -\n", + " 10000 * (eps / n_actions)) < 200\n", + " print('e=%.1f tests passed' % eps)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f88ovLBQEmiA" + }, + "source": [ + "### Q-learning via gradient descent\n", + "\n", + "We shall now train our agent's Q-function by minimizing the TD loss:\n", + "$$ L = { 1 \\over N} \\sum_i (Q_{\\theta}(s,a) - [r(s,a) + \\gamma \\cdot max_{a'} Q_{-}(s', a')]) ^2 $$\n", + "\n", + "\n", + "Where\n", + "* $s, a, r, s'$ are current state, action, reward and next state respectively\n", + "* $\\gamma$ is a discount factor defined two cells above.\n", + "\n", + "The tricky part is with $Q_{-}(s',a')$. From an engineering standpoint, it's the same as $Q_{\\theta}$ - the output of your neural network policy. However, when doing gradient descent, __we won't propagate gradients through it__ to make training more stable (see lectures).\n", + "\n", + "To do so, we shall use `x.detach()` function which basically says \"consider this thing constant when doing backprop\"." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "id": "bOIpO142EmiB" + }, + "outputs": [], + "source": [ + "def compute_td_loss(states, actions, rewards, next_states, is_done, gamma=0.99, check_shapes=False):\n", + " \"\"\" Compute td loss using torch operations only. Use the formula above. \"\"\"\n", + " states = torch.tensor(\n", + " states, dtype=torch.float32) # shape: [batch_size, state_size]\n", + " actions = torch.tensor(actions, dtype=torch.long) # shape: [batch_size]\n", + " rewards = torch.tensor(rewards, dtype=torch.float32) # shape: [batch_size]\n", + " # shape: [batch_size, state_size]\n", + " next_states = torch.tensor(next_states, dtype=torch.float32)\n", + " is_done = torch.tensor(is_done, dtype=torch.uint8) # shape: [batch_size]\n", + "\n", + " # get q-values for all actions in current states\n", + " predicted_qvalues = network(states) # shape: [batch_size, n_actions]\n", + "\n", + " # select q-values for chosen actions\n", + " predicted_qvalues_for_actions = predicted_qvalues[ # shape: [batch_size]\n", + " range(states.shape[0]), actions\n", + " ]\n", + "\n", + " # compute q-values for all actions in next states\n", + " predicted_next_qvalues = \n", + "\n", + " # compute V*(next_states) using predicted next q-values\n", + " next_state_values = \n", + " assert next_state_values.dtype == torch.float32\n", + "\n", + " # compute \"target q-values\" for loss - it's what's inside square parentheses in the above formula.\n", + " target_qvalues_for_actions = \n", + "\n", + " # at the last state we shall use simplified formula: Q(s,a) = r(s,a) since s' doesn't exist\n", + " target_qvalues_for_actions = torch.where(\n", + " is_done, rewards, target_qvalues_for_actions)\n", + "\n", + " # mean squared error loss to minimize\n", + " loss = torch.mean((predicted_qvalues_for_actions -\n", + " target_qvalues_for_actions.detach()) ** 2)\n", + "\n", + " if check_shapes:\n", + " assert predicted_next_qvalues.data.dim(\n", + " ) == 2, \"make sure you predicted q-values for all actions in next state\"\n", + " assert next_state_values.data.dim(\n", + " ) == 1, \"make sure you computed V(s') as maximum over just the actions axis and not all axes\"\n", + " assert target_qvalues_for_actions.data.dim(\n", + " ) == 1, \"there's something wrong with target q-values, they must be a vector\"\n", + "\n", + " return loss" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "lKi6AK3DEmiB" + }, + "outputs": [], + "source": [ + "# sanity checks\n", + "s, _ = env.reset()\n", + "a = env.action_space.sample()\n", + "next_s, r, terminated, _, _ = env.step(a)\n", + "loss = compute_td_loss([s], [a], [r], [next_s], [terminated], check_shapes=True)\n", + "loss.backward()\n", + "\n", + "assert len(loss.size()) == 0, \"you must return scalar loss - mean over batch\"\n", + "assert np.any(next(network.parameters()).grad.detach().numpy() !=\n", + " 0), \"loss must be differentiable w.r.t. network weights\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LgL6G5lFEmiB" + }, + "source": [ + "### Playing the game" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "zsHb_fjjEmiB" + }, + "outputs": [], + "source": [ + "opt = torch.optim.Adam(network.parameters(), lr=1e-4)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "id": "nJ_-xtsjEmiB" + }, + "outputs": [], + "source": [ + "def generate_session(env, t_max=1000, epsilon=0, train=False):\n", + " \"\"\"play env with approximate q-learning agent and train it at the same time\"\"\"\n", + " total_reward = 0\n", + " s, _ = env.reset()\n", + "\n", + " for t in range(t_max):\n", + " a = get_action(s, epsilon=epsilon)\n", + " next_s, r, terminated, truncated, _ = env.step(a)\n", + "\n", + " if train:\n", + " opt.zero_grad()\n", + " compute_td_loss([s], [a], [r], [next_s], [terminated]).backward()\n", + " opt.step()\n", + "\n", + " total_reward += r\n", + " s = next_s\n", + " if terminated or truncated:\n", + " break\n", + "\n", + " return total_reward" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "40mKYuVIEmiB" + }, + "outputs": [], + "source": [ + "epsilon = 0.5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EXy8ij00EmiB" + }, + "outputs": [], + "source": [ + "for i in range(1000):\n", + " session_rewards = [generate_session(env, epsilon=epsilon, train=True) for _ in range(100)]\n", + " print(\"epoch #{}\\tmean reward = {:.3f}\\tepsilon = {:.3f}\".format(i, np.mean(session_rewards), epsilon))\n", + "\n", + " epsilon *= 0.99\n", + " assert epsilon >= 1e-4, \"Make sure epsilon is always nonzero during training\"\n", + "\n", + " if np.mean(session_rewards) > 300:\n", + " print(\"You Win!\")\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XJPoF9XtEmiB" + }, + "source": [ + "### How to interpret results\n", + "\n", + "\n", + "Welcome to the f.. world of deep f...n reinforcement learning. Don't expect agent's reward to smoothly go up. Hope for it to go increase eventually. If it deems you worthy.\n", + "\n", + "Seriously though,\n", + "* __ mean reward__ is the average reward per game. For a correct implementation it may stay low for some 10 epochs, then start growing while oscilating insanely and converges by ~50-100 steps depending on the network architecture.\n", + "* If it never reaches target score by the end of for loop, try increasing the number of hidden neurons or look at the epsilon.\n", + "* __ epsilon__ - agent's willingness to explore. If you see that agent's already at < 0.01 epsilon before it's is at least 200, just reset it back to 0.1 - 0.5." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lhKiN-qOEmiB" + }, + "source": [ + "### Record videos\n", + "\n", + "As usual, we now use `gymnasium.wrappers.RecordVideo` to record a video of our agent playing the game. Unlike our previous attempts with state binarization, this time we expect our agent to act ~~(or fail)~~ more smoothly since there's no more binarization error at play.\n", + "\n", + "As you already did with tabular q-learning, we set epsilon=0 for final evaluation to prevent agent from exploring himself to death." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2yqPkj6HEmiB" + }, + "outputs": [], + "source": [ + "# Record sessions\n", + "\n", + "from gymnasium.wrappers import RecordVideo\n", + "\n", + "with gym.make(\"CartPole-v0\", render_mode=\"rgb_array\") as record_env, RecordVideo(\n", + " record_env, video_folder=\"videos\"\n", + ") as env_monitor:\n", + " sessions = [\n", + " generate_session(env_monitor, epsilon=0, train=False) for _ in range(100)\n", + " ]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "afqi2qomEmiC" + }, + "outputs": [], + "source": [ + "# Show video. This may not work in some setups. If it doesn't\n", + "# work for you, you can download the videos and view them locally.\n", + "\n", + "from pathlib import Path\n", + "from base64 import b64encode\n", + "from IPython.display import HTML\n", + "\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", + "\n", + "HTML(\"\"\"\n", + "\n", + "\"\"\".format(data_url))" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys, os\n", - "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - " !touch .setup_complete\n", - "\n", - "# This code creates a virtual display to draw game images on.\n", - "# It will have no effect if your machine has a monitor.\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "env = gym.make(\"CartPole-v0\").env\n", - "env.reset()\n", - "n_actions = env.action_space.n\n", - "state_dim = env.observation_space.shape\n", - "\n", - "plt.imshow(env.render(\"rgb_array\"))\n", - "env.close()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Approximate Q-learning: building the network\n", - "\n", - "To train a neural network policy one must have a neural network policy. Let's build it.\n", - "\n", - "\n", - "Since we're working with a pre-extracted features (cart positions, angles and velocities), we don't need a complicated network yet. In fact, let's build something like this for starters:\n", - "\n", - "![img](https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/yet_another_week/_resource/qlearning_scheme.png)\n", - "\n", - "For your first run, please only use linear layers (`nn.Linear`) and activations. Stuff like batch normalization or dropout may ruin everything if used haphazardly. \n", - "\n", - "Also please avoid using nonlinearities like sigmoid & tanh: since agent's observations are not normalized, sigmoids might be saturated at initialization. Instead, use non-saturating nonlinearities like ReLU.\n", - "\n", - "Ideally you should start small with maybe 1-2 hidden layers with < 200 neurons and then increase network size if agent doesn't beat the target score." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import torch\n", - "import torch.nn as nn\n", - "import torch.nn.functional as F" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "network = nn.Sequential()\n", - "\n", - "network.add_module('layer1', )\n", - "\n", - "\n", - "\n", - "# hint: use state_dim[0] as input size" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def get_action(state, epsilon=0):\n", - " \"\"\"\n", - " sample actions with epsilon-greedy policy\n", - " recap: with p = epsilon pick random action, else pick action with highest Q(s,a)\n", - " \"\"\"\n", - " state = torch.tensor(state[None], dtype=torch.float32)\n", - " q_values = network(state).detach().numpy()\n", - "\n", - " \n", - "\n", - " return int( )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s = env.reset()\n", - "assert tuple(network(torch.tensor([s]*3, dtype=torch.float32)).size()) == (\n", - " 3, n_actions), \"please make sure your model maps state s -> [Q(s,a0), ..., Q(s, a_last)]\"\n", - "assert isinstance(list(network.modules(\n", - "))[-1], nn.Linear), \"please make sure you predict q-values without nonlinearity (ignore if you know what you're doing)\"\n", - "assert isinstance(get_action(\n", - " s), int), \"get_action(s) must return int, not %s. try int(action)\" % (type(get_action(s)))\n", - "\n", - "# test epsilon-greedy exploration\n", - "for eps in [0., 0.1, 0.5, 1.0]:\n", - " state_frequencies = np.bincount(\n", - " [get_action(s, epsilon=eps) for i in range(10000)], minlength=n_actions)\n", - " best_action = state_frequencies.argmax()\n", - " assert abs(state_frequencies[best_action] -\n", - " 10000 * (1 - eps + eps / n_actions)) < 200\n", - " for other_action in range(n_actions):\n", - " if other_action != best_action:\n", - " assert abs(state_frequencies[other_action] -\n", - " 10000 * (eps / n_actions)) < 200\n", - " print('e=%.1f tests passed' % eps)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Q-learning via gradient descent\n", - "\n", - "We shall now train our agent's Q-function by minimizing the TD loss:\n", - "$$ L = { 1 \\over N} \\sum_i (Q_{\\theta}(s,a) - [r(s,a) + \\gamma \\cdot max_{a'} Q_{-}(s', a')]) ^2 $$\n", - "\n", - "\n", - "Where\n", - "* $s, a, r, s'$ are current state, action, reward and next state respectively\n", - "* $\\gamma$ is a discount factor defined two cells above.\n", - "\n", - "The tricky part is with $Q_{-}(s',a')$. From an engineering standpoint, it's the same as $Q_{\\theta}$ - the output of your neural network policy. However, when doing gradient descent, __we won't propagate gradients through it__ to make training more stable (see lectures).\n", - "\n", - "To do so, we shall use `x.detach()` function which basically says \"consider this thing constant when doingbackprop\"." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def compute_td_loss(states, actions, rewards, next_states, is_done, gamma=0.99, check_shapes=False):\n", - " \"\"\" Compute td loss using torch operations only. Use the formula above. \"\"\"\n", - " states = torch.tensor(\n", - " states, dtype=torch.float32) # shape: [batch_size, state_size]\n", - " actions = torch.tensor(actions, dtype=torch.long) # shape: [batch_size]\n", - " rewards = torch.tensor(rewards, dtype=torch.float32) # shape: [batch_size]\n", - " # shape: [batch_size, state_size]\n", - " next_states = torch.tensor(next_states, dtype=torch.float32)\n", - " is_done = torch.tensor(is_done, dtype=torch.uint8) # shape: [batch_size]\n", - "\n", - " # get q-values for all actions in current states\n", - " predicted_qvalues = network(states)\n", - "\n", - " # select q-values for chosen actions\n", - " predicted_qvalues_for_actions = predicted_qvalues[\n", - " range(states.shape[0]), actions\n", - " ]\n", - "\n", - " # compute q-values for all actions in next states\n", - " predicted_next_qvalues = \n", - "\n", - " # compute V*(next_states) using predicted next q-values\n", - " next_state_values = \n", - " assert next_state_values.dtype == torch.float32\n", - "\n", - " # compute \"target q-values\" for loss - it's what's inside square parentheses in the above formula.\n", - " target_qvalues_for_actions = \n", - "\n", - " # at the last state we shall use simplified formula: Q(s,a) = r(s,a) since s' doesn't exist\n", - " target_qvalues_for_actions = torch.where(\n", - " is_done, rewards, target_qvalues_for_actions)\n", - "\n", - " # mean squared error loss to minimize\n", - " loss = torch.mean((predicted_qvalues_for_actions -\n", - " target_qvalues_for_actions.detach()) ** 2)\n", - "\n", - " if check_shapes:\n", - " assert predicted_next_qvalues.data.dim(\n", - " ) == 2, \"make sure you predicted q-values for all actions in next state\"\n", - " assert next_state_values.data.dim(\n", - " ) == 1, \"make sure you computed V(s') as maximum over just the actions axis and not all axes\"\n", - " assert target_qvalues_for_actions.data.dim(\n", - " ) == 1, \"there's something wrong with target q-values, they must be a vector\"\n", - "\n", - " return loss" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# sanity checks\n", - "s = env.reset()\n", - "a = env.action_space.sample()\n", - "next_s, r, done, _ = env.step(a)\n", - "loss = compute_td_loss([s], [a], [r], [next_s], [done], check_shapes=True)\n", - "loss.backward()\n", - "\n", - "assert len(loss.size()) == 0, \"you must return scalar loss - mean over batch\"\n", - "assert np.any(next(network.parameters()).grad.detach().numpy() !=\n", - " 0), \"loss must be differentiable w.r.t. network weights\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Playing the game" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "opt = torch.optim.Adam(network.parameters(), lr=1e-4)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def generate_session(env, t_max=1000, epsilon=0, train=False):\n", - " \"\"\"play env with approximate q-learning agent and train it at the same time\"\"\"\n", - " total_reward = 0\n", - " s = env.reset()\n", - "\n", - " for t in range(t_max):\n", - " a = get_action(s, epsilon=epsilon)\n", - " next_s, r, done, _ = env.step(a)\n", - "\n", - " if train:\n", - " opt.zero_grad()\n", - " compute_td_loss([s], [a], [r], [next_s], [done]).backward()\n", - " opt.step()\n", - "\n", - " total_reward += r\n", - " s = next_s\n", - " if done:\n", - " break\n", - "\n", - " return total_reward" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "epsilon = 0.5" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for i in range(1000):\n", - " session_rewards = [generate_session(env, epsilon=epsilon, train=True) for _ in range(100)]\n", - " print(\"epoch #{}\\tmean reward = {:.3f}\\tepsilon = {:.3f}\".format(i, np.mean(session_rewards), epsilon))\n", - "\n", - " epsilon *= 0.99\n", - " assert epsilon >= 1e-4, \"Make sure epsilon is always nonzero during training\"\n", - "\n", - " if np.mean(session_rewards) > 300:\n", - " print(\"You Win!\")\n", - " break" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### How to interpret results\n", - "\n", - "\n", - "Welcome to the f.. world of deep f...n reinforcement learning. Don't expect agent's reward to smoothly go up. Hope for it to go increase eventually. If it deems you worthy.\n", - "\n", - "Seriously though,\n", - "* __ mean reward__ is the average reward per game. For a correct implementation it may stay low for some 10 epochs, then start growing while oscilating insanely and converges by ~50-100 steps depending on the network architecture. \n", - "* If it never reaches target score by the end of for loop, try increasing the number of hidden neurons or look at the epsilon.\n", - "* __ epsilon__ - agent's willingness to explore. If you see that agent's already at < 0.01 epsilon before it's is at least 200, just reset it back to 0.1 - 0.5." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Record videos\n", - "\n", - "As usual, we now use `gym.wrappers.Monitor` to record a video of our agent playing the game. Unlike our previous attempts with state binarization, this time we expect our agent to act ~~(or fail)~~ more smoothly since there's no more binarization error at play.\n", - "\n", - "As you already did with tabular q-learning, we set epsilon=0 for final evaluation to prevent agent from exploring himself to death." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Record sessions\n", - "\n", - "import gym.wrappers\n", - "\n", - "with gym.wrappers.Monitor(gym.make(\"CartPole-v0\"), directory=\"videos\", force=True) as env_monitor:\n", - " sessions = [generate_session(env_monitor, epsilon=0, train=False) for _ in range(100)]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Show video. This may not work in some setups. If it doesn't\n", - "# work for you, you can download the videos and view them locally.\n", - "\n", - "from pathlib import Path\n", - "from IPython.display import HTML\n", - "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", - "\n", - "HTML(\"\"\"\n", - "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/week04_approx_rl/seminar_tf.ipynb b/week04_approx_rl/seminar_tf.ipynb index 70c51945a..4f69a60d4 100644 --- a/week04_approx_rl/seminar_tf.ipynb +++ b/week04_approx_rl/seminar_tf.ipynb @@ -27,7 +27,7 @@ " %tensorflow_version 1.x\n", " \n", " if not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", "\n", " !touch .setup_complete\n", "\n", @@ -99,6 +99,18 @@ "keras.backend.set_session(sess)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert not tf.test.is_gpu_available(), \\\n", + " \"Please complete this assignment without a GPU. If you use a GPU, the code \" \\\n", + " \"will run a lot slower due to a lot of copying to and from GPU memory. \" \\\n", + " \"To disable the GPU in Colab, go to Runtime → Change runtime type → None.\"" + ] + }, { "cell_type": "code", "execution_count": null, @@ -123,7 +135,7 @@ " recap: with p = epsilon pick random action, else pick action with highest Q(s,a)\n", " \"\"\"\n", " \n", - " q_values = network(state[None])[0]\n", + " q_values = network.predict(state[None])[0]\n", " \n", " \n", "\n", @@ -368,15 +380,25 @@ "# work for you, you can download the videos and view them locally.\n", "\n", "from pathlib import Path\n", + "from base64 import b64encode\n", "from IPython.display import HTML\n", "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", "\n", "HTML(\"\"\"\n", "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" + "\"\"\".format(data_url))" ] } ], diff --git a/week04_approx_rl/test_td_loss/compute_td_loss.py b/week04_approx_rl/test_td_loss/compute_td_loss.py new file mode 100644 index 000000000..6c418ba18 --- /dev/null +++ b/week04_approx_rl/test_td_loss/compute_td_loss.py @@ -0,0 +1,214 @@ +import torch +import torch.nn as nn +from typing import Protocol + + +class ComputeTdLossProtocol(Protocol): + """ + An Protocol which the compute_td_loss function should match. + """ + + def __call__( + self, + states: torch.Tensor, + actions: torch.Tensor, + rewards: torch.Tensor, + next_states: torch.Tensor, + is_done: torch.Tensor, + agent: nn.Module, + target_network: nn.Module, + gamma: float, + ): + pass + + +class MockAgent(nn.Module): + """ + An nn.Module, which outputs a value which does not depend on its input. + Designed to be used for testing the compute_td_loss function. + """ + + def __init__(self, output_q_values: torch.Tensor): + super().__init__() + assert output_q_values.dtype == torch.float, output_q_values.dtype + assert output_q_values.ndim == 2, output_q_values.shape + self.output_q_values = nn.Parameter(output_q_values) + + def forward(self, state): + return torch.clone(self.output_q_values) + + +@torch.no_grad() +def test_is_done_is_used(compute_td_loss: ComputeTdLossProtocol): + """ + Tries to catch the error when compute_td_loss ignores its is_done argument. + """ + + states = torch.empty(1) + actions = torch.tensor([0]) + rewards = torch.tensor([1], dtype=torch.float) + is_done_first = torch.tensor([True]) + is_done_second = torch.tensor([False]) + next_states = torch.empty(1) + gamma = 0.99 + + q_values_agent = torch.tensor([[1, 1, 1]], dtype=torch.float) + q_values_target_network = torch.tensor([[1, 1, 1]], dtype=torch.float) + agent = MockAgent(q_values_agent) + target_network = MockAgent(q_values_target_network) + + loss_kwargs = dict( + states=states, + actions=actions, + rewards=rewards, + next_states=next_states, + agent=agent, + target_network=target_network, + gamma=gamma, + ) + + loss_first = compute_td_loss(is_done=is_done_first, **loss_kwargs).item() + loss_second = compute_td_loss(is_done=is_done_second, **loss_kwargs).item() + + abs_diff = abs(loss_first - loss_second) + if abs_diff > 0.5: + msg = "compute_td_loss returned close values for different is_done inputs" + + assert abs(loss_first - loss_second) > 0.5, msg + + +@torch.no_grad() +def test_compute_td_loss_vanilla(compute_td_loss: ComputeTdLossProtocol): + """ + Checks compute_td_loss on manually precomputed examples. + Note: this is a test for vanilla compute_td_loss + and it should NOT be used for double_dqn + """ + + samples = [ + { + "q_agent": [0, 1, 2], + "action": 1, + "is_done": False, + "q_target": [0, 1, 2], + "gamma": 0.5, + "reward": 5, + "answer": 25, + }, + { + "q_agent": [0, 1, 2], + "action": 1, + "is_done": False, + "q_target": [2, 0, 1], + "gamma": 0.5, + "reward": 5, + "answer": 25, + }, + { + "q_agent": [3, 1, 2], + "action": 1, + "is_done": True, + "q_target": [0, 1, 2], + "gamma": 0.5, + "reward": 5, + "answer": 16, + }, + { + "q_agent": [0, 1, 2], + "action": 0, + "is_done": False, + "q_target": [0, 1, 2], + "gamma": 0.5, + "reward": 5, + "answer": 36, + }, + ] + + for sample in samples: + agent = MockAgent(torch.tensor(sample["q_agent"], dtype=torch.float)[None]) + tn = MockAgent(torch.tensor(sample["q_target"], dtype=torch.float)[None]) + ans = compute_td_loss( + states=torch.empty(1), + actions=torch.tensor(sample["action"])[None], + rewards=torch.tensor(sample["reward"])[None], + next_states=torch.empty(1), + is_done=torch.tensor(sample["is_done"])[None], + agent=agent, + target_network=tn, + gamma=sample["gamma"], + ).item() + abs_diff = abs(ans - sample["answer"]) + assert abs_diff < 1e-8, abs_diff + + +@torch.no_grad() +def test_compute_td_loss_double(compute_td_loss: ComputeTdLossProtocol): + """ + Checks compute_td_loss on manually precomputed examples. + Note: this is a test for vanilla compute_td_loss + and it should NOT be used for double_dqn + """ + + samples = [ + { + "q_agent": [0, 1, 2], + "action": 1, + "is_done": False, + "q_target": [0, 1, 2], + "gamma": 0.5, + "reward": 5, + "answer": 25, + }, + { + "q_agent": [0, 1, 2], + "action": 1, + "is_done": False, + "q_target": [2, 0, 1], + "gamma": 0.5, + "reward": 5, + "answer": 20.25, + }, + { + "q_agent": [3, 1, 2], + "action": 1, + "is_done": False, + "q_target": [-1, 1, 2], + "gamma": 0.5, + "reward": 5, + "answer": 12.25, + }, + { + "q_agent": [3, 1, 2], + "action": 1, + "is_done": True, + "q_target": [-1, 1, 2], + "gamma": 0.5, + "reward": 5, + "answer": 16, + }, + { + "q_agent": [0, 1, 2], + "action": 0, + "is_done": False, + "q_target": [0, 1, 2], + "gamma": 0.5, + "reward": 5, + "answer": 36, + }, + ] + + for sample in samples: + agent = MockAgent(torch.tensor(sample["q_agent"], dtype=torch.float)[None]) + tn = MockAgent(torch.tensor(sample["q_target"], dtype=torch.float)[None]) + ans = compute_td_loss( + states=torch.empty(1), + actions=torch.tensor(sample["action"])[None], + rewards=torch.tensor(sample["reward"])[None], + next_states=torch.empty(1), + is_done=torch.tensor(sample["is_done"])[None], + agent=agent, + target_network=tn, + gamma=sample["gamma"], + ).item() + abs_diff = abs(ans - sample["answer"]) + assert abs_diff < 1e-8, abs_diff diff --git a/week04_approx_rl/utils.py b/week04_approx_rl/utils.py deleted file mode 100644 index 0229b3007..000000000 --- a/week04_approx_rl/utils.py +++ /dev/null @@ -1,90 +0,0 @@ -import numpy as np -import psutil -from scipy.signal import convolve, gaussian -import torch -from torch import nn -import os - - -def get_cum_discounted_rewards(rewards, gamma): - """ - evaluates cumulative discounted rewards: - r_t + gamma * r_{t+1} + gamma^2 * r_{t_2} + ... - """ - cum_rewards = [] - cum_rewards.append(rewards[-1]) - for r in reversed(rewards[:-1]): - cum_rewards.insert(0, r + gamma * cum_rewards[0]) - return cum_rewards - - -def play_and_log_episode(env, agent, gamma=0.99, t_max=10000): - """ - always greedy - """ - states = [] - v_mc = [] - v_agent = [] - q_spreads = [] - td_errors = [] - rewards = [] - - s = env.reset() - for step in range(t_max): - states.append(s) - qvalues = agent.get_qvalues([s]) - max_q_value, min_q_value = np.max(qvalues), np.min(qvalues) - v_agent.append(max_q_value) - q_spreads.append(max_q_value - min_q_value) - if step > 0: - td_errors.append( - np.abs(rewards[-1] + gamma * v_agent[-1] - v_agent[-2])) - - action = qvalues.argmax(axis=-1)[0] - - s, r, done, _ = env.step(action) - rewards.append(r) - if done: - break - td_errors.append(np.abs(rewards[-1] + gamma * v_agent[-1] - v_agent[-2])) - - v_mc = get_cum_discounted_rewards(rewards, gamma) - - return_pack = { - 'states': np.array(states), - 'v_mc': np.array(v_mc), - 'v_agent': np.array(v_agent), - 'q_spreads': np.array(q_spreads), - 'td_errors': np.array(td_errors), - 'rewards': np.array(rewards), - 'episode_finished': np.array(done) - } - - return return_pack - - -def img_by_obs(obs, state_dim): - """ - Unwraps obs by channels. - observation is of shape [c, h=w, w=h] - """ - return obs.reshape([-1, state_dim[2]]) - - -def is_enough_ram(min_available_gb=0.1): - mem = psutil.virtual_memory() - return mem.available >= min_available_gb * (1024 ** 3) - - -def linear_decay(init_val, final_val, cur_step, total_steps): - if cur_step >= total_steps: - return final_val - return (init_val * (total_steps - cur_step) + - final_val * cur_step) / total_steps - - -def smoothen(values): - kernel = gaussian(100, std=100) - # kernel = np.concatenate([np.arange(100), np.arange(99, -1, -1)]) - kernel = kernel / np.sum(kernel) - return convolve(values, kernel, 'valid') diff --git a/week05_explore/README.md b/week05_explore/README.md index bb31b3f9d..5cbb50c25 100644 --- a/week05_explore/README.md +++ b/week05_explore/README.md @@ -1,4 +1,4 @@ -[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/spring20/week05_explore/week5.ipynb) +[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week05_explore/week5.ipynb) ### Slides - [here](https://yadi.sk/i/H0zVBROe3TWWHz) @@ -6,14 +6,14 @@ * [__main__] David Silver lecture on exploration and expoitation - [video](https://www.youtube.com/watch?v=sGuiWX07sKw) * Alternative lecture by J. Schulman - [video](https://www.youtube.com/watch?v=SfCa1HQMkuw) * Alternative lecture by N. de Freitas (with bayesian opt) - [video](https://www.youtube.com/watch?v=vz3D36VXefI) -* Our lectures (russian) +* Our lectures (russian) - "mathematical" lecture (by Alexander Vorobev) '17 - [slides](https://yadi.sk/i/JAeItALT3JmvCL), [video](https://yadi.sk/i/bVHmu9gt3Hi9Ym) - "practical" lecture '18 - [video](https://yadi.sk/i/_myWJ13O3TdzXo) - Seminar - [video](https://yadi.sk/i/du7FLXs13TdzZS) - - - -## More materials + + + +## More materials * Gittins Index - the less heuristical approach to bandit exploration - [article](http://www.ece.mcgill.ca/~amahaj1/projects/bandits/book/2013-bandit-computations.pdf) * "Deep" version: variational information maximizing exploration - [video](https://www.youtube.com/watch?v=sRIjxxjVrnY) * Same topics in russian - [video](https://yadi.sk/i/_2_0yqeW3HDbcn) @@ -22,17 +22,9 @@ * Same topics in russian - [video](https://www.youtube.com/watch?v=WCE9hhPbCmc) * Note: UCB-1 is not for bernoulli rewards, but for arbitrary r in [0,1], so you can just scale any reward to [0,1] to obtain a peace of mind. It's derived directly from Hoeffding's inequality. +* Very interesting blog post written by Lilian Weng that summarises this week's materials: [The Multi-Armed Bandit Problem and Its Solutions](https://lilianweng.github.io/posts/2018-01-23-multi-armed-bandit/) + ## Seminar -In this seminar, you'll be solvilg basic and contextual bandits with uncertainty-based exploration like Bayesian UCB and Thompson Sampling. - -You will also need Bayesian Neural Networks. You will need theano/lasagne for this one: -``` -# either -conda install Theano -# or -pip install --upgrade https://github.com/Theano/Theano/archive/master.zip -# and then lasagne -pip install --upgrade https://github.com/Lasagne/Lasagne/archive/master.zip -``` +In this seminar, you'll be solving basic and contextual bandits with uncertainty-based exploration like Bayesian UCB and Thompson Sampling. You will also get acquainted with Bayesian Neural Networks. Everything else is in the notebook :) diff --git a/week05_explore/action_rewards.npy b/week05_explore/action_rewards.npy deleted file mode 100644 index 231bcb18b..000000000 Binary files a/week05_explore/action_rewards.npy and /dev/null differ diff --git a/week05_explore/all_states.npy b/week05_explore/all_states.npy deleted file mode 100644 index 43940d9ba..000000000 Binary files a/week05_explore/all_states.npy and /dev/null differ diff --git a/week05_explore/bayes.py b/week05_explore/bayes.py deleted file mode 100644 index ffb9b9adc..000000000 --- a/week05_explore/bayes.py +++ /dev/null @@ -1,153 +0,0 @@ -""" -A single-file module that makes your lasagne network into a bayesian neural net. -Originally created by github.com/ferrine , rewritten by github.com/justheuristic for simplicity - -See example in the notebook -""" - -import numpy as np - -from theano import tensor as T -from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams - -import lasagne -from lasagne import init -from lasagne.random import get_rng - -from functools import wraps - -__all__ = ['NormalApproximation', 'get_var_cost', 'bbpwrap'] - - -class NormalApproximation(object): - def __init__(self, mu=0, std=np.exp(-3), seed=None): - """ - Approximation that samples network weights from factorized normal distribution. - - :param mu: prior mean for gaussian weights - :param std: prior std for gaussian weights - :param seed: random seed - """ - self.prior_mu = mu - self.prior_std = std - self.srng = RandomStreams(seed or get_rng().randint(1, 2147462579)) - - def log_normal(self, x, mean, std, eps=0.0): - """computes log-proba of normal distribution""" - std += eps - return - 0.5 * np.log(2 * np.pi) - T.log(T.abs_(std)) - \ - (x - mean) ** 2 / (2 * std ** 2) - - def log_prior(self, weights): - """ - Logarithm of prior probabilities for weights: - log P(weights) aka log P(theta) - """ - return self.log_normal(weights, self.prior_mu, self.prior_std) - - def log_posterior_approx(self, weights, mean, rho): - """ - Logarithm of ELBO on posterior probabilities: - log q(weights|learned mu and rho) aka log q(theta|x) - """ - std = T.log1p(T.exp(rho)) # rho to std - return self.log_normal(weights, mean, std) - - def __call__(self, layer, spec, shape, name=None, **tags): - # case when user uses default init specs - assert tags.get( - 'variational', False), "Please declare param as variational to avoid confusion" - - if not isinstance(spec, dict): - initial_rho = np.log(np.expm1(self.prior_std)) # std to rho - assert np.isfinite(initial_rho), "too small std to initialize correctly. Please pass explicit"\ - " initializer (dict with {'mu':mu_init, 'rho':rho_init})." - spec = {'mu': spec, 'rho': init.Constant(initial_rho)} - - mu_spec, rho_spec = spec['mu'], spec['rho'] - - rho = layer.add_param( - rho_spec, shape, name=( - name or 'unk') + '.rho', **tags) - mean = layer.add_param( - mu_spec, shape, name=( - name or 'unk') + '.mu', **tags) - - # Reparameterization trick - e = self.srng.normal(shape, std=1) - W = mean + T.log1p(T.exp(rho)) * e - - # KL divergence KL(q,p) = E_(w~q(w|x)) [log q(w|x) - log P(w)] aka - # variational cost - q_p = T.sum( - self.log_posterior_approx(W, mean, rho) - - self.log_prior(W) - ) - - # accumulate variational cost - layer._bbwrap_var_cost += q_p - return W - - -def get_var_cost(layer_or_layers, treat_as_input=None): - """ - Returns total variational cost aka KL(q(theta|x)||p(theta)) for all layers in the network - - :param layer_or_layers: top layer(s) of your network, just like with lasagne.layers.get_output - :param treat_as_input: don't accumulate over layers below these layers. See same param for lasagne.layers.get_all_layers - - Alternatively, one can manually get weights for one layer via layer.get_var_cost() - """ - cost = 0 - for layer in lasagne.layers.get_all_layers( - layer_or_layers, treat_as_input): - if hasattr(layer, 'get_var_cost'): - # if layer is bayesian or pretends so - cost += layer.get_var_cost() - return cost - - -def bbpwrap(approximation=NormalApproximation()): - """ - A decorator that makes arbitrary lasagne layer into a bayesian network layer: - BayesDenseLayer = bbwrap()(DenseLayer) - or more verbosely, - @bbpwrap(NormalApproximation(pstd=0.01)) - BayesDenseLayer(DenseLayer): - pass - - """ - - def decorator(cls): - def add_param_wrap(add_param): - @wraps(add_param) - def wrapped(self, spec, shape, name=None, **tags): - # we should take care about some user specification - # to avoid bbp hook just set tags['variational'] = True - if not tags.get('trainable', True) or \ - tags.get('variational', False): - return add_param(self, spec, shape, name, **tags) - else: - # we declare that params we add next - # are the ones we need to fit the distribution - # they don't need to be regularized, strictly - tags['variational'] = True - tags['regularizable'] = False - param = self.approximation(self, spec, shape, name, **tags) - return param - return wrapped - - def get_var_cost(self): - """ - Returns total variational cost aka KL(q(theta|x)||p(theta)) for this layer. - Alternatively, use function get_var_cost(layer) to get total cost for all layers below this one. - """ - return self._bbwrap_var_cost - - cls.approximation = approximation - cls._bbwrap_var_cost = 0 - cls.add_param = add_param_wrap(cls.add_param) - cls.get_var_cost = get_var_cost - return cls - - return decorator diff --git a/week05_explore/bnn.png b/week05_explore/bnn.png deleted file mode 100644 index 6ff8059fb..000000000 Binary files a/week05_explore/bnn.png and /dev/null differ diff --git a/week05_explore/deep_see.png b/week05_explore/deep_see.png new file mode 100644 index 000000000..a1601b725 Binary files /dev/null and b/week05_explore/deep_see.png differ diff --git a/week05_explore/q_learning_agent.py b/week05_explore/q_learning_agent.py new file mode 100644 index 000000000..f7f52fca7 --- /dev/null +++ b/week05_explore/q_learning_agent.py @@ -0,0 +1,112 @@ +from collections import defaultdict +import random +import math +import numpy as np + + +class QLearningAgent: + def __init__(self, alpha, epsilon, discount, get_legal_actions): + """ + Q-Learning Agent + based on https://inst.eecs.berkeley.edu/~cs188/sp19/projects.html + Instance variables you have access to + - self.epsilon (exploration prob) + - self.alpha (learning rate) + - self.discount (discount rate aka gamma) + + Functions you should use + - self.get_legal_actions(state) {state, hashable -> list of actions, each is hashable} + which returns legal actions for a state + - self.get_qvalue(state,action) + which returns Q(state,action) + - self.set_qvalue(state,action,value) + which sets Q(state,action) := value + !!!Important!!! + Note: please avoid using self._qValues directly. + There's a special self.get_qvalue/set_qvalue for that. + """ + + self.get_legal_actions = get_legal_actions + self._qvalues = defaultdict(lambda: defaultdict(lambda: 0)) + self.alpha = alpha + self.epsilon = epsilon + self.discount = discount + + def get_qvalue(self, state, action): + """ Returns Q(state,action) """ + return self._qvalues[state][action] + + def set_qvalue(self, state, action, value): + """ Sets the Qvalue for [state,action] to the given value """ + self._qvalues[state][action] = value + + def get_value(self, state): + """ + Compute your agent's estimate of V(s) using current q-values + V(s) = max_over_action Q(state,action) over possible actions. + Note: please take into account that q-values can be negative. + """ + possible_actions = self.get_legal_actions(state) + + # If there are no legal actions, return 0.0 + if len(possible_actions) == 0: + return 0.0 + + value = max([self.get_qvalue(state, a) for a in possible_actions]) + return value + + def update(self, state, action, reward, next_state, done): + """ + You should do your Q-Value update here: + Q(s,a) := (1 - alpha) * Q(s,a) + alpha * (r + gamma * V(s')) + """ + + # agent parameters + gamma = self.discount + learning_rate = self.alpha + + q = reward + gamma * (1 - done) * self.get_value(next_state) + q = (1 - learning_rate) * self.get_qvalue(state, action) + learning_rate * q + + self.set_qvalue(state, action, q) + + def get_best_action(self, state): + """ + Compute the best action to take in a state (using current q-values). + """ + possible_actions = self.get_legal_actions(state) + + # If there are no legal actions, return None + if len(possible_actions) == 0: + return None + + idx = np.argmax([self.get_qvalue(state, a) for a in possible_actions]) + + return possible_actions[idx] + + def get_action(self, state): + """ + Compute the action to take in the current state, including exploration. + With probability self.epsilon, we should take a random action. + otherwise - the best policy action (self.get_best_action). + + Note: To pick randomly from a list, use random.choice(list). + To pick True or False with a given probablity, generate uniform number in [0, 1] + and compare it with your probability + """ + + # Pick Action + possible_actions = self.get_legal_actions(state) + action = None + + # If there are no legal actions, return None + if len(possible_actions) == 0: + return None + + # agent parameters: + epsilon = self.epsilon + + if np.random.rand() < epsilon: + return np.random.choice(possible_actions) + + return self.get_best_action(state) \ No newline at end of file diff --git a/week04_approx_rl/replay_buffer.py b/week05_explore/replay_buffer.py similarity index 99% rename from week04_approx_rl/replay_buffer.py rename to week05_explore/replay_buffer.py index 915a107b9..9136dd078 100644 --- a/week04_approx_rl/replay_buffer.py +++ b/week05_explore/replay_buffer.py @@ -72,3 +72,4 @@ def sample(self, batch_size): for _ in range(batch_size) ] return self._encode_sample(idxes) + diff --git a/week05_explore/river_swim.png b/week05_explore/river_swim.png deleted file mode 100644 index 233244c6c..000000000 Binary files a/week05_explore/river_swim.png and /dev/null differ diff --git a/week05_explore/und1.mp4 b/week05_explore/und1.mp4 new file mode 100644 index 000000000..d67190f54 Binary files /dev/null and b/week05_explore/und1.mp4 differ diff --git a/week05_explore/und2.mp4 b/week05_explore/und2.mp4 new file mode 100644 index 000000000..1e41469fe Binary files /dev/null and b/week05_explore/und2.mp4 differ diff --git a/week05_explore/week5.ipynb b/week05_explore/week5.ipynb index 8d9a270bc..b4c5f3538 100644 --- a/week05_explore/week5.ipynb +++ b/week05_explore/week5.ipynb @@ -2,21 +2,62 @@ "cells": [ { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 98, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Defaulting to user installation because normal site-packages is not writeable\n", + "Looking in indexes: https://pypi.yandex-team.ru/simple/\n", + "Requirement already satisfied: bsuite in /home/npytincev/.local/lib/python3.8/site-packages (0.3.5)\n", + "Requirement already satisfied: plotnine in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (0.8.0)\n", + "Requirement already satisfied: matplotlib in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (3.5.1)\n", + "Requirement already satisfied: pandas in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (1.4.2)\n", + "Requirement already satisfied: termcolor in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (1.1.0)\n", + "Requirement already satisfied: absl-py in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (0.12.0)\n", + "Requirement already satisfied: scikit-image in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (0.19.2)\n", + "Requirement already satisfied: numpy in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (1.22.3)\n", + "Requirement already satisfied: six in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (1.15.0)\n", + "Requirement already satisfied: immutabledict in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (2.2.1)\n", + "Requirement already satisfied: dm-env in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (1.5)\n", + "Requirement already satisfied: scipy in /home/npytincev/.local/lib/python3.8/site-packages (from bsuite) (1.6.0)\n", + "Requirement already satisfied: dm-tree in /home/npytincev/.local/lib/python3.8/site-packages (from dm-env->bsuite) (0.1.6)\n", + "Requirement already satisfied: packaging>=20.0 in /home/npytincev/.local/lib/python3.8/site-packages (from matplotlib->bsuite) (20.9)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /home/npytincev/.local/lib/python3.8/site-packages (from matplotlib->bsuite) (2.8.2)\n", + "Requirement already satisfied: pyparsing>=2.2.1 in /home/npytincev/.local/lib/python3.8/site-packages (from matplotlib->bsuite) (2.4.7)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /home/npytincev/.local/lib/python3.8/site-packages (from matplotlib->bsuite) (4.31.2)\n", + "Requirement already satisfied: pillow>=6.2.0 in /home/npytincev/.local/lib/python3.8/site-packages (from matplotlib->bsuite) (8.4.0)\n", + "Requirement already satisfied: cycler>=0.10 in /home/npytincev/.local/lib/python3.8/site-packages (from matplotlib->bsuite) (0.10.0)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /home/npytincev/.local/lib/python3.8/site-packages (from matplotlib->bsuite) (1.3.1)\n", + "Requirement already satisfied: pytz>=2020.1 in /home/npytincev/.local/lib/python3.8/site-packages (from pandas->bsuite) (2022.1)\n", + "Requirement already satisfied: descartes>=1.1.0 in /home/npytincev/.local/lib/python3.8/site-packages (from plotnine->bsuite) (1.1.0)\n", + "Requirement already satisfied: patsy>=0.5.1 in /home/npytincev/.local/lib/python3.8/site-packages (from plotnine->bsuite) (0.5.1)\n", + "Requirement already satisfied: mizani>=0.7.3 in /home/npytincev/.local/lib/python3.8/site-packages (from plotnine->bsuite) (0.7.4)\n", + "Requirement already satisfied: statsmodels>=0.12.1 in /home/npytincev/.local/lib/python3.8/site-packages (from plotnine->bsuite) (0.12.2)\n", + "Requirement already satisfied: tifffile>=2019.7.26 in /home/npytincev/.local/lib/python3.8/site-packages (from scikit-image->bsuite) (2022.3.25)\n", + "Requirement already satisfied: PyWavelets>=1.1.1 in /home/npytincev/.local/lib/python3.8/site-packages (from scikit-image->bsuite) (1.3.0)\n", + "Requirement already satisfied: networkx>=2.2 in /home/npytincev/.local/lib/python3.8/site-packages (from scikit-image->bsuite) (2.5.1)\n", + "Requirement already satisfied: imageio>=2.4.1 in /home/npytincev/.local/lib/python3.8/site-packages (from scikit-image->bsuite) (2.16.1)\n", + "Requirement already satisfied: palettable in /home/npytincev/.local/lib/python3.8/site-packages (from mizani>=0.7.3->plotnine->bsuite) (3.3.0)\n", + "Requirement already satisfied: decorator<5,>=4.3 in /usr/lib/python3/dist-packages (from networkx>=2.2->scikit-image->bsuite) (4.4.2)\n" + ] + } + ], "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - "\n", - " !pip install --upgrade https://github.com/Theano/Theano/archive/master.zip\n", - " !pip install --upgrade https://github.com/Lasagne/Lasagne/archive/master.zip\n", - "\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week05_explore/bayes.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week05_explore/action_rewards.npy\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week05_explore/all_states.npy\n", - "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week05_explore/q_learning_agent.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week05_explore/replay_buffer.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week05_explore/und1.mp4\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week05_explore/und2.mp4\n", + "\n", + " !pip install -q gymnasium\n", + " !pip install -q shimmy[bsuite]\n", " !touch .setup_complete\n", "\n", "# This code creates a virtual display to draw game images on.\n", @@ -28,7 +69,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 99, "metadata": {}, "outputs": [], "source": [ @@ -39,12 +80,75 @@ "np.set_printoptions(precision=3)\n", "np.set_printoptions(suppress=True)\n", "\n", - "import pandas\n", + "import pandas as pd\n", "\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import HTML\n", + "\n", + "HTML(\"\"\"\n", + " \n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "HTML(\"\"\"\n", + " \n", + "\"\"\")" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -52,14 +156,12 @@ "## Contents\n", "* [1. Bernoulli Bandit](#Part-1.-Bernoulli-Bandit)\n", " * [Bonus 1.1. Gittins index (5 points)](#Bonus-1.1.-Gittins-index-%285-points%29.)\n", - " * [HW 1.1. Nonstationary Bernoulli bandit](#HW-1.1.-Nonstationary-Bernoulli-bandit)\n", - "* [2. Contextual bandit](#Part-2.-Contextual-bandit)\n", - " * [2.1 Bulding a BNN agent](#2.1-Bulding-a-BNN-agent)\n", - " * [2.2 Training the agent](#2.2-Training-the-agent)\n", - " * [HW 2.1 Better exploration](#HW-2.1-Better-exploration)\n", - "* [3. Exploration in MDP](#Part-3.-Exploration-in-MDP)\n", - " * [Bonus 3.1 Posterior sampling RL (3 points)](#Bonus-3.1-Posterior-sampling-RL-%283-points%29)\n", - " * [Bonus 3.2 Bootstrapped DQN (10 points)](#Bonus-3.2-Bootstrapped-DQN-%2810-points%29)\n" + " * [HW 1.1. Nonstationary Bernoulli bandit (2 points)](#HW-1.1.-Nonstationary-Bernoulli-bandit)\n", + "* [2. Exploration in MDP](#Part-2.-Exploration-in-MDP)\n", + " * [2.1 Epsilon-greedy q-learning](#2.1-Epsilon-greedy-q-learning)\n", + " * [2.2 Reward shaping](#2.2-Reward-shaping)\n", + " * [2.3 Curiosity-driven Exploration](#2.3-Curiosity-driven-Exploration)\n", + " * [HW 2.1 Random network distillation (3 points)](#HW-2.1:-Random-network-distillation)\n" ] }, { @@ -72,9 +174,9 @@ "\n", "The bandit has $K$ actions. Action produce 1.0 reward $r$ with probability $0 \\le \\theta_k \\le 1$ which is unknown to agent, but fixed over time. Agent's objective is to minimize regret over fixed number $T$ of action selections:\n", "\n", - "$$\\rho = T\\theta^* - \\sum_{t=1}^T r_t$$\n", + "$$\\rho = T\\theta^* - \\sum_{t=1}^T \\theta_{a_t}$$\n", "\n", - "Where $\\theta^* = \\max_k\\{\\theta_k\\}$\n", + "Where $\\theta^* = \\max_k\\{\\theta_k\\}$ and $\\theta_{a_t}$ corresponds to the chosen action $a_t$ on each step.\n", "\n", "**Real-world analogy:**\n", "\n", @@ -85,7 +187,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 100, "metadata": {}, "outputs": [], "source": [ @@ -107,6 +209,11 @@ " \"\"\"\n", " return np.max(self._probs)\n", "\n", + " def action_value(self, action):\n", + " \"\"\" Used for regret calculation\n", + " \"\"\"\n", + " return self._probs[action]\n", + "\n", " def step(self):\n", " \"\"\" Used in nonstationary version\n", " \"\"\"\n", @@ -119,7 +226,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 101, "metadata": {}, "outputs": [], "source": [ @@ -186,7 +293,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 102, "metadata": {}, "outputs": [], "source": [ @@ -195,7 +302,10 @@ " self._epsilon = epsilon\n", "\n", " def get_action(self):\n", - " \n", + " if np.random.random() < self._epsilon:\n", + " return np.random.randint(len(self._successes))\n", + " else:\n", + " return np.argmax(self._successes / (self._successes + self._failures + 0.1))\n", "\n", " @property\n", " def name(self):\n", @@ -207,13 +317,13 @@ "metadata": {}, "source": [ "### UCB Agent\n", - "Epsilon-greedy strategy heve no preference for actions. It would be better to select among actions that are uncertain or have potential to be optimal. One can come up with idea of index for each action that represents otimality and uncertainty at the same time. One efficient way to do it is to use UCB1 algorithm:\n", + "Epsilon-greedy strategy have no preference for actions. It would be better to select among actions that are uncertain or have potential to be optimal. One can come up with idea of index for each action that represents optimality and uncertainty at the same time. One efficient way to do it is to use UCB1 algorithm:\n", "\n", "**for** $t = 1,2,...$ **do**\n", "\n", "   **for** $k = 1,...,K$ **do**\n", "\n", - "       $w_k \\leftarrow \\alpha_k / (\\alpha_k + \\beta_k) + \\sqrt{2log\\ t \\ / \\ (\\alpha_k + \\beta_k)}$\n", + "       $w_k \\leftarrow \\alpha_k / (\\alpha_k + \\beta_k) + \\sqrt{2\\log(t) \\ / \\ (\\alpha_k + \\beta_k)}$\n", "\n", "   **end for** \n", "\n", @@ -226,20 +336,21 @@ "\n", "**end for**\n", "\n", - "__Note:__ in practice, one can multiply $\\sqrt{2log\\ t \\ / \\ (\\alpha_k + \\beta_k)}$ by some tunable parameter to regulate agent's optimism and wilingness to abandon non-promising actions.\n", + "__Note:__ in practice, one can multiply $\\sqrt{2\\log(t) \\ / \\ (\\alpha_k + \\beta_k)}$ by some tunable parameter to regulate agent's optimism and wilingness to abandon non-promising actions.\n", "\n", "More versions and optimality analysis - https://homes.di.unimi.it/~cesabian/Pubblicazioni/ml-02.pdf" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 116, "metadata": {}, "outputs": [], "source": [ "class UCBAgent(AbstractAgent):\n", " def get_action(self):\n", - " " + " pulls = self._successes + self._failures + 0.1\n", + " return np.argmax(self._successes / pulls + np.sqrt(2 * np.log(self._total_pulls + 0.1) / pulls))" ] }, { @@ -273,18 +384,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 117, "metadata": {}, "outputs": [], "source": [ "class ThompsonSamplingAgent(AbstractAgent):\n", " def get_action(self):\n", - " \n" + " return np.argmax(np.random.beta(self._successes + 1, self._failures + 1))" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 118, "metadata": {}, "outputs": [], "source": [ @@ -308,7 +419,7 @@ " action = agent.get_action()\n", " reward = env.pull(action)\n", " agent.update(action, reward)\n", - " scores[agent.name][i] += optimal_reward - reward\n", + " scores[agent.name][i] += optimal_reward - env.action_value(action)\n", "\n", " env.step() # change bandit's state if it is unstationary\n", "\n", @@ -331,26 +442,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 120, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":4: RuntimeWarning: invalid value encountered in sqrt\n", + " return np.argmax(self._successes / pulls + np.sqrt(2 * np.log(self._total_pulls + 0.1) / pulls))\n" + ] + }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA+4AAAHjCAYAAAC95UVJAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvAOZPmwAAIABJREFUeJzs3Xd0VVXexvHvSe+FNEoIJHREWgLSRTojCowoIirYKGLDCo7DgMqIwviiOOjgoKJiAJGiOBQZDIrUhE4oIRAgIQmQ3ts97x+BqxlCJySE57MWy3vP2Wef373JdeW5e599DNM0EREREREREZGqyaayCxARERERERGRC1NwFxEREREREanCFNxFREREREREqjAFdxEREREREZEqTMFdREREREREpApTcBcRERERERGpwhTcRURERERERKowBXcRERERERGRKkzBXURERERERKQKs6vsAq6Fr6+vWb9+/couQ0REREREROSKRUVFnTFN0+9S7W7q4F6/fn0iIyMruwwRERERERGRK2YYxrHLaaep8iIiIiIiIiJVmIK7iIiIiIiISBWm4C4iIiIiIiJShd3U17iXp6ioiPj4ePLz8yu7FJGbmpOTE4GBgdjb21d2KSIiIiIit7RqF9zj4+Nxd3enfv36GIZR2eWI3JRM0yQlJYX4+HiCg4MruxwRERERkVtatZsqn5+fj4+Pj0K7yDUwDAMfHx/NXBERERERqQKqXXAHFNpFrgN9jkREREREqoZqGdxFREREREREqgsF9wpga2tL69atrf+mTZt2xX1ERkby3HPPAfDFF1/wzDPPXHU9MTExDBgwgAYNGhAaGspdd93FL7/8ctX9XczkyZOZMWPGJdudOXMGe3t7PvnkkwqpIz09ndmzZ5fZlpiYyIABA67reSZNmsTatWsB6N69O5GRkde1/z+aN28ejRo1olGjRsybN6/cNqmpqfTu3ZtGjRrRu3dv0tLSADhw4AAdO3bE0dGxzM+nsLCQbt26UVxcXGF1i4iIiIjItVFwrwDOzs7s3LnT+m/ChAlX3EdYWBgffvjhNdeSn5/P3XffzahRo4iNjSUqKopZs2Zx5MiR89reyPD27bff0qFDB8LDwyuk//KC+/vvv89TTz11Xc/z5ptv0qtXr+vaZ3lSU1OZMmUKW7ZsYevWrUyZMsUayv9o2rRp9OzZk5iYGHr27Gn90qhGjRp8+OGHvPzyy2XaOzg40LNnTxYuXFjhr0FERERERK5OtVtV/o+m/LCP6JOZ17XP5rU9+Ns9t13VsfXr1+eBBx5g5cqVODs7880339CwYUO+/fZbpkyZgq2tLZ6envzyyy9EREQwY8YMVqxYUaaPuLg4Hn/8cc6cOYOfnx+ff/45QUFBjBw5Eg8PDyIjI0lKSuK9995jyJAhzJ8/n44dO3Lvvfda+2jRogUtWrQASkfIY2NjOXLkCEFBQXz99ddMmDCBiIgICgoKGDduHKNHjwZg+vTpLFq0iIKCAgYPHsyUKVMAmDp1KvPmzcPf35+6desSGhpKbGws999/P9u3bwdKR/2HDh1qfR4eHs4//vEPHnroIeLj4wkMDARg7ty5vPvuu3h5edGqVSscHR356KOPOH36NGPGjOH48eMAzJw5k86dOzN58mSOHz/OkSNHOH78OC+88ALPPfccEyZMIDY2ltatW9O7d2+mT5/Od999x9tvvw1ASUlJua8zIiKCSZMm4e7uzuHDh7nrrruYPXs2pmnyxBNPEBkZiWEYPP7444wfP56RI0cyYMAAhgwZUubnFB4ezt///ndM0+Tuu+/m3XffBcDNzY3nn3+eFStW4OzszPLlywkICLjk787q1avp3bs3NWrUAKB3796sWrWKYcOGlWm3fPlyIiIiABgxYgTdu3fn3Xffxd/fH39/f3788cfz+h40aBATJ05k+PDhl6xDRERERERuvGod3CtLXl4erVu3tj6fOHEiQ4cOBcDT05M9e/bw5Zdf8sILL7BixQrefPNNVq9eTZ06dUhPT79o388++ywjRoxgxIgRfPbZZzz33HMsW7YMKJ0KvmHDBg4cOMC9997LkCFD2LdvH23btr1on9HR0WzYsAFnZ2fmzJmDp6cn27Zto6CggM6dO9OnTx9iYmKIiYlh69atmKbJvffeyy+//IKrqysLFixg586dFBcX07ZtW0JDQ2nQoAGenp7s3LmT1q1b8/nnn/PYY48BcOLECRITE2nfvj0PPPAACxcu5KWXXuLkyZO89dZbbN++HXd3d3r06EGrVq0AeP755xk/fjxdunTh+PHj9O3bl/379wOl08B//vlnsrKyaNKkCWPHjmXatGns3buXnTt3AnD06FG8vb1xdHQESr8gKO91AmzdupXo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IiIiIiIiInWM3wTuQE8gzVqbYa0tA/4FXFXLeaoWm/KWAjAk5Xe1nBMRERERERGpa/wpcE8EdlV4v9u7rRJjzK3GmBXGmBXZ2dk1lrkzYWJa084dQ/OY1rWdFREREREREalj6tzidNbaN4E3Abp3725rOTun5KH/N6W2syAiIiIiIiJ1lD/1uO8Bkiu8T/JuExEREREREam3/Clw/wloZ4xpZYwJAa4HPq3lPImIiIiIiIjUKr8ZKm+tLTfG3AXMAwKBd6y1G2s5WyIiIiIiIiK1ym8CdwBr7Vxgbm3nQ0RERERERMRf+NNQeRERERERERE5igJ3ERERERERET+mwF1ERERERETEjylwFxEREREREfFjCtxFRERERERE/JgCdxERERERERE/psBdRERERERExI8pcBcRERERERHxYwrcRURERERERPyYAncRERERERERP6bAXURERERERMSPKXAXERERERER8WMK3EVERERERET8mAJ3ERERERERET9mrLW1nYfTZozJBjJrOx+nKA44WNuZEPkVVGalLlF5lbpGZVbqEpVXqWvqUpltYa1tfLJEdTpwr0uMMSustd1rOx8ip0plVuoSlVepa1RmpS5ReZW65lwssxoqLyIiIiIiIuLHFLiLiIiIiIiI+DEF7jXnzdrOgMivpDIrdYnKq9Q1KrNSl6i8Sl1zzpVZzXEXERERERER8WPqcRcRERERERHxYwrcRURERERERPyYAvcaYIy5whizxRiTZoy5v7bzI/WTMSbZGLPIGPOzMWajMeaP3u0xxpj5xpht3p+NvNuNMeYVb7ldZ4zpWuFcY73ptxljxtbWNcm5zxgTaIxZbYyZ433fyhizzFsuPzTGhHi3h3rfp3n3t6xwjge827cYY4bWzpVIfWCMaWiM+dgYs9kYs8kYk6o6VvyVMWai935ggzFmhjEmTHWs+BNjzDvGmCxjzIYK26qtTjXGdDPGrPce84oxxtTsFf46CtzPMmNMIDAVGAZ0BEYbYzrWbq6knioH/tda2xHoDdzpLYv3Awutte2Ahd734Cmz7bz/bgXeAE+FCTwK9AJ6Ao8eqTRFzoI/ApsqvH8OeMla2xbIA272br8ZyPNuf8mbDm8Zvx7oBFwBvO6tl0XOhr8CX1prOwApeMqu6ljxO8aYROBuoLu1tjMQiKeuVB0r/uRdPOWqouqsU98Abqlw3NG/y68ocD/7egJp1toMa20Z8C/gqlrOk9RD1tp91tpV3tdFeG4oE/GUx394k/0DGOV9fRXwnvX4EWhojGkGDAXmW2tzrbV5wHz8vKKTuskYkwSMAN72vjfAQOBjb5Kjy+uRcvwxMMib/irgX9Zah7V2O5CGp14WqVbGmAZAP2AagLW2zFqbj+pY8V9BQLgxJgiIAPahOlb8iLX2OyD3qM3VUqd6951nrf3RelZrf6/CufySAvezLxHYVeH9bu82kVrjHeLWBVgGNLHW7vPu2g808b4+XtlVmZaa8jJwL+D2vo8F8q215d73Fcuer1x69xd406u8Sk1pBWQD073TO942xkSiOlb8kLV2D/ACsBNPwF4ArER1rPi/6qpTE72vj97utxS4i9Qzxpgo4N/ABGttYcV93hZHPSNSap0xZiSQZa1dWdt5ETlFQUBX4A1rbRfgML8M4QRUx4r/8A4VvgpPg1MCEIlGdkgdU9/qVAXuZ98eILnC+yTvNpEaZ4wJxhO0/9NaO8u7+YB3uBDen1ne7ccruyrTUhP6AFcaY3bgmWI0EM/84YbeYZ1Quez5yqV3fwMgB5VXqTm7gd3W2mXe9x/jCeRVx4o/Ggxst9ZmW2udwCw89a7qWPF31VWn7vG+Pnq731Lgfvb9BLTzrtIZgmcBj09rOU9SD3nnok0DNllrX6yw61PgyAqbY4HZFbbf6F2lszdQ4B2aNA+43BjTyNtif7l3m0i1sdY+YK1Nsta2xFNvfm2tHQMsAq7xJju6vB4px9d401vv9uu9KyK3wrP4zPIaugypR6y1+4Fdxpj23k2DgJ9RHSv+aSfQ2xgT4b0/OFJeVceKv6uWOtW7r9AY09v7Gbixwrn8UtDJk8iZsNaWG2PuwlNoAoF3rLUbazlbUj/1AW4A1htj1ni3PQg8C8w0xtwMZALXeffNBYbjWWimGBgHYK3NNcY8gadRCuBxa+3RC4eInC33Af8yxjwJrMa7EJj35/vGmDQ8C9lcD2Ct3WiMmYnnhrQcuNNa66r5bEs98Qfgn96G+gw89WYAqmPFz1hrlxljPgZW4akbVwNvAp+jOlb8hDFmBnAZEGeM2Y1ndfjqvG+9A8/K9eHAF95/fst4GstERERERERExB9pqLyIiIiIiIiIH1PgLiIiIiIiIuLHFLiLiIiIiIiI+DEF7iIiIiIiIiJ+TIG7iIiIiIiIiB9T4C4iIlKPGWMmGGMiajsfIiIicnx6HJyIiEg9ZozZAXS31h6s7byIiIhI1dTjLiIiUk8YYyKNMZ8bY9YaYzYYYx4FEoBFxphF3jSXG2OWGmNWGWM+MsZEebfvMMY8b4xZb4xZboxp691+rfdca40x39Xe1YmIiJy7FLiLiIjUH1cAe621KdbazsDLwF5ggLV2gDEmDngIGGyt7QqsAO6pcHyBtfZC4DXvsQCPAEOttSnAlTV1ISIiIvWJAncREZH6Yz0wxBjznDGmr7W24Kj9vYGOwBJjzBpgLNCiwv4ZFX6mel8vAd41xtwCBJ69rIuIiNRfQbWdAREREakZ1tqtxpiuwHDgSWPMwqOSGGC+tXb08U5x9Gtr7W3GmF7ACGClMaabtTanuvMuIiJSn6nHXUREpJ4wxiQAxdbaD4C/AF2BIiDam+RHoE+F+euRxpjzK5zitxV+LvWmaWOtXWatfQTIBpLP/pWIiIjUL+pxFxERqT8uBP5ijHEDTuB2PEPevzTG7PXOc/9vYIYxJtR7zEPAVu/rRsaYdYADONIr/xdjTDs8vfULgbU1cykiIiL1hx4HJyIiIielx8aJiIjUHg2VFxEREREREfFj6nEXERERERER8WPqcRcRERERERHxYwrcRURERERERPyYAncRERERERERP6bAXURERERERMSPKXAXERERERER8WP/H26slP2kNJxQAAAAAElFTkSuQmCC\n", + "image/png": "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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ "# Uncomment agents\n", "agents = [\n", - " # EpsilonGreedyAgent(),\n", - " # UCBAgent(),\n", - " # ThompsonSamplingAgent()\n", + " EpsilonGreedyAgent(),\n", + " UCBAgent(),\n", + " ThompsonSamplingAgent()\n", "]\n", "\n", "regret = get_regret(BernoulliBandit(), agents, n_steps=10000, n_trials=10)\n", @@ -363,7 +484,7 @@ "source": [ "# Bonus 1.1. Gittins index (5 points).\n", "\n", - "Bernoulli bandit problem has an optimal solution - Gittins index algorithm. Implement finite horizon version of the algorithm and demonstrate it's performance with experiments. some articles:\n", + "Bernoulli bandit problem has an optimal solution - Gittins index algorithm. Implement finite horizon version of the algorithm and demonstrate it's performance with experiments. Some articles:\n", "- Wikipedia article - https://en.wikipedia.org/wiki/Gittins_index\n", "- Different algorithms for index computation - http://www.ece.mcgill.ca/~amahaj1/projects/bandits/book/2013-bandit-computations.pdf (see \"Bernoulli\" section)\n", " " @@ -380,7 +501,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 300, "metadata": {}, "outputs": [], "source": [ @@ -429,17 +550,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 301, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -452,7 +575,7 @@ " drifting_probs.append(drifting_env._probs)\n", "\n", "plt.figure(figsize=(17, 8))\n", - "plt.plot(pandas.DataFrame(drifting_probs).rolling(window=20).mean())\n", + "plt.plot(pd.DataFrame(drifting_probs).rolling(window=20).mean())\n", "\n", "plt.xlabel(\"steps\")\n", "plt.ylabel(\"Success probability\")\n", @@ -470,7 +593,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 302, "metadata": {}, "outputs": [], "source": [ @@ -479,17 +602,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 303, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":5: RuntimeWarning: invalid value encountered in sqrt\n", + " np.sqrt(2 * np.log(self._total_pulls + 0.1) / (self._successes + self._failures + 0.1)))\n" + ] + }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYsAAAEGCAYAAACUzrmNAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAABUYElEQVR4nO3dd1hUV/rA8e+hIwqIoiKoFEWRIgrYu7H32DVGU3RjiimbbJJN3bRNYnqyiTE/U0zs3dhLNPYCigUsdAERBQRBOnN+f9yBoBFBZRjK+TwPD8Plzr3vzDDzck95j5BSoiiKoih3YmLsABRFUZTqTyULRVEUpVwqWSiKoijlUslCURRFKZdKFoqiKEq5zIwdgCE0btxYurq6GjsMRVGUGiUkJCRFSul4u9/VymTh6upKcHCwscNQFEWpUYQQcWX9TjVDKYqiKOVSyUJRFEUpl0oWiqIoSrlqZZ/F7RQUFJCQkEBubq6xQ1GUGs3KygoXFxfMzc2NHYpShepMskhISKBBgwa4uroihDB2OIpSI0kpSU1NJSEhATc3N2OHo1ShOtMMlZubS6NGjVSiUJT7IISgUaNG6gq9DqozyQJQiUJRKoF6H9VNdSpZKIqi1FqFeRDyM5z93SCHV8miiqSmpuLv74+/vz/NmjXD2dkZf39/7O3tad++vbHDu2s6nY65c+fi4+ODr68vQUFBxMTEGPScrq6upKSkANC9e/f7Pt6YMWPo2rXrfR+nLD///DOXLl0y2PEVBYCCHDj0LXzVEX5/Fs6sMchp6kwHt7E1atSI0NBQAN5++23q16/Piy++SGxsLCNGjDBucPdg+fLlXLp0iVOnTmFiYkJCQgI2NjZVdv6DBw/e1/3T09MJCQmhfv36REdH4+7uXkmR/eXnn3/Gx8eH5s2bV/qxFYVrcXBkPoQuhtwMaNUDRn0NHv0NcjqDX1kIIUyFECeEEBv1P7sJIY4IISKFEMuFEBb67Zb6nyP1v3ctdYxX9dvPCyEGGzrmqlZUVMSsWbPw9vZm0KBB5OTkABAaGkrXrl3x8/Nj7NixXLt2DYC+ffvy/PPPExgYiJeXF8eOHePBBx+kTZs2vP766wDExsbSrl07pk2bhpeXF+PHjyc7OxuAV155hfbt2+Pn58eLL75Ysn///v3x8/NjwIABXLx4EYCZM2cyd+5cunfvjru7O6tWrQIgKSkJJycnTEy0PyEXFxcaNmwIwJw5cwgMDMTb25u33nqr5HG6urry6quv4u/vT2BgIMePH2fw4MF4eHgwf/58APbs2UPv3r0ZPnw4bdu25YknnkCn0/3tOatfv37J/n379mX8+PElj7d49cfNmzfTrl07AgICmDt37k1Jec2aNYwcOZLJkyezbNmyku1RUVF07doVX19fXn/99ZLzAMybN4+goCD8/PxKHldsbCxeXl5/e/1WrVpFcHAw06ZNw9/fv+Q1VZT7lnUV1j0FX/nD0R+g9QPwyFZ4ZDO0HgCG6lOSUhr0C3gBWAJs1P+8Apisvz0fmKO//SQwX397MrBcf7s9cBKwBNyAKMD0TucMCAiQtwoPDy+5/faGM3Li/IOV+vX2hjN/O2dZ3nrrLTlv3jwppZQxMTHS1NRUnjhxQkop5YQJE+Svv/4qpZTS19dX7tmzR0op5RtvvCGfffZZKaWUffr0kf/617+klFJ+8cUX0snJSV66dEnm5uZKZ2dnmZKSImNiYiQg9+/fL6WU8pFHHpHz5s2TKSkp0tPTU+p0OimllNeuXZNSSjlixAj5888/SymlXLhwoRw9erSUUsoZM2bI8ePHy6KiIhkWFiY9PDyklFLGx8fLVq1ayQ4dOsgXXnhBHj9+vOTxpaamSimlLCwslH369JEnT56UUkrZqlUr+e2330oppXzuueekr6+vvH79urxy5Yps0qSJlFLK3bt3S0tLSxkVFSULCwvlAw88IFeuXFly/6tXr0oppbSxsSnZ39bWVsbHx8uioiLZtWtXuW/fPpmTkyNdXFxkdHS0lFLKyZMny+HDh5fE+MADD8i9e/fK8+fPSx8fn5Ltw4cPl0uWLJFSSvndd9+VnGfbtm1y1qxZUqfTyaKiIjl8+HD5559/3vH169Onjzx27Fh5fw41Uun3k1JFdDopQ5dK+UELKf/TSMotr0iZnlCppwCCZRmfqwa9shBCuADDgf/T/yyA/sAq/S6/AGP0t0frf0b/+wH6/UcDy6SUeVLKGCAS6GzIuKuam5sb/v7+AAQEBBAbG0tGRgbp6en06dMHgBkzZrB3796S+4waNQoAX19fvL29cXJywtLSEnd3d+Lj4wFo0aIFPXr0AOChhx5i//792NnZYWVlxWOPPcaaNWuoV68eAIcOHWLq1KkATJ8+nf3795eca8yYMZiYmNC+fXuSk5MB7Uri/Pnz/Pe//8XExIQBAwawa9cuAFasWEGnTp3o2LEjYWFhhIeH3zbuLl260KBBAxwdHbG0tCQ9PR2Azp074+7ujqmpKVOmTLkpltvp3LkzLi4umJiY4O/vT2xsLOfOncPd3b1kLsCUKVNK9k9OTiYiIoKePXvi6emJubk5Z86cKXkeJkyYAFDyfABs376d7du307FjRzp16sS5c+eIiIgo8/VTlEqVdBJ+GQlr/wFN28OcgzDkv2DnXGUhGLrP4gvgX0AD/c+NgHQpZaH+5wSg+NE6A/EAUspCIUSGfn9n4HCpY5a+TwkhxGxgNkDLli3vGNRbI73v/pEYkKWlZcltU1PTCjVZFN/HxMTkpvubmJhQWKg9vbcOcRRCYGZmxtGjR9m1axerVq3im2++4Y8//qhwfFLfxFO8fejQoQwdOpSmTZuybt063N3d+eSTTzh27BgNGzZk5syZN43Jv9e4KxqfqalpyXHKsmLFCq5du1aSSK5fv87SpUt5//33y7yPlJJXX32Vf/zjHzdtj42NvafXT1EqRFcEB76A3f8FKzsY+jEEPQ4mplUeisGuLIQQI4ArUsoQQ52jNCnlAilloJQy0NHxtuXYaxQ7OzsaNmzIvn37APj1119LrjIq6uLFixw6dAiAJUuW0LNnT7KyssjIyGDYsGF8/vnnnDx5EtBGFxW33S9evJhevXrd8djHjx8vGemj0+k4deoUrVq14vr169jY2GBnZ0dycjJbtmy5q5gBjh49SkxMDDqdjuXLl9OzZ8+7Pkbbtm2Jjo4u+S9/+fLlJb9bunQpW7duJTY2ltjYWEJCQkoee9euXVm9ejXATX0ZgwcP5scffyQrKwuAxMRErly5cscYGjRoQGZm5l3HriiA1oH92zjY9Q60Gw5PH4Mu/zBKogDDXln0AEYJIYYBVoAt8CVgL4Qw019duACJ+v0TgRZAghDCDLADUkttL1b6PrXaL7/8whNPPEF2djbu7u789NNPd3X/tm3b8r///Y9HH32U9u3bM2fOHDIyMhg9ejS5ublIKfnss88A+Prrr3nkkUeYN28ejo6O5Z7rypUrzJo1i7y8PEBrCnr66aexsrKiY8eOtGvX7qZmsLsRFBTE008/TWRkJP369WPs2LF3fQxra2u+/fZbhgwZgo2NDUFBQYB2JRAXF3fTkFk3Nzfs7Ow4cuQIX3zxBQ899BDvv/8+Q4YMwc7ODoBBgwZx9uxZunXrBmgd7L/99humpmW/cWfOnMkTTzyBtbU1hw4dwtra+q4fh1IHSQmnlsPml7TbIz6HgEcM13Fd8bgM28Gtb7boy18d3Cu5uYP7Sf3tp7i5g3uF/rY3N3dwR3OfHdx1QUxMjPT29jZ2GHdt9+7dN3VE34/MzEwppZQ6nU7OmTNHfvbZZ+Xe58aNGyWd/0uXLpWjRo2qlFhqm7r2fqoyN1KlXP6wlG/ZSrlwsJRpMVV6eu7QwW2MeRYvA8uEEO8BJ4CF+u0LgV+FEJFAGlrCQEoZJoRYAYQDhcBTUsqiqg9bqWl++OEHfvnlF/Lz8+nYsePf+htuJyQkhKeffhopJfb29vz4449VEKmiAFF/wNo5kJ0KA96CHs8arcnpdoQs1WFZWwQGBspbl1U9e/YsXl5eRopIUWoX9X6qRDod7PkA9s6Dxm1h3A/g1MEooQghQqSUgbf7nZrBrSiKYix5Wdpw2HMboeNDMHQeWNQzdlS3pZKFoiiKMdxIgV/HQHIYDP4vdJ1j/E7sO1DJQlEUpaplp8GiMZAaAVNXQJuBxo6oXCpZKIqiVKWcdPh1LKRcgKnLDFb4r7KpEuVVyNTUtKRMub+/Px9++OFdHyM4OJi5c+cCWlXTp59++p7jiYiIYMSIEXh4eBAQEEC/fv1uKilSmfr27cutgw5uZ926dQghOHfunEHiCA0NZfPmzX875zvvvFOp5xk2bFhJ+ZLSxQgrm5SSuXPn0rp1a/z8/Dh+/Pht9wsJCcHX15fWrVszd+7ckpn4K1euxNvbGxMTk5ten9OnTzNz5kyDxV1n5WXC4vFa09OkX2tMogCVLKqUtbU1oaGhJV+vvPLKXR8jMDCQr7766r5jyc3NZfjw4cyePZuoqChCQkL4+uuviY6O/tu+5ZXPqExLly6lZ8+eLF261CDHv12y+Pjjj3nyyScr9TybN2/G3t6+Uo95O1u2bCEiIoKIiAgWLFjAnDlzbrvfnDlz+OGHH0r23bp1KwA+Pj6sWbOG3r1737S/r68vCQkJJdWHlUqQfwMWT4DE4zDhJ/CsWQW0VbKoBlxdXfnXv/6Fr68vnTt3JjIyEtD+6/Px8aFDhw4lb+Y9e/bcdv2Luy0xvnjxYrp161ZS2A+0D47i/ybffvttpk+fTo8ePZg+fTpXr15l3LhxBAUFERQUxIEDBwC4ceMGjz76KJ07d6Zjx46sX78egJycHCZPnoyXlxdjx44tqZf0448/8txzz5Wc84cffuD5558HICsri/3797Nw4cKbSm3odDqefPJJ2rVrx8CBAxk2bFjJ4wgJCaFPnz4EBAQwePBgkpKSAO1K5uWXX6Zz5854enqyb98+8vPzefPNN1m+fDn+/v4sX76cCxcuYGlpSePGjQHKfJzFz0e3bt1o06YNP/zwA6CVau/duzf+/v74+PiUlGcpvVBTMSklL730UsmCUcUlSO5UZr0869ev5+GHH0YIQdeuXUlPTy95DoolJSVx/fp1unbtihCChx9+mHXr1gHg5eVF27Ztb3vskSNH3vQ6KPehIAeWTob4IzDu/8BrpLEjumt1s89iyytw+XTlHrOZLwy9c7NSTk5OSXVSgFdffZVJkyYBWi2o06dPs2jRIp577jk2btzIO++8w7Zt23B2di5p0ijLM888w4wZM5gxYwY//vgjc+fOLflASEpKYv/+/Zw7d45Ro0Yxfvx4wsLC6NSp0x2PGR4ezv79+7G2tmbq1Kk8//zz9OzZk4sXLzJ48GDOnj3L+++/T//+/fnxxx9JT0+nc+fOPPDAA3z//ffUq1ePs2fPcurUqZJzTZw4kffff5958+Zhbm7OTz/9xPfffw9oH3xDhgzB09OTRo0aERISQkBAAGvWrCE2Npbw8HCuXLmCl5cXjz76KAUFBTzzzDOsX78eR0dHli9fzmuvvVYyka6wsJCjR4+yefNm/vOf/7Bz507eeecdgoOD+eabbwD46aefbnoenn322ds+ToBTp05x+PBhbty4QceOHRk+fDhLly5l8ODBvPbaaxQVFZWsGXI7a9asITQ0lJMnT5KSkkJQUFDJPwEnTpwgLCyM5s2b06NHDw4cOEDPnj15/vnn2b1799+ONXnyZF555RUSExNp0eKvajguLi4kJibi5ORUsi0xMREXF5e/7VOewMBAPvzwQ/71r3+Vu69yB9lpsHSKlijGfg8+Dxo7ontSN5OFkRQ3Q91OcQntKVOmlPyn3aNHD2bOnMnEiRN58ME7/4EdOnSINWu05RSnT59+0xv8diXGbzV27FgiIiLw9PQsOc6oUaNK6hnt3LnzplLj169fJysri+3bt7NhwwY++eQTQGveunjxInv37i3pW/Hz88PP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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -498,944 +631,878 @@ " ThompsonSamplingAgent(),\n", " EpsilonGreedyAgent(),\n", " UCBAgent(),\n", - " YourAgent()\n", + "# YourAgent()\n", "]\n", "\n", - "plot_regret(DriftingBandit(), drifting_agents, n_steps=20000, n_trials=10)" + "regret = get_regret(DriftingBandit(), drifting_agents, n_steps=20000, n_trials=10)\n", + "plot_regret(drifting_agents, regret)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Part 2. Contextual bandit\n", + "## Part 2. Exploration in MDP\n", "\n", - "Now we will solve much more complex problem - reward will depend on bandit's state.\n", - "\n", - "**Real-word analogy:**\n", - "\n", - "> Contextual advertising. We have a lot of banners and a lot of different users. Users can have different features: age, gender, search requests. We want to show banner with highest click probability.\n", - "\n", - "If we want use strategies from above, we need some how store reward distributions conditioned both on actions and bandit's state. \n", - "One way to do this - use bayesian neural networks. Instead of giving pointwise estimates of target, they maintain probability distributions\n", + "The following problem, called \"deep see\", illustrates importance of exploration in context of mdp's." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", "\n", - "\n", - "Picture from https://arxiv.org/pdf/1505.05424.pdf\n", + "The deep sea problem is implemented as an $N×N$ grid with a one-hot encoding for state.\n", + "The agent begins each episode in the top left corner of the grid and descends one row\n", + "per timestep. Each episode terminates after N steps, when the agent reaches the bottom\n", + "row. In each state there is a random but fixed mapping between actions $A = {0,1}$ and\n", + "the transitions ‘left’ and ‘right’. At each timestep there is a small cost $r = −0.01/N$ of\n", + "moving right, and $r = 0$ for moving left. However, should the agent transition right at every\n", + "timestep of the episode it will be rewarded with an additional reward of $+1$.\n", "\n", + "**Question:** Why is the deep see a challengin exploration problem?\n", "\n", - "More material:\n", - " * A post on the matter - [url](http://twiecki.github.io/blog/2016/07/05/bayesian-deep-learning/)\n", - " * Theano+PyMC3 for more serious stuff - [url](http://pymc-devs.github.io/pymc3/notebooks/bayesian_neural_network_advi.html)\n", - " * Same stuff in tensorflow - [url](http://edwardlib.org/tutorials/bayesian-neural-network)\n", - " \n", - "Let's load our dataset:" + "See full paper [here](https://openreview.net/forum?id=rygf-kSYwH)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 304, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "State size: 60, actions: 10\n" + "\u001b[1m\u001b[37mLoaded bsuite_id: deep_sea/0.\u001b[0m\n" ] + }, + { + "data": { + "text/plain": [ + "{'size': 10, 'mapping_seed': 42}" + ] + }, + "execution_count": 304, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "all_states = np.load(\"all_states.npy\")\n", - "action_rewards = np.load(\"action_rewards.npy\")\n", + "import gymnasium as gym\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import torch\n", + "from torch import nn\n", + "from time import sleep\n", + "from tqdm import tqdm\n", + "from IPython.display import clear_output\n", "\n", - "state_size = all_states.shape[1]\n", - "n_actions = action_rewards.shape[1]\n", + "from q_learning_agent import QLearningAgent\n", + "from replay_buffer import ReplayBuffer\n", "\n", - "print(\"State size: %i, actions: %i\" % (state_size, n_actions))" + "env = gym.make(\"bsuite/deep_sea-v0\", size=10, seed=42)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2.1 Epsilon-greedy q-learning " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 150, "metadata": {}, "outputs": [], "source": [ - "import theano\n", - "import theano.tensor as T\n", - "import lasagne\n", - "from lasagne import init\n", - "from lasagne.layers import *\n", - "import bayes\n", - "\n", - "as_bayesian = bayes.bbpwrap(bayes.NormalApproximation(std=0.1))\n", - "BayesDenseLayer = as_bayesian(DenseLayer)" + "def get_state_number(s):\n", + " return np.argmax(s.flatten())\n", + "\n", + "def test_agent(agent, greedy=True, delay=.5):\n", + " v = get_all_states_value(agent)\n", + " s, _ = env.reset()\n", + " done = False\n", + " while not done:\n", + " fig, ax = plt.subplots(ncols=2)\n", + " ax[0].imshow(s)\n", + " ax[0].set_title('State')\n", + " im = ax[1].imshow(v)\n", + " plt.colorbar(im)\n", + " ax[1].set_title('Value function')\n", + " clear_output(True)\n", + " plt.show()\n", + " s = get_state_number(s)\n", + " if greedy:\n", + " a = agent.get_best_action(s)\n", + " else:\n", + " a = agent.get_action(s)\n", + "\n", + " s, r, terminated, truncated, _ = env.step(a)\n", + " done = terminated or truncated\n", + " sleep(delay)\n", + "\n", + "def get_all_states_value(agent):\n", + " s_shape = env.observation_space.shape\n", + " s_shape_flatten = np.prod(s_shape)\n", + " v = np.zeros(s_shape_flatten)\n", + " for i in range(s_shape_flatten):\n", + " v[i] = agent.get_value(i)\n", + " v = v.reshape(s_shape)\n", + " return v\n", + "\n", + "def to_one_hot(x, ndims):\n", + " \"\"\" helper: take an integer vector and convert it to 1-hot matrix. \"\"\"\n", + " x = x.long().view(-1, 1)\n", + " x = torch.zeros(\n", + " x.size()[0], ndims).scatter_(1, x, 1)\n", + " return x" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 151, "metadata": {}, + "outputs": [], "source": [ - "## 2.1 Bulding a BNN agent\n", - "\n", - "Let's implement epsilon-greedy BNN agent" + "agent = QLearningAgent(\n", + " epsilon=1, \n", + " alpha=0.5, \n", + " discount=1, \n", + " get_legal_actions=lambda s: range(env.action_space.n)\n", + ")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 152, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ - "class BNNAgent:\n", - " \"\"\"a bandit with bayesian neural net\"\"\"\n", - "\n", - " def __init__(self, state_size, n_actions):\n", - " input_states = T.matrix(\"states\")\n", - " target_actions = T.ivector(\"actions taken\")\n", - " target_rewards = T.vector(\"rewards\")\n", - "\n", - " self.total_samples_seen = theano.shared(\n", - " np.int32(0), \"number of training samples seen so far\")\n", - " batch_size = target_actions.shape[0] # por que?\n", - "\n", - " # Network\n", - " inp = InputLayer((None, state_size), name='input')\n", - " # YOUR NETWORK HERE\n", - " out = \n", - "\n", - " # Prediction\n", - " prediction_all_actions = get_output(out, inputs=input_states)\n", - " self.predict_sample_rewards = theano.function(\n", - " [input_states], prediction_all_actions)\n", - "\n", - " # Training\n", - "\n", - " # select prediction for target action\n", - " prediction_target_actions = prediction_all_actions[T.arange(\n", - " batch_size), target_actions]\n", - "\n", - " # loss = negative log-likelihood (mse) + KL\n", - " negative_llh = T.sum((prediction_target_actions - target_rewards)**2)\n", - "\n", - " kl = bayes.get_var_cost(out) / (self.total_samples_seen+batch_size)\n", - "\n", - " loss = (negative_llh + kl)/batch_size\n", - "\n", - " self.weights = get_all_params(out, trainable=True)\n", - " self.out = out\n", - "\n", - " # gradient descent\n", - " updates = lasagne.updates.adam(loss, self.weights)\n", - " # update counts\n", - " updates[self.total_samples_seen] = self.total_samples_seen + \\\n", - " batch_size.astype('int32')\n", - "\n", - " self.train_step = theano.function([input_states, target_actions, target_rewards],\n", - " [negative_llh, kl],\n", - " updates=updates,\n", - " allow_input_downcast=True)\n", - "\n", - " def sample_prediction(self, states, n_samples=1):\n", - " \"\"\"Samples n_samples predictions for rewards,\n", - "\n", - " :returns: tensor [n_samples, state_i, action_i]\n", - " \"\"\"\n", - " assert states.ndim == 2, \"states must be 2-dimensional\"\n", - "\n", - " return np.stack([self.predict_sample_rewards(states) for _ in range(n_samples)])\n", - "\n", - " epsilon = 0.25\n", - "\n", - " def get_action(self, states):\n", - " \"\"\"\n", - " Picks action by \n", - " - with p=1-epsilon, taking argmax of average rewards\n", - " - with p=epsilon, taking random action\n", - " This is exactly e-greedy policy.\n", - " \"\"\"\n", - "\n", - " reward_samples = self.sample_prediction(states, n_samples=100)\n", - " # ^-- samples for rewards, shape = [n_samples,n_states,n_actions]\n", - "\n", - " best_actions = reward_samples.mean(axis=0).argmax(axis=-1)\n", - " # ^-- we take mean over samples to compute expectation, then pick best action with argmax\n", - "\n", - " \n", - " chosen_actions = \n", - "\n", - " return chosen_actions\n", - "\n", - " def train(self, states, actions, rewards, n_iters=10):\n", - " \"\"\"\n", - " trains to predict rewards for chosen actions in given states\n", - " \"\"\"\n", - " loss_sum = kl_sum = 0\n", - " for _ in range(n_iters):\n", - " loss, kl = self.train_step(states, actions, rewards)\n", - " loss_sum += loss\n", - " kl_sum += kl\n", - "\n", - " return loss_sum / n_iters, kl_sum / n_iters\n", - "\n", - " @property\n", - " def name(self):\n", - " return self.__class__.__name__" + "test_agent(agent, greedy=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 2.2 Training the agent" + "Let's try to solve this by q-learning with high epsilon!" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ - "N_ITERS = 100" + "for i in range(5000):\n", + " s, _ = env.reset()\n", + " done = False\n", + " while not done:\n", + " i_s = get_state_number(s)\n", + " a = agent.get_action(i_s)\n", + " s_next, r, terminated, truncated, _ = env.step(a)\n", + " done = terminated or truncated\n", + " i_s_next = get_state_number(s_next)\n", + " agent.update(i_s, a, r, i_s_next, terminated)\n", + " s = s_next" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ - "def get_new_samples(states, action_rewards, batch_size=10):\n", - " \"\"\"samples random minibatch, emulating new users\"\"\"\n", - " batch_ix = np.random.randint(0, len(states), batch_size)\n", - " return states[batch_ix], action_rewards[batch_ix]" + "test_agent(agent)" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "from IPython.display import clear_output\n", - "\n", - "from pandas import DataFrame\n", - "moving_average = lambda x, **kw: DataFrame(\n", - " {'x': np.asarray(x)}).x.ewm(**kw).mean().values\n", - "\n", - "def train_contextual_agent(agent, batch_size=10, n_iters=100):\n", - " rewards_history = []\n", - "\n", - " for i in range(n_iters):\n", - " b_states, b_action_rewards = get_new_samples(\n", - " all_states, action_rewards, batch_size)\n", - " b_actions = agent.get_action(b_states)\n", - " b_rewards = b_action_rewards[\n", - " np.arange(batch_size), b_actions\n", - " ]\n", - "\n", - " mse, kl = agent.train(b_states, b_actions, b_rewards, n_iters=100)\n", - "\n", - " rewards_history.append(b_rewards.mean())\n", - "\n", - " if i % 10 == 0:\n", - " clear_output(True)\n", - " print(\"iteration #%i\\tmean reward=%.3f\\tmse=%.3f\\tkl=%.3f\" %\n", - " (i, np.mean(rewards_history[-10:]), mse, kl))\n", - " plt.plot(rewards_history)\n", - " plt.plot(moving_average(np.array(rewards_history), alpha=0.1))\n", - " plt.title(\"Reward per epesode\")\n", - " plt.xlabel(\"Episode\")\n", - " plt.ylabel(\"Reward\")\n", - " plt.show()\n", - "\n", - " samples = agent.sample_prediction(\n", - " b_states[:1], n_samples=100).T[:, 0, :]\n", - " for i in range(len(samples)):\n", - " plt.hist(samples[i], alpha=0.25, label=str(i))\n", - " plt.legend(loc='best')\n", - " print('Q(s,a) std:', ';'.join(\n", - " list(map('{:.3f}'.format, np.std(samples, axis=1)))))\n", - " print('correct', b_action_rewards[0].argmax())\n", - " plt.title(\"p(Q(s, a))\")\n", - " plt.show()\n", - "\n", - " return moving_average(np.array(rewards_history), alpha=0.1)" + "But if we do bigger env:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 305, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "iteration #90\tmean reward=0.560\tmse=0.457\tkl=0.044\n" + "\u001b[1m\u001b[37mLoaded bsuite_id: deep_sea/1.\u001b[0m\n" ] }, { "data": { - "image/png": "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\n", "text/plain": [ - "" + "{'size': 12, 'mapping_seed': 42}" ] }, + "execution_count": 305, "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Q(s,a) std: 0.178;0.011;0.000;0.000;0.195;0.000;0.000;0.124;0.023;0.000\n", - "correct 4\n" - ] - }, + "output_type": "execute_result" + } + ], + "source": [ + "env = gym.make(\"bsuite/deep_sea-v0\", size=12, seed=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 317, + "metadata": {}, + "outputs": [], + "source": [ + "agent = QLearningAgent(\n", + " epsilon=1,\n", + " alpha=0.5,\n", + " discount=1,\n", + " get_legal_actions=lambda s: range(env.action_space.n)\n", + ")\n", + "\n", + "for i in range(5000):\n", + " s, _ = env.reset()\n", + " done = False\n", + " while not done:\n", + " i_s = get_state_number(s)\n", + " a = agent.get_action(i_s)\n", + " s_next, r, terminated, truncated, _ = env.step(a)\n", + " done = terminated or truncated\n", + " i_s_next = get_state_number(s_next)\n", + " agent.update(i_s, a, r, i_s_next, terminated)\n", + " s = s_next" + ] + }, + { + "cell_type": "code", + "execution_count": 318, + "metadata": {}, + "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAEWCAYAAABollyxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvAOZPmwAAG2NJREFUeJzt3X+U1XW97/HnSwaYQBCEAXEGHVBT8EcIKHkqJD2SUUtTyDA6okJU11t4O92j3XPW6eo6p6x1u6bV7YjmjzTBrtd14JBRBHogE3Hkh04RSxKMIQQcAZEfwgzv+8f+UluYYTazvzN75svrsdas2d/v9/P9fD58Yb34zGd/5rMVEZiZWXadUOoOmJlZ23LQm5llnIPezCzjHPRmZhnnoDczyzgHvZlZxjnoLXMkdZf0e0mD2uO+Y2xjoKQ1krrnnfuypG+3VZtmDnrLohnAkojYfOiEpL+RtFjSLkk7Jc2TdE5L96UtIrYAzyRtHXI/MEXSgLZq145vDnrLoi8Cjx46kHQJ8CtgLnAqMAR4GXhOUnVz97WhnwJfOHQQEfuAXwA3tEPbdhxy0FunI2mDpK8n0yzbJT0kqTy5dhowFHgh75bvAD+JiHsiYldEvBUR/wQsB77R3H2SJiRt7JK0SdLXCuzfJyStlPS2pI2S/udhRV4Ahko6Pe/cs8AnjuU5mBXKQW+d1RTgY8AZwPuBf0rOnw+8FhENAJJ6AH8D/N8m6vgZML6p+xI/Br4QEb2A84DFBfZtN7nReR9y4f0lSZ86dDFpYx3wgbx71hx2bJYaB711Vj+IiI0R8Rbwr8D1yfk+wK68cieT+3fe1Lz7ZqCimfsADgDDJfWOiO0RsaKQjkXEsxHxSkQcjIiXgdnApYcV25W0mX98UiH1mx0rB711VhvzXr9Obu4dYDvQK+/aduAg0NRKmkHAm83cBzARmAC8Luk/k7n+FkkaI+kZSdsk7SQ399//sGK9gB2HHe8spH6zY+Wgt85qcN7r04A/J69fBoZIKgOIiN3A88Cnm6jjOnJz40fcl9z7YkRcDQwA/p3cVE8hHgfmAYMj4iTg3wAdupi0cSawOu+eYYcdm6XGQW+d1S2SqiSdDPwj8ARARNSRm/++OK/s7cBUSV+R1EtSX0n/AnwE+GZT90nqJmmKpJMi4gDwNrmfDEiuh6RxzfStF/BWROyTdDHw2cOuXwxsiIjX885dSm7ljVnqHPTWWT1Obsnka8AfgX/Ju3Yf8HeHDiLiN+TeuL2W3Lz8W8BU4PKIqG3uvuT1Bklvk5t+mQIgaTC5OfVXmunbfwHulLQL+GeO/ElgCrlRPkl95eSmiB5p6Q9t1hryB49YZyNpAzA9In7dzPXuwEpyQX7Em7CSLiD3S0ufjYhfFnpfXrnPAedGxNdb0fcBwH8CFybr55H0ZXLTPP9wrPWZFcJBb51OS0FfYB0fAcYA3ztsSaVZ5pS1XMQseyJiKbC01P0waw8e0ZuZZZzfjDUzy7gOMXXTv3//qK6uLnU3zMw6lZdeeunNiKhoqVyHCPrq6mpqampK3Q0zs05F0ustl/LUjZlZ5jnozcwyzkFvZpZxHWKO3sysVA4cOEBdXR379u0rdVeaVV5eTlVVFV27dm3V/Q56Mzuu1dXV0atXL6qrq5HU8g3tLCKor6+nrq6OIUOGtKoOT92Y2XFt37599OvXr0OGPIAk+vXrV9RPHC0GvaQHJW2VVJt37mRJCyW9mnzvm5yXpHslrZP0sqSRre6ZmVk76aghf0ix/StkRP8wcOVh524HFkXEWcCi5Bjg48BZydcM4EdF9c7MzIrW4hx9RCyRVH3Y6auBccnrR8h9Ss9tyfmfRG4DnWWS+kgadLQtX83MOpLn/1ifan2XnNGvxTILFixg5syZNDY2Mn36dG6//fYW7zkWrX0zdmBeeL8BDExeV/Lez/KsS841tSf4DHKjfk477bRWdsOaM+vBx4/5nhk3H/5BSGbW1hobG7nllltYuHAhVVVVXHTRRVx11VUMHz48tTaKfjM2Gb0f8xaYETErIkZHxOiKiha3ajAzy6Tly5dz5plnMnToULp168bkyZOZO3duqm20Nui3SBoEkHzfmpzfxHs/tLkqOWdmZk3YtGkTgwf/NTarqqrYtCnd2Gxt0M8j95mbJN/n5p2/IVl980Fgp+fnzcxKq8U5ekmzyb3x2l9SHfAN4C7gZ5KmAa8D1yXFnyb3IcfrgD3ATW3QZzOzzKisrGTjxr++tVlXV0dlZWWqbRSy6ub6Zi5d3kTZAG4ptlNmZseLiy66iFdffZX169dTWVnJnDlzePzxY19McTTeAiGr3n0buvcudS/MOp1ClkOmqaysjB/84Ad87GMfo7GxkZtvvplzzz033TZSrc3MzI7ZhAkTmDBhQpvV771uMupgj3oOlm9tuaCZZZ6D3sws4xz0ZmYZ56A3M8s4B72ZWcY56M3MMs7LK83M8q1fmm59Qz7SYpGbb76Z+fPnM2DAAGpra1ssf6w8ojczK7Ebb7yRBQsWtFn9DnozsxIbO3YsJ598cpvV76A3M8s4B72ZWcY56M3MMs5Bb2aWcV5eaWaWr4DlkGm7/vrrefbZZ3nzzTepqqrijjvuYNq0aanV76A3Myux2bNnt2n9nroxM8s4B72ZWcY56M3MMs5Bb2aWcQ56M7OMc9CbmWWcl1eameV58Y0XU63volMuOur1jRs3csMNN7BlyxYkMWPGDGbOnJlqHxz0ZmYlVFZWxne/+11GjhzJrl27GDVqFFdccQXDhw9PrQ1P3ZiZldCgQYMYOXIkAL169WLYsGFs2rQp1TYc9GZmHcSGDRtYuXIlY8aMSbVeB72ZWQfwzjvvMHHiRL73ve/Ru3fvVOt20JuZldiBAweYOHEiU6ZM4dprr029fge9mVkJRQTTpk1j2LBhfPWrX22TNrzqxswsT0vLIdP23HPP8eijj3L++eczYsQIAL75zW8yYcKE1Npw0JuZldCHP/xhIqJN2yhq6kbSf5P0O0m1kmZLKpc0RNILktZJekJSt7Q6a2Zmx67VQS+pEvgKMDoizgO6AJOBbwN3R8SZwHYgvY9JMTOzY1bsm7FlwPsklQE9gM3AZcCTyfVHgE8V2YaZmRWh1UEfEZuA/wX8iVzA7wReAnZERENSrA6obOp+STMk1Uiq2bZtW2u7YWZmLShm6qYvcDUwBDgV6AlcWej9ETErIkZHxOiKiorWdsPMzFpQzNTN3wLrI2JbRBwAngI+BPRJpnIAqoB0N20wM7NjUszyyj8BH5TUA9gLXA7UAM8Ak4A5wFRgbrGdNDNrL7tfWJ5qfT3HXHzU6/v27WPs2LG8++67NDQ0MGnSJO64445U+1DMHP0L5N50XQG8ktQ1C7gN+KqkdUA/4Mcp9NPMLJO6d+/O4sWLWb16NatWrWLBggUsW7Ys1TaK+oWpiPgG8I3DTr8GHP2/MDMzA0ASJ554IpDb8+bAgQNISrUN73VjZlZijY2NjBgxggEDBnDFFVd4m2Izs6zp0qULq1atoq6ujuXLl1NbW5tq/Q76jNrTGOxpbODthgNHfJlZx9SnTx8++tGPsmDBglTrddCbmZXQtm3b2LFjBwB79+5l4cKFnHPOOam24d0rzczytLQcMm2bN29m6tSpNDY2cvDgQa677jo++clPptqGg97MrIQuuOACVq5c2aZteOrGzCzjHPRmZhnnoDczyzgHvZlZxjnozcwyzkFvZpZxXl5pZpZn09rtqdZXeXbfgso1NjYyevRoKisrmT9/fqp98IjezKwDuOeeexg2bFib1O2gNzMrsbq6On7+858zffr0NqnfQW9mVmK33nor3/nOdzjhhLaJZAe9mVkJzZ8/nwEDBjBq1Kg2a8NBb2ZWQs899xzz5s2jurqayZMns3jxYj73uc+l2oaD3syshL71rW9RV1fHhg0bmDNnDpdddhmPPfZYqm14eaWZWZ5Cl0N2Jg56M7MOYty4cYwbNy71ej11Y2aWcQ56M7OMc9CbmWWcg97MLOMc9GZmGeegNzPLOC+vNDPLs/F3L6da3+BzL2ixTHV1Nb169aJLly6UlZVRU1OTah8c9GZmHcAzzzxD//7926RuT92YmWWcg97MrMQkMX78eEaNGsWsWbNSr99TN2ZmJfab3/yGyspKtm7dyhVXXME555zD2LFjU6u/qBG9pD6SnpT0B0lrJF0i6WRJCyW9mnzP3g5BZmYpqqysBGDAgAFcc801LF++PNX6i526uQdYEBHnAB8A1gC3A4si4ixgUXJsZmZN2L17N7t27frL61/96lecd955qbbR6qkbSScBY4EbASJiP7Bf0tXAuKTYI8CzwG3FdNLMrL0UshwyTVu2bOGaa64BoKGhgc9+9rNceeWVqbZRzBz9EGAb8JCkDwAvATOBgRGxOSnzBjCwuC6amWXX0KFDWb16dZu2UczUTRkwEvhRRFwI7OawaZqICCCaulnSDEk1kmq2bdtWRDfMzOxoign6OqAuIl5Ijp8kF/xbJA0CSL5vbermiJgVEaMjYnRFRUUR3TAzs6NpddBHxBvARklnJ6cuB34PzAOmJuemAnOL6qGZmRWl2HX0XwZ+Kqkb8BpwE7n/PH4maRrwOnBdkW2YmVkRigr6iFgFjG7i0uXF1GtmZunxFghmZhnnLRDMzPLs++OOVOsrP6NPi2V27NjB9OnTqa2tRRIPPvggl1xySWp9cNCbmZXYzJkzufLKK3nyySfZv38/e/bsSbV+B72ZWQnt3LmTJUuW8PDDDwPQrVs3unXrlmobnqM3Myuh9evXU1FRwU033cSFF17I9OnT2b17d6ptOOjNzEqooaGBFStW8KUvfYmVK1fSs2dP7rrrrlTbcNCbmZVQVVUVVVVVjBkzBoBJkyaxYsWKVNtw0JuZldApp5zC4MGDWbt2LQCLFi1i+PDhqbbhN2PNzPIUshwybd///veZMmUK+/fvZ+jQoTz00EOp1u+gNzMrsREjRlBTU9Nm9Xvqxsws4xz0ZmYZ56A3M8s4B72ZWcY56M3MMs5Bb2aWcV5eaWaWZ/369anWN2TIkKNeX7t2LZ/5zGf+cvzaa69x5513cuutt6bWBwe9mVkJnX322axatQqAxsZGKisrueaaa1Jtw1M3ZmYdxKJFizjjjDM4/fTTU63XQW9m1kHMmTOH66+/PvV6HfRmZh3A/v37mTdvHp/+9KdTr9tBb2bWAfziF79g5MiRDBw4MPW6HfRmZh3A7Nmz22TaBrzqxszsPVpaDtkWdu/ezcKFC7nvvvvapH4HvZlZifXs2ZP6+vo2q99TN2ZmGeegNzPLOAe9mVnGOejNzDLOQW9mlnEOejOzjPPySjOzPNu3L0u1vr59P9himbvvvpsHHngASZx//vk89NBDlJeXp9YHj+jNzEpo06ZN3HvvvdTU1FBbW0tjYyNz5sxJtY2ig15SF0krJc1PjodIekHSOklPSOpWfDfNzLKroaGBvXv30tDQwJ49ezj11FNTrT+NEf1MYE3e8beBuyPiTGA7MC2FNszMMqmyspKvfe1rnHbaaQwaNIiTTjqJ8ePHp9pGUUEvqQr4BPBAcizgMuDJpMgjwKeKacPMLMu2b9/O3LlzWb9+PX/+85/ZvXs3jz32WKptFDui/x7wD8DB5LgfsCMiGpLjOqCyqRslzZBUI6lm27ZtRXbDzKxz+vWvf82QIUOoqKiga9euXHvttfz2t79NtY1WB72kTwJbI+Kl1twfEbMiYnREjK6oqGhtN8zMOrXTTjuNZcuWsWfPHiKCRYsWMWzYsFTbKGZ55YeAqyRNAMqB3sA9QB9JZcmovgrYVHw37VjtbzzIQQ7SsL/xyIsNAqB3uVfXmh2ukOWQaRozZgyTJk1i5MiRlJWVceGFFzJjxoxU22j1iD4ivh4RVRFRDUwGFkfEFOAZYFJSbCowt+hempll2B133MEf/vAHamtrefTRR+nevXuq9bfFOvrbgK9KWkduzv7HbdCGmZkVKJWf3SPiWeDZ5PVrwMVp1GtmZsXzb8aamWWcg97MLOMc9GZmGeegNzPLOC+kNjPL89z2XanW96G+vVosc88993D//fcTEXz+85/n1ltvTbUPHtGbmZVQbW0t999/P8uXL2f16tXMnz+fdevWpdqGg97MrITWrFnDmDFj6NGjB2VlZVx66aU89dRTqbbhoDczK6HzzjuPpUuXUl9fz549e3j66afZuHFjqm14jt6sk9i0dnuq9VWe3TfV+qx1hg0bxm233cb48ePp2bMnI0aMoEuXLqm24RG9mVmJTZs2jZdeeoklS5bQt29f3v/+96dav0f0ZmYltnXrVgYMGMCf/vQnnnrqKZYtS/cDyh30ZmZ5ClkOmbaJEydSX19P165d+eEPf0ifPn1Srd9Bb2ZWYkuXLm3T+j1Hb2aWcQ56M7OMc9Cb2XEvIkrdhaMqtn8OejM7rpWXl1NfX99hwz4iqK+vp7y8vNV1+M1YMzuuVVVVUVdXx7Zt20rdlWaVl5dTVVXV6vsd9GZ2XOvatStDhgwpdTfalKduzMwyzkFvZpZxnroxO06luUmaN0jr2DyiNzPLOAe9mVnGOejNzDLOQW9mlnEOejOzjHPQm5llnIPezCzjHPRmZhnnoDczyzgHvZlZxrU66CUNlvSMpN9L+p2kmcn5kyUtlPRq8t2/G21mVkLFjOgbgL+PiOHAB4FbJA0HbgcWRcRZwKLk2MzMSqTVQR8RmyNiRfJ6F7AGqASuBh5Jij0CfKrYTpqZWeulMkcvqRq4EHgBGBgRm5NLbwADm7lnhqQaSTUd+ZNdzMw6u6KDXtKJwP8Dbo2It/OvRe5DGJv8IMaImBURoyNidEVFRbHdMDOzZhS1H72kruRC/qcR8VRyeoukQRGxWdIgYGuxnTSzji3Nve3B+9unrZhVNwJ+DKyJiP+dd2keMDV5PRWY2/rumZlZsYoZ0X8I+DvgFUmrknP/A7gL+JmkacDrwHXFddHMzIrR6qCPiN8Aauby5a2t18zM0uXfjDUzyzgHvZlZxjnozcwyzkFvZpZxDnozs4xz0JuZZZyD3sws4xz0ZmYZ56A3M8s4B72ZWcY56M3MMq6obYot+57/Y32LZS45o1879MTMWssjejOzjHPQm5llnIPezCzjPEd/HHt7X8N7jguZjzezzscjejOzjPOI3oqW5k8CXsFjlj6P6M3MMs4j+uPQnoMNTZ5/6406AE4+pao9u5Npm9ZuL3UXzDyiNzPLOo/oLZMKfd/A7wnY8cAjejOzjPOI3joUr+U3SPe9jcqz+6ZWV2flEb2ZWcY56M3MMs5Bb2aWcQ56M7OM85uxZnn8C06WRR7Rm5llnEf0doRDWyE0p6UtElq6vyXF1O/tG8yO5BG9mVnGeUR/HCnr8eZfXjfs6d/qeoodsZfS4X1ff8Lb7znuRp/27I5Zu2iTEb2kKyWtlbRO0u1t0YaZmRUm9RG9pC7AD4ErgDrgRUnzIuL3abdlR3dC4z5OaNgDwMGyHi2Wf9+O+bzbuzpX/oTzjl73wdqCyjVlz9a9R73edf87R79/x1/v7zHgfcfcfr7f//m9I/qu+1s39jn31N5F9cPaTkdfSdUeWzS0xYj+YmBdRLwWEfuBOcDVbdCOmZkVoC3m6CuBjXnHdcCYwwtJmgHMSA7fkbS2le31B95ssdTxx8/lSH4mR/IzOVJneianF1KoZG/GRsQsYFax9UiqiYjRKXQpU/xcjuRnciQ/kyNl8Zm0xdTNJmBw3nFVcs7MzEqgLYL+ReAsSUMkdQMmA/PaoB0zMytA6lM3EdEg6b8CvwS6AA9GxO/SbidP0dM/GeXnciQ/kyP5mRwpc89EEVHqPpiZWRvyFghmZhnnoDczy7hOF/SSTpa0UNKryfcmf61MUqOkVclXJt8MbmmrCUndJT2RXH9BUnX797L9FfBcbpS0Le/fx/RS9LO9SHpQ0lZJtc1cl6R7k+f1sqSR7d3HUijguYyTtDPv38k/t3cf09Lpgh64HVgUEWcBi5LjpuyNiBHJ11Xt1732kbfVxMeB4cD1koYfVmwasD0izgTuBr7dvr1sfwU+F4An8v59PNCunWx/DwNXHuX6x4Gzkq8ZwI/aoU8dwcMc/bkALM37d3JnO/SpTXTGoL8aeCR5/QjwqRL2pZQK2Woi/1k9CVwuSe3Yx1LwFhyHiYglwFtHKXI18JPIWQb0kTSofXpXOgU8l8zojEE/MCI2J6/fAAY2U65cUo2kZZKy+J9BU1tNVDZXJiIagJ1Av3bpXekU8lwAJibTFE9KGtzE9eNJoc/seHSJpNWSfiHp3FJ3prU65H70kn4NnNLEpX/MP4iIkNTc+tDTI2KTpKHAYkmvRMQf0+6rdUr/AcyOiHclfYHcTz2XlbhP1vGsIJcj70iaAPw7uemtTqdDBn1E/G1z1yRtkTQoIjYnP15ubaaOTcn31yQ9C1wIZCnoC9lq4lCZOkllwElAfft0r2RafC4Rkf8MHgC+0w796si8bUkTIuLtvNdPS/o/kvpHRGfZ8OwvOuPUzTxgavJ6KjD38AKS+krqnrzuD3wIyNp++IVsNZH/rCYBiyP7vyHX4nM5bP75KmBNO/avI5oH3JCsvvkgsDNvevS4JemUQ+9pSbqYXF52yoFShxzRt+Au4GeSpgGvA9cBSBoNfDEipgPDgPskHST3l3NX1j74pLmtJiTdCdRExDzgx8CjktaRe9Npcul63D4KfC5fkXQV0EDuudxYsg63A0mzgXFAf0l1wDeArgAR8W/A08AEYB2wB7ipND1tXwU8l0nAlyQ1AHuByZ11oOQtEMzMMq4zTt2YmdkxcNCbmWWcg97MLOMc9GZmGeegNzPLOAe9ZVbeDqa1kv5DUp8S9aO6uR0SzdqDg96y7NAOpueRWy9/S3s0muygadZhOOjtePE8eRt1Sfrvkl5MNja7I+/cV5LXd0tanLy+TNJPk9c/SjbL+92h+5LzGyR9W9IK4NOSRiWbYa2mnf6DMWuOg94yLxlhX06yFYKk8eQ2p7oYGAGMkjQWWAp8JLltNHCipK7JuSXJ+X+MiNHABcClki7Ia6o+IkZGxBzgIeDLEfGBtv3TmbXMQW9Z9j5Jq/jrdtYLk/Pjk6+V5HYoPIdc8L9ELvR7A++S+ylgNLmgX5rce10yal8JnEvuw00OeQIgeS+gT7LfOcCjbfKnMytQZ9zrxqxQeyNihKQe5Pa+uQW4FxDwrYi47/AbJK0nt/fNb4GXgY8CZwJrJA0BvgZcFBHbJT0MlOfdvrsN/yxmreYRvWVeROwBvgL8fbJd8y+BmyWdCCCpUtKApPhScmG+JHn9RWBlsplVb3JhvlPSQHIfwddUezuAHZI+nJya0jZ/MrPCOOjtuBARK8mN0K+PiF8BjwPPS3qF3Mcs9kqKLgUGAc9HxBZgX3KOiFhNbsrmD8n9zx2lyZuAHyZTR1n/+Ebr4Lx7pZlZxnlEb2aWcQ56M7OMc9CbmWWcg97MLOMc9GZmGeegNzPLOAe9mVnG/X8bidNH9WJ3RgAAAABJRU5ErkJggg==\n", + "image/png": "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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:37: FutureWarning: pd.ewm_mean is deprecated for ndarrays and will be removed in a future version\n" - ] } ], "source": [ - "bnn_agent = BNNAgent(state_size=state_size, n_actions=n_actions)\n", - "greedy_agent_rewards = train_contextual_agent(\n", - " bnn_agent, batch_size=10, n_iters=N_ITERS)" + "test_agent(agent)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## HW 2.1 Better exploration\n", + "## 2.2 Reward shaping" + ] + }, + { + "cell_type": "code", + "execution_count": 308, + "metadata": {}, + "outputs": [], + "source": [ + "class BaseIntrinsicRewardModule(nn.Module):\n", + " def __init__(self):\n", + " super().__init__()\n", + "\n", + " def get_intrinsic_reward(self, state, action, next_state):\n", + " return 0.0\n", "\n", - "Use strategies from first part to gain more reward in contextual setting" + " def get_loss(self, state_batch, action_batch, next_state_batch):\n", + " pass" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 309, "metadata": {}, "outputs": [], "source": [ - "class ThompsonBNNAgent(BNNAgent):\n", - " def get_action(self, states):\n", - " \"\"\"\n", - " picks action based by taking _one_ sample from BNN and taking action with highest sampled reward (yes, that simple)\n", - " This is exactly thompson sampling.\n", - " \"\"\"\n", + "def train_with_reward(env, agent, reward_module, n_episodes=100, update_reward_period=100, batch_size=100, n_iter=10):\n", + " buffer = ReplayBuffer(size=int(1e6))\n", + " \n", + " if list(reward_module.parameters()):\n", + " optimizer = torch.optim.Adam(reward_module.parameters())\n", + " else:\n", + " optimizer = None\n", + "\n", + " losses = []\n", + " s, _ = env.reset()\n", + "\n", + " for i in range(n_episodes):\n", + " done = False\n", + " \n", + " while not done:\n", + " i_s = get_state_number(s)\n", + " a = agent.get_action(i_s)\n", + " s_next, r, terminated, truncated, _ = env.step(a)\n", + " done = terminated or truncated\n", + " i_s_next = get_state_number(s_next)\n", + " \n", + " state_t = torch.tensor(s).float().view(1, -1)\n", + " action_t = torch.tensor(a).float().view(1, -1)\n", + " next_state_t = torch.tensor(s_next).float().view(1, -1)\n", + "\n", + " r_intr = reward_module.get_intrinsic_reward(state_t, action_t, next_state_t)\n", + " r += r_intr\n", + "\n", + " agent.update(i_s, a, r, i_s_next, terminated)\n", + " buffer.add(s, a, r, s_next, terminated)\n", + "\n", + " s = s_next\n", + "\n", + " if (i + 1) % update_reward_period == 0 and optimizer is not None:\n", + " \n", + " for _ in range(n_iter):\n", + " optimizer.zero_grad()\n", + " state_batch, action_batch, _, next_state_batch, _ = buffer.sample(batch_size)\n", + " \n", + " state_tensor = torch.tensor(state_batch).float().flatten(1, 2)\n", + " action_tensor = torch.tensor(action_batch).float().view(-1, 1)\n", + " next_state_tensor = torch.tensor(next_state_batch).float().flatten(1, 2)\n", + " \n", + " loss = reward_module.get_loss(state_tensor, action_tensor, next_state_tensor)\n", + " loss.backward()\n", + " optimizer.step()\n", + " losses.append(loss.item())\n", + " \n", + " fig, ax = plt.subplots(ncols=2)\n", + " ax[0].set_title('Value function after iter: %d' % i)\n", + " im = ax[0].imshow(get_all_states_value(agent))\n", + " ax[1].plot(losses)\n", + " ax[1].set_title('Random network distillation loss')\n", + " clear_output(True)\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 310, + "metadata": {}, + "outputs": [], + "source": [ + "class GoRightReward(BaseIntrinsicRewardModule):\n", + " def __init__(self):\n", + " super().__init__()\n", "\n", - " " + " def get_intrinsic_reward(self, state, action, next_state):\n", + " # " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 311, "metadata": {}, + "outputs": [], + "source": [ + "agent = QLearningAgent(\n", + " epsilon=.1, \n", + " alpha=0.5, \n", + " discount=.9, \n", + " get_legal_actions=lambda s: range(env.action_space.n)\n", + ")\n", + "\n", + "go_right = GoRightReward()\n", + "\n", + "train_with_reward(env, agent, go_right, n_episodes=500)" + ] + }, + { + "cell_type": "code", + "execution_count": 312, + "metadata": { + "scrolled": true + }, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "iteration #90\tmean reward=0.360\tmse=0.590\tkl=0.038\n" - ] - }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYQAAADnCAYAAAAeqiGTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAdDUlEQVR4nO3de5hddX3v8fcnNyLhEjAKSBCx4iV6VCyCVk9LC2pAH7DW0tBHEQ821YpHhdqD2gd7qLTq8YIerYqC3FSkeDmpTY14wTtIkIhCRCOCJNwM96skM5/zx1oT9kz2zKyZvfbea898Xs+znuxZ+zdr/VaSvb9r/S7fn2wTERExp98ViIiIZkhAiIgIIAEhIiJKCQgREQEkIERERGlevysQETETvORPF/n2O4Yqlb3iqt+vsb28y1WasgSEiIgabL5jiMvWLK1Udv5ev17S5epMSwJCREQtzJCH+12JjiQgRETUwMAwgz3RNwEhIqImw+QJISJi1jNmS5qMIiLCwFCajCIiAtKHEBERlE8IA549OgEhIqImg92DkIAQEVEL4/QhREQE2LBlsONBAkJERD3EEOp3JTqSgBARUQMDw3lCiIgIIE8IERExMjEtASEiYtYzsMWDveZYAkJERA2MGBrwRSgTECIiajLswW4yGuxwNiAkvVDSDyXdLekOST+Q9FxJx0n6/hSO8wRJlpRAHtEwI30IVbamyhdLl0naBfgq8AbgQmAB8N+B3/ezXhFRNzE04H0Ig137wfBkANuftz1k+0HbXwe2AJ8Ani/pPkl3AUh6qaQrJd0j6UZJ/9RyrO+Wf95V/s7zy9/5H5LWS7pT0hpJ+/bs6iICGFkxbU6lramaW7OZ45fAkKRzJB0uaTcA2+uB1wM/sr2T7cVl+fuBY4HFwEuBN0h6efneH5d/Li5/50eSjgLeAbwCeAzwPeDz3b+siGhli4c9t9LWVAkIXWb7HuCFFDcQnwJ+J2mVpD3GKX+J7Z/ZHrZ9FcWX+59McIrXA/9qe73trcC/AM/OU0JE7w2jSttkJC2XdK2kDZJObvP+4yV9u2xNuErSEXXUPwGhB8ov6+NsLwWeATwOOL1dWUkHl//Qv5N0N8UX/pIJDr8v8GFJd5XNTncAAvau8xoiYmJFp/KcSttEJM0FPgYcDiwDjpG0bEyxfwQutH0AsAL4tzquIQGhx2z/AjibIjC0y3zyOWAVsI/tXSn6GUZuKdqVvxH4W9uLW7ZH2f5h/bWPiPEVncpVtkkcBGywfZ3th4ELgKPGlDGwS/l6V+CmOq4gAaHLJD1V0kmSlpY/7wMcA1wK3AoslbSg5Vd2Bu6w/ZCkg4C/bnnvdxRrcDyxZd8ngLdLenp5/F0l/WX3rigi2plip/ISSWtbtpUth9qb4kZvxEa2f+L/J+BVkjYCq4E31XENGXbaffcCBwMnSloM3EUxDPVtwEPA1cAtkoZtLwH+DviApI8C36EYqroYwPYDkk4DfiBpPrDc9pcl7QRcUPYb3A1cDPx77y4xIgCGqk9M22z7wA5OdQxwtu0PlKMNz5P0DNsdLdqWgNBltjcBR09Q5KVjyl8EXDTB8U4BThmz7zzgvA6qGREdMmKLa/lK3QTs0/Lz0nJfq+OB5QDlaMOFFH2Nt3Vy4jQZRUTUoK5OZeByYH9J+5XNySso+hVb/RY4FEDS04CFFE3KHckTQkREDYym0mQ0/nHsrZJOANYAc4GzbF8t6VRgre1VwEnApyS9lSIWHWe74+V5EhAiImpS1yxk26spOotb953S8voa4AW1nKxFAkJERA1sBj6XUU8DwgLt4IUs6uUpYxZ5iPt52L9vbirJLpNkYH/bG2o+7h4Uo9YOAM6wfVKdx5/k3PcBz7R9Xa/OOV1Fp3Jz01JU0dOAsJBFHKxDe3nKmEUu8zf7XYWOSPoa8OPWpoFy/1HAJ4GlZXqSXlsJbAZ2qaOdejySLgHOt/3pkX22d+rW+bph0BfIGezaR8ws51BMNhr7lPNq4LN9CgZQpEe5ppvBYCYwYtjVtqbqKCBMloApIqbkK8CjKdbLAKDMjvsy4FxJB0n6UZm36mZJHx0zy52W37tE0utafh61GFM5g/7icsGmayW1nSsj6WzgNcA/lCnXD5N0tqR3t5Q5pJwxO/Lz9ZL+vky6drekL5Tj5EfeP0rSujLF+6/L75HTyuv+aHmej5ZlLelJ5etdJZ1b5vm6QdI/SprTen2S3l+mgf+NpMOr/9XXo6Zhp30z7ZpVTMAUERXZfpBiZvqxLbuPBn5h+6fAEPBWiglIz6cYh/53Uz2PpEUUs9k/BzyWMjlau8+v7eOAzwLvK1Ouf6PiaY6mmDi1H/BM4Ljy3AcB51LM1F9MkdL9etvvpEjdfkJ5nhPaHPP/UuTteSJFBuBjgde2vH8wcC3F38/7gDPbPG11jYFhz6m0NVUnNauSgCkipuYc4JUtd9THlvuwfYXtS21vtX09Rb/CRKnRx/Myii/hz5THuhL4IlBnDqyP2L7J9h3AfwDPLvcfTzGu/uIyxfumMuHjhMob0BXA223fW17/Byia00bcYPtTtoco/s72Atqmme+OastnztQlNNslYDp4bKEyadNKgIXs2MHpImY+29+XtBl4uaTLKW68XgEg6cnAB4EDgR0pPr9XTOM0+wIHl+nSR8yj3vQnt7S8foAi5TsUKRlWb198UkuA+cANLftuYHTSt23nLPN+AfSsU9qQUUaTsX0GcAbALto9nVIRkzuX4sngKcAa27eW+z8OXAkcY/teSW8BXjnOMe6HUXdge7a8vhH4ju0XTbN+Ex17MjcCfzDOexN9P2ymWHZ2X+Cact/j2T7HT9/YanRzUBWd1L5KAqaImLpzgcOAv6FsLirtDNwD3CfpqcAbJjjGOuAVknYsO2WPb3nvq8CTJb1a0vxye26ZE6eKdcARknaXtCfwloq/B3Am8FpJh0qaI2nv8lqgSAf/xHa/VDYDXQicJmnnMrPvicD5Uzh319W0HkLfdFKzKgmYImKKyvbxHwKLGP2Z+nuK9THupViO9QsTHOZDwMMUX7LnUHQMjxz/XuDFFJ/ZmyiaWt4L7FCxiucBPwWuB74+ST1Gsf1jio7gD1Gkav8OxV0/wIcp+k/ulPSRNr/+Joqnk+uA71N0ip9V9dzdVqyHUM8Smv2iToYWq1jH83QeScB02kTld9HuzsS06JbL/E3u8R3N/bTFjPa4p+/m4y84pFLZdz/zK1d0uB5CV3TUh9AuAVNExGxUDDsd7PuRJLeLiKhBchlFRMQ2daW/7pcEhIiIGhTpr9NkFDGrLZi/yAsXLp603PC8wb57nO3uv2vjZtuPmahM+hAiZrmFCxfz3APfOGm5h3Zvm4cuBsQPv/S2GyZ6v8h2OthBf7BrH9ElyeQbU1WkrphTaWuqPCFEjNGSyfdFFDm6Lpe0qlzHNmIceUKImImSyTemZdBnKucJIWJ7k2bybc3iu8MOu/auZtFYGWUUMUuNyuK7897J4hsAA99klIAQsb1k8o0pG1lTeZAlIERsb1smX4pAsIIiy2jEuAxsHfAnhMGufUQX2N4KnACsAdYDF9q+ur+1ikFQ15rKVYY9Szpa0jWSrpb0uTrqnyeEiDamlMn3vgeZ850rJy/359utMBszietpMqoy7FnS/sDbgRfYvlPSYzs+MXlCiIioRY0L5FQZ9vw3wMds3wlg+7Y6riEBISKiJsPlU8JkG7BE0tqWbWXLYdoNe957zKmeTLEM6g8kXSppeR31T5NRREQNprhAzuYOV0ybB+wPHEIxCu67kv6b7bs6OOb0nxAk7SPp2y2dGm/upCIREYPMiK3Dcyptk6gy7HkjsMr2Ftu/AX5JESA60kmT0VbgJNvLgOcBb5S0rNMKRUQMqpr6ELYNe5a0gGLY86oxZb5C8XSApCUUTUjXdVr/aTcZ2b4ZuLl8fa+k9RTtXEkAFhGzj+tZD8H2Vkkjw57nAmfZvlrSqcBa26vK914s6RpgCHib7ds7PXctfQiSngAcAFzW5r1tOV8WsmMdp4uIaJwp9iFMfKw2w55tn9Ly2sCJ5VabjgOCpJ2ALwJvsX3P2PdH5XzR7sn5EhEz1qxOXSFpPkUw+KztL9VTpYiIwWPE0OQdxo027YAgScCZwHrbH6yvShEz06L/uKJSubtWVBuNOP/+PHA3TZPXOqiik3D2AuDVwJ9JWlduR9RUr4iIgWJPaWJaI3Uyyuj7MODhMKINSfsA5wJ7UPQVnmH7w/2tVQwCN/jLvorMVI7Y3sgcm59I2hm4QtLFWVM5Jtbsu/8qEhAixsgcm5iuPCFEzGATzbGJaGXD0HACQsSMNNEcm0y4jHYGfZRRAkJEG5PNscmEyxjLpMkoYsbJHJuYnsHvVB7saXUR3ZE5NjEtdrWtqfKEEDHGlOfYSGj+ggoHHq50uN2+/LNK5W499pmVygEsuqXauaMzaTKKiIhylNFgN7okIERE1KTJzUFVJCBERNQkTUYREYFRAkJERBQGvMUoASEiohYGJ3VFRERA+hAiIqI06KOMOh40K2mupCslfbWOCkVEDKKRXEZVtqaq4wnhzcB6YJcajhURMZgMNPjLvoqOAoKkpcBLgdOAE2upUcSAkYTmV/goqeKXRcV2hz0v+EW14wG/Xfm0SuV2++VQ5WPG9ga9yajTJ4TTgX8Adh6vQPLGR8TsoIEfZTTtPgRJLwNus33FROVsn2H7QNsHzmeH6Z4uoufSPxZT5orbJCQtl3StpA2STp6g3F9IsqQDa6h9R53KLwCOlHQ9cAFFquDz66hUREOM9I9FTM71dCpLmgt8DDgcWAYcI2lZm3I7U/wfrW1512kHBNtvt73U9hOAFcC3bL+qropF9FNL/9in+12XGCD1PCEcBGywfZ3thyluuI9qU+6fgfcCD9VRdcgCORHjOZ2if6ztQgKSVkpaK2ntw67t8xgDTxW3Ce0N3Njy88Zy3yNnkZ4D7GP7P2updqmWgGD7Etsvq+NYEf1WpX+stW9sgRb2sHbRaMMVN1gyckNRbiurnkLSHOCDwEn1Vj4zlSPaGekfOwJYCOwi6fw0icaEpjYPYbPt8TqCNwH7tPy8tNw3YmfgGcAlxfLf7AmsknSk7bVTqvMYaTKKGCP9YzFdNa2pfDmwv6T9JC2g+D+46pFz+G7bS2w/ofw/einQcTCABISIiPrU0KlseytwArCGYpTbhbavlnSqpCO7VnfSZBQxIduXAJdMWEhCC+bXd1JVvE9z2/7utvY959eVym140xMrlXvs2urnnlVqSl1hezWwesy+U8Ype0gtJyUBISKiNprlqSsiIgKKp4MBT12RgBARUZc8IUREBJCAEBERpQSEiIiY9QvkRETEIzLKKCIiCgkIEREBeUKICAl2mHw1QFVcU9kVF+aterypHPNJZ2ysVO6a/7VXpXJLLx7sNvUpSx9CRERUXR6zyZLcLqINSYslXSTpF5LWS3p+v+sUA6CmNZX7paOAkA9NzGAfBr5m+6nAs8jaylGBhqttTdVpk9HIh+aVZd7uHWuoU0RfSdoV+GPgOIByXduH+1mnGBANvvuvYtpPCC0fmjOh+NDYvqumekX0037A74DPSLpS0qclLWotMGpN5eEH+1PLaBS5+tZUnTQZTfqhgdEfnC38voPTRfTMPOA5wMdtHwDcD5zcWmDUmspzHtWPOkYTWdW2huokIEz6oYHRH5z5TD40L6IBNgIbbV9W/nwRxf/1iInN4k7lfGhiRrJ9C3CjpKeUuw4FruljlWJADHqT0bQ7lW3fIulGSU+xfS350MTM8ibgs+VgieuA1/a5PtF0bvYIoio6HWWUD03MSLbXAQdWKjxHaGF9zaHdaGGuPKu54ozmp51+e6VyG/73TpXK7XHhwkrlGq/Bd/9VdBQQpvShiYiY6WZzQIiIiEc0uX+giqSuiIgIIE8IERH1GfAnhASEiIg6ZJRRRERsM+BPCOlDiIiogahvYpqk5ZKulbRB0nYZICSdKOkaSVdJ+qakfeu4hgSEiIi61JC6QtJc4GPA4cAy4BhJy8YUuxI40PYzKbJEvK+O6icgRETUob5spwcBG2xfV6ZevwA4atSp7G/bfqD88VJgaR2XkD6EiE7NmYNrnKk8k/zBv1bLcPzQB+6qVG7rv+3ZQW16oHqn8hJJa1t+PsP2GeXrvYEbW97bCBw8wbGOB/6r8pknkIAQEVGTKUxM22y74ywPkl5FkS3iTzo9FqTJKKItSW+VdLWkn0v6vKQZkmwnuqqe9NebgH1afl5a7htF0mHAO4Ejbdey2EwCQsQYkvYG/idFp90zgLnAiv7WKhqvajCYPCBcDuwvab8ycegKYFVrAUkHAJ+kCAa31XUJaTKKaG8e8ChJWyjWCr+pz/WJAVBHLiPbWyWdAKyhuBk5y/bVkk4F1tpeBfwfYCfg38tMtr+1fWSn505AiBjD9iZJ7wd+CzwIfN3211vLSFoJrARYOG+X3lcymqmmiWm2VwOrx+w7peX1YfWcabQ0GUWMIWk3imF++wGPAxaVnXfbjFpTed6O/ahmNJCGq21NlYAQsb3DgN/Y/p3tLcCXgD/qc52i6errQ+ibBISI7f0WeJ6kHVU00B4KrO9znaLhNIWtqToKCBmaFzOR7cso0gH8BPgZxefkjAl/KQIG/glh2p3KLUPzltl+UNKFFMOjzq6pbhF9Y/tdwLsqFZbwoxZ0t0IN44prNKviGs07vKNax/xzPnF5pXIAP373cyuXrcugr5jW6SijDM2LiBgx4AFh2k1GtjcBI0PzbgbuHjs0D4rheZLWSlq7hVom00VENI9n8SijKkPzYPTwvPkkAVhEzGAD3ofQSadyhuZFRLSoa4GcfukkIGRoXkREqwF/Qph2p7LtyySNDM3bSrGCT4bmRcSs1eS7/yo6GmU0paF5EREzmZnKAjmNlOR2ERE1ELP8CSEiIlokIEREBFSfmd1UCQgRHfIcMbTj/H5Xo5kqprig4hfpVSc+q/KpTz7znErl3vO211Q+5oQaPoKoigSEiIiaDHofQtJfx6wl6SxJt0n6ecu+3SVdLOlX5Z+79bOOMVhmbeqKiBngbGD5mH0nA9+0vT/wzfLniGoGfGJaAkLMWra/C9wxZvdRwEjj8znAy3tZpxhgFdNWNLlZKX0IEaPtYfvm8vUtwB7tCklaCawEWLjDrj2qWjReg7/sq8gTQsQ4bI/7gD8qi++8RT2uWTTRyMS0PCFEzBy3StrL9s2S9gJu63eFYnBouMHf9hXkCSFitFXAyMD01wD/r491iUFStUO5wTEjTwgxa0n6PHAIsETSRopEje8BLpR0PHADcHT/ahiDpslDSqtIQIhZy/Yx47x16JSOM1ds3SkzlZvm/W/cbgHHtr73mU9WKjf3SxUK1XT3L2k58GFgLvBp2+8Z8/4OwLnAHwK3A39l+/pOz5smo4iImtTRqSxpLvAx4HBgGXCMpGVjih0P3Gn7ScCHgPfWUf8EhIiIOpgiJ1OVbWIHARtsX2f7YeACivkxrVrny1wEHFquXNmRSQNCpvdHRFQzhdQVSyStbdlWthxmb+DGlp83lvtoV8b2VuBu4NGd1r/KE8LZZHp/RMSEpjgPYfPIPJZya8Tyw5MGhEzvj4iooGpz0eRNRpuAfVp+Xlrua1tG0jxgV4rO5Y5Mtw+h0vR+KKb4jzwWbeH30zxdRETz1TRT+XJgf0n7SVoArKCYH9Oqdb7MK4FvlTPrO9LxsFPblsa/xPJR6AyAXbR7g6dkRER0qIZvONtbJZ0ArKEYdnqW7aslnQqstb0KOBM4T9IGihacFZ2fefoBIdP7IyLGqCtPke3VwOox+05pef0Q8Jf1nO0R020yyvT+iIhWBoZcbWuoSZ8QMr0/YmL33bNp83fWnHxDm7eWAJt7XZ8umCnXAW2uZe5elX9338kKNDmTaRWTBoS6pvdHzFS2H9Nuv6S1tg/sdX3qNlOuA3pwLZ336/ZVchlFY625ad2Uyh/0kge6U5GIimb8E0JERFTQ8NTWVSQgRHRPI2af1mCmXAd08VoEqMEdxlUkIER0SVPSEXRqplwHdP9alD6EiIhIk1FERJQq5SlqtKyHEFEzScslXStpg6SBzgQs6XpJP5O0TtLaftdnKvqRur+mXEZ9k4AQUaOKq10Nmj+1/ewBnItwNr1O3V9PttO+SUCIqFeV1a6iB3qeut/FKKMqW1MlIETUq8pqV4PEwNclXTFmVa9BVTl1/7S44tZQ6VSOiIm80PYmSY8FLpb0i/LOe+BNlrp/OgZ92GmeECLqVWW1q4Fhe1P5523AlymaxAbZrWXKfrqSuj99CBHRospqVwNB0iJJO4+8Bl4M/Hzi32q87qXuNzBccWuonjYZ3cudm7/hi5qYJng2n7+x1z6FtMQjJk1P3G3jrXbV52pN1x7AlyVB8V3xOdtf62+Vqut16n7hgW8y6mlAaGqa4Nl8/tl87d3SbrWrQWT7OuBZ/a7HdPUldf9wg2//K0inckREHUaajAZYAkJERE3SZFSPfmdTnM3nn83XHlGvBITO9Tu97mw+/2y+9oh6NXtIaRWNCAgREQPPQIPTUlSRgBARUZNB70Po6cS0ydICS9pB0hfK9y+T9IQaz72PpG9LukbS1ZLe3KbMIZLuLlP9rpN0So3nnzCNsAofKa/9KknPqfHcT2m5pnWS7pH0ljFlar32TlIPS3pNWeZXkl7TrkxEI2WmcjUV0wIfD9xp+0nAh4D31liFrcBJtpcBzwPeOE5a4u+VqX6fbfvUGs8PE6cRPhzYv9xWAh+v66S2rx25JuAPgQco0hCMVee1n800Ug9L2p1iAtHBFGkS3lV3zvqIrjAw7GpbB6rcWEl6tqQflTe/V0n6qyrH7uUTQpW0wK2paS8CDlU5TbJTtm+2/ZPy9b3AepqVhfIo4FwXLgUWj+RcqdmhwK9tt5sxXpsOUg+/BLjY9h227wQuZvvAEtFAFZ8OOn9CqLKmwwPAsbafTvH5OV3S4skO3MuAUCUt8LYytrcCdwOPrrsiZVPUAcBlbd5+vqSfSvovSU+v8bSTpRHuVdrkFcDnx3mvW9c+okrq4ZmWPjpmk94EhElvrGz/0vavytc3USTxa5spotWs61SWtBPwReAttu8Z8/ZPgH1t3yfpCOArFE04deh7GuEy2dqRwNvbvN3Na99ON1IPR/SVgaGeTFWe0poOkg4CFgC/nuzAvXxCqJIWeFsZSfOAXYHb66qApPkUweCztr809n3b99i+r3y9GpgvaUkd566QRrgXaZMPB35i+9Y29evatbeoknp4RqWPjtnE4OFqW5Fwb23LNqrVQNI3JP28zTaqmd32hEvulJ+z84DX2p40WvXyCWFbWmCKD/gK4K/HlBlJTfsj4JXAt8oL7ljZF3EmsN72B8cpsydwa3n3ehBFwOw4IJWpg+fYvlePpBEe22m7CjhB0gUUHap3t9wF1OUYxmku6ta1jzHy7/sexk89vAb4l5aOshfT/okmonmqf11tniipo+3DxntP0q2S9rJ98wQ3VkjaBfhP4J1lv+SkehYQxksLLOlUYK3tVRRf2OdJ2kDRIbmixiq8AHg18DNJ68p97wAeX9bvExRB6A2StgIPAitqCkht0whLen3LuVcDRwAbKDqEXlvDebcpA9GLgL9t2dd6/lqvXVNIPSzpQOD1tl9n+w5J/0xxAwFwqu2xndMRzTMyyqj7Jr2xKpuHv0wxUOWiqgdWTTfgERGz2q4L9vAf7VHtHvZrGz9yxXTTvkt6NHAhxc3sDcDR5Y3UthsrSa8CPgO0rsVxnO11Ex171nUqR0R0TQ9usG3fTps1HWyvBV5Xvj4fOH+qx05AiIiogw1DQ/2uRUcSECIi6jLgTfAJCBERdUlAiIgI6DxPUb8lIERE1MFQYe5XoyUgRETUpTepK7omASEiog42DCcgREQEpFM5IiIKzhNCRERsWyBngCUgRETUoXfJ7bomASEiogYGnNQVERFRLI+ZPoSIiACcJqOIiAAG/gkhC+RERNRA0teAquuQb7a9vJv1mY4EhIiIAIqF1CMiIhIQIiKikIAQERFAAkJERJQSECIiAoD/Dw+/o8WlaUwFAAAAAElFTkSuQmCC", "text/plain": [ - "" + "
" ] }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Q(s,a) std: 0.000;0.028;0.277;0.000;0.044;0.059;0.063;0.093;0.000;0.018\n", - "correct 2\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] + "metadata": { + "needs_background": "light" }, - "metadata": {}, "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:32: FutureWarning: pd.ewm_mean is deprecated for ndarrays and will be removed in a future version\n" - ] } ], "source": [ - "thompson_agent_rewards = train_contextual_agent(ThompsonBNNAgent(state_size=state_size, n_actions=n_actions),\n", - " batch_size=10, n_iters=N_ITERS)" + "test_agent(agent, greedy=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2.3 Curiosity-driven Exploration" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 313, "metadata": {}, "outputs": [], "source": [ - "class BayesUCBBNNAgent(BNNAgent):\n", - " q = 90\n", - "\n", - " def get_action(self, states):\n", - " \"\"\"\n", - " Compute q-th percentile of rewards P(r|s,a) for all actions\n", - " Take actions that have highest percentiles.\n", - "\n", - " This implements bayesian UCB strategy\n", - " \"\"\"\n", - "\n", - " " + "class MLP(nn.Module):\n", + " def __init__(self, input_size, hidden_size, output_size):\n", + " super().__init__()\n", + " self.layers = nn.Sequential(\n", + " nn.Linear(input_size, hidden_size),\n", + " nn.ReLU(),\n", + " nn.Linear(hidden_size, output_size)\n", + " )\n", + " \n", + " def init_weights(tensor):\n", + " if isinstance(tensor, nn.Linear):\n", + " nn.init.xavier_uniform_(tensor.weight)\n", + " \n", + " self.layers.apply(init_weights)\n", + " \n", + " \n", + " def forward(self, x):\n", + " return self.layers(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.3.1 Uncertainty with forward dynamics" + ] + }, + { + "cell_type": "code", + "execution_count": 319, + "metadata": {}, + "outputs": [], + "source": [ + "class ForwardDynamics(BaseIntrinsicRewardModule):\n", + " def __init__(self, states_size, actions_size, hidden_size, alpha=.1):\n", + " super().__init__()\n", + " self.module = MLP(\n", + " actions_size + states_size,\n", + " hidden_size,\n", + " states_size\n", + " )\n", + " self.alpha = alpha\n", + " self.mean_reward = 0\n", + " \n", + " def forward(self, s, a):\n", + " sa = torch.cat([s, a], dim=-1)\n", + " return s + self.module(sa)\n", + "\n", + " def get_intrinsic_reward(self, state, action, next_state):\n", + " with torch.no_grad():\n", + " r = # \n", + " r_centered = r - self.mean_reward\n", + " self.mean_reward = self.alpha * (r) + (1 - self.alpha) * self.mean_reward\n", + " return r_centered\n", + "\n", + " def get_loss(self, state_batch, action_batch, next_state_batch):\n", + " # " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 320, "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "iteration #90\tmean reward=0.630\tmse=0.354\tkl=0.047\n" - ] - }, { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Q(s,a) std: 0.067;0.027;0.093;0.069;0.014;0.148;0.173;0.026;0.043;0.101\n", - "correct 5\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] + "metadata": { + "needs_background": "light" }, - "metadata": {}, "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:32: FutureWarning: pd.ewm_mean is deprecated for ndarrays and will be removed in a future version\n" - ] } ], "source": [ - "ucb_agent_rewards = train_contextual_agent(BayesUCBBNNAgent(state_size=state_size, n_actions=n_actions),\n", - " batch_size=10, n_iters=N_ITERS)" + "agent = QLearningAgent(\n", + " epsilon=.1, \n", + " alpha=0.5, \n", + " discount=.9, \n", + " get_legal_actions=lambda s: range(env.action_space.n)\n", + ")\n", + "\n", + "forward_dynamics = ForwardDynamics(\n", + " np.prod(env.observation_space.shape), \n", + " 1, \n", + " 16\n", + ")\n", + "\n", + "train_with_reward(env, agent, forward_dynamics, n_episodes=2000, update_reward_period=100, batch_size=100, n_iter=25)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 321, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAHVCAYAAADsApjCAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvAOZPmwAAIABJREFUeJzs3Xt8z3X/x/HHZ+exzWEHcz4OwxhmM+eIVJSihIRUSCpJCFEJoVwl6UqJHEJS5BRRTmNsM+Qwhxmb02ZjBztvn98frsuPy2nYfIfn/Xa7btv3+30fnt9tuvba+/N5vw3TNBERERERERGR/Gdl6QAiIiIiIiIiDyoV3SIiIiIiIiIFREW3iIiIiIiISAFR0S0iIiIiIiJSQFR0i4iIiIiIiBQQFd0iIiIiIiIiBURFt4iIiIiIiEgBUdEtIiIiIiIiUkBUdIuIiIiIiIgUEBtLTezm5mZWqlTJUtOLiIiIiIiI3LHQ0NBzpmm636qdxYruSpUqERISYqnpRURERERERO6YYRjH89JOl5eLiIiIiIiIFBAV3SIiIiIiIiIFREW3iIiIiIiISAGx2D3d15OVlUVMTAzp6emWjiIPMAcHB8qVK4etra2lo4iIiIiIyAOuUBXdMTExODs7U6lSJQzDsHQceQCZpkl8fDwxMTFUrlzZ0nFEREREROQBV6guL09PT8fV1VUFtxQYwzBwdXXV1RQiIiIiInJPFKqiG1DBLQVOP2MiIiIiInKvFLqiW0RERERERORBoaL7f5w9e5bu3btTpUoVGjZsSGBgIL/++muBzDV79mzeeOONPLcfO3YsZcuWxdfXl5o1azJgwAByc3MB6N27N2XLliUjIwOAc+fOUalSJQCioqIwDINp06ZdHuuNN95g9uzZ+fZeRERERERE5Foquq9gmiadOnWiRYsWREZGEhoaysKFC4mJibmmbXZ2tgUSwuDBgwkPD2f//v3s3buXjRs3Xn7N2tqaWbNmXbefh4cHX3zxBZmZmfcqqoiIiIiIyEOvUO1efqUPf9/H/lNJ+TpmrTIujOlY+4avb9iwATs7O/r373/5uYoVKzJo0CDg0sr00qVLSUlJIScnh40bNzJ58mQWL15MRkYGzzzzDB9++CEA8+bN48svvyQzM5OAgAC+/vprrK2t+eGHH5gwYQLFixenXr162Nvbk5ycTN26dTl06BC2trYkJSVRr169y4+vJzMzk/T0dEqUKHH5ubfffpupU6fy6quvXtPe3d2dpk2bMmfOnOu+LiIiIiIiIvlPK91X2LdvHw0aNLhpm7CwMJYsWcLGjRtZu3Ythw8fZseOHYSHhxMaGsqmTZs4cOAAixYtYuvWrYSHh2Ntbc38+fM5ffo0Y8aMYevWrWzZsoX9+/cD4OzsTKtWrVi5ciUACxcu5Nlnn71uwT116lR8fX0pXbo01atXx9fX9/JrFSpUoFmzZsydO/e62YcNG8aUKVPIycm50y+RiIiIiIiI3IZCu9J9sxXpe2XgwIFs2bIFOzs7du7cCUDbtm0pWbIkAGvXrmXt2rXUr18fgJSUFA4fPsyePXsIDQ2lUaNGAKSlpeHh4UFwcDCtWrXC3d0dgK5du3Lo0CEAXnnlFSZNmkSnTp344YcfmDlz5nUzDR48mHfffZesrCy6dOnCwoULeeGFFy6/PmLECJ5++mmefPLJa/pWqVKFgIAAFixYkE9fIREREREREbkZrXRfoXbt2oSFhV1+PH36dNavX09cXNzl54oWLXr5c9M0GTFiBOHh4YSHh3PkyBH69u2LaZr06tXr8vMRERGMHTv2pnM3bdqUqKgo/v77b3JycqhTp85N29va2tK+fXs2bdp01fNeXl74+vqyePHi6/Z7//33+fTTTzFN86bji4iIiIiIyN1T0X2F1q1bk56ezowZMy4/l5qaesP2jz32GLNmzSIlJQWAkydPEhsbS5s2bViyZAmxsbEAJCQkcPz4cQICAti4cSPx8fFkZWXx888/XzXeSy+9RPfu3enTp88ts5qmydatW6lateo1r40cOZIpU6Zct1/NmjWpVasWv//++y3nEBERERERkbujovsKhmHw22+/sXHjRipXroy/vz+9evXi008/vW77du3a0b17dwIDA/Hx8aFLly4kJydTq1Ytxo0bR7t27ahbty5t27bl9OnTlC5dmrFjxxIYGEjTpk3x9va+arwePXpw/vx5unXrdsOM/72nu06dOuTk5PD6669f06Z27do3vTd95MiR192RXURERERERPKXYanLjP38/MyQkJCrnjtw4MA1hejDZMmSJSxbtuyGG6FJ/nnYf9ZERERERAqb+LR4nO2csbO2s3SUPDEMI9Q0Tb9btSu0G6k9bAYNGsTq1atZ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o1GjRgAMGDAAHx8fjhw5kucx6tSpQ8uWLYmPj+fDDz+kVKlSzJo1i88//xxbW1ucnZ2ZO3cu5cqV4+OPP6ZVq1aYpknHjh158skn87xSPGXKFDZv3oyVlRV169alXbt2+Pv7X74v2t/fHy8vr9v+Glwvf3Jy8m2NERgYSPv27fHx8aFUqVL4+PhQrFix67b97z3dWVlZ1K9fn379+l3Tpl69etSrV4/9+/dfd4xRo0bRsGHD28ooIiIiIiJ5k56dzpsb3iQxI5E57edQzrmcpSMVSoalLr/18/MzQ0JCrnruwIEDeHt7WyRPQRo1ahRubm433aW7MMvP/CkpKTg5OXHx4kWaNWvGnDlzqFu3bj6kvD0P6s+aiIiIiMi9kGvmMnTjUNYdX8fUR6bSpsK1ey096AzDCDVN85aXAGulW+6pvn37EhERQXp6Oi+//LJFCm4REREREbk708Ons/b4Wt5p+M5DWXDfDhXd98C4ceMsHeGu5Gd+7SguIiIiInJ/+/3o73y751ue9XqW3rV7WzpOoaeN1ERERERERCRPws6GMSZoDP6e/owKGHXLU41ERbeIiIiIiIjkQXRyNG//9TZlnMrweavPsbW2tXSk+4KKbhEREREREbmppMwk3lj/BjlmDl+1/opi9tc/hUiupXu6RURERERE5Iayc7N59+93OZF0gn+3/TeVilWydKT7ila6rxAVFUWdOnWuem7s2LFMmTLl8uMpU6ZQs2ZNfH19adSoET/++CMArVq1okaNGvj6+uLt7c2333573Tlu1q5SpUp07tz58uMlS5bQu3dvAGbPno2VlRV79uy5/HqdOnWIioq627ctIiIiIiJyXaZpMnHHRLad3sbowNH4l/a3dKT7joru2/DNN9+wbt06duzYQXh4OOvXr+fKc87nz59PeHg4W7duZdiwYWRmZl53nJu1Cw0NZf/+/dftV65cOT755JP8fVMiIiIiIiI38POhn1kUsYg+tfvwrNezlo5zXyq0l5d/uuNTDiYczNcxa5asyTD/YXfcf/z48fz999+4uLgA4OLiQq9eva5pl5KSQtGiRbG2tr7peNdrN2TIED755BPmz59/TfsOHTqwadMmIiIiqFGjxh2/DxERERERkVvZH7+fiTsm0rRMU95q8Jal49y3tNKdR0lJSSQnJ1OlSpUbtunRowd169alRo0ajB49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\n", + "image/png": "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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ - "plt.figure(figsize=(17, 8))\n", - "\n", - "plt.plot(greedy_agent_rewards)\n", - "plt.plot(thompson_agent_rewards)\n", - "plt.plot(ucb_agent_rewards)\n", - "\n", - "plt.legend([\n", - " \"Greedy BNN\",\n", - " \"Thompson sampling BNN\",\n", - " \"UCB BNN\"\n", - "])\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part 3. Exploration in MDP\n", - "\n", - "The following problem, called \"river swim\", illustrates importance of exploration in context of mdp's." + "test_agent(agent)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "\n", - "Picture from https://arxiv.org/abs/1306.0940" + "### 2.3.2 Uncertainty with reverse dynamics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Rewards and transition probabilities are unknown to an agent. Optimal policy is to swim against current, while easiest way to gain reward is to go left." + "[The paper](https://arxiv.org/pdf/1705.05363.pdf)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 322, "metadata": {}, "outputs": [], "source": [ - "class RiverSwimEnv:\n", - " LEFT_REWARD = 5.0 / 1000\n", - " RIGHT_REWARD = 1.0\n", - "\n", - " def __init__(self, intermediate_states_count=4, max_steps=16):\n", - " self._max_steps = max_steps\n", - " self._current_state = None\n", - " self._steps = None\n", - " self._interm_states = intermediate_states_count\n", - " self.reset()\n", - "\n", - " def reset(self):\n", - " self._steps = 0\n", - " self._current_state = 1\n", - " return self._current_state, 0.0, False\n", - "\n", - " @property\n", - " def n_actions(self):\n", - " return 2\n", - "\n", - " @property\n", - " def n_states(self):\n", - " return 2 + self._interm_states\n", - "\n", - " def _get_transition_probs(self, action):\n", - " if action == 0:\n", - " if self._current_state == 0:\n", - " return [0, 1.0, 0]\n", - " else:\n", - " return [1.0, 0, 0]\n", - "\n", - " elif action == 1:\n", - " if self._current_state == 0:\n", - " return [0, .4, .6]\n", - " if self._current_state == self.n_states - 1:\n", - " return [.4, .6, 0]\n", - " else:\n", - " return [.05, .6, .35]\n", - " else:\n", - " raise RuntumeError(\n", - " \"Unknown action {}. Max action is {}\".format(action, self.n_actions))\n", - "\n", - " def step(self, action):\n", - " \"\"\"\n", - " :param action:\n", - " :type action: int\n", - " :return: observation, reward, is_done\n", - " :rtype: (int, float, bool)\n", - " \"\"\"\n", - " reward = 0.0\n", - "\n", - " if self._steps >= self._max_steps:\n", - " return self._current_state, reward, True\n", - "\n", - " transition = np.random.choice(\n", - " range(3), p=self._get_transition_probs(action))\n", - " if transition == 0:\n", - " self._current_state -= 1\n", - " elif transition == 1:\n", - " pass\n", - " else:\n", - " self._current_state += 1\n", - "\n", - " if self._current_state == 0:\n", - " reward = self.LEFT_REWARD\n", - " elif self._current_state == self.n_states - 1:\n", - " reward = self.RIGHT_REWARD\n", - "\n", - " self._steps += 1\n", - " return self._current_state, reward, False" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's implement q-learning agent with epsilon-greedy exploration strategy and see how it performs." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class QLearningAgent:\n", - " def __init__(self, n_states, n_actions, lr=0.2, gamma=0.95, epsilon=0.1):\n", - " self._gamma = gamma\n", - " self._epsilon = epsilon\n", - " self._q_matrix = np.zeros((n_states, n_actions))\n", - " self._lr = lr\n", - "\n", - " def get_action(self, state):\n", - " if np.random.random() < self._epsilon:\n", - " return np.random.randint(0, self._q_matrix.shape[1])\n", - " else:\n", - " return np.argmax(self._q_matrix[state])\n", - "\n", - " def get_q_matrix(self):\n", - " \"\"\" Used for policy visualization\n", - " \"\"\"\n", - "\n", - " return self._q_matrix\n", - "\n", - " def start_episode(self):\n", - " \"\"\" Used in PSRL agent\n", - " \"\"\"\n", - " pass\n", - "\n", - " def update(self, state, action, reward, next_state):\n", - " \n", - " # Finish implementation of q-learnig agent" + "class InverseDynamics(BaseIntrinsicRewardModule):\n", + " def __init__(self, states_size, n_actions, hidden_size, alpha=0.1):\n", + " super().__init__()\n", + " self.module = MLP(\n", + " 2 * states_size,\n", + " hidden_size,\n", + " n_actions\n", + " )\n", + " self.alpha = alpha\n", + " self.mean_reward = 0\n", + " self.n_actions = n_actions\n", + " \n", + " def forward(self, s, s_next):\n", + " # \n", + " \n", + " \n", + " def get_intrinsic_reward(self, state, action, next_state):\n", + " with torch.no_grad():\n", + " r = # \n", + " \n", + " r_centered = r - self.mean_reward\n", + " self.mean_reward = self.alpha * (r) + (1 - self.alpha) * self.mean_reward\n", + " return r_centered\n", + "\n", + " def get_loss(self, state_batch, action_batch, next_state_batch): \n", + " a_pred_proba = self.forward(state_batch, next_state_batch)\n", + " a_one_hot = to_one_hot(action_batch, self.n_actions)\n", + " return -(torch.log(a_pred_proba) * a_one_hot).sum(dim=-1).mean()" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 323, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ - "def train_mdp_agent(agent, env, n_episodes):\n", - " episode_rewards = []\n", - "\n", - " for ep in range(n_episodes):\n", - " state, ep_reward, is_done = env.reset()\n", - " agent.start_episode()\n", - " while not is_done:\n", - " action = agent.get_action(state)\n", - "\n", - " next_state, reward, is_done = env.step(action)\n", - " agent.update(state, action, reward, next_state)\n", - "\n", - " state = next_state\n", - " ep_reward += reward\n", - "\n", - " episode_rewards.append(ep_reward)\n", - " return episode_rewards" + "agent = QLearningAgent(\n", + " epsilon=.1, \n", + " alpha=0.5, \n", + " discount=.9, \n", + " get_legal_actions=lambda s: range(env.action_space.n)\n", + ")\n", + "\n", + "inverse_dynamics = InverseDynamics(\n", + " np.prod(env.observation_space.shape), \n", + " env.action_space.n, \n", + " 16\n", + ")\n", + "\n", + "train_with_reward(env, agent, inverse_dynamics, n_episodes=3000, \n", + " update_reward_period=100, batch_size=100, n_iter=25)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 324, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:6: FutureWarning: pd.ewm_mean is deprecated for ndarrays and will be removed in a future version\n", - " \n" - ] - }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXsAAADnCAYAAAD/7faHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAcZElEQVR4nO3dfZRdVZnn8e+vigSSEBIgvAcBMeJEmwZXBN9GsXkxIAtc3WonjgoOPTTO0CONjoPdvXAW3fQo0+3bwKhpoYGWF2kUO+OkiTQt2ijQBIhgiNFAA0mAQAwk4TWpqmf+OKfirUrVvbvqnnvPuff+Pmudxb3n7jpnnyL3Obv22fvZigjMzKy79ZVdATMzaz0HezOzHuBgb2bWAxzszcx6gIO9mVkP2K3sCpiZdYP3vmdG/HrzYFLZ+x58dXlELGxxlUZwsDczK8CmzYPcs3xuUtkpBz0yp8XV2YWDvZlZIYLBGCq7EuNysDczK0AAQ1R3kqqDvZlZQYZwy97MrKsFwQ5345iZdbcABt2NY2bW/dxnb2bW5QIYrHAWYQd7M7OCVLfH3sHezKwQQbjP3sys20XAjurGegd7M7NiiEFUdiXG5WBvZlaAAIbcsjcz635u2ZuZdblsUpWDvZlZVwtgR1R3PSgHezOzAgRisMKL/znYm5kVZCiq241T3dtQF5H0Tkk/lbRF0mZJP5H0FklnS7pzAsc5XFJI8k3arGKG++xTtjI4aLSYpL2A7wOfAG4CpgL/Hni1zHqZWdHEYIX77Ktbs+7xeoCIuCEiBiPi5Yj4AbAD+DrwNkkvSHoeQNL7JD0gaaukdZL+R82xfpz/9/n8Z96W/8x/lLRa0nOSlks6rG1XZ2bA8EpVfUlbGRzsW++XwKCkaySdKmlvgIhYDZwH3BURe0bE7Lz8i8DHgNnA+4BPSHp//tm78v/Ozn/mLklnAn8C/C6wH/AvwA2tvywzqxUhtkd/0lYGB/sWi4itwDvJbvx/AzwraamkA8Ypf0dEPBQRQxHxIFngfnedU5wH/M+IWB0RA8BfAse4dW/WfkMoaSuDg30b5IH47IiYC7wJOBj48lhlJR0v6YeSnpW0hSyYz6lz+MOAr0h6Pu8K2gwIOKTIazCz+rIHtH1JWxkc7NssIn4BXE0W9MfKpHE9sBQ4NCJmkfXrDzcFxiq/DvjDiJhds02LiJ8WX3szG1/2gDZlK4ODfYtJeoOkT0mam78/FFgM3A1sBOZKmlrzIzOBzRHxiqTjgA/XfPYs2foIr63Z93Xgs5LemB9/lqQPtu6KzGwsVX9A66GXrbcNOB64UNJs4HmyoZj/DXgFWAU8LWkoIuYA/xn4a0mXAz8iG645GyAiXpJ0KfATSVOAhRFxi6Q9gRvzfvotwG3A37fvEs0MYLDCk6oUFV4z0cysUxz5WzPiL2+Zn1R20bwV90XEghZXaQS37M3MCjD8gLaqHOzNzAoQqNLdOA72ZmYFKevhawoHezOzAkRQ6dw4bQ32U7V77MGMdp7SesgrvMj2eLW6f0e3mKQA5kXE2oKPewDZ6K5jgSUR8akij9/g3C8AR0fEo+0652QFYkdJqRBStDXY78EMjteJ7Tyl9ZB74vayq9AUSbcC/xoRF4/afybwDWBunhKj3c4FNgF7RQuH70m6A/hWRHxzeF9E7Nmq87VClR/QVrdmZr3nGuAjkkb/dfJR4LqSAj1kKTkebmWg7waBGIq0rQxNBXtJCyWtkbRW0kVFVcqsR30P2JdsvQMA8iyppwPXSjpO0l15HqSnJF0+avY1NT93h6Q/qHk/YqGcfGb3bfliOmskfWic41wNnAV8Jk+rfZKkqyX9RU2ZEyStr3n/mKRPS3owX7Dn25L2qPn8TEkr8zTej+Rx5NL8ui/Pz3N5XjYkvS5/PUvStXneqMcl/Zmkvtrrk/RXearvf5N0avqvvhhF5cZJja2Sfi//HTUcsz/pYC+pH7gCOBWYDyyWlDajwMx2EREvk82Y/ljN7g8Bv4iInwGDwB+TJcZ7G3Ai2YzrCZE0g2yW9fXA/sAi4P+M9f2NiLOB64DL8rTa/5R4mg8BC4EjgKOBs/NzHwdcSzaDfDZZ2u7HIuJPydJzn5+f5/wxjvm/gVlk6ULeTfZ7+njN58cDa8h+P5cBV47xV1LLBDAUfUlbPamxVdJM4JPAPSn1a6ZlfxywNiIejYjtwI3AmU0cz8yyrpwP1LSEP5bvIyLui4i7I2IgIh4j68evl/56PKeTBdi/zY/1APAdoMicSl+NiCcjYjPwf4Fj8v3nAFdFxG15Gu8NeXLAuvIAuAj4bERsy6//r8m6uIY9HhF/ExGDZL+zg4AxU4m3RtqShAnLEqbG1j8HvkCWdqWhZoL9IWQZF4etZ4y0upLOlbRC0oodXonPrK6IuJPsYej7JR1J9sW/HkDS6yV9X9LTkraSrV1QL/31eA4Djh9Oi52nxv4PwIGFXETm6ZrXLwHDD1oPBR6ZxPHmAFOAx2v2Pc7ImLPznBHxUv6ybQ94A9gR/UkbMGc4LubbuTWHahhbJb2ZLDPu/0utX8tH40TEEmAJwF7axw94zBq7lqxFfxSwPCI25vu/BjwALI6IbZIuAD4wzjFeBKbXvK8N5OuAH0XEyZOsX71jN7IOOHKcz+rFh01kS3keBjyc73sNsGEC526pCDXsoqmxabK5cfLnFF8k7xpL1UzLfgPZXXrYXCr0izfrYNcCJwH/ibwLJzcT2Aq8IOkNZIvYj2cl8LuSpucPOM+p+ez7wOslfVTSlHx7i6R/l1i/lcBpkvaRdCBwQeLPAVwJfFzSiZL6JB2SXwtkKb9fO9YP5V0zNwGXSpqZZ3i9EPjWBM7dcgXls28UW2eSrYdxh6THgLcCSxs9pG0m2N8LzJN0RD4iYBHZohtm1oS8P/qnwAxGfqc+Tba+wTayJS6/XecwXwK2kwXQa8gesg4ffxtwCtl39kmy7o8vALsnVvHvgJ8BjwE/aFCPESLiX8keqn6JLB33j8ha6wBfIXte8Zykr47x439E9lfFo8CdZN1bV6Weu9WyfPaFLEtYN7ZGxJaImBMRh0fE4WRrY5wRESvqHbSpFMeSTiNbXq+f7KHLpfXK76V9wpOqrFXuidvZGpt7dgatlevgN+4d59x4QlLZvzj6e3VTHI8VWyVdAqyIiKWjyt4BfLpRsG+qzz4ilgHLmjmGmVk3yIZeFtPWGCu2jp5ZXbP/hJRjOhGamVkBnBvHzKxHOMWxmVmXy1IcV/eRkYO9WZOm9k+Laf17NS7YV91AYI1tfXXjpojYr16ZspKcpXCwN2vStP69ePuBixuWi2mpIxutipb/8rLH632eZb2sbjdOdWtmViJndLWJytIl9CVtZXDL3myUmqyDJ5PlJblX0tKIeLj+T1pvc8verNM4o6tNSkEzaFvCLXuzXY2VdfD42gJ5lsJzAfbon9m+mllleTSOWReqzeY6a+oBzuZqAJXuxnGwN9uVM7rahA2vQVtVDvZmu9qZdZAsyC8iyzZpNq4ABtyyN+scETEg6XxgOb/JOriq5GpZB3A3jlmHmUhG19ixg4H1jXt5ht55TNK5p2zcmlTOKibcjWNm1vWGFy+pKgd7M7OCuGVvZtblily8pBUmHewlHUq2MPIBZNe5JCK+UlTFzMw6SSAGhrrzAe0A8KmIuF/STOA+Sbc5f4iZ9aqu7LOPiKeAp/LX2yStJptm7mBvZr0nurQbp5akw4FjgXvG+Ow3OUSYXsTpzMwqp2v77IdJ2hP4DnBBROwyQLg2h8he2sc5RMysa3VtsJc0hSzQXxcR3y2mSmZmnScQg934gFaSgCuB1RHxxeKqZNZZ1N9H/56N16Dte+BXScfbdsqbksrN/PmzSeWsfar8gLaZ29A7gI8CvyNpZb6dVlC9zMw6SuQPaFO2MjQzGudOqPBtzGySPIfEJiu6tc/erEt5DolNghOhmXUUzyGxyXLL3qxD1ZtDYlYrAgaHHOzNOk69OSQjJgtqRgm1syrq1tE4Zl2r0RySiFgSEQsiYsHUvj3aX0GrnCDrxknZGpG0UNIaSWslXTTG5+dJeigfBXmnpPmNjulgbzaK55DY5KQNu2z0EFdSP3AFcCowH1g8RjC/PiJ+KyKOAS4DGv47dbA325XnkNikRKRtDRwHrI2IRyNiO3AjcObI84zoVpxB9odFXe6zNxtlwnNI+vrRzD0bFhva9Oukw+1112NJ5Ta+77VJ5QD2//HG5LI2eRMYjTNH0oqa90vyPGKQjfxaV/PZeuD40QeQ9F+AC4GpwO80OqGDvZlZAbLROMmdJZsiYkFz54srgCskfRj4M+CseuXdjWNmVpCCunE2AIfWvJ+b7xvPjcD7Gx3Uwd7MrCAFjca5F5gn6QhJU4FFwNLaApLm1bx9H9Awy567cczMChCkDatseJyIAUnnA8uBfuCqiFgl6RJgRUQsBc6XdBKwA3iOBl044GBvZlaYolZniohlwLJR+y6uef3JiR7Twd7MrAgB4XQJZmbdz4nQzMx6QMJIm9I0PRpHUr+kByR9v4gKmZl1oiJz47RCES37TwKrgcaLcJqZdasAurUbR9JcsjGel5JN2zXrPUNDxEsvNyzW97rDkw4XTz6TVG7/u9LSLwCsO/PApHKH/sPTyce0XVW5G6fZlv2Xgc8AM8crMCLvN9ObPJ2ZWVWp0qNxJt1nL+l04JmIuK9eudq831PYfbKnM2s7P4+yCYvErQTNtOzfAZyRp37dA9hL0rci4iPFVM2sdH4eZemi2kMvJ92yj4jPRsTciDicLHfDPzvQW7eoeR71zbLrYh2kwi17J0IzG9uXyZ5HDY31oaRzJa2QtGJ7vNLWilmVKXFrv0KCfUTcERGnF3Ess7KlPI8asQatvAat5YYStxJ4Bq3Zrvw8yiau4uPs3Y1jNoqfR9lkFbR4SUu4ZW9mVpQunlRl1tUi4g7gjrqFJNgt4au0cVPSOQfe8JqkclMeS19E/KC70iY0/vqtBySV2/duL2A+pgp34zjYm5kVRG7Zm5l1uRBUOF2Cg72ZWVHcsjcz6wEO9mZmPcDB3sysy1V8UpWDvZlZQTwax8ysFzjYm5l1P7fszbpZn9D0hMyXSuvPnbIubabtS0fPTSoHMH1N2rq2+25OW03u5SP3TSo37ZH0dXK7gvvszcy6XIkLk6Rw1kuzMUiaLelmSb+QtFrS28quk3WAbl2pyl8I62JfAW6NiDcAv022Fq1ZXRpK28rQbMveXwjrOpJmAe8CrgSIiO0R8XyplbLOUFDLXtJCSWskrZV00RifXyjpYUkPSrpd0mGNjjnpYO8vhHWxI4Bngb+V9ICkb0qaUVtgxBq0gy+XU0urFEX6Vvc4Uj9wBXAqMB9YLGn+qGIPAAsi4mjgZuCyRvVrpmXf8AuRV3znl2IHrzZxOrO22Q14M/C1iDgWeBEY0boasQZt/7Qy6mhVFErb6jsOWBsRj0bEduBG4MwRp4n4YUS8lL+9G2g4NKuZYN/wC5FXaueXYgppw7rMSrYeWB8R9+Tvbyb7t25WXzHdOIcA62rer8/3jecc4B8bHbSZYO8vhHWliHgaWCfpqHzXicDDJVbJOsQEunHmDPd45Nu5kzqf9BFgAfC/GpWd9Dj7iHha0jpJR0XEGvyFsO7yR8B1kqYCjwIfL7k+VnUxoZE2myJiwTifbQAOrXk/N983gqSTgD8F3h0RDfvIm51U5S+EdaWIWEnWYmpMfcTuU4s7+dQpScWm//LZ5ENuffNBSeVmPpR2zGmPP59U7rm37J9Ubu9702b4Vl4xY+jvBeZJOoIsyC8CPlxbQNKxwDeAhRGR9MtrKthP6AthZtbtCgj2ETEg6XxgOdAPXBURqyRdAqyIiKVk3TZ7An+vLA3HExFxRr3jOl2CmVlBikqEFhHLgGWj9l1c8/qkiR7T6RLMzHqAW/ZmZkWpcCI0B3szsyJMbDRO2znYm5kVxS17M7PuJrxSlZlZb3CwNzPrcgkZLcvkYG/WrD4R0xsn+YvENWj7tg8klZtIXNnz0W1px0ycCTywd1qmz9SZsdvnzk4qN3X980nlSuMHtGZm3a/KLXtPqjIbg6Q/lrRK0s8l3SBpj7LrZB2gW9egNetGkg4B/ivZSkBvIstPsqjcWlnlpQb6koK9u3HMxrYbME3SDmA68GTJ9bEO4G4csw4SERuAvwKeAJ4CtkTED2rLjFiDduClsQ5jvajCLXsHe7NRJO1NtubnEcDBwIx8RaCdRqxBu9v0MqppFaShtK0MDvZmuzoJ+LeIeDYidgDfBd5ecp2s6ireZ+9gb7arJ4C3SpqubGWIE4HVJdfJKk4T2MrQVLD38DTrRhFxD3AzcD/wENn3ZEmplbLOUOGW/aRH49QMT5sfES9LuolseNrVBdXNrDQR8Tngc0ll+8TgtMbrxsZuiW2rF9KKxczGs3aHaSCto3go4ToApmzcmlRuyzH7JZWbtTJt7duhPdNm7gL0vfByctmiVHk0TrNDLz08zcxsWIWD/aS7cVKGp8HIIWo7eHXyNTUzq7Lo0tE4KcPTYOQQtSmk/9lpZtZxKtxn38wDWg9PMzOroUjbytBMsPfwNDOzWhVu2U/6AW1E3CNpeHjaAPAAHp5mZj2sa0fjTGR4mplZVwu8eImZWbfzguNmZr3Cwd7MrPspqhvtHezNmhR9YnB6469S3/a0Dt1XDkxLmbzby4NJ5QCGpqYNvNNAYrDab2ZSsVk/25RUbnDvGUnl+p97MakcwKuv2Tup3O5PPJd8zLpKHGmTwsHezKwgVe6zd4pj61mSrpL0jKSf1+zbR9Jtkn6V/zeteWhGcekSJC2UtEbSWkkXjfH5uyTdL2lA0gdS6uZgb73samDhqH0XAbdHxDzg9vy9WZoCJlVJ6geuAE4F5gOLJc0fVewJ4Gzg+tSqOdhbz4qIHwObR+0+E7gmf30N8P521sk6WGKqhISunuOAtRHxaERsB24k+3f5m1NFPBYRDzKBkf0O9mYjHRART+WvnwYOGKvQiGyuO9IfGlqXS2/Zzxn+95Nv59Yc5RBgXc379fm+pvgBrdk4IiKksdthEbGEPD3IzL3mVvixnLXLBCdVbYqIBa2rza4c7M1G2ijpoIh4StJBwDNlV8g6h4YKue9vAA6teT8339cUd+OYjbQUOCt/fRbwDyXWxTpJahdO4/vBvcA8SUdImkq23OvSZqvnYG89S9INwF3AUZLWSzoH+DxwsqRfka3Z8Pky62idpYihlxExAJwPLCdLG39TRKySdImkMwAkvUXSeuCDwDckrWpUN3fjWM+KiMXjfHTihI7TDztm9jcsp8HGZbIDphV7de+0xcEB+lJnxiYuJjc0RUnldszcJ6nctCe2pB3v4FlJ5SB9ZuyyH303qVz/QQmFCnp6ExHLgGWj9l1c8/pesu6dZA72ZmYFqfIMWgd7M7MiBFDhRGgN++w9pdzMLE1R6RJaIeUB7dV4SrmZWV3D4+w7dsFxTyk3M0sQkb6VYLJ99klTyiGbVg6cC7AHaXm6zcw6UZUf0DY9zj4i6k4TiIglEbEgIhZMSR3XZWbWiYqZVNUSkw32G/Op5HhKuZlZpqP77MfhKeVmZrUCGIy0rQQN++zzKeUnkKXkXA98jmwK+U359PLHgQ+1spJmVfbi8xs2/eSWzzw+xkdzgLRFWKutW64DxriWpJmxmcMaFahyn33DYF/UlHKzbhUR+421X9KKdqexbYVuuQ5ow7VUeFKVZ9B2meVPrpzwz7z34GMKr4dZL+rolr2ZmSUocaRNCgd7s9ZZUnYFCtIt1wEtvBYBKunhawoHe7MWyZcu7Hjdch3Q+muR++zNzLqcu3HMzHpBeXlvUnhZQrOCSVooaY2ktZI6OiOspMckPSRppaQVZddnIspIz96NM2jNbAyS+oErgFOB+cBiSfPLrVXT3hMRx3TgWPuraXd69gpnvXSwNyvWccDaiHg0IrYDN5KlBLc2a3t69shG46RsZXCwNyvWIcC6mvfr832dKoAfSLovT1fe6ZLTs09KhbNe+gGtmdXzzojYIGl/4DZJv8hbzB0vIkIqtge9ykMv3bI3K9YG4NCa93PzfR0pIjbk/30GuIWsm6qTtTY9u/vszXrGvcA8SUdImgosIksJ3nEkzZA0c/g1cArw8/o/VXmtS88ewFDiVoK2duNs47lN/xQ3VzEVbNecfwLpWmvOvbYrrp2EFLStFhEDks4HlgP9wFURsarkak3WAcAtkiCLFddHxK3lVildu9Ozi6h0N05bg31VU8H28vl7+dpbJSKWAcvKrkezIuJR4LfLrsdklZKefaikZnsCP6A1MyvCcDdORTnYm5kVxN04jZWdVa+Xz9/L125WLAf7+spOodrL5+/lazcrlhOhmZl1vwAGI21roFEyPUm7S/p2/vk9kg5vdEwHezOzgigiaat7jLRkeucAz0XE64AvAV9oVLe2BvtW3K0mcO5DJf1Q0sOSVkn65BhlTpC0JU/nulLSxQWev26qWGW+ml/7g5LeXOC5j6q5ppWStkq6YFSZQq+9mfSyks7Ky/xK0lljlTGrpGJm0KYk06tN6HYzcKLyCRHjaVuffc3d6mSy5FD3SloaEQ/XFNt5t5K0iOxu9fsFVWEA+FRE3J/PCrxP0m2jzg/wLxFxekHnHO09ETHeBKJTgXn5djzwtfy/TYuINcAxsPP/wwayqe+jFXntVwOXA9fW7BtOL/v5/GZ/EfDfa39I0j5kk18WkP1hfF/+7+S5gupl1hoBDCX32c8Z1ehbUvP8aqxkeqNjwc4y+US+LcC+1Jmg2M6WfUvuVqki4qmIuD9/vQ1YTbWyEZ4JXBuZu4HZwzk8CnYi8EhEjDWTuTBNpJd9L3BbRGzOA/xt7JqT3KyCElv1Wct+U0QsqNlaPlChncE+JfXriLsVMHy3KlTePXQscM8YH79N0s8k/aOkNxZ42kapYtuVGncRcMM4n7Xq2oelpJftthTB1kuK6cZJSaa3s4yk3YBZwK/rHbQSQy/bSdKewHeACyJi66iP7wcOi4gXJJ0GfI+sW6UIpaeKzRNznQF8doyPW3ntu2hFelmzUgUwWMgU2p3J9MiC+iLgw6PKDCd0uwv4APDPEfXvIu1s2bfkbjURkqaQBfrrIuK7oz+PiK0R8UL+ehkwRdKcIs6dkCq2HalxTwXuj4iNY9SvZddeIyW9bFelCLZeEhBDaVu9o2S9GsPJ9FYDN0XEKkmXSDojL3YlsK+ktcCFJCyv2M5gn5L6tTb9aNLdKlXe938lsDoivjhOmQOHnxFIOo7s99P0zUZpqWKXAh/LR+W8FdhS0+VRlMWM04XTqmsfJSW97HLgFEl756N1Tsn3mVVfQfnsI2JZRLw+Io6MiEvzfRdHxNL89SsR8cGIeF1EHJcnraurbd0446V+lXQJsCK/iCuBv8vvVpvJbghFeQfwUeAhSSvzfX8CvCav39fJbjCfkDQAvAwsKuhmM2aqWEnn1Zx7GXAasBZ4Cfh4AefdKb/JnAz8Yc2+2vMXeu2aQHpZSQuA8yLiDyJis6Q/J2scAFwSEaMf9JpVz8RG47SdCmo4m5n1tFlTD4i3H5DWPr11/Vfva3dq7557QGtm1jIVbjw72JuZFSECBgfLrsW4HOzNzIrilr2ZWQ9wsDcz63ZR6dE4DvZmZkUIiAYTpsrkYG9mVpRi0iW0hIO9mVkRImDIwd7MrPv5Aa2ZWfcLt+zNzLpdWpKzsjjYm5kVoeKJ0BzszcwKEEA4XYKZWZeLaLgwSZkc7M3MChLuxjEz6wEVbtl78RIzswJIuhVIXbd5U0QsbGV9RnOwNzPrAe1ccNzMzEriYG9m1gMc7M3MeoCDvZlZD3CwNzPrAf8fbJZMDI5qc2MAAAAASUVORK5CYII=", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ - "env = RiverSwimEnv()\n", - "agent = QLearningAgent(env.n_states, env.n_actions)\n", - "rews = train_mdp_agent(agent, env, 1000)\n", - "plt.figure(figsize=(15, 8))\n", - "\n", - "plt.plot(moving_average(np.array(rews), alpha=.1))\n", - "plt.xlabel(\"Episode count\")\n", - "plt.ylabel(\"Reward\")\n", - "plt.show()" + "test_agent(agent)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let's visualize our policy:" + "## 2.3.3 Intrinsic Curiosity Module algorithm" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 336, "metadata": {}, "outputs": [], "source": [ - "def plot_policy(agent):\n", - " fig = plt.figure(figsize=(15, 8))\n", - " ax = fig.add_subplot(111)\n", - " ax.matshow(agent.get_q_matrix().T)\n", - " ax.set_yticklabels(['', 'left', 'right'])\n", - " plt.xlabel(\"State\")\n", - " plt.ylabel(\"Action\")\n", - " plt.title(\"Values of state-action pairs\")\n", - " plt.show()" + "class Embedder(nn.Module):\n", + " def __init__(self, states_size, embedding_size, hidden_size):\n", + " super().__init__()\n", + " self.module = MLP(\n", + " states_size,\n", + " hidden_size,\n", + " embedding_size\n", + " )\n", + " \n", + " def forward(self, s):\n", + " return self.module(s)\n", + " \n", + "class ICMModule(BaseIntrinsicRewardModule):\n", + " def __init__(self, states_size, n_actions, hidden_size, embedding_size):\n", + " super().__init__()\n", + " # \n", + " \n", + " def get_intrinsic_reward(self, state, action, next_state):\n", + " with torch.no_grad(): \n", + " # \n", + "\n", + " def get_loss(self, state_batch, action_batch, next_state_batch):\n", + " # " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 337, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ - "plot_policy(agent)" + "agent = QLearningAgent(\n", + " epsilon=.1, \n", + " alpha=0.5, \n", + " discount=1, \n", + " get_legal_actions=lambda s: range(env.action_space.n)\n", + ")\n", + "\n", + "icm = ICMModule(\n", + " states_size=np.prod(env.observation_space.shape), \n", + " n_actions=env.action_space.n, \n", + " hidden_size=16, embedding_size=10\n", + ")\n", + "\n", + "train_with_reward(env, agent, icm, n_episodes=3000, update_reward_period=100, batch_size=100, n_iter=200)" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 338, "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ - "As your see, agent uses suboptimal policy of going left and does not explore the right state." + "test_agent(agent)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Bonus 3.1 Posterior sampling RL (3 points)" + "## HW 2.1: Random network distillation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Now we will implement Thompson Sampling for MDP!\n", - "\n", - "General algorithm:\n", - "\n", - ">**for** episode $k = 1,2,...$ **do**\n", - ">> sample $M_k \\sim f(\\bullet\\ |\\ H_k)$\n", - "\n", - ">> compute policy $\\mu_k$ for $M_k$\n", - "\n", - ">> **for** time $t = 1, 2,...$ **do**\n", - "\n", - ">>> take action $a_t$ from $\\mu_k$ \n", - "\n", - ">>> observe $r_t$ and $s_{t+1}$\n", - ">>> update $H_k$\n", - "\n", - ">> **end for**\n", - "\n", - ">**end for**\n", - "\n", - "In our case we will model $M_k$ with two matricies: transition and reward. Transition matrix is sampled from dirichlet distribution. Reward matrix is sampled from normal-gamma distribution.\n", - "\n", - "Distributions are updated with bayes rule - see continious distribution section at https://en.wikipedia.org/wiki/Conjugate_prior\n", - "\n", - "Article on PSRL - https://arxiv.org/abs/1306.0940" + "Implement algorithm from [this](https://arxiv.org/abs/1810.12894) paper" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 328, "metadata": {}, "outputs": [], "source": [ - "def sample_normal_gamma(mu, lmbd, alpha, beta):\n", - " \"\"\" https://en.wikipedia.org/wiki/Normal-gamma_distribution\n", - " \"\"\"\n", - " tau = np.random.gamma(alpha, beta)\n", - " mu = np.random.normal(mu, 1.0 / np.sqrt(lmbd * tau))\n", - " return mu, tau\n", - "\n", - "\n", - "class PsrlAgent:\n", - " def __init__(self, n_states, n_actions, horizon=10):\n", - " self._n_states = n_states\n", - " self._n_actions = n_actions\n", - " self._horizon = horizon\n", - "\n", - " # params for transition sampling - Dirichlet distribution\n", - " self._transition_counts = np.zeros(\n", - " (n_states, n_states, n_actions)) + 1.0\n", - "\n", - " # params for reward sampling - Normal-gamma distribution\n", - " self._mu_matrix = np.zeros((n_states, n_actions)) + 1.0\n", - " self._state_action_counts = np.zeros(\n", - " (n_states, n_actions)) + 1.0 # lambda\n", - "\n", - " self._alpha_matrix = np.zeros((n_states, n_actions)) + 1.0\n", - " self._beta_matrix = np.zeros((n_states, n_actions)) + 1.0\n", - "\n", - " def _value_iteration(self, transitions, rewards):\n", - " # YOU CODE HERE\n", - " state_values = \n", - " return state_values\n", - "\n", - " def start_episode(self):\n", - " # sample new mdp\n", - " self._sampled_transitions = np.apply_along_axis(\n", - " np.random.dirichlet, 1, self._transition_counts)\n", - "\n", - " sampled_reward_mus, sampled_reward_stds = sample_normal_gamma(\n", - " self._mu_matrix,\n", - " self._state_action_counts,\n", - " self._alpha_matrix,\n", - " self._beta_matrix\n", - " )\n", - "\n", - " self._sampled_rewards = sampled_reward_mus\n", - " self._current_value_function = self._value_iteration(\n", - " self._sampled_transitions, self._sampled_rewards)\n", - "\n", - " def get_action(self, state):\n", - " return np.argmax(self._sampled_rewards[state] +\n", - " self._current_value_function.dot(self._sampled_transitions[state]))\n", - "\n", - " def update(self, state, action, reward, next_state):\n", - " \n", - " # update rules - https://en.wikipedia.org/wiki/Conjugate_prior\n", - "\n", - " def get_q_matrix(self):\n", - " return self._sampled_rewards + self._current_value_function.dot(self._sampled_transitions)" + "class RandomNetworkDistilationModule(BaseIntrinsicRewardModule):\n", + " # " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 332, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:7: FutureWarning: pd.ewm_mean is deprecated for ndarrays and will be removed in a future version\n", - " import sys\n" - ] - }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA2QAAAHjCAYAAABMwtyBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvAOZPmwAAIABJREFUeJzsvXe4JFd17v1W6nTCnDNRo5FGoyxLApRAQggwRshkbOMA+MPGNuGzMb44cC9OBAMGG0zG2IQLBowMyMIgBBKSECggJI2kURqFkSank2PHSvePqr1rV3VVd1V3V6ezfs+jR3P69Omu7qrae6+93vUuybZtEARBEARBEARBEN1H7vUBEARBEARBEARBrFUoICMIgiAIgiAIgugRFJARBEEQBEEQBEH0CArICIIgCIIgCIIgegQFZARBEARBEARBED2CAjKCIAiCIAiCIIgeQQEZQRAEQRAEQRBEj6CAjCAIgiAIgiAIokdQQEYQBEEQBEEQBNEj1DRedOPGjfaOHTvSeGmCIAiCIAiCIIi+57777pu1bXtTs+elEpDt2LEDO3fuTOOlCYIgCIIgCIIg+h5Jkg7EeR5JFgmCIAiCIAiCIHpE04BMkqSzJUnaJfy3LEnSO7txcARBEARBEARBEMNMU8mibdtPALgAACRJUgAcAfDdlI+LIAiCIAiCIAhi6EkqWXwxgKdt246lhyQIgiAIgiAIgiCiSRqQvQ7A1WG/kCTprZIk7ZQkaefMzEz7R0YQBEEQBEEQBDHkxA7IJEnKAHg1gO+E/d627S/Ytn2JbduXbNrU1N2RIAiCIAiCIAhizZMkQ/YyAPfbtj2V1sEQBEEQBEEQBEGsJZIEZK9HhFyRIAiCIAiCIAiCSE6sgEySpBEALwFwbbqHQxAEQRAEQRAEsXZoansPALZtFwFsSPlYCIIgCIIgCIIg1hRJXRYJgiAIgiAIgiCIDkEBGUEQBEEQBEEQRI+ggIwgCIIgCIIgCKJHUEBGEARBEARBEATRIyggIwiCIAiCIAiC6BEUkBEEQRAEQRAEQfQICsgIgiAIgiAIgiB6BAVkBDEg/P7/vQfPfN+NvT4MgiAIgiAIooPEagxNEETv+dmTM70+BIIgCIIgCKLDUIaMIAiCIAiCIAiiR1BARhAEQRAEQRAE0SMoICMIgiAIgiAIgugRFJARBEEQBEEQBEH0CArICIIgCIIgCIIgegQFZAQxYNi23etDIAiCIAiCIDoEBWQEMWCYFgVkBEEQBEEQwwIFZAQxYOgmBWQEQRAEQRDDAgVkBDEA6KbF/10T/k0QBEEQBEEMNhSQEcQAUNZN/m+DAjKCIAiCIIihgQIyghgAKkJARpJFgiAIgiCI4YECMoIYAKq6lxXTKUNGEARBEAQxNFBARhADgChZpBoygiAIgiCI4YECMoLoc0zLRrkmShYpICMIgiAIghgW1F4fAEEQjTn9b36IUzYU+M8G1ZARBEEQBEEMDZQhI4g+xrad4OvAXIk/RpJFgiAIgiCI4YECMoLoY6pGffClhzxGEATRLWZXqzi+VOn1YRAEQQwNFJARRB9TrBp1j5HtPUEQveSSD96Myz58S68PgyC6SkU38aXb98K0aA4mOg8FZATRx5QEMw+GblGGjCAIgiC6yWd+sgcfvP4x/M8DR3p9KMQQQgEZQfQxxVpIhowkiwRBEATRVWZXagCojptIBwrICKKPKVZDMmQkWSQIgiCIrsICMU2hpTPReeiqIog+phSWIaPdOYIgCILoKjVXnZJRaelMdB66qgiijxEzZNsm8gBILkEQRH/A2nIQxFqAzb0ZRerxkRDDCAVkBNHHiBmyN12+AwA1hiYIoneIQRhtDhFrCaZOoX0IIg0oICOIPqbouiz+9K9+Ga+9+CQAJFkkCKJ3iL0RKzqNRcTagUkWdbK9J1KAAjKC6GNKbh+yzeNZqK5MggIygiB6hdiKo6LXmw4RxLDC5l6D5mAiBSggI4g+plgzIUlATlWQcZ2dSCZEEESvEGXU5ZA+iQQxrLAMGZUNEGlAARlB9DGlqoGCpkCWJW61qxs0GRCDy9Mzq/jwDx+jTO+A4suQGRSQEWuHKpcs0thFdB4KyAiijynWDBSyKgBAkSXIEmDQZEAMMN974Aj+/ba9uPb+w70+FKIFilXKkBFrE7aJpBs0BxOdhwIyguhjilUTIxmF/6wpMkkWiYHmqZlVAMCnb3kKVcqwDBxihqxMNWTEGkJ3pYoGmXoQKUABGUH0MaWagXxG5T9rikySRWKgeWp6FZvHsjiyWMa3d1KWbNAQA7IquSwSawjuskg1ZEQKUEBGEH1M1bCQVb3bVFMkqr0hBhbDtLBvtohfv2gbNo9l8fDhxV4fEpEQn6kHZciINQS5LBJpQgEZQfQxpmVDlSX+8/qRDO7dP09BGTGQHFooQzdtnLFpFKNZFWXKsAwcxaogWaQaMmINUaU+ZESKUEBGEH2MYdq8/xgA/OVVZ+Px4yu4afdUD4+KIFpjqawDADaMZpDTFJSFbAsxGIgZMnJZJNYCDx9ewjfvPsivfdoQJdJAbf4UgiB6hWFZKKjebXrxKZMAgIVSrVeHRBAtwxYymiIjn1FI8jaArFTIZZFYW7zqs3f4fibJIpEGlCEjiD7GtPwZspzmOC7SQogYRJhddEaRUcgoPoMIYjBYqRi8rrVCATWxBiFTDyINKCAjiD5GN/01ZIUMBWTE4FJlGTJVdiWLdB0PGssVHRtGMlBkCRWqASTWINQLlEgDCsgIoo9xTD1El0UZqiyhRDvTxAAiZsjymtL3GZY/+uq9+PNv7er1YfQVKxUd43kNOVUmySnRNT78w8fwhdue7vVhAHBquwmi01BARhB9jG5ZUATJIgCn9oYyC8QAwqQ+2oBIFm95fBrffeBIrw+jr1guGxjLqchqCjX2JrrGv9+2F//4w8d78t6yfwpGjWrIiBSggIwg+hjTsqEFZoPCgAVkT02vYLmi9/owiD6AmXpkmGQxJMNycK6EqeVKtw+NiMlyRcd4TkNWlXmjXIJIk15n0vNu7TaDMmREGlBARhB9jGHaUGT/bZqPWMj2K1d+/Db87hfv7vVhEH0AW8BrioR8Jlyy+IKP3opL//GWbh8aEZOVipMhy6gy78tEEGlyZLHM/92LrGxOCMgmChrVkBGpECsgkyRpQpKkayRJelySpMckSXpu2gdGEIRTPKzKQcmi2vdSL4bpNtB8+MhSj4+E6AeY1CejyChoCnTTpp4+A8ayW0OWVWVUydSD6AKH5kv831NL1a6/vxiQrR/JkMsikQpxM2SfAnCDbdvnAHgWgMfSOySCIBjBxtAAkNfknks4mrFU0vGOqx/AcZKeEQLBPmQAIrO9tk2Lnn7Dtm1fhoxqaYhuIAZkhxdLDZ6ZDlnNWyqPZFTqQ0akQtPG0JIkrQPwAgBvAgDbtmsAqCstQXQBw7LrMmSFjIpSzYj4i/7gP+7aj+sePIrRLPWeJzzEGrK80MJhPKcB8DKqALBY0jE5kun+QbqIx0I4lGomTMt2a8jI1IPoDocFyeLRxe5v8mVVL0OmKhJlyIhUiJMhOxXADICvSJL0gCRJX5IkaST4JEmS3ipJ0k5JknbOzMx0/EAJYi3iNIb236aOGcJg7NAVq/0dOBLdxashk3mhvGhQs1rxrpfDC2X0kkGq0+wWK+75YZJFMvUgukGxamDE3cDpheGPJWzOaIpMMmsiFeIEZCqAiwB83rbtCwEUAbw7+CTbtr9g2/Yltm1fsmnTpg4fJkGsTXSzvobMcVns70CHHTLL5ClB32BiTVLjtveSF5AJgY/oxnl4ofvSJJFBcjLtFuz8kKkH0U1qhsU3AZbKjR17F4q1jkv6RWmupkgwhADt8ePLeOjwYkffj1ibxAnIDgM4bNs2s0m7Bk6ARhBEyjgZsmANWf+7LEqSc8zMfCQYVBJrE920oCkSJEnikkXRoEYMyI4u9bb+sN/rNHvBsrsYZrb3ZOpBdIOqYSGryliX17BUahyQXfiBm/Ab//rzjr6/mAlWZdlXQ/bST96OV3/2zo6+H7E2aRqQ2bZ9HMAhSZLOdh96MYDdqR4VQRCwbRuGFWJ7PwANdVl2gUmcNIU6bBCAbljIuNcCy5CJgc+KIFnsdUAk3mNUT+bAzo+TIVPI1IPoCjXDQkaVMZ7XmmbIAGD3seWOvr9uWjhryyhueOfzoVENGZEScSvu3wHgPyVJygDYC+AP0jskgiAAbxFYb3sf3r+pn1hxMx1M70+SRQJwpD+a6gZkIRkyMSDrdZ2GmIWuGRY/3rUMy2B6tvf9PQ4Rw4GTIVOQUWVfFr1b6KaFy07bgHNOGHcyZNSHjEiBWAGZbdu7AFyS8rEQBCHAdOpByaLYv6lfM09sYT294vSM0RQKyAj4rtkCD8i8IGxZ2P3utWGEeFxVw6SADMCyL0NGtvdEd6gaJjKuZLEXph41wxu3yGWRSIv+XM0RBOEFZCEZMqC/XeCWK37TEcqQEQBQM2wuWRxzre7FrNiKsPvdywyZbdt48vgK/7nXwWG/QDVkRC+oiTVkMSSLnUY3bR6QZchlkUgJCsgIok9hhcNqSA0Z0N8ucEFZSfAzEGsT3XRqQQBgXd4JyMQFFgvkRzJKT3ehr3voGN53nVcqTW6CDisVAxlFRk5TnD5ktDAlukDVrSHrRUBm2zZqwrilKhIMd2wSAzOqMyXahVZJBNGnREkWN7jNcqeXq10/prisBDJkSSWLX7p9L56aXunroJNIxlPTq3j4yBK/FpxFvd/GeqWio5BRkM+oPQ2CDs4VfT9TA2SH5YqO8bxT6ZBx+5DZNi1EiXRhGbLxnIqVihEZ/KRxLbJ5OOOOW6ri1ZCJ81ypz1vREP0PBWQE0ad4ph7+2/TUjaMAgL2zq10/prisBDJkSSSLpZqBD17/GK78+G34pffcQDuPQ8KVH/8Z9s0WfXWPEwW/jfXcag2ThQwyitRTWdDWdXnfz5Qhc1gu6xh3paZZN2NA3w2RBMuyE0uAnQyZgnE3q75aCQ9+0pgq2DjExi1N9mrIxOOgzUOiXSggI4g+ReeSRX8wc8qGAiQJeHqmGPZnfUEwQ5Zknlyt+v+W9PrDBZP+AMBEPoPFco3/PLVSwZbxLM++9AopsH+QRtBxx55ZHJrvbfPrpKxUDIzlnAwZC8jI2INIwt997xGc9Xc/SvQ3Yg0ZgFDZ4pNTK6nMFWwc8kw9vBoyUZrf761oiP6HAjKC6FPMCMliTlNw0mQee2f6M0Nm2zZWqwZOGM/xx4wE9UDB3U/agR8uxAzZuryGRSFDNrVcxZbxHLQeF84Hr9c0gsM//sZ9+PId+zr+umniSBYDGTIy9iAS8M27DwJIVnMluiwC8G3iAMB9BxZw1SduS+V+YhsOrF0HG5ts2/ZtPBZJski0CQVkBNGnMFlEmNzvtI2j2NunGbLFkg7TsnHpaev5Y0kW18Wqf6eRLYZ//tQsbnz0eGcOkugqRSHrKV7N6wr+Iv2p5Qq2jOeQUXsckAUWi53eFChWDaxUjYGTOfkzZI65EGXIiFZIcn9X3QzZiROOlPjwQtn3e5Zpvu/AQucO0IXNw1l3I2nbRA66aWNquepTcwzavUz0HxSQEUSfElVDBgBb1+Uws9qfph6s99hzT9vAH0vimLdS9ctRaqaFYtXAG750N9729fs6c5BE17jvwDz2THvZXLFdw4TgmlaqGVipGNg8noWmyD3NjLKi/fe+6lwA6HgD5Bn3Hhm0YEasIcvwDBktRInkJA3IMqqM0zeNQpKAPVN+dYjsblqmkcnWmWRRdd7jjM1jAIA90yu+WmmSLBLtEqsxNEEQ3YfXkIU4FOY0BZU+XQhNrziNO0/dOMIfSzL5BiWLNcPCDx462pmDI7qKYVp47efv8j0mLlxEG2vmGrplLNfzXj9sA+EZ29YB6HzgNOtupgxSfzPbtrFc0etqyEhSTLRC3E0627bdGjIF+Ywj198zveJ7DhORiPeTbduQgsWgLVALmHqcucUx1dozteqbmykgI9qFMmQE0aeYEY2hASCr9W9TVraw3jye4xOlkSQgq9YHZHNFp2Ygq9KQNUgE5acAUBLO70RBQ6lmomqYmFp2AnkmWexlsMKu10LGCT46fa+xDNkgBTO37ZlFRbdw7onjALwM2SAFlUT/EHfDhQVEbOw/c/MYnpoOr58W++JVDQvvv+5RfOn2vW0dZ9DUY8NIBpMFDXumV3mjdAAo61RDRrQHrW4Iok9hsilVqb9Nc6qCmmnB6qEl/F98exc+d+tTdY8zKeXmsSwefO9VeMOl2xNJFsMCMjYpBmt7iP5mNaTQvShmyApOT72lko7ZVSfo3jiWgaZIPW0Mza6z0awTkHU6Q8bukUGSLH7z7gPYNJbFK55xIgCvhixpUDm9XMF1D1LGe60TN5Bnz2MB2embRrB3NtAn0N0wEV+zalj4yp378cHrH2vrOO94ahaAtwEhSRJO2zSKfbOrfMwCKENGtA8FZATRpzCnt7AMWU5rbTHUSa69/wg+euMTdY9PL1cxklEwklUxltOwYSQD3YrfQDZomV8zTT7Rmi30sCF6R7FaH5CJDVS3ry8AcFo41ExnQZNVlZ5nyNjufSHr3mdp1ZANUMPp2dUaztw8yhemWa21DNkbv3wP3nH1A6HXBrF2iLu5xuY4dt2NZjXUDMvn0sjqUsX7SbxnW924nF6p4CM/etx5f2FjdMNIBgtFHTOrVWwczTrHQAEZ0SYUkBFEn9JQsuhOTv1QR/Yb/3qnL6s1vVLBZsHyXlNk2HY8m+P9s0X8170HfY9VhQwZ4F/QE/2NGFy/4dLtAPy1I+e58rdHjy7xx1VZ6gvbe1kC8iltfLCArJdZwKQYpuXL1rMFajVhUHlg3sluiAvyUs3AG774C+yZWon6M2LIiC1ZDGTIWN2W+PdsHqz5HvP+/ePdU7jmvsOJj1GUKovtOiYLGSyUaphZqWL7esf5kTJkRLtQQEYQfYoe0YcM8DJklR7tsIs7jvcfXMR+QUIys1LFJnfXEPCOP86O6B989V4cmvdbGtcMyzfRBiWNRP/CsiC/c8nJeM8rz637/cbRLE4Yz+GRI0teRliRnAxZL009LCf4aLVO6thSGf//1++LvFYH0dTDsGxowuYQy5AlDVZdJbavrvSup+fw86fn8KEfticvI/obUSUR99oPZsjYRkBYQKYb3uuL7TTe+/1H8P7vP5r4eMVrWxPm4ckRJyCbXali60QeGUWmgIxoGwrICKJPMd2VixJie5/TWIasNwu6Rk0wizUDoznPwJVNoHEW2GFZtJph+XYqaeIbHFhA9qbn7UBOU/CW55+Kb775Ut9zzt82jkePLvPrXZVlZJRem3o4wYcqS5Cl5EHHP9/wBG549Dh+9PCx0N97ksUBCshM29cTkd/XCT+D6S7Kxewge41MSL0sMTyILS+SZ8icTUiNZ8i864fNg6J6YrbotYWZWq62lOX2uTYKj08WNOimjf1zRWwazSKfUVAm5QbRJjT6EUSfoseoIeuVZLGueXNAKsICRsCTeugxJsSztozVPVYz/Rkyqj0ZHFbcc8XMMf72Fefi8jM2+p5z3onr8PTMKpZdeaOm9F6yaFo2VEWGJEnIugY6SWD3ZT6jhP5+EPuQ6Zblk21luZwz2RjENl3E88u+hwy5qA41YkuT+DVkzvXFgnVNjc6QLQuvPycYbgBoyQRLvD8nXQMiwMmQAYBlA5vGsihkFNooJNqGRj+C6FPMhpLF3taQMSnW6559MgB/sFXRTeRUbyGaRLK4fkSre0w3gzVkNPENCsVAQBbGeSeOw7KBhw8vAQCXCvba1IPtxGdUObGpB8sEyCF9kGzb9lwW2/yMhmnh0HyprdeI/162byzKtml7XwtYlAMUkA07K8JmWpwNOkDIkLlznhYiWSyH3J/zQoaMv1bCDRD23p963QW+vppicLZpzMmQlfqgnpsYbGj0I4g+hTeGDpMstmg53SnYQnvCnZiC8hG2ew54E2ichZsRYnJQMyzf56QM2eDAztVIg4DsfLf58oOHFwGIph49tL0X5HlZVU58n7GNkmANmWFa+NefPs0/W7v37z/f+ASe/8+34vhSpa3XiYNp2b6xKNNmY2jxXq9yWRotSTrNI0eWMLNS7QvDFDFDFjc4qgbkrF4NWb1kUSSYIRNfKy5sztq6Lu97XNw43DTqZMjIZZFol+hZkiCIntK4MXSvJYvOxDpZcCYmcbeyqpsByWL8DFnNtHDaxhGcs3UMP3z4uPOYa+oxllOxUjEoQzZArFQNZARzjDC2rsthsqDhmBtUqLJn6mHbNqSQLFPa6JbFg49WsnVsgbgaaOHwk8eneauIDSOZtm3vb3tyBgAwV6zihHW5Js9uDzFrCHjBU6sBmThm6IE6IaIzLJV0vOZzd/K5ZP9HXtHT4xE3KOJuuHgZMlZDFi1ZFJkNCciS3sesFUdw/BIzZOdvW4eCptJGIdE2tB1FEH2K6DoXxLO9702GbJVnyJyAzFdDZpi8xg0In0CjMEwbmiL7duId23sT613d/o2PHu9pfRERn2LVb/AShiRJvCYDABRZQiakcL+bONdh+xmy4CLtTrfJLABsm8x3rIYsZou/tjCscFOPVgOyWojkjCSLnWV6pRKr3Ui3WCh5QZIRO0PmryFj82HNaBaQ1UsWk9Y7RpnNhEkWw2STBJEEGv0Iok8xeIYszGWxtYL6TrFaJ1n0Gjfrpu2vIZPjB2S6aUF1TR0YNbeGjL3Xjx45js/csqczH4RIlWLVxEi2edaDF+wrEiRJ4gvzXgXehuX13MqqSuKgY9m13F4NOK/dIQZkE/mBcll0MmTefcnOU6tjkB4iQ+5+LnS4CWaJ7G5E7g2YL3rHE3czouZuymRUt6bTvQZ//vQsf72wYIgZ54gkvY+jahvX5Z2NyF+/cBsAkKkH0REoICOIPoXbgLdo6nH1PQex493Xx96JTAJbQLGsFcvmseMRJYtsIo2T7ai5iz72N4AnWZzIe7r9Xa4BBNHfrFYNjGSaK+PZQp8F70nqDtNAN20uFU4adNi2jVl3oShmyI4tlfH0jNev76TJPCw7fqYgjG7KOQ3hO2Fk22hPII4H7HsapEbZg4AYAAG9/37Fuq64x8LuD03xjw3/+MPH8fov/AJA+Dw4veJIoNcJ80ZiyWJEbaMsS3jwvVfhY7/1LABwbe8pICPag2rICKJPiWd7Hz3BfNhtsrpSMXySsE6w6treTwYki15AVp8hi7PwNEwbGUX2Z8gMJ0OWF17z6enVNj8B0Q1WK0ZDh0UGkweyaz2JzDUNDCEblFSyWKyZfCEn1pDdscfJjl37J5fDsmzsPLAAwLl3VKW9vdG4FuLtwFoBiGS15HJOhnhu2XhCUuTOEnQa1E2rp7JQMUCMc67f9Z0HseuQa/YjZNEZT7hGJWHzIMsOThQ03iQ6salHg3YMYqDnZMiohoxoD8qQEUSfwrT/Sot9yNgkkoYdb7FqQJaAsZzf1KPiTnhhfcjiSFSYZFGUabKALKPKvGbtyGI5VJJC9BdLZZ2fs0ZogfqQdh382sWwbN+xJNlZF+/JVaFf38+fnsPG0QwuPHkCl+xY33JjZRE2MnQjkHH6kAUyZKrSEdt7L0NGAVknmavLkPX2+50v1jDu1pTG2aC79YkZ7HE339i1p4UER1Hz4GhW9WW3Ws2QNWtYXsioJFkk2oYCMoLoU2oBqYZILoapB5tEgk5vnWC1amAkq3oWxEZ0hoy7LMaQqLA6FU2ULJpeQLbrPVfhU6+7AAD4rifRvyyUar4C+ChYAMZ2wTM9z5DZ0OTWashEEwVRsnhksYzTN41ymWGmzT5eIml/T6Zlw7brN4cyLRieMMTxoOhmFwapUfYgEJQs9vr7nStWuYV8TTj/tm3jpt1TvuvYtm0sCiYg7H4MC44quskDPZGRrOJz7kwiPf7crU/h/dftdt6zSVYxrzljRD8ZqBCDBwVkBNGnPDm1gi3j2dDePKoiQ5WlhhMMm0SCvZA6QdGtDdK4+YK/hkycBFlAGceFSnddFjNByaIgtWESuDQ+Vzd4+PASrDUwcdu2jflijdcZNoLXh8j+YKVnLouWxTNkWU1OZE8vygeLNdHm2y8X60QWkJWQpf096RGbQ9kWmmYHXxPw7uVe1zgNG/UZst6bemxx2zOI5/+up+fwlq/txCduepI/tlo1fPcSm2vCNijLuslNnwBweftEPuO755JsfrD2FEDzgKyQUfhxEESrUEBGEH3KAwcXcdH2ycjC/ZymNMyQsYkrjf4obHHJsl9eDVm9ZPGMzaPQFAn3uTUzzV5XC5EsVg2LB2msyfAg9n25Z988XvXZO/DlO/b1+lBSp6ybqBpWrPpFXkMWKNzvqakHqyFTkmWBRCmWrxGucA0DnlFAJ7IWesrfU1RPRNYvLi7iIjxUsjhArpODwFzA+r3X3+98sYYtY9m6Y1lxz//jx73m1YslvwLCqy+tnw/LuukbZ5hMenJE891zrWx+SFJ4HbdIwZ2TqI6MaAcKyAiiD5ldreLgfAkXbZ+MfE5WlVGJkSFLI3AxXfmSFrC0r4ZIFkeyKi49dQN++sR009c1LLtOsnjtA0ewUjH4ArZRhswwrb7OnD3l1kM8tQZMSZhcan0MyaLnshiQ8/XS9l72MmSJAjI3eMlriu9aZLJbRieDzrQli15PxLAMWWv1dbovICNTjzSYWaliJOONxb38fi3LyZhvGXczZEL2iwVNolOh2LMMqHdZBJxgybRsVHQLG4SAjBlurB9pPUPG3wPN3UwL7nxHTotEO1BARhB9yF7XHvvsE8Yin+NkyJoHZCtpBGSWBUWWIMsSFFnCf99/GLc+Ps0DRDEgA4DnnbERT06tYqnUuO6rZjhSsbA6gTrJYkht3F9+50Gc/94bW/pM3YDtoBZi9OYadBaKzrmOkyELNn3VQpq/dhPR4j2T0NqdZZPW5TXfZkidZLETph7uOjHtwFW3mGQxxNQjwXuLGX0xQ8Kk1/oakPJ2i1LNwL7ZIv7wilPxR1ecCqC3NWQl3YRlA2M5FZoi+YJDJvUTDagWhLlClrz6RTEgkyWJ/60ojR53A7LpN5P2AAAgAElEQVSJgj8ga6VnXpxLkkkWydiDaAcKyAiiD2GBVqOmumM5Fcvl6GArTcmiadk+Ccmh+TLe8/1HUK7VSxYBp+cS4PWGiUI3rTrbewZbwI66xdvFEHnI93YddX7Xp1kylgmI05tr0Jl3d7jXjyRwWQwU7vdqR19sgpzVlEQLOXbMEwUNxZrJ6wVrhr+xciezgGnXBrEMWbipR/zv5uEji/zf4jGzf+uGhUs+eDPe9vWd7RzumuCPvnovrnvwaOTvdx9dhmUDzzppAlecuRFAb2vIRPWEpsi+gJwFMmVhTPcZeihiZtm7BiUAJXes3zAqBGSu++/6Qsb3/LQ2ePIUkBEdgAIyguhDwswxgmway2J2Ndr6PZNyQCZL/h3LQ/Nl3LNvDgCQCxz3JrduoJlVPZMshjXDDmbIVhq4R/arJT7LkOUzayFD5iyo4rgsMomqFrC971mGTLC9z7q297YdbzErZsgAv4NgmKlHe7b3rOl6yhkyZuoh+5cMSSSLtm3jD7/qBVpiIMq+M920MLtaxY2PTrV7yEPPLY9P4x1XPxD5+4cOLwEAnnHSup5tcJiWjb/57sN4/PiyryWKpsi+Y2HjohjQLBQjAjLhHpIkp+8fAJ9kke0bTI5k+D0CpNdGo+BusJFkkWgHCsgIog+pGuGZJpFNo9lYgUc6kkWhT5MwWX5752EA9ZLFjaNuQNYggAScHXJVkUIzZKyGLKvKUGSpYaDZ7H16xVraQeU1ZAlcFoOmHr20vRezdZYdv/kyy0KwgGxquQrTsutMPQbN9h5A3UZJElOP4PdnmDYfv9jxUw1ZPOJsDjw9s4rJgoYt4znvfuryBsfMShXfvPsgXvrJ23mGLKu6GTJfewhXslgLlyyKWa6Mr4bMmwfWj2T545b7/UwGeiCmF5A5812YaoMg4kIBGUH0IXEzZDOr1cjJmS300siQGSEZMsCrBQgGknEzZDVXssgm3bc8/1ScvN6RO2bc70KSJIxm1YYZstk+zZAxk4dWrcIHidnVKhRZ4vKhRrDzrfSRqYcm2N4D8QMnFrwwp7crP/4zfOAHu+szZErnbO/TziQabg1ZO6YewT6EDx1exLM/dDO+de9B/p31qhH4oBFHeljWTe5IG3TD7Rai6yAz6ci67rx+yaLzvNWqweczUbKo+iSLQkAGb84RM2TsemJqCkaS66uZ1b0IUzxQhoxoBwrICKIPYRNHWA8yxqaxLGqGheWIwKRqsoCs85OEZXs1ZEweco5gQBLMkI3nVGRUuWnmirssupPuBSdP4gVnbnJ/502mo1kVX//FgUjJTr9myNiiZC0sPPdMr+LUjSOQm1hGA6KDmj/r2lNTj8CxxD1n7DoV+yL9x1376zJknhFA+xsm6fchc15fk1s39WDGIFeduwUZVca+Wce46IZHjvPsmZghoWxZNOJYGEXVsPj84WWcu1tDJp7Px445lva8hsw9v7/YO4fvu7VwNcPiig4xQybeN2IdoyR5G47MyAPwsrHBoCpJvWMuQUBGph7d4eBcyddWZNiggIwg+hAekGmNM2RAdNaJLWbTsIE3TJsvtJn05NUXnMh/HwwkJUlqKrE0LZtLIUW3PTbRLpe9CZpNymJRu23bPDiMeh/btvGdnYd6tpPJFhlVw8LUcgU73n09vvvA4Z4cS9o8cXyloUuoCFswBrOuvTIh0E2LSxbZPRh3MWcEJIsAYNuOW5u4QIybNW4EW5p2y/Y+1NQjZraXZUSed8ZGZFWZb9qIzYuXhHt8PtDUmPBodF+85nN34oM/2I2qbvLv2Gu03u0MmXdtsHmIZ8jcz/C6L/wCB+ZK3t+4G4gLvgxZ+KaOBIm/h5gNu/gUp13MSZMFCCVkiTZ4gpuKjSho1IcsbRaKNbzgo7fivd9/tNeHkhoUkBFEH+JJFhvXkAHRCzo2+YbZw7eLmCFj7zNZyOA1blAW1rdl41jjgIwbBwiSRU2V+cJWXKwdX6q47+P9/WrV4BbFUe/zk8en8a5rHsInb36y6WdMA1aoXjUsPOE2Qb3mvuELyFarBg7Ol3DOlpgBmVq/0AeAWgs21Z3AydR6ph7OsSSTLIoBGUOUW41mVeQ1BdNtBGSm7ZlhpIlne18vWUxaQ8baWrAxTpQXi/d4vxrz9AONsgQPHlrEl+7YF5Eh68x18v0Hj+I7Ow81fZ4YoKxUnHObDWTIgrCNj0VfDVn4PChmyAqCUdI7fuVM3PKXL8QZm0fFeCyRMiFJQEaSxfRh0tQfPnysx0eSHhSQEUQfEleyCETL89gCMo1dO8Oy+W452/kuZBR88ncuwJMffFno32wazTRcZHGZiSBZzCgyXn7+VgDAay7Yxp/LFoGnbhjhj4kTePB9dh1axJ9+837ekHmxST+0tGALzppheXU58vANw09OOcFm3AwZC8BZMT4LhnqVIXMki+41qCaTLIq290EyPoc4CVvGs5habtwKouF7Ga6lfg9NPXTT5r9vhLjhoioSN0CYXQ3PhDVrkbGWiXNfVHWL1yB3uq/fn139AN51zUMNXX4Bf4aM1fw6GbJGAZnzuC9D1kD2zN5DDMgUWcLpm0brnhvn87/lazvx9V8cqOu514iMKkOVJV8fNaKex48v4+IP3NTSmMfOnbhpM2wM30qAIIaAqmEiq8qhmSbGiRN55DQZP318OvT3bACrpbCotcSAzH39QkaFJEmRxdDjea2hEQcL7FRFwjlbx3DFGRtx9glj2L6hgP0feQXO37au7m+2TuT4v8UJfLniH7TvenoOP3joGL54+14AyQq2Owk7J1XD5DKwRouNQYVlAjeP55o804EF4MyfRjT1MC0b3955qKu1A7pl8XoptqhNbOqRr3eXzAQWeZvHcm1lyFjmigVmacEWz8HNgyTfDa9Dc11UWW1rVDBJGbJo4mS6qobJDWkyHZYA593s0Xd2Ns7u+ySL7tjv2N5LkcfCriVx0yxKsqibFn+PkWzz3o5xNlVu2j2Fv/+fRxCzywUnn1EoQ9aEb/ziAOaKNfyohSwXO3fD3DueAjKC6EOc3c3Gt+dIVsXvPXcHvrvrSOiOE5u005B9GZYNRfI7dxWa9NYaz2lcthKGuIO+cTSLb7z5Um6XH+STv3MBAPh25ll91oaRTF3gx2QwbDe+2c5uWrCsWNWwfBKuYYNnVGIGm8GAjPW7qhkW7j+4gP99zUO4d/9C5w80BNOyYduAIgczZDFryBpIFoMbAZvG47WuCGJZNmzb7ppdvGH6M5eMbILvxhCCuowi11mEB8e7NMyIhgWxhYAVsUIt1kzeD7LTksUT1jkbLftmVxs+T2z0vMwzZAqyqsIlq0GqhomaYWG1ajRs+wI4AeZqVYcsNVaTMJrNheL3o8cwThEpZBSqIWsCc9yNMiJrRBJDlkGFAjKC6EOqhhlLw37xKZOw7fDdZLbTmIbsyxQyZIxmAdlYTvXZGgfRBcliM37twm244oyNvs92eMEpDD9j82hIQOafXNuRibWKs4B2JWaG5WUdYnzeQYMFZMFrJAq20Lfh/J0sS+4uurcDHrWA6zTeefHXkFXi2ru7C7mRbP39EAzINo9lMd3Ctfiaz92JZ3/oFh4opR6QuZ8pzNQDiCeZ9DJkjmQtOAwEx49etTwYBMRs8aoQBIjB2ZGFMs+QaR029WCBx7El79pdKNbqxvaiT7LIashkbBrLRmaGq7qFxbKbYR9rnmFfKOkYcdUZzagaFuZWq7h3/3zo70XjKNO9Xt9w6famrwsAIxmVXBabEGbQFZe44+8gM3wrAWJNcHSxjLv3zvX6MFKjolt8Mm1EpsHOZ5VnyDo/kIUHZI0lI6NZFZbtn6RFRMliHDRF8n22vTNF5DQZZ58wVidZrOoWxrIqPvIbz8DZW8Ywtdz9DJm4q101TN6/KWglPgwws4m4ARlb2IvrOU2RncCVS2+7MyGz89SqqYchBB5Bgo9tGc+hWDMTO6E+fGQJs6tVLwvetQyZ//iTtCfwMuBSnYkL4MngGHH7m61FxI0o0bRJvA7KuimYenS2DxkLPFhAtvvoMi78wE347/uPhD4PEGvIFGxdl8PxpQoswTyHUTUsLlfcPBaukBBZLNW4qUYYYqBW1S189ef78cYv3x3+WkKgoFs2Xv+ck/GPv/6MpscAkGQxCcH5OQ5ihqxbm3PdhgIyYiD5t589jdd/8ReRO12DjlND1jxDlolYLNq2LWTIUgjI7FYyZM7uWJRs0YhwcosiWBi+d2YVOzaMYF1ecxwXAwFQVpPxuudsx4vO2YzplUpkpi4txMa4NcPiu8yUIauXLLLHdNMSpLfdWaCz65NtMLD7MK6pR5QBBlCf/WWyxkZS3qjXB7yFedrmJ1HyWhZYxXl/sbl02D0eXFSvBYlSq4h9yMRgPjjWc1MPV37bqVpDFngwt9tHji4BcGp1/c/zjo0dZ06TsXVdDjXTwnypxmWVjKphCTWoTkDWaKheKOoN68d+/7mnAADO3DyKmmlhrlhDRbdCa1JFwwhDaH0RB0eySNdsI9j304qplrhBc3xpOA1/hm8lQKwJSjUTlu24PS0MYb+aqm411c8D0f2axGxMGrvnYRmyZkXVYznn91E2/DUjvE4likzAcnvvbBGnbxrFWE6FbcPneOVYQDsT/+axLHTT9jUe7QZiTULVsPjxDaOpBw/IYsiIACEgg3fdsvPLznG3eijtn3WkrztcB0+WqY4bIOgNgtGgZJHfvwkWykcXy/zffNMl5WA1ytQjoyi+3zd+Db+pR5D6gIwyZFGI470ozw5uWrA5RJYlqLLUkXuo5ta/jrsS9JWKznvRBeesoGRRkpxNiRPW5QEAxxYrqJoWTts0gi///iUAnPtsgWfI4kgWazy7+sbLTsFF2yd8v79kx3rs/8grcPL6AqqGyeVyYdeXLyALmeMakc+o5LLYBJbZinKGboR4vj724yc6dkz9BAVkxEBimI7pxbGlCn7w0NHmfzBgVBJmyIITrTgxd0+y2LyGDIgu6BVNPeKQcSVtgPMZD82XcNqmkdBMnNiTZ3Kkvq9ZNxAXzVXD4g1Q49Q+DBot15AJcYlzftPN9Iaxb7YIANixsQBANK6ImSFj17Hs9NATzT2CGTKvBiv+Qu7pGc9IgfXm6ZWph2inXqpF14cC/vs7bNNFlCyOZlXKkDXAV0NWDZcsAvDNIY2s5pPAsmOnubbyx5cqvL4nOGeVa6aQBTa4c/CJrjvu0aUyaoaFVz7zRJzl9iysGhaXtG0YcZxKG2XI9s4WsdU1GfnAr52Pa//keaHPY/MFm39CA7KSmCGrl1M2oqApvowgUQ9ThUy1kOFi48EVZ2zEzY9NdfS4+gUKyIiBRLdsbHEttVtx7Ol34rgsAt6CKDi5sEXsaFZtaxKeW62G9gMyBZdFRrPjTVOyyJpCbxzNYtTN1Ik7x1Xd5IvfsWzrhcXt4MtaGp5ZRbcCjW6SNCDL8AyZ8Jgq49YnpnHbnlkA3ZMs7p8rIqPKONHdxU8qWWTnWVEk3Pd3V+Luv3kx/10wQ5bhAU38DNl+N2AUObxQxo53X9+SnXQcokw9mFnE0zOrOPc9N+I7DZqci20ewox7csGAjGrIIhHHErGeJniPiGOypkix1RKLpRr+7WdPhwbYzB3ztE1OBvnYUoUvlusyZFWDB2SGZfN7ibk0Hpgr8r/zMtEWv9fYJl6Qq99yGd50+Q4Azmc+RehHGUVWk51gj2fI6gN+tkknS84YlkROTpLF5pRrznmda0HVxK6JLeO5rs0F3YYCMmIg0Q0LhYwCRZaG0mq2EtNlMcrUg/08klVg2YjVuDWMiz94M57zoVvqHncmK//irFmmh02uUb3I2KI0rqkHa0oLeJ83o8rC+3gBV8WwkHW/z3Fhx7absGOUJGcxUNYN3+PDRFJTD42benjXqaZImC/WcN2DTgY8jX56YeybLeKU9QXIrA8ZWyjGlCPxeitZgqrIvvu4LiBL4FLICNuAesJtxP29XemoBTyjk0AfMvdnVst7a0RPRMCfIQszYRAz7Dl38UyEI44Z4vcUHEuC117cseZv/+cRfORHj+OuEOMsFnSwxsu/93/vwcd+/CSAkAyZbvoapLMAceNIFpoiYf9cif9dVvF62vENRXcTL3jnP/f0DXj+mRv5zyyb3QiWIWPzQljAz2qbNEWGblmJ5OR5CsiawjYPqoYV2a4hCjb+juXUttY0/QwFZMRAYrgBQV5T+K7LMBE3QxZl6sEmaVbX1ekdJdOyIbsB2NVvuQzv+tWzm/4NryGLcJTjQVWSDJkgWWSPjYX0OqkKjmOedLLLGTI3oBjNqL4M2TDu9iXNkLFrSZxjg8FLt76nwwtlbF/vLfASSxZ5QNbcZbGV/lCNFn0s89BpopqYs0CauZaKi+8gou192GbTZadt4P/OqspQ3hedImgQxAheo6JTrzNexlvEsixS2DlgksUdIVkpI9C7q1QzMZZTwfbq2HmXZQlbxnM825tVZV+tJstejbqtI8IydWLwlyhD1kiyKNSX2Xb4PRwF9SFrjvj9lBPW21Xc8zWeS2dN0w9QQEYMJLrrgJTPKDzTMEyINU+NiFrQsR33MRaQtZCFEesUghONadt8cfbc0zfg7S86o+nrNZMsJu3LpamSZ+0vWGqPh5iHiN/neAvOdp3A60+lOjVka0GyGLM+jj1NXHYFg5c0vyfWaBlwewAK2Rq2QRA3IPMMMJqbejSzjX/kyBL2uNkvRiPL500xbMJbIereZMd/0M105LVoYx/PZVEKrTc9+4Qx3PauF+G7f3K5u3imbEMUhs8gKK5ksTM1ZGwuWJfXsHHUf70F75Fi1UAho/LrRDyeE9flfQEZv890i2evGhlFiVnWHRviZMicID+OZJERV63hHI+Kip4887OWEIOwpNlEdk2MUkBGEP2FYdrIKLKbIRu+ibuix5QsNjH1YBNaKxOx2PRTdHYDnKaZckJ3wJGMAlmKlgqyzNloSEPdMDLuAsNpuOxl10ZDpJGiy2Iz6WRaMEnmSNZZGLDrdhilWaZQRxUH/iyfZLF7Adlv//td+BdXdmVatq83nCRJyKjxAwTTsiFJCL0/gtlfrYlk8ZWfuQMv+cRtvscajXdptXII9mZjsHP0lGs0UmzQT41lyDKKHNqzUFNkbN9QwIXbJ5FRSLLYCD0iQxZ02/Wbejg1ZJZlN72Wmfw87GpiToL5jFIXWAdlvfPFGibyGr/uxTnthHU5HHXnmKymQHZrC1kNWUaRGxpbXXDyBF737JNxySmT2DaRb/h5nPeQUawZ/LoKu76C7n9JJIvsu0ia+VlLiGNX0nVb1TChyhI3/6kmMEIaFGIFZJIk7Zck6WFJknZJkrQz7YMiiGYYlsV3WodRt500Q/Yfdx3AD4WCfraLyRY+rewmHZwv8X8fWggEZEKGLC6SJGE0q+Lfb9tbF+ABXoA0nouWPYlkFBm2qyXXDU8OFe6yaHJJzGjGkdB039TDC5INy+bHRxmy8AVgsEYgrR1Ry7Lx0OEl7HcNBgzThhKQKmVVObbJhG7avO9TkKgMWRLb+pIgvw2S1ncUJUHNuH3I2O9XqtH3lJdlk0I3m8TXzsaoITMtG1+8bS+uf+hY1x1Te01UDVmU7T3gZcjed92jOPvvbmg5eGcL6UJGqRu7xGOp6CamV6o4abLANx7E63brhCevZY9nVKfOy+nDKYc2jGcosoSPvPaZuOaPL4+lqsiqsu91wu7nwwsl389JTT2A5JmftYQYrCYNXNmaKKpMYxhIkiF7kW3bF9i2fUlqR0MQMdFNxwHJkSwO3wBYTWjq8dT0Kv7kP+8H4OySv/bzdwHw9NatLPrFgOxIICAzrOQZMgD4/y47BTXDwt376ovFWU3XWMyATMwucMmiKqOg1U+MYk2eLDuB4XLFQEU3ceOjxxN/jlZgu9cjbpC8WNZ9jw8TSU092NMsYcUU3EFNo58eAMwWq6iZnrObEVLMn1UV/Mdd+/GVO/c1fT3TsiI/d7TtffzPVq6ZvGEuAJy7dZz/u5rSd8QNOSL6kDGWy9EZMoNLOeVQyaL42llVaZrFeeDgAj70w8fw9m/ejz/4yj2NP8CQEVVDFmyfIGaYWLDztbsOAIg57oQ8peQLyPxPEAOyI+6m28nr855kUQgQt457ARmb67JuJrpmWMhq4e0RWiW4GRK8vizLxuGFMjYLst9Eph7uZxhGxU6nKOsmJt0606T1dmxNRAEZQfQZumlBk6WhlCw6kpJkph6+v7e9311+huNE1UpAdtyVk8iSY3QQPMZWGhr/7mWnAAgfTFcqBjRFitUQG/A31WWvl1FkR/qiOjvsFd1ERTd9kkXAycItV3T88w1P4G1fvw87XZe4NGELUiYjZd/vME4sppksINux0SnK/+MXerWIlcCCKa1MIttsYIvJMAdRtrv+/ut2N309I+TvGVrgfm3F1KOsG77anbe+4DQ88cGXYjSrpnYt6aYFOUSGqan+nxsZ5fgli00yZDEykmxMOueEMcyuJrfRHmT0JjVkLDEtziHr8prPbrzRNcfORJiTHeu1lc8ouPKXNvt+Jx4LOz9Ohsx5RbHX3FZBZpgVMmiiZJFdE3aoeDIZQfljMAM7u1pFzbBw5pZR/liSGjKmRikNYU17pyjXTKx3e8slliy6m6peM/rh28iMG5DZAH4sSdJ9kiS9NewJkiS9VZKknZIk7ZyZmencERJECIZpD61ksVgzYNte8WojFFlCcM3LpHH/68Vn8p5crdRjLFd0jGZVnLy+wHc7vfeo70MWB95INmQwXS7rGM9psRsli9kFz/betSpXZVR0E8/50M145vt/zCUwjLGcipWKgb2zTu3LzEoVacMmkAu3T2DzWJYXpQ+lZNFOJlkcz2nY/5FX4BXP3MofqwQzZCkFG0cXncC4wpss1282iDv7zYr2jZC/Z0RmyBJ8tnLNxGhW5e8xllORVRWeAUmDim75FtOM4OdpJANuJlkUsyFsYd4INiadfcJYQ6OTYSQ6Q+Y6ubrjvrhhd8qGgk/1EOdaCcvcehkyFf/wmvNx27texBszi0E0k/+dNJnnGw+i+oH1+QOEgExTeECW1RRI6F6GjMnyz9w8xh+Lkh6HQZLF5vgCslYki5QhAwBcYdv2RQBeBuDtkiS9IPgE27a/YNv2JbZtX7Jp06aOHiRBBNEti/f4GbbJmNVSxZXuBScatnmqyBIPUFrZTVqpGBjLqThpMu/T1lu8niR5gl3sNRNk2X2/uLCmuroQkLGJ35E8ORbHNT7Be8c7ntewUtG53bpoYJIWbFf7uadvwD1/eyV2vecqvPKZW4dyYmlkbBGX4ISd1o4oq2cUM2T1NWReABEs/A9ihPz9e155LlRZCjHFiN6giKrxKdUc6c4P/uwKfOOPLsUvn+1kKZjJTRqUdTO0d1gw47dcMWCYFv73NQ9iz9QK9s0WeeDE+7NFuCyK9TpxbO8PL5SxfiSDyUJmzRmAsPOsyFJoDdkoN3PyrqHt6wu8zxbgD7Y+cdOTuPOpWf4z20cJtb1nph7u4nj7hgLu+usX46LtE/xY9s6s4tbHp6Epjr19hgdk3vh+8noxIHOuB6dXmOlrUwKE15AlJag4CWZg2Rx31hYvIIub4QcEUw8KyEKxbRsl3cSGESe7n9hl0d1U9cbM4fueY61+bNs+4v5/WpKk7wJ4DoDbGv8VQaQHc1nUFGnodqS8gCxecKLJMirwJhduLy1LQno/+YJlpaJjLKdi20Qetz7hZb3FhVVSGu1urVR0bkkfBxZ81YywgEyuk/LkfJJFlWdGAOBQoJg7DdiutrjrmlHk1GqjeonZYgZVpBJYMKUVuLKAgTnEGZZVFziJi7lD8yVsGY/u92WG/P0fXnEq/vCKU+ue22iDIvj5vcdN5DUF55wwDpzgPZ5qhqwWXtMqZshymoyVio7Hjq3g2zsP45Ejy9h9bBkAsP8jr/DVoYVl29Q6U4/G4/qRxTK2TeTr7vW1ABuDCxnFF1iw878ur+HYUsU37ou99cTnAsCnbtkDwDlPvueEjE01w6mxDAYrrO5vbrWKl3ziNpiWjZc/4wQosiRkyLw5bZ0w1rPNMmbmYtvOPccur7AAPil1AVngXplzZa9ioNiSZHHI1iOdgp3X9aOtSRYrut/UYxg3YZpucUuSNCJJ0hj7N4CrADyS9oERRCMM0+IWqMPWjHEloblFUNUhOqLx3aQWBi8nQ6bhpMkCZlaqPBPJjBfkNiSLYQEikyzGfy2v/qYmNJ0FnMVhoyapo1kVq1WDB2WH5utdHzsNqyET627SXET3EifL1F5AFsyQpRW4soCMnQfHZTE8kwU0D97D/j4KTY2+H8TPL14jpZoZukDNqOkF92U9/D3F1gSbx3LQTZs7HgYz97rpmJ3IshSabVOTShYXSjwgq+hWapb//QgbS0azqu+c19zA9F9++1l43bNP9jXb3r7e3zw5zrUSNjZF1UiyYGq+WINp2fjn33wm/vV3LwbgXd/inCZK0301ZLrlmHqoCk7fNIp3XnkmPve7FzU91mbUB2ThNariHJSkMXSeSxaHaz3SKVgAtsGVLLZi6pFVFX4eh3HejHO1bQFwhyRJDwK4B8D1tm3fkO5hEURjdIu5LKqRO8mDStIMWbDw2hACslZc3MTjGHczZIAn7eIZshYW3KoiQ5Y6JFkUXRYFUw/A3a0NLOhF2VlWdaSux5aczxS0O04Ddg7ESb5TzVr7jU4EZEHS+p7YdV3RTdi27S44g8GEd481C94Ny67roRZFI9v7KIvockSPQkfulaJksYlV/RbX+XF6xdnkCJrziLV1YX3IxNfKxAjIppar2DqRQ9Y9rmHMNEfBrsdCxu9GyR4/ZcMIPvLaZ/qC4u0bojNk0e9T/xzHUKv++s66m0vsWl1fyPDfsXMZNb6zsZll2VibEkmS8M4rz8JJk80bPzeDfRfsMkOMs0IAACAASURBVAtKFtm8xmqcgKQZMpIsNoJfF7yGLNn9ysoO1rSph23be23bfpb733m2bX+oGwdGEI3QTUcWVMgoqJkW3zEcBphT2XjM4MQIBGSWL0PW+m6SI1nUcNKkE5CxTAILAFutD4rayV+pJMuQZUIki2zSzWpyXeNncYdUUyVMr1T5oN4NUw8uWVT8C89hnFiMDgRkb7p8h+/n1CWLhsUdSoObDeJ7rzRwEgQcyWPcz67IEiQpPJiIaqJabpAhS0vGU46QLIrs2OBkYPbNOv3cgq52uiszBxAa3AVt703LjhzXbdtGsWZgLKvy+3oYJUxRsGssWGvH23+EBBKjWZVnJwAv2ArLLLK/Ds2QmREZMrdul12rYhaUqSuC4zu7TZh6gc0NzGWxk7DrcaKQgSJLdfcc+z42jHrfURLbfTL1aAwLyCYLGUiS59YZF8dlkUw9CKLvcHZbvVqEYepFltTUI+j6Jmaw2ODVWg2Zk7FidV2r7nGZbWTIACcrFJohKyfLkHmSRVuoIfNcFmcD5gtiQCb2T9o4mumKMQyv7VP8GbJhnFgsu/2A7H2vPg+fet0F/Oc0MmTFqoHFkg5Jchb0olmCiF8W1vg4GrksBpEkZ9OkWUDG5D26acGw7HDHw1RdFsNNPUTOO9Hph/bg4SUA9RIx3bT4Qj7U9l6pl7BFBVm8zkhTeIZs2MydGsGusWAD7WpAKRDkZKGOjF0rjTaEwu45wzXUCuLIDU0+F4sBPDs3wfH96rdchlc/60SMuhlTJj8NmjB1AnZNjefUUEmsYTpGRGL2NolxFUkWGyMG6k6pSWumHp4yZvjudwrIiIHgieMrvsCDZcjyQygTSCpZFDNklmULNWSyJ4lKuJi1bRvLboYsG5A9tpshy4ZkyHTTkbokM/Xw6m/Y4oK5vuU0pa43UVZYIIhSnvGc1pXddT0sQ6Y4O7XDVv9ittinLoi4qKsZFu47sID5Yud6TjHJ6raJPKqGya/t4M64KAtrdq2E9TFrRDYiKBc3mdjipRSSfWCkaRATJVkUOWvLGBRZwkOHFwHUOzCKC/lQx0Zfhiw6IPvkzU/inL93qibymldT0qxvGQDcd2ABS6XGGc5BQDcdWWxG8QcWNTezFNU65JQN9QGZYdV/b3bgOXXvHXJvs+CQlRDkfQFZfQ0ZAFx62gZ8+vUX8rlkJKuiVDV4vVAnYWP+eF7jwaOIbtVLMcM+Z+Tru33TKEMWDhvPCm5AlnQTndUutlMX3+9QQDbElGsmnxwHmV2HFvGrn7wNX7x9L3+M3Zxs0B+mQXClokORpaYLoDBq7g46ACiytyhKOng52QIbYzm1ztWo3QxZWK1LqeqcP9Y0Odbr+PqQeU1nAWdBtxToieTLkAV6khkN5FGdQnSZCx7HofkyFkvD09zWtOyWTF+CiOfswcNLeO3nf45/+fETbb8ugzWvPW3TKHTTazAe3BkPc7KLQg+xvW+EpobXEYbVkLFMQ2hAFvE6nSBOQDaW0/zW6oE9hmaSRV9jaPf3Rxfr6/U+efMe/u98RuFBe7NA2bJsvPbzP8fvf+Ue93gsfPqWPVitDl5GwwluJd63i6GbVp2ZiojotMiC97AMGZNXh7VjMMyoDJniBmQsQ+Y9h21oNJPhr8trWCzrvAlwJ2EB3nhO48cqEibFTJLllyQJhRYyP2sFvpmkKchnlMSb6EwVRZJFYiC59oHD+I1//flATjgiB+acmoSHjzhSmOmVCky3cH4YddurVUe6F7dBskhVt2Ba3qKyUZ+jRvA6trxWNwAmbfobJGwByhYHjRYTda8j1JDxDJlg6hHEL1n0jp1l5SopD/BskSNO+ux4X/DRW3HFP92a6vt3k05lyMLOo9HBmrubH5sCAJy5eRQA+FhZV0Mm9n0KXLv37p/Hdx84zH82LSvxznpohqzmz5Dtmy1i91HHRj60hixNU4+ahVwTyWI+I+PUjZ6Tn7jgNdxegezaD60hC7kvXvmZOxq/p5AhayZZZOeQbVLuOrSIj9/0JO7YM9Poz/qCekdAd3EaOOc1o77lgkiYZDFsI4r9LjRDFuWy6LYfKIdsGjARRzMZ/kReQ6lmolg1Oh6QsbllLKciq8nYN1vEr/zLT70+ea5zs0hY4NmIVgKNtYIoWSxkkgeuTBXFWoUMY80oBWRDzFJZh2HZKA14QMbUXLIk4eBcCc/50C0AnEmbLaabFdoPEisJ3QZFHNmV829V9gavMBe3ZscAuHr7wABomp5pSCuELRy97FGChaxQH6ebFmTJO6agwxvgXwQGJYsA6iQsnYY1hhYd+MTjGPSNExHTsttqCs0IqyNpoR+5j1ufmMZLPv4z7J1ZxTd+cRBvunwHTnaNa9giIbjgZNfrxtFM3bX7W/92F/78Ww/yn/UEtveAYzATlqUo6971cHSxjBd97Kf4g6/eCyA8oEm9hqxJhiynKThNCMiWhTG5pJu+2jp2bYivKW5AjWbjqQNymhzb1CMoaZxedmpMi1Xvvp8v1vgGYL9w0+4pnP13N+DRo0v8MYMtTrX6fouNNrUu2j7pPddkksX6a8/Lnlk4NF/CX1/7MA94jUiXRQW6aaPojmNh10uzeW2i4IzFxZrpk5h3Aq+GzJEs3r1vHntnirj2PmczRRfcUdmlmMTUA3A2SkprqJYxCTy7r7k1ZC1KFr15f7hk/gAFZEMNm5wHfSdB7Ku1Z3qFP67KEm8uuSDUBRSrxkAvblcqOsay8WupRCq6xWsCFFnifY6S1paIdWyRGbIOmnoEGzvHQayPC0p1wjIrYj2SWPQ+nncWCd3KkImfMcnnHSTMDph6APA182a0O569+78fwp7pVew65GRKfvW8E/jir1gLz5BtXec0gl4/km0a9CStIYvOkHmPBWWaYYvVtAIy27ZjSRbzmoJTNwkBmSAZfvmnbseRxbLvev/CGy/GDe98fuhrXflLW3DlL20BALzi07fjpt1Toc/LaQq/15s1h666JgAs8GP2/KIJw1Wf+Ble+NGfNnydbvOTx53P/sBBr/yAZRuzgXNeayJZPGPzKH76V7/MX0P8vwh7rGZYeMFHb8XV9xzEE8eduTfSZdHdPPng9Y8BQKgrZ7MGz2INcaddFr0aMtX3HU24zpOGkMFlJiNJx7B8Rk3sHrhWYJtdhYzqSG0TBmS6aZFkkRhc+KA64JbwrBGxJPmzCKoi8x21pbJXf3PBP/wY57/3Rt9r2Hb6NUKdIqnboIhoTKAKtvdsMAw6MkbBsqojmZCATAj4WiHM9p4HZEkki0Ixf820fIu9MLmLKKHJCAv9bmXIDNOCJNX3WxpGOmF7D4RnyNqdiNnO6rElZ0G+eTzLM6psdz9YA/aNN1+Kz77hQoxl1cj35xkEy07UUDbSZVG4HusMakKum7QaQ+umYxTUzGWxkFF9kkWxhvPwQhm7Di367tGrzjsBp2zwNytmqIqMy093mho/enQZb/36TgD141deU/i5axaoB8/btNvqoliL/p77ARZAisY/umVDk+U6t8Ca2dwuvn48r58T2Hh8fLnCFSpso4/1AA0iBuCS5L9G//HXn4ELt080leFPCL3LOl9DxiSLmm/DjtW1sRolACi4GdqkG2atSPHWCmUhQ5bTlMQboIZpQ1MkKLLkti0Yvu95OFcDBADR1nYwApEoLKFmaVHIhGmKxAdw8fGwVPZX7tyPM/72R1jooENbWsysVrFxLNvS31YNz9RDliW+0//pW/bg7r1zOOfvb8Cnb9nT6CUAwGddrLivwwZAdjm1FZDVZciYKUf812QT6XJFdzJkYkAWspAXsy1aWA1Zyg3Ga6ZdJ/VptmOcBvtmi6m7OlqW3XKNoUjYoqzd8YxtzByad5qBbxnP8QUaC8iCUqWt6/J45TNPdHt9hS8E2BgUVovSiGyEGYdYE7V+JIMXnrXJ9zdBgo57nSLMxjyMrCrjtI2j/Oflcr2MPIkEbESQLbLLdS4wfuczQoasWQ1Z4LthvQfDFtD9ZKHP7iMxcDLcDai6PmSG1TSI4LW37pgbNl+yx+aKXusQdm05ksX68/jyZ2zl/86pii/4esOl2/HdP3lew+MCnBoyRqdt70ezKt71q2fjVc86ESeM5/jj7Ht1JIue22MrUEAWDcsc5jJyqMtlM0SXVk2RKENGDBaNCnMHgdWqgXv3z3sBhiRxmQkAqLKMkYwCVZawGDL5i3zr3kMAgK/ddYAXxvcr08sVbG4xIKvoJt9FVmXJNym+/7rdqJkWviS4VUa/jmtd7AYMYhBltJshC8kItCJZHM2q0BQJ80UdumH7/jZM6pbLhNduscCumeSpXURJDGNS2BHuBvcdWMCLPvZTfPOeg6m+T8cyZCHnsd3xjI0nB+dLKGQUjArNhVk9UdSxN8pCLbgumWbCzx7Vi65UMyBJwCWnTOK9rzrX19RX7KPnO7YUxnqx9qMRsixhy3iWbzIUQxamSUwS8pn6RfHUcsX3c05T+MK9aQ1ZRIYsrMY66NDaS9ilJCaymGwwuEFQM5q7EwYzZGG29+x3C0W97rEoyeL529bhb15+jnusrW34MMULEH7vt4MkSXj7i87AqRtHcOYWb+NANDdh1+eIe+0lNegokKlHJGXdhCJLyCgycgF30AcPLTZ0GbZt29duIU0Do15CAdkQUzMHOyD782/twm/9212YcqVFsizxQmzA2SWRJCdLttikt4ztejB/4uYn8fJP357eQbdJsWqgWDOxeSzX/MkhiBkytii84OQJAMDuY04get6J65q+DrcuVr2AjA2gbP5uNQMSZs/dSkAmSRImCxksFGuOZFEVbbNDMmTCglJctHQrQ2ZYdt3nW5eg71on2DPl1IHcfyDddhhWSpLF9SOZtmV5rJbvwFwJW9ydcp4h4zVk4ddhsGZHhGfIQs5zIzQlPENWqpkYyai45o8vx2su2OavkQy5vjMRr9OMmmBVHobnjtb8M0mShN++5OTI3z/rpOZjD2MkkD1eKuu8tpXB5E9A8z5k7Lyxq3LaDe7CAsdm80k3YQYoVkCyqCoyvx5ZxruZqQfgjX1igMVg2WN2HYk9/7jixorOwk3knU2DVjO14njYacmiyFlbxvi/Rft/ltl+98vOwXhOxWmbwiW1UThSPArIwijXLOQ1J3OaU2U+5hyaL+E1n7sT7/7vhyP/VuytCjglB4NeihMGBWRDTHXAM2Qsk3XcnTgVGZhaEQMy5/KdKGhNezjFLJ3qOWzXttUMmb+GzPl+vvZHz/E9ZyFGvysuU3IXYeKOFM+QJXSgYoTtbtWMesOLOEwWMlgo1UJqyOp3V5u6LLoT6a997k68/7pHEx1HHJhtr8jkSHczZHqbPeTiYtqdsb0P1sNsm8i3PZ6xifzIYhmb3PuMBThRtvf8eBoEZKyO1TCtRMFo1GsWqwZGBemUeM2G1QllVBmWHW5j3ogP/+gx/N6X74n8fTlmhozxvlefhxedvSn0d394xamxj6sQyJDtny3WBZw50fa+yUI4uIDzJIv1GbI4Y2S3YP38gm0ENDfbYNle1rdZHzLAG2PDTD34msF9TKxj5K6MZvS9LWa4WkG0xT9hXWubknFgbS4Af6aQfTfPO2MjHnrfrza16Q+SU5W+krv2E2Xd4IqbnOZ9T1/9+X4AwFMzq5F/y65vlpl1NiIGZFGXAArIhhjusjigOwls8XrczYpJkPiuJuDdnBN5LXRHU6yTSbtmplOwz7d5PH5A9hcvOYv/23FZ9BpDA0AhsJCKs/tbCdSNZDVv0Wh1oA9ZtMtistecHNGwUKpBN/w1ZGG291HuhsxApaJbeMp13/vKnfsTHUccmEuUyGTMBUyxauDhw0vNn9iAim7y66vVYDouHbO9V2U859T1+MCvnY/P/+5FToasgxtMLEPGMsGsQXnU9xO2mcCuNTFDlsRl0TH1qB+fVquGr45KvL7DFt1io/QkHF4o815MYTSrIds2ka97LGxj5Za/fCG2rqt/bhQjAev7lYpRJ69zasg8c59GiL/XTQvzbtAVVvPTTxkyNnWJUjgmG2QbCTUhkGq2qcVNEXgg4l17LCALa5Mi1qRHSU8n2pRgixsZzz8zPKjvBDtC+uVFSTGTkNPk1JUW7WKYVugmRNqUa55Ta1b1vqedBxYANL7n2DXK1gdpGRj1GgrIhhjRunYQYYP+MXexoJuWr6ibLW4nClpoDZk4MA5IPCZkyOLvDv7Zi8/Era6VsZMhYzVezvfDpC2M+VKtaYBaJ1lUZB7Y8wbHbdSQBQvJW5EsAo6EbaGk1+0Ms38HZU/iMTCYZPG+A/O4xu1JI7rFdYqwCT9u1uHvv/cIXvXZO3w1lEl56Sdvw2d+8hQAoJJynUOnGkNLkoRvv+25eONlp+Blz9jqk852AlaXFcyQhfVZAsIXAiyTs8BNPZJ9dme3t/58rFbN6AxZhKkHkHy8r+hmw139Rn2lAOCmv3gBdr3nJf5jCRyfIks4fdMokhA0vCnWjLpd8Zwqe5LFphkyZnsPzK3W+JwQtjhtprjoJizzVxSOk8kG2TkX1TBx7OLFOl4xQ8augzCjDzGAi9o4i7vB1Ii/uuosfOGNF3dE8hyFpsh48D1XAfAHmlH3fVzEzE+Qcs3Ejndfj8/d+lRb7xHF3GoV39t1pOnzvnLnflz1idtSOYZGlISAzKkhM2HbNmbdNc/sahWzq1UsFGv4lX/5KW+zAHhZf7bmczbGhi8TSQHZEDPIph6PHFniO4LH3RqymmHxxQHg7Zasy2ew5E6gYqAhTmADEo+1LFkUd4nFxtAM0TWqZlhNnaAquiO78nakPDcv1oes1QxI2KK61YBswq0h001/3Q5v5BvxPYoLRvbdfPH2ffi3nz0NoHkD01bQLbtusRS0gY4KlJkjoDhJxeXhw0t44vgK9s+V+GPzKS84DcvmUqtO0umdURbwsPuHLc4bmXoEMzHscy4yyaJl19nmNyLsM928ewrHFssYzSUIyFrsz1PVG9eQ3bFnFqos+epuRAoZtS4zEjy+S09dH/n6t/7VL+N/3l7vwBeULBarRp1kUVVkqLIEWWpeA+rVkPnNocTG0Ow6aGYS1U3Y5kmpGsiQyRLvRydmyOK00hBd6sQasqpbjxZ2j3mSxfpMP2NdBwKyP/2VM3HVeSe0/TrNWFfQnO9BaJDdboYs65pVhI3jbD0Sx1SrFf74P+/H//qvXXXGN0EOL5RweKHcddVQWTcFyaIjtdVNG7OrVZy7dRwA8OTUCm7aPYW9M0V84Tbve9JNf4ZMU4fTZbHzqw6ibxhUUw/LsvHKz9zBf15xg7CKYfoCCZZBEzNk4kK/VDUBd1O2VdenbrNQrEGWkmvxvV1iK7RP2EhWwXzRCTRWKgbmi7WG1r4V3UROlXnAINa5mG3WIWUUqW53i9veq8lec71bQ1Y1TN+u7XLZuWY2jmZxQAhE+DEIi5ZcyAKmmfypFcJcFuve17BCpWFnbB7FvfsX8Nix5URSHsO08KrP3lH3eNrtHyzLTqXHWrbD7lrsHmC1ImxDJOo8ZVS5TgLOrmX2nZpWfa1gI0T5DuDsdL/5a07fLTFTG6eGDEhuqFAxzMieQJZl47oHj+L5Z25MVO8oZuT/662X4dwTxyOfG5WNHgkGZDUToyH7K5IkIasqzRtDC0ELy1JsXZfzZcjYHsJCqYav3rkPtzw+jbym4G0vPB0XnzLZ8PXTIjRD5soGvQyZ85w4ph6A3xRBlIFWdNMnYRTxMknRgQsz9RgURIdTw7Ix0mYz6qxwDwbHcbYESaM1BQAcW3KURM1q2NhYEzXXpEU5kCEDnKxY1bBw5pZR7D62jNWKgeWKs5YTN0XZNcrWfGFOzcMAZciGGHHXrN/4i2/two53Xx/6uyjL4aDGmC168q5MwLZt32C0f66I/3nASeEH47HvPnC41UNPFd3ttdGsgWYQNhGUhQlVDMjYQLh9fQFA86J1cTcLcBbCbNJnAVk7GbJOSRYnRzKwbEeCJP7tSZNOrcqzd4TvzPt7loVYq6dwz6xWjaafL2oyZYvTpC0bojJh3ciQpSE5irKIj0vQ8GLUrVNaP5LB5rEsHnLr9KI2G1jfJ3F3mV0rT06tuu+R7LMHZU4zq55xkU+y2KTxOZcsJrx2K7pjBBTm0HjfwQUcXarg1RecmOg12XWe02RcdtoGbpyThGAj6lLVgB5RyJ/VmktZxd/f+OgUAOCUDQW+yefMH85zFos6vvaLA7h9zyx+vHsK7/jm/YmPv1MwpYi4Gclkg3U1ZLEli5IvwGIsl/W66yAY6BtWtLRv0Brdi46/Uf3VksACjbBxnM2b4nX45FRyxUMULGsZFVAzWIDfbfORsm5yGTIbv5jy40S3DrVmWtxJdVwMyAJlEhlVjhwLBpnBunuIRPRzY+hrH4jWOs8KCxKR+cCuvjjpW7ZzM4s7zV+76wDe+a1dWK7odQuxP//Wg3jwULrW361gtVh7wwKuUtUQLGK915Fcs+eTJ52ALPhdBqnols+pUDT1aDtDFiLRajkgczOJU8sV30LkpeefgB+84wr85sXbIo+BEZ4h6+xkVa6Z2Ll/ARdtb7zLHiW7Yt/X0zPFRO87u+KdZ7EmR+wvlAaWnU5A1q5kUZSnAX4p7zO2reP3RSPbe8BbxNq2ze+L3ceWoZtWYtv7nKb4MrLzq945E49PDMLCNmwy/NiSBmSW+//6a/77u44iq8p4ybnJJGTsXhzNti5hy/g+ryNZjDr3eS28Ie/nbn0K/3n3AQDhSpEdG0ZweKGM6x865lso/+zJGewV7rVOGNS0Cjs/olyfyQbrashiShb9gYi3sP2dL/yClwgw1rty1GZ9yMTX/s2LT2p6DP2Azz24Q6YeQPg4zr5vNn9e9+BRXPWJ2/Ctew+2VRvMYONts/uf3efdNh9ZrRooMIm4u145vOBk9ZgxUM3wAjJx7AuuDzKqMrBmdY2ggGyIGVTb+9nV8GAhmNVhAYG3K2X5bHqZlnq1YoT2munH/RXDsltyL5RlCSMZBcWaGRowsT5sJ693Br5mGbKKbvqcCkWJAM+QteqyqMgwLZu/DgDuMtdKhgxw5ExibyZJknD+tnWhDXQB/2IvzDGs0xmy2/bMoKybeOn59QvbZ+/wgrQo2RW7h5Puas4Vvc2N8ZyGn73rl/G2F56G1aqRaiPspMYWcXF2Rls/NytVfyAqTvrnb/N6ZEXWkAWyUIZlw7KBs7aMomZY2DO1CsNKZnuf05x7i90PonFRVA1Zw2OL+H6OLZVxNMRNsdxggXbv/nk89/QNvkxdHNixbhztjIStoDljW9RicySr+gIWxvd2HeGOqWHfC6t5evs37+eZKEnyWq0w0m4T0Qh2fsS5Tecui55UHUCd22wUogQ96Fx5z755AN5ml6ZKUGXJZwLSaJx+8oMvw8d+61mxPluvEb8Hpk5pB2aCFTZOBzNXP97tZGn/z38/jOd86Ja23hfwXI+bBVrs9+UuZ8jmV2vcRImt2Zi767ZJLyBjkkVTUCEEbe+pMTQxcLABNC3NcicIKywVF5EiwV19Nr7xSSngFsb6zBSrBndPE+nhHBuJadktW5KzRUmYZJF9zUyyON8kQ1IJSBZDa8ha7UMWspPPFtlJbe/XC2YCkyGWy1GL2GaLlk7XkD017cjZwjJk33jzpfin1z4DQIMMWYvy4zlftkXBKRtG+DXwa5/7eWoF5pbdn6YewXFADDTOEHoTRV2HXL6lezU7gHdedx9bdswBEkoWAS8Yn4uSLDYLyJqYejz3wz/B5R/5Sd3j3o55/QJtdrWGrS30g2IL9vUd6rNXyKoo1QyezQlKNkeyauimW81wWlksur0KgywL8vjHXcOcMAOSNB3/msHOiy9D5soGvZol93qMbeohh0oWAc+GnMm9D82XfRshSa/vfkasCTVMu3OSxZDNLlGl89mf7MHde+faeq8g7Br9P9c8hH+64XG86Sv3+FolMBrd72lR0U2sVA2+QROULLIMWdWw+D0pjmNsrcCUC1HOtIMOBWRDzCDY3gd3jW589Dj+9JsPhD43OKGyz5UXMmTiIMNkAHPFmi8bw2gWqJqW3VTa12nasQsfyapYFSSLouyKmZpsXZeHIktNTR0qhsl3+4BAQNZmH7KgzAZoR7LoLfg2hFT8Ry2stSaLlk7LIdh3F1b7k1UVbHSP/Ts7D+HPrq6//qst3suzIYt7FsQ+dmwZ9x90Fl8XfeAmvPk/7uXP3TO10taEbXbAsSwM1jLBarHTezDgFTNkYjaqkcsiUG+YtH2DE+ROLVdg29GSxzCYZJYdmzjmiG0borK9dccW4xr5+E1P4q+vfRiAt/kQzJhalo2FUq2loIodSyu1Y2GMZBQUqyb/3u/52yvx2D+8NPD7+k039l08cGixbpPl06+/EGJy6C53gXz56RsBAOcJRiRJzmenYfehKMlkGTKxvsuy7Dq32SjEjQ0WKLCM2N37nO/hOUJg6n++/f/Y+84ASa7q6lOpq8OknZnNUZsVVzlnISGEyAgsMgZj+ABjwLLBBhwwRjbgANhggrENGIONydEghMBIQiCU80qrzXFmJ3Wq9P2ouq9eVb8KnWZ6Zur80U6rQ3V11Xv33nPuuW0zSb2CoGSxAwxZrGTRX7M+/MPHmIFQp0Br1qOHpvCJW3fi1keP4K5dYw3PIwOf2WTIaE0bLrn7HCWu+ycqkCRguTfmp27aTL0THIQeclnk3DEXEhbGXZVBiF429SCEg4f3feOBwN8iJoMcCOl7sUXQtAKLDMVsUTawSYHLn33zQZz5/v+d1UqS1YZdeEl3+ygoyeVjCNoK+vIqhgpasqlHPcSQKX7TvKhHrRmIAsfWTT38gG9EEDi2ypCFjRvahTuwVYrsRaF+vS/euRs/ePCg8HiA5tluXv5LNuK8Wx4xaGMzdfzo4cMA3Er81X93G975lXub+iwe7VzHcWh1+DHBn8w41AAAIABJREFUCsmz+rjhwzwbldRDFl5bBwsa8prMBm83k4yGjQCCkkX/+k7LkKUpJnz0x4/jS7/cDcv2Lc7DQeRExYBlOxgpNTeCA/DPU7vjI1570Qb84bXbGPtP60SfrgbWpyjJIn23u58eZ3PIAODcDcN47o5VePd12/GJl5+JYk5hjMXW5X346psuxFuu2Mye32s9ZCQb5K9H+q6pesh4hsxbz3/w9kvxvNNXYc+YKyMjY6SRUi70/OZcRHsZuho8D+1+rzyn1iH85NHD2PCu72D3WKPb74vO9Hvt2o0zRPuxKCGjY+v2LEoelJCNeAwZFaGOTddRyqnI5/x1nfYsPj5ocFlUM8lihnmGuZpD9jv//iu85J9vT/XccIB54sqgPfKOtYMI42M3noEXnrEaF2wcARDUbYukZq0mZF++a497jLPY/NoWQ5ZzGTJbwJBRRtanq1hSyqXoIUtj6tHa8kGbViVU8QWalyzyQfSIoF+l1YQM6GwhI6m3g4oKFcNlAcLJYKv3Mi9/IzaIZzxEDDDZa9/yiJugPbR/Ehve9R38xmPT0sByuiNr0ttMyMyQPItnyHib9Tjbe8BP2L/mmRPlFBkjJR2HJj3b/BYki1RM4n8T3ogl6d5IOxialwrzrFg4ICTpuOi+SgIx8v1tMmR/+pyT8f8u34xSTsVM3U3IFFlqCD77PHVAGHQu7t49Hjgvee+8DhVzeNapK7FyMM/kU7qm4Kz1SwKz1eaSEPJd8YKMgSpLAZt1+l1FLHwY/PkihkyT5cD1pmsKfnrT5fj+71/KAmDLdppmgHsZgV66mPlqaeEXh/3f6kt37gYA4fp5/Wkr8cEXunL1dtU4ooTs9p3H8Mmf7gyYhjDJ4ixK/kipQZJFWvOOzdRRzCls7SrXTWbfz69NLD7gXRYFw8vnOxbGXZVBiLlKyP73oUOsMTgJ4WMbDvUBhRM0ANi2vB9/+9LTWXDEB/giGj7KJCSJbWA9eFZrC9evdo3hLf9xd1PyKst2Wq7GxvWQUYBUyCkYLuaSXRbNsKmHPxhaxMA1A2Kyxsp1PHxgEnUvmNAUqWm7f/75okp+lD1z+By/59knNjynk72XdcuOlUny82Acp1HK23JCxrMtHhvEyzyPCa4DGkBLG/ZPHnUTs//1mtDTwLRav47j0OrwY0JYuhyQLAYYsnhTj5pp49dPj+Pm7z0CwA1eh0s5Fvg0a+oBcAwZt17x10G7PWQEvhjDB/lhhoyOoxWGjFlXFzoz6rRI7L8lZjFIHRAGreH37D4e+P+50HuMlHTs99wFSQLPXw/NDPruNKhwxRdqTNtdT6hoVjdt9runYchG+nLs92WW4ooUWIfyqttzurRfR06V8eTRGezzXPG6IUeeCzRKMdscDC0w9aA7WGRHP1zKsQJZ2wmZYO/8lbdG/d3/PsYeY6Ye9dmLC8NrCRlwjc3U0aerkCQJOUXGr3aNs+MLMGRWMKbh45GFhCwhW8Do1cHQgRk+oWOjTZN6anKKjI+/7IyAE114oDFflRLR/lH9Ummr7K0yZK/7t1/h2/cdiJyrJkI7DdMlXUW5bjFZFv8+yzyNdk6RsaSkxdqef/72XXjyyAwLTIBg8/P+467ue0hgopEG1Ot1z+5xXPfRn+G79x9IdO5K976Nx0NJwdblfQ3/j8frL9mIHWuCbGwn75uk+UDhqnY4GWT3soA9i8PxMm/q4d43/NDx8XKwv9JxHFY5p49pRaJqO625hSYhLQvEw7IdfPXXe2HZTkNQxLNiJU6+GNVLwksmA8mSInsJWfMMmc71wAJBUyO+mJPEfNC5SbK95gM/voDVyJAFZUbNgBKydhkyArH/dUs8A4v+fxh108a64SJm6habMQc0Mjz8d6SkhL8ewnH6nU8ew88fP4qpqoE7OmzOwMO2HdS4taPmMbOGZ0Dh95D5/XVp2P+RPh3HZmrue9m+XJxPyPSQy+49e47j0g/9xHvuAknIGqSY7TJkgoTMW0hFfewjfTlWoBQVx5pBeH3m16BRrr96LuaQhdl2UjVZtoOid5/lVBl3eoX8fl0N9pgvEsliZ8pXGXoO1OALzF0PWVSTLH+jhRvJZ+omzlg3hC+87jy89+sP4E2Xb8JIn467nhrDXbvGIUlBGQ8QXAQpqOnXVUx5G/S4N1D63c/ajumaiY/d8oT72SkXpFbPH5sLYjcRPLYxv6lPVzAdwZB9/OVn4H8fOoS1w0UMl3K4e3f0DLb3fuNBAKEN2VsAHcfBXbvGcOKKgaatsAm0AX3/wYNwHDdATNuMnuZ9w/jWWy5mdv9xCFeWO8qQmfHuZ3wgRM+HHvqbO67w86PAswL0e/Hn2XGCssav/GoPNoyUAu9BgUSYvfze/QdwwtIStq9oZLHNLpl6aC0kZF/65W685+sPYLJqNHw3/h4p6elNPWqGHRycrsoY6cvh9p1eQtbMHDI12HcyNlPHs09biaV9Op51qj8moVOmHvycMz4oC0uYWELWgqkHreuDhQ4lZLqCcs21vRcxzSVd5Zh29/+blg3bAS7dOoov3LEb9+/zE7Lwe/Ay3gJLyPzrIRxM//m3HgIAnL5uCP9x52786B2XYvOy/ja/ZSNoDRooaDg6XUPdslmgrYZ7yEw/sUrCSCkHw3IwWTUDQ3d5Iyf+3+FiwMKULLYvs9a59YFAhS1bUEgbKens88ci3KXTIrxmXbBpBD97/CiAINtLjOtsmnocm64jp8jsOPj9i3qbc6oM1ICNoyWo3OByALBCLQ3EbDqO07SqppexMO6qDA3gk4i5SsjGIvqU+ObkcNA7UzNRyqko6Sr+9qWnMzaFNplSTm24AfmEjBYZmmsB+BKd09cO4Q2XbmSPpz0v4QDn3j3HGwZNi0CmBs0wbJbVekJWzLmSRctqTMiW9efx8vPWA3Ala+Mz9USmhZq7AX+jqRgW7n76eMCBq1lQleyuXePsPcn0oh1EMXanrhlMxeaR3IQCsk5W4GoJdtR0DTPDmjBDZrZ2P1M/GNDILBP2c4Ng/+ir9+Ob9+4P/H+6Tj7648fx5v+4mz3+pi/ejWv//mfC97R7yNSDGOrDUzWhbIjAB51RgRnfw8avATlVxkgpx46ruR4y35TItGwcrxjYvLQPf/bckwN9nKkliwnn5uhMRELWIFl0A8QlLSRk77h6G248dx2uP21l068Voej1kEVLFt1rm99b6DysWVLE9hXBZCn8HrxDK/0e/P3Cn5ty3cQjBydxZLrGmMDbdzbHkj12aAoP7p9IfB7NQ1sx6B5f3bQDM5l4l0ViRtNKFgE3+afrWJElFHL+a/OhghyPBcOQqQoL7N0iUocYMrNRshjueSpoCgo5hcn4jkW0VqRFWCK+eVkfLt+2FIAfZzmOw/4dx5BNVAx83euP7QSOlw0MFTUWu/HXFiVptLaO9OVcRY7I1MMrBJDkuJcN61pBlpAtUPCylbmidqMWmJmavxCEb6hy3WpgwAB/Q+BlJAS6uWuc7f0aPiHzApCcKqM/r+E3773a/eyU54VfGJ44PIXn/eP/4a+//0ji62h9bKYS5TJkrd2WJFkk16woydhwKQfTdhiDGAad6zIXzNNi+dihaVQMC6etaTRbSYtiTkVBU1jV+cH9E/j2vftbZshIathsIrtxtITXXLiB/U3fm+zPOzk4OcnUY7Qvhz+6djtef/EJws+ut3g/l2sWOy+i+wpAw7DgWx89wv7tOE5gQOd37juAHz54EOd+4Eexn9utWUWt9JDRcZiW3eCyyIMv9ESxe4GenVBCNsz1WjVzLRLTVjVsjJcNOE5zBjXh/5/MkPmV+GAPmX/N3fbYETx+aBqjfXpL9+XSfh0ffOGpqZncJCwp5jBdM3F0ui5kZ6g/kp9FxnqqFBmXbl0aeH74XuQHWBNbVuSOvWpasG133ML9eydge8z+sn73N/9FkwnZ+7/9EP7kaw8kPo+MIM7d4BpY8YmXJssBCS/tU6kSMu9avfl7D+OjnmJEkkI9ZNy/w3WMhWJ7r3lMDCW57c8hC/aDAj4zVqkH91u6zgYKKjRFatkG/w5PPhte20ZKOfzra8+FIvtsEx/LxCVkf/w/9+P3v3wPHjk42dIxhTFTNwMsXZAh8yWL7t8qdDXYIxY2/Wq3l7hXkUkWFygCFfU5umijmlT5nqowezRdM4VSOLoBRwWzpviqFMl+lvb7w0yJIdM4/TEQf174gJh/Hh37r59OdpyjoKwZrbZlOy07elFQMlU1IEvRVs0DnoxoomwI5wSNlnLYP1HFR244nT1G5+yg54C0rL/5YbE8Rvpy2Os1iH/3ftfmvdWetC+94XxMV8XJZRxu+YPLA39TcNOfV3FkqtbZHrIEhkySJLzp8k34lsdOxTJkTRzXTN3Esn4dByaqkRLTcEK2j/vbnWsXfP5PHj2cGDzYbZjTxKEVhoyCR5PrIXvujlWxv0eUJItfO3hGTfcYMkIzSQzvEuvP62khIRPM9+NRzLnGF2Nlf/3lGSVap8Zn6njVv/wSAHDV9mVpv0ZXccGmEfzdj4BbHz2Mtd5gcx4kexIxZDlVxqVbluJTtz3J/l/49+HPN/W9ybLEzlmlbuG8D/4Y/XkVLzl7LQB3rSaTi4cPNBe4TlZNHJoQu//yuHv3OPp0lc1Eq5t2wIRDVWQosuT2kDWRkNH3/cGDQaOeQA8Z9z7hkQILZTC07knf/HPaqR6yRslieHA5FV0kScLpa4fwc09e2Cx+61N3AECDaoUKRLoqs3gmjhHnsXfcdRydanJf/fgtj2Pf8SpzjiSU6xbrFaNj0j0WjPp4af0q6YpXYPCPtcH2nvXLLiynxYVR5sjQgFYr6p0EP5SWMFE28JyP/5z9LWTIBCwYbaCifhXeZbFuOcipQfte6iGjDYaXeUSBTyb5hYH6ONIEhCTZqjQx78O0W2fIKCiZqBixFfok6/CqaeOV569nw24BfwEkW2/eGKIViIY4i5qe06CYU7FsoL0EEfCvi34vcZlNUw+CHnFtun1jydctD8t2UDVsVsXnJVife+05bM5SlAsp4LLc4fNAUtPYz+6W7X0LPWQ+Q+awa+z3n7EFH75hR+Rrog6dMRKWFVAh5FQ5sG4157LoB3HU/C5MyBKunyTDE/ruU1U/Idsz7s9GouuqzAVtO9YOJR7/bODMdUMYLGgwI2ZFUbGBN/bgE5SzNywJmBRFJWSrh4K9pnTPVA0LR6ZqePLIDO7h+m+f9qzy4+4hEco1E0ena4kOvPfvncBpawYZi1ozrQaDA5qlxTOCSRAVNgFEMmRhw5R2+317BWTq4RubtLdmaV6CXDUsTFYNHJyoMskirzi5cvsyXLHNL3Zcc9IKPHRgko1eSAs+weLXow0jRZag8X1yfBIWp9yh9SvKEC0KH/7hY/jSL3c3PD5TM1l8ArhJKF2DvKkH4DFkmixkyGgtz3FKhYWEhXFXZWhAqz0n7YLvSxJJFo+FGlfDNxT1kIVBVfwTVzY2TtOQwaphs8C3IJDK0A2vyhJkKf5m5hMy/nkkP0izEDCGrIlFw25D6kVByWTFTEjIyERAfFw1w2po4mYMmdfT0EpfCY9R7/X9XJLQjBtlN8ASMq9CPpumHuFjCN+zhmWjTxf3l0WBAoClXkLGM2RXbFuGV3tyzUkvQL9q+zL83pWbA+8xXq4HAgkAeOLwNPt3VJuY2W2GrJmEzAuyTNvhDAzif4uoRnH+8/nqbE6RA/1ezQR2vMyJDVAVWM0nXT+yLEGVpcj1nthBnk3mZXMU3BncuQ33Xs0VVEXGSd4IFFEyIOwh876HrrrugTeeu46dQ00N/j5DBXc9umJ7UNpI9wy/hv9mzzhL3HYfmwHgJizNFN7KdQum7eB4wpo3XjawrF8PJNumYCZTjbsem2HIwshzr+UTsgaGbMH0kMlB1rEDa1ZelVE1bFz7d7fh/A/+mMVE1Krx05sux7+85hy8/eqt7DXnbXSTp4eaZFr5PkQ+Ifv6my/C5mWuszAxUUCYIYu+XinZb7bQEIVy3UIpJJknmTDdY6wtxZtLFughY5LF9Cqn+YgsIVugmCvJIn8TiSSL4WAhQEtbrg5eZD5A73vK6sbeJVWRoSkSxst11EwLOVUONI0S6GaWJCkwf0QEnqoXJbdpzinrIatb+M3ucbzys3cmWlKbtt2yXXiJJWRGbMCZhiEL937QAkgym/C8uGZx+tohXLR5BEsH/MBTZFs9m6Dz0tcNhixBskjgXfwCrzdtDOSbOy5yWLx48yje/oytuGDTiPCzKBF+5QXrsXl5MACvGnaD1IaHqHgCtFdYiEP7PWRef2WLAaXIRAFwK7j879sMy81Lrtm8HkEPWZqBvzlVDiRUBNv22cGo+4wCNFoXti3vx+XbekOyCLhSYkAsK6PeYlF/Mq3773vOSfjMq84GAJy1bkng9SetGsC/vvYcvO/6kwOPX7x5tMFi+9BkDVeftNz9PO7eEClCokBmO0cSpL/luoVCTg1c92F5HWPIvHmZaRiynCouWvLOoXxRjz+vwAJzWeQMejrRG1fIKagYJjNLoho1FbZEn1FkDGhze8793CgHfug9z0YFGDIu3opjyOinb+aajsNM3UQxFNdR4ZOOlda3oq5C1xSxqUe4h6zFGbG9ioVxV2VoAF3MqizNKvNQS6DEw7plfqOjzU1kPvDuZ23HB15wCs6LcPdzHOBff7ELX7xzNzRFwqaljXOn+ICJnz8iAs8K1ATJbVMMmWHh10+P42ePH00c/mjbzZtTEGiDna4lMWQU9Df+PoYXtIYTWiZZnKpCV+XAxt0K3nrVFnzx9ecHrJXnGj5D1nlTj/SSRbEktm7ZzGwk7SZEVe2hYg5ve8aWhiSbroNJb33IawqWhqRMdctGOSZRjjIKMe3uzCErCFzMkkDBIz+HrNVkMRAYe0GCLAHrR4qpXBpFoNdV6xaOzdQhScHh3eyzUwbaokILP3ojqi8kPJD1nddsTVVEmC3Q9R8e6gz4hQG65n/88CHmAMqft0u3LsUv3nUlrjl5RcN7XL5tWcP3ff/zT8Hbn7G14bmXbBlteKwZUwYqltAg8ShU6iaKOSUgZQ7L64gha6aHDIBwDY8yYaFraoMnY18wLouKay5Fe3wnvtdwKRdQBzkIMmQi4xC9RQke9YP262qDyRD/3j5Dls7Ug4o2rSZk4faDSt0KmOQA/vVHxRQJ7nkhhkxo6hFyWeykiqUX0DurbYaOgqq3l21dit1j5aabjlsFH8SKAlpKAqh/g7/pKAkSMWQjfTpeft76SClRYEirKuPaU1bgP15/Hp596srA4/6/ldiAuyxw6wKCA3qTwCdktHAkWeCbtt1yQkbfr2JYsQFhXA8dPaaHEiUaXntosiYMFltFu4ldJ9Hosuieiy/9cjeeODzV8vt+/JbH8cjBKeH8pDD4uUIEy2M3iLlLO0ahHFPgAPxAddIL0POagqX9wd+2ZlgB63wgOFtKdK9SX0w3JIt8v2ha+PMAHeZE1uo9FgiMTfd73vaHVyCvKcGErInATpIk6KqMqmnj6HQNQwVNeHx0Pi8MMZ08ogpNvLwyPID2OTtWYevyPjzuXeOMWeqhZAzw5c0iySKtIxXDNbf4n7t9y+5wgrJqKHkmIQ+R2mLtcJEVB0i+eHS6hp1HpvGLndHmDL944iiOTfuGQXEMmeM4KBuu67CQIZOJISMThCAjmAQRQ5ZUINsw6s7xa7Xft9ewYdRNMGm4dyeYv2X9eRzhEhk6VzMxDBk/4Btw2fyH9ifHbDzzFaW+4eV/aU09xmfcRK/VhCzMws/UzIa9gq4/WtOpwEU9ZGH1FNDIkGWmHhnmBehGfeGZa6DKEr593/6EV3QG/E0uChxJiz8QCnoBv7oZNS8pLTRFhiRJuHDzaCAY5SulvK5ahHJNnFiK7GOjwEw9DN/9MYl1cV0W2wsWZ2pmbDAcV42jBTuSIZuott0/xkMUFMwVyDCC7yFzHAfv+foD+Mqv9rb0no7j4MM/fCzw/nEIb8yA/zuxhCxlT2jS/STLEnKKjCnGkMkNzf41026QK52y2jfWEV1m7bJQceBnDqYF1XBMy048tpedty62Ss738hBTkQv1NQDNJ3x5TUHVsPDE4WlsFLD7hJ/94RX47KvPiT4+VZyQ8TPTwo36b3/GFlx/2irc8eQY9o6XmeQxzfU6m+iLkSzSdfGerz+Are/5HsCd/nZZPhFrNFTUMOoVL9Z5ro9Hp2u46iM/xcs+fafwfQzLxss+cycu/uufsMfiEjJ3/XGTTZFUloJTctGj4DSNtNX9XqLEVvzaj9ywA+dvHGa9Z0m9b/MFV5+0HKWcgi/ftQdAZ3rjlvbrgd+VmeV4RSTR2hAeKP0X334I1330Zw0OuITP/d9T+Pfbd7FrwbCcyASLZ81p3VRlKbaoRc7UR6da6yHjEzLHcYTjjOhvWq/o+i3pgh4ybvYewJmrZQxZhl7H/XsncMeTYwCA5QM6Rvv0RK16pxAIJAWBIyUmZL0ekCx6gV+4+bNZ8IlXISYhi7uZZxIki80kZFXDr14mva4ddzrd22Ar9c4zZPSaqZqJJW06LPIQBQVzBZHLoumxU83a/xKsEHObBBFDRv+mRLHZHrIohoyOiSTNuqoE2C/6rDBDdhk300l0DZHxTTcYMp4JSQv6DUyujyoqYfqrF5yKxz9wXeR7SZKbxNYtmyUufi9PtItfEvKajErdwiMHJrEtxkhj7XAxllXOqbIwYefX4rBsuqSruO5UV8J3+85jPcuQkamNaJZcuLDzf0/4LFX7CVnj64cKOSbvpYQssR/M29/4azdO5sjuX03xjZg4JiQsWaS9N+33FSWa4XWf8KKz1uA/33ABNoy4DNnCECy6bMzZG4Zx717XObMT7pFL+3UcnvR/V9o7aN0WFXzCUnUaylyOSJr+/FsP4X3feDBwL/PuqcH3llncRce1aqgQKfuumRb73FYZsvD4CdN2GhmyXFDtQGuzz5DxkkXv3MnB4tdCS8iyOWQ9igf2TWD1UKElNoK3lc+pcoOFaDeRxJDRTUbzr/hAgQK/dmVsfIWQNmpVlgIBYlQlmRCQLFqNC0OSOQcAkPqhwksWExgy02rdnY4SzrJhYTAmafJNPUQ9fu5jeigI4c9pJyWLUXNv5gIiySL9bq0ajoSltGmPgb82a97v1N+kqcdMjASYoHMJWV6TGyTBNdMOsMUfvfEMPOe0lXAc4IPfe0R4LEw61YXGf3KBq9TTr2csIQswZK0fG3Nmo2GyHFNBaJYhK+kqdh6ZxmTVxIltOBsmSRZLOaXBpKWQU1gBp2L4AX+anrXZBLsvBfuKpkhQZIn91se5WWvtfg+RjC+nysy9dLCoYaioYXeCZXm4sAHEJ3Ek4XcH5brf4YF9E2xeoy9ZdINXCvxFsyVF4JPYN1+xyX0sYe9942WbMFTU8IIzVqf6jPmAYk5psFVvB8v69UDMMBliE0VrT9jMiWTkSUqAr/3Gl+ZWDRtXbV+Gm67d1vDetH89emgKeU3GlmV9gXmTPPh7R3TNpgFfwKT9I1wYfNm56/ClX+7GM71+TlpPS7oC3VvHHMeBJEkwLQcSN1s1M/XIMKu4/mM/x0s/dXvb76MpcqI8r1M4MFEJJIOi5IMWGL8fplGaFVWli8NX33QB+zdf5aKAPyxFSHJZLNdNJsfiAwA6RieFdJl6TGqGxb53Uv+P3RZD5n5XK8HhjhazAxNVbHjXd/DNe305Kx1fFEMGIDbZaxYULP3WOWvxi3dd2bH3bQX0nfnEh67PsO1zWgRmVaWRLAqG+zZIFtMyZBEbIQ9dldlGSIHnioE8TlxJg2iDPWSlnAJJkvC7l23Cqy9YLzyWpz0r8LXDzfXqpIGqyMgpclMMGTF2aRiyNMh5ErGwi1+rph6Ay37e7c232iaYtdjMscVJFkXD14uaEqhW+5X83goP+mOuf0mSIuXP7TJka5Y0DqIG/FlexZyCgbyGu5+On88nYjviEjJiDnjJ4qd/9hT+3xd+DYC3AHd7yI6XDeQUscOwCPSbX7JlFDc9czuAaFMPQk6V8aoLNnTEjbBXwN+3Sd8/DShRJ4RN1URrg8JGVliB0UFR61zUtb5xaalhVquuKqgZNj5+y+P47M+fwpZl/SjpauQ+Qse7tF9vqleXB1/AZIXBkCPvluX9eOT9z2LzTmmNchmyIGNo2HagwEf75L17JrCQsHDuqgUECt4fOzSd8Mxk5FSZSRq6jU/f9lTgb6Fk0TuOvOYlitxz/FkTzQdLZ60fxglewzG/AdOmE+5BzilybHJUrlso6SqTJxHSMGPh5wYZsiRTj9YZMn5jie8hc59311OurPUrnn4e8N3rwps6/97tSkp5ULC8eVmfcFj0bILNQdF9l0XqeZxuUbIYmFWVRrJIG5EoIWuVIYuwpg8fEwUjd/zxVazAUTXtQCAZZafMg9atLcu7M8Mqr8lN9ZDRLWtajt9/00ZCRnLnqNk47vs3t7Xy8/jaSWRziixco+gx0fwpVZFZMs6vVb3ksAhwM8EifvuoYLpdhuzUNY2jVgA/8C7lVPTnVew65jNkjqBiFw5uh4pawPwhDLrvCiHDGGI4aZ/Mq67cdaJSx2BRizS+CiMfMlWg91psCDoSdkCyKOjDJchS9N6cU92Y5BAndxQlRHXTjkzURImy7hWfqZd5ab/OJNIiUPFxpJSLNf4Ig5fn8/slfQ4NgI6CySSLSsOQe8tyAkX1nDdH8B9+/Dh+9viR1MfY61h8d988QCdt6mlgaSctvKPAa5j782qsZFHXlIaAjs2aaFFORIspX9mlSpIdysh0LYEhq/nuVgH5mCBQjgLvbETnP42pR7uW3EB8wElBPwUQywZ0vPKzd+KPv3Y/Z+oRzZAVYwL8ZkE/Syffs1XQJpBXFWiKFGDIplqVLHLXWBrGgW1E3Ovo3z5zl+5eLqfYCHkmlA9G6Dgs79u8AAAgAElEQVTGy/XARlvSlcBrRdfz44enoCkS1g+LmYV2UcgpTVVuLS84JrdKKSYoSgN/mKwNSfLZNv5cNmsOQL8tgIY+vlaOLQwqDERJ4GXZdXp0JYvNmUPMFsLup2FEGVJ0IrH84dsvxasuWB94jDFkuhIYug6Ii5HhAevrR0o4PBlte8/3gIq+AwXfS/t1HJmu4XjZwFAT1w7tjUF30N76zWcDgTWwAwzZ8sF85P+LO7+kZOL7wkSJV1x8KNpjiNEnnL52CAVNiewho7V1pC8XmNGWBH7dma7xskfyBojf440AQxZUipihuIhMPQDxvNv5isV3980D0A3XiZkYuionGlh0CuOc9nggrwk3TtajpDZKKY02GDJ6TyBc9Xf/bYUqlqJei8/f8TSTW5UNCyVPux9lVJIkY6szhsxmyWmiqUcHXBaB+MG0FGw/ddT9rgN5DT97/Cj+487dnKmH2GURiJfANQtiyKKCqdlEjrt+aHYLnY+WJYtN9pDRtS+S8rKB1Sk3yHLdnUcXxxCw76zIgSRFVWQosoQjk8EKfpghsx3gH3/yBF7zuV+yx584NI2No31dC+4KmtKcZNH7DQzbbtjYWwGx5nXLCQRA7bgs0m+bU8QDe1MfW4QUm4KdOEOeQk5BtYcli30ccy1CtySLALB1eT9ef/HGwGNBhix4XkXrfDl0zW4YKWKyakYyfhXD76kW3cN0HS8fyGNspo4jUzUMNSEn9xOy3nG6nQvwe10nihAbPaWOCKIZZP5nKx775e81omtjohKdgIhm9FH8N5BXcdX2ZXjjZZuQ19yi1g8fPIjnffzngYI1FQKGS+71XU0ZO/LHOs31HdMcy6S4gRQHeU1uYMgMy45cazshM+0V9NaKmwGA31TZiaG5OUHi0y08edSXWA4UtNiGf90LeoPD/9oLBGhjEd2sYQVJuJJ8dLqG9379AVz2oVth2Q7KNZNp9wPHaHK0fFJCxjFkVI1K6iGz2hioy2/acUGnpkjgP4L/HrVUDFnnE7JOzH9pFxTMDBY09ru3berBBcdpNntJkhqc8ugY+mNMDUSoGTZ0tdGogwcdU9jEhf5f2AUuyJC5r/nQDx7FrY/6spH9E9Wu9I8R8s0mZNRDZjltFTwIPEPGB1j8+zZraEIB/UAhveRMeGwJph5xhjyU6DJTj15jyBJ6KLuZkAE+Q0dYNehe44NFLcBwAuJ7tBwaH7HecyyMcrLzGTJVWNygfXLFgMvIPHZoqil2leT8veR0Oxfg175OBPeSJOG2m67ANoFkO65IRUwWLxEXKQF40w0gOHokasYZyRy3rehHTpWR19yC4zu+ci/u3TvBbO4Bv3Aw4rHpYWY3Cvx9yUsWZ7jrOA5U4NBVpYEhq5t2aI6s/+9m5Ou9jsV9J/YomOtZBwJfTZGZNrmbsGwHT3Ma+sGCGjkYmoLEBskiOR21yJDx1X5C9CYdlFsRWwQA9+097vaQ5dSG/jve1SfKkpZAgU3VsDiGLIVkscXvT+cUiK/Qk3U3gXeBimTIAn15HZQseqdWbiMI7RQu2jSKr77pAmxe1seYUUpQW+8ha06yCDSOZKBNeSCvQZLSM2Q1005MAul3FQUiOVXG4amgpKqoBRkyHg5LfOyuBvOFnMI24e8/cDBxQ+Zt703LaTv5pzXBsOzIAEtp8h6mYH8g3969FS1ZJIYsKSGzY+255xJxLotA93rI2Od7CeGaJW4idsrqAfzLa87GpVuWNiZkgnU+HNhuGIm3y08aW0H7BEnkJqsmBgvpHXDzEQzZ+64/CZ9/3bmp32e+g5e/dUqmu26kiPdef1LD47GtBB67HUjIBGtbOCEb4JJw0R6jqzJmaq4Uma4lSsbp77P+8kf42x8+6n5m3e8hA4BqgqPtVNXAZNUIXPN8+wrJF0sJPWSfefXZ+JsXn4al/XrDnLGyYQVHGHG/U6vGI72ILCHrQVBC1omhub78qrsX7WTFCPSaREkW+SCxmFMCzAMNWm2dIRMkZBGbWTjofeqIn5BNVU2U6y5DFn4e/++kyhHPkKWeQ2Y7bSUneoqEjH8e4LotEiJ7yLosWezCyKqmIcsSzlo/DMAPbEmuUbfslu4h3tQjrSFM+Jor825rEQyICDXTSpQj0XUgMmrRVZkFi88/fRWAYD9a+L0peDBtJ1Yy2y4K3hDlp4/N4I1f+DX+96FDsc+3uUTRsu22h7/S0FLDdiLXqjhpkgiUiHWCvROtMVTsWjkU3d9CvXn1nmfIxPdhLuJa7lRCllNl/P1LT8eXf9c1vJEkCVduXw5FlhoSMtE9SvcHJbrEkB2aFCdkvMuiCMTCLh/wTSSakSwSMxb+nX/74hNwyZalopcsSPAMWSf7JkWqg7i1J6fK+O79B/GxWx5njwkTMi8+JCMgfsyBSLLIy5ipmErmLfxIlE/8dCcATrLYl4s8Bh6//5/34Lp/+Bn2H/fjCF6eu2fMtddfNRSvmlg+kMdLzl4LgBuU7d3r1boViIf5fycVxucTemvFzQAAOO7Rx51IyFSvWbvbPWThRtNoyaLFgv0VA/lAMmC2OQuEFkBN9V8fdQ7zWtA6eycntyzXLc9lUSBZ5ALsuMqMbTvMNajC296ncFls1wEOSA7s+E1477jPbEYxZLyMqt05cTwogOjke3YCuipjvGzggX2+re5MrfmF3+Sul7SyYQr4CdRTUMypWD1UwHcfOJDK+Kdm2sKgIPBZ3u8skjrpqsL6Qm+6djt23fzsSB0/4M+eMW27I/N8okDSOirmJBVGKA+2vHuy3WPTNVdqbZh2JIvUbGLV36GETFfje8jWRli4A36iS+tdr80h01UZv3XOWnzpd86Pfd7ygWDS2ckB5c8/YzVWCwJLGlpNoPv3zf9xN/7hR26ATYHjd3/vEnzoxadhvceQHZwQz4NKy5Ct4L5vM6YedP86SDHDZQEj0EPWwX4kcd9fvKkHADywb5I9VhXEGLT2L/MScX7tFrss+t8pzJDx8dEKj2ml644YsqSE7JGDU9g7XsHr/+0u9hgfG+06OoNVg/mm5KDheZwVI5iQKbKER//yWvb/xmbq+OzPn8KehFmAvY7eWnEzAPAlZHxi0SokSWqYet4NTHoU9bknuAxDf14856Jq+EHiyqF8YDNiPWQtVqloAeQlCFGLQH9ew1TVZDKrp47MsOCqargJWUFTmbkDoSZgLkTgg6Ka4fci1RIWN7tNdoEW3yS5Ef89eDMWCqrjFs9iBzet915/Et57/Um4bGtvVWRzqoyfPnYEH/rBo+yxVmSLAbfElPcgBfwE3v76L59/CvaMVfDPP92J23cei30f6iGL/SzvehkQBHKB2XPChC2ckLnXkSsL7F5CRg3paVnn8ByytlkoxR8MHcWQNSuLpIC+XeluXlOEQRytrWEmh0ch5/eQuX2mPUBbc5AkCTe/6DSct3FE+P+pT3jZwOyPz2iULLrn+zv3HcDf/ci1Gydzg01L+3DD2WsxXMwhp8iBoiQPko5F9ZJTQsbfm83MiGTX2uLOxyKdZtt+X64YRrFJ3L4sYqTFksU6JAlsTMxAwb/2olwWCUXWN6g0HONKryeyUrcgS/6eEFd4rhoW9k9UsG15f2DgPP+ap47NYEOM0YkIPkPGJWQC5luW3GN49OAU3v/thwJtM/MRWULWgyBKmjeQaAc5Rel6QkZVm5ueuQ27bn621zQq6CHjZFQrBwsYLxvs5mUuiy3b3nvJiJrM5gzkNZi2w+ZsHJysYvMytwnXZchMlyFTYiSLMclVPWTKwKj3FAxZO4VpWsgG8vEbM/VhhKt4lIDEbUydtKjvz2t43cUn9FzwJ5L6TdWaH0fBm3qk7f0KX3O8dOmMdUsAAP90607c+Ok7Yt+nGcmiKCHj2VaRpDEcQEwyhqz1Psg0yGsKqrxzaQqjHMD9LVyGrL1tj1iouhUtf2zV9r7dZLGgKSgbVsMcLCM0M02EvKag7Lks9ho7lgaUeC/rj5Zldgv0+9EyVjOsBha7XHdHqRBjJ8sSVgzmIxOysifTimL4aJ+UJAnP8yTFcT2CYdDb2oKZaYsJacfFNP2+3D1EhhVx93d4re7XVWFCdmCiimX9OmOM+L1elPCJeuopIeMTp9E+MvGwUMypbJ+P69HdM1aG4wA3nL0m8DgfG+06OsPkuWnRwJCFJIuAe90XcyoqdYsxY+u6NGpltjD/Vt1FAFrIO9X35TJk3e4hc4MxWhx0VYZhOQ3zv6qGzbTrKz2K/KA3i4WC13ZNPfQUph60gRKzVzdtJveoGBZm6hZzWeTPncEZFlRipFLB2WUWS/ySGDLLaY8hi5OgBY7PO9erl4h13XFuUL0mL+wGRAFpS5JF7vpf3p+ucj/an8Mvdh7FQ/td6UqFky4VckrqPpFmTD1ECTx/LYkS5kjJomV31TWzkJO9AcbpZ/sB7giCTrssRiUuzX4GVa7bldcVcwos2wlIqwHewTb4/qRoAHzJomHZLasU5hKMIfPusx1rBpmsqdugGUu039QtG7tD1fqyYTXID92ETCxZrAiez4PfJ//uJafjc689B1eftDz1MRNDtsjzscAa2cnCIC9/pGQnriASXqsHChoqAkONPWNlrF1SZOsvPwNPaOrBsWCUZFFCxht60ZpRMdz+ebqWv3HPPmx413dwUFA4oFmmZ61fwh7r01XG0k+UDYyXDZww2lyiRMkpre0ihoy+R9mwsGe8DFmK75GdD5h/q+4iAEnIOsVqRSVHnQQlkZQIsApHiBXgq/akWT5w3N2QaGZTq1UqCoICjoARCRkxAkxmZTssSZuoGKibNvp1FUNFLSDp4xO3OMkis472+oH84DHNHLLYp8QijvEQYY0gIfvojWfEvqaTph69ClHv1XQLDBld/2+5YjNedcGGVK/5qxecinLdwrfv2w/ADeQ0RWqwuU5C+z1k8cl9pGSxA0lPHApNShaJLTKszs0hq5mua1lU8ahZYyJamts9bdS0H5YZiUaK/Pidl+Hff9t306PzWo9JNHsZ1AvFX6+zNWOL4njab2qGjafHXKMout4q9cagclUMQyZ6Pg/+t5RlCVdsW9aSbXsXw4J5gW4NQOfflwwtkkw9eOQ1WchO7R2vYO1wMTB3lWIX0QgDkckZXaeT1caZZ8Tk0nO+fo+7Dz18wO9tA4BbHz2M3+weBwCcwEkSBwsayl7fMxW8aaZZWtC5qMUwZO73kVH1GLKVg4Wem53YLOb30S9Q7PNMFjplxEGbUlrJVCsIJ2SswhGSE/F9LaRZpg2pU70LmmABCsNnyPyqfiGnQJUlHPYYu4GChlVDBRyYqPjDZS2bfcfYHjJudlRal0XHoQp+G7eld+7S2meLGtSfu2NV7GsWQ0ImCkinWughI1OPZ568IjX7sX6khBWDeezzChWVuhUItKI2nccPTeGKD9/K5hqlkSxSdZzvQyDE9Ze5/1/MkFm201XLdDL1SGuUQ0Pha4brstgphiw8rJRHsx+xfWU/BvIq3nn1traOjYKWshG8VnnJ4vkbXVZs1WAhcF1RD1nNjP5evQybXcvu9bqklF6+1y7omhr1+npqps36WchkpFw3A2MjAGDFYAGHJqvCYikFxoRfvOtKnMcxmu0WFhhDtsibyDpp5MGDT7C2rxgA4CuJ0oDuRx6GZePARAVrlhS4fnEZP/+jK3HzC08VumPyLQbFUEI2XTNx2ppBnHfCMFtHSbKYzwXXAH7/qhoWXvO5u/BPt+5ETpUxxElll5Q0rg3FUz01ea2m6SGj71ExLOwZr3R19uVsIfWqK0mSIknSbyRJ+nY3D2ixw3Ec7B13A7FOMWSs2tDFWWSTVQOaIrEKDbuhrOCCUuVcFkc8Gn9sxnWVbFfqRHkcH3BFVb9IokWUveHNJyrkFByihCzvJmSG5eCIF+TWLRt9eRWyFN/sSgnZQEFD1bBZ4Bsnr6I9uZ2NliSRaRkyUUKWhEUhWRRcN625LLYmw109VMB+LiHjA7Mo+/x/+b+n8NTRGXzv/gMA0pl60PUYJ1lc2icObMPJHm/q0U3be5rPSAlgogzYO111y/aOrQNOhpSQRXzPZotKA3kN9/3ZM3HxltG2jo2uk/DaZNr+dfjpV52NL7/h/Ib7mAZuG5bTNdagq/DWz20r+vH+55+Cj9ywY9Y++pItS/F7V27GB190KgD3vqKCCl0i5boVGBsBuL1FhuUwJoGHO3vJD6ZXDRVYj4yuyrGy8jRYUnLv+ZFZTFx7Ed1ig/l7aOvyPgBgsYUI1VB8Row1jwPHq7Ad1y1V52KtwYKG3zp3nbCQQkokgDf18J+nKf6gaMDfbxp6tgLH6h9XeO9YUsyx4ya5eLNrLp07fnSQmCFz++x2ezLO+Y5muvPfBuBhAANdOpYMAI5M11AzbfTp4sHKrSA40yG9C1MzmKgYgV6TqCSQDxLzIeYuTgKUBhIaNfFRgRExSBTUETtX0BQ2F2agoDI2bO94BcsH8qh5De/FnJrKZbHBfSsmKaagqZ2AkRbVpB4ywjUnr8D3HzyIct0KDMeOw3yUMzULEbPUjmSxWcZh9VABdzzpuii6vSf+dcRvgCY3nHjYC6yOeQWOND1kFASINju6h9dEbHQNph4V3/a+mwwZuXyOc98zDmRaYNkOKobV/hwyz9TDtJxESehsg5Ks8NrkD3uW0Z/XhE6FBc/ds2pYPTeDLA1oqZclCa88f/2sfrYiS3jHNdtYP1jdtFmxj9b8mZrZoC4ocr/XUOg2q9TNBkdb+l36E0yb0uB5O1bDMB284MzVbb/XfEa37mF+n1zrJdJxa1U43strSoMqY4+nnlozXMDDB10JYdLewrclFFhCxisu3NFINSZZNFHS1dixS/z6QuoKYqsGClpgJiV9RjPwe8jcwpdhOeKETJMxPlPHkanavDf0AFIyZJIkrQHwbACf6e7hZKAhepuWlmBYTmDYchqIpA9h+rddPHF4Gi/79B2B+T+TFSMQKEZ9Jh8kuvJEv9pi2u31LkQVpS/ZMooPvvDUwGPEIE1yfS+qIqHIMWT9HkMGgLEVZOrhygmSTT34hlsg/jfw8rH2EjIjmvEQYevyPnzn9y7BV990IQBg87K+xNf0miNiNxAOSCWpNdt702ptQ1q9pICDk1WYlo1K3QxsRh95yQ5W4eRlyEMFLyGbpkQlWbIYNQgc8GfgiPoMAWB5yM1uqmrAth3YTvtugXGge/cIk2amc1kEgONlo232Luf15Na7bF7SCug6CUudKDCKW18LnkRpsmLMS8nih2/YgZeftw5nrhuas2Og81szbRZM0z12cKLaMCOtGJFA02PhBM6XEbfvdCvLEl5yztp5+Vt3Et1ig/l9Mo0SJVysJZMdHuQmuHZJkSlpkoonS/v8/q2wqQfgJnQ6x5CRu6eqyIH1IuD8yx0XFQc+/7pz8Zwdq7ByIM+uZ9r/ml1zKUmumzb7rCjJ4uOH3RmyaxdLQgbg7wH8IYDueqdnYEN6N3mBcbN9ZKYoIdP8akMncPfT4/jFzmMseSzXTdz22JGATI71rYU+c6ZmoqiTRbCEPDfnyzDbY8goBgxr4j//uvNw47nrAo/1CxgyVXape2IYXMmiu4GS/KTOGDIlwdTDPYbGhCz6NYwhayPhqTKpZLoNmzaN4VIO73/+KYEm/8WM8Cbdl1Mx3ZLLIknFmtuQVg0VYDvAd+4/4G6Q3Ga0driId127HUBQ5mJ4nzXGM2QJ1V8/IWt8HiU8UQzZYFHDY3/5LNz7p9dg9VABk1WTrT/dnENGxYYjU36vXBz4hGxspt6+qYd3bczUzJ4LZqMki4aZLJ0ledxExZiXDNna4SI+8IJT25bytQN/r7WYhJeq/Acnq1gTCsxZz1/dxL/fvosNOwfEph50P6ctuGVIxmwYv6Rxxq2G1rGCIMbYO16BIktYOZhne3dSzMT3ftH1xl9Xuiojr8oNph5AcF/g40d+fSG10dkbhvGxG89ASXdn0Nq24+9/Ta65fmHDYoVBUdGQP0eLoodMkqTrARx2HOfXCc97gyRJv5Ik6VdHjhzp2AEuNlDgv2lpqwlZ4/P5i7sTmKwGbfk/+dMnMVk1AxWKoEzSx1TVDMj4dM2nyg273R4y96ZPQyoWNAWKLAX6XnKqHKhIDhRU9Oc19OkqY83qpseQafEJGfUONcOQtaq3Drx/Sobsj6/bjsu3BRuAX3n+esYILnY0JGR5lUkWx2fq+Mpde1K9j9EiQ7bFK8i87T/vwUTFaKyUc4EfgTYuxhyl6CGj4aJDgvlFlPBEMWSAm5wMFjRm391qAtoMaPgtS8gSemP5OUtjM/WOzPoCXEOg8O/aSk9mJxElWUzTXJ9XeYZs4bPg3YDOSfXJMKpm2qz3JzxmhBiLHz18GO/7xoP4wHceYv9PzJA1Wp1naA+z0S+ZRlUSZsP6dDWQoAOuZHHlYB6qIjNFkIT09yqtfXnuO7sMmRxkyGiMA3f98XsNz5CF+9VZUciwWEzTbKFdliVoihRgyERmYgXOJGex9JBdBOC5kiRdByAPYECSpC84jvMK/kmO43wKwKcA4Oyzz17ctj1toFxzp6RTD1BU39fXfrMXP3nkSINFuZgh66xkkRYJqs5TUvPhG07zPzPUlOk+37VUDksb6bhMqzPubGnmqkiShP68ip89fhS/d5UF07ahylJgAaLjLOQU9l3JWa2Ya2y45UEW/iVu45Sl+OCx1cWLR9oesjdcuglvuHRTU+/9/uefgr1j5eQnLgCEN+kStzm+/Sv34NZHj+CsDUtY4SQKzG68yULDWeuX4E2Xb8Inbt2JJw5P47KtweSZD/wIFITvY6ZAyZLFP33OSTh/44hQ5nXYS3jSbHTrhov45VNjs8qQHZ5KJ1nkE7KKYbV9bPT5YzP1Bobsu2+7BMfL9bbevx34ksVgIFfzpNZxgSFVoKeqJnKzZBe/0KDKEmTJlRJPcUYdTx51ZVWrQ41itN8cmXILfmToBXiujLlgiEb3s4jRztAaZsvA5id/cHns71YI/daDBQ0TFQOO47D7dg9nXkGJWJrB3qWcghkuXlEVmbnFaorsKpW8xGemZqLPM59x4xd3neXVGCKGzP8efkJmWK0XmWlkEO1rUbb3gPsbLk0557OXkXglOo7zbsdx1jiOswHAbwG4JZyMZWgfjuPgr7//CO586hgKmpLY9/X2L9+Lb967v+Fx04rpIeuQy+I0q/z5OuElRS0Q/IXnSAC+PJC/gXVeshhjI50GFGuktfGdrpq4b+8EvnLXHs9QRGYVF0WWWEWGGl4f2DeBsZm6x6SpDX0aPIgh4xOy4ZIey1JSQia3IVmkgDity2IzeOX56/Hu607s+Pv2IsKSrT5dxVTVxCd/uhO3PuoqAET3Whj0nGaTbEmScOX2ZQDceyiql6Qm0PUfm6nBtGzYTnKw0Z/X8OKz1ggD9Y/feAbO2bAklfx17RJ3PASxdF1NyLzjSS9ZDP7dLkNGxQ7LbpRYDxY0rB8piV42KyiyOWTBL103begJaytLyGomchlD1hIkSULOKzJOVkwmo995xDVMamTI3HO+66hb6OIdVCuG1SDT4mdPZegMuilZvOmZ2/Dxl7lF8xNGS2zUjwj/9PIz8Sfe/rp6qIDBggbLdgKJ1J7xClMssBaNFAnZT/7gcnzzLRcFHqNrL6e6DFnVk9ZWDIv1hfGF3UiGLKTGYUWhOseQtaB80j2TIfqsvIAho99u7XBxQfS2Z3d1j8CyHXzi1p24a9c4CjlFKElKA5FksdNzyHy7aZt9ZliilBc0l1PFsD/EkBFVT0lRq6Deq7QU/idfcRYA4OGDUwAAjWPI+vMqu8HzmoJbHzuC6z/2c0iShBecsVqo7+bh95D5i8jSfj1esui0zy7ccNYaALNX9VuoCAc8/XkVMzUTN3/vEfZYlP08D+rraqXQwLtGNfSSCCTBdK9VDX8Ta8dB7FmnrsR/vfHCVBvd2uEibAfY7TGoSjcli16QQN8xkSGznYDhT9sMGRek9JrjqC9ZDDFkKfoJ+TUjC/hbh64qmK6ZqBgWq9o/ecRlyFYOik09iEGjPYWc5cKFGPpdZmvg9WJAN51S33zFZlx/WvxcT8LqoQJ+59KN+NE7LsW333qxbzzmuXVWDQtHpmqsp5cVoFPUn5cN5HHamqAKghw8NUWGriqwbAfHyxSjuYWdYEIWVDsRwk7SPEPGj9toFi5D5veQiRgyarF4/unpznGvoykhsuM4twK4tStHssjBSw3zHEMWnk3R8DormAzFM2Sd6SFjkkXTT6S0UJAjai6nRI6/gfn5F+3aZf/uZZtwdLqGV16QzvL4GSctxymrB7DTc+lRFZktUmFZJRkl/PDtl2L5QB5f+dUeVOrRrnu0EPEM2WhfLnYOidkGvU+4+UWn4c+fd/KCqBbNJWiT27i0hD+6dju+dvc+HJwI/nZxCTnBMP2BvM1iaZ/OJL2F0EBZkQyZ3yQpMZqtwI36R5/0RieE14NOoqC5A9xpzUxi/i3HwZJijt3D7bos8kFKuxb6nQZfneZBZkRx4BOyfBbwtwxdlXHM6+Nc2q/j0GQNR6ZqKOWUBsaLglcatUKSRVpbwgkZLetZwa1z6LWiyuZl/QD8dWaiYmDVUIGt7xQ/sTE/LX4OXXs5bn7sUe+6paI5HweJ5PFAdA9ZuW75CpEW9gPqa4vrIXvl+evxnNNWYlnIvXS+oreuxEUMnr3iJYtJrFa4OiyyyWfJnffc/3viaGz/UxKmaiGGzGpkyEg6c3S6hgmv6uInZOEeMl/62E71erCg4W9evKOphuf1wyXs9KqXmuIzZLxMi99EadZTkssiLUTBhEyPTYo7YerhSi2zhu92QWzlNSetwDNPXoG+vIrxcnAO2UxMQk4wbRuS1NpvKnNJR1gfT9fk/uMV/ONPnoBtO4Hr8dkf/TmA2QvcSEbz9DE3Ieum7b0kSZFSGhFs22UaKCQ7nG8AACAASURBVPBqlyHjP3tYYIYyl8ipMlRZapBTuwxZfJLFr3NJz80QjbymsP5GshyfrpnQBPdieK0em6ljqmqw/TnMjFNPdpaQdQ5yF9eqdsAnZIBftKciUDMMmQh07RFDBvgJGcVQ4XXWsh385NHDwYQsJFnMc0Uhsw3JYk6Rg7b3EbMyF0oyBmQJWc/A4BKrQk7xe0QSqr9hZx6RjIqSgpmaiZ1HpvHyz9yJP/3mAy0fK2/nC7gGFuFKcdGT6v3ldx7Gjr/4Ib5xzz684rN3AoDAZdF9n3qbPWStYN1IEUe9uU2qLLHzt3V5v3+Mqh/I0fEVNDXe1EPgsjjal0slWexmMJshHeyQOUWfrmJsphZ4Tpqihsset35Nv+PqrbjhrDV49YVB1peuyb/41kP40A8exa2PHRYez2wNLu7XSV7jJqndZo4GIqQ0IliOA0WW2GuUNo+ND1KWD/ZeMCCSU9dNK5kh466VuKGwGeIxUFAZ00WFlKmqKQxKRef5eNlgktMwK0DXepYwdx6vvWjDXB9CAOGELNyP5btKt5aRFbgesjBDNiCQLFYNG7c8chiv/dxduHfPcfZ4WLJIid6Nn76Dqala2Q+IIaO1TGR7v9CQldJ7BIYVlCzmBD0iIlRjGLLXXLgBgD8D43jZYLKdJ70m41YwHRp4aVp2Q9BZDN08X717H/t3f8jUg1WALHvW2Z31XJ+Oqsh43umrUTNt/NlzT+aOkZIw/zsVcwrKhhVwQOJhClwW+/MaTNsRMopAZxiyDJ0B1TVkLiELk8+pJItWezLcN1+xWfg4FWwoid8zVmkozvDP6zYomJ+hDbjLA5N5Y6A0g6EVScJAQcXR6VrbDBnvlBbuCeoFFLRGB9g0PWS8TJHcyzI0j6FCDg/smwTgJ2TTEUYpiiwxWfLyAVfeWDNtdi+HpcrEkPWazG6+Y9fNz57rQ2gAMU+TYYaM7Unu/SqS8qVBIdRDBgBHp9z4MMrUY583J/ew5wqqKRJOGA2aGA1xrzngjXFq1WWxzt8LLX7P+YTsru4RGBGSxaQesrAEjhK7T77iTJZUFDRXrvP4oSk8sG8CQHsVbKp68Hb14fcLT3nn/3eDZNGw8cmf7sTdu4/Pek/GKDfFXlMknHvCMD58Q1D2SJUZvipZyLlNsFGSUn8OWXAAIxAtQ21Hb52hs2BspZds9+UbCwVxPYSEqOS7XdC1RJvfgYkqKoaFUoT5R7dBn8Mqol2+hgMMWUJvrOO4iTUFOO0mi3wBZnkPymWoWMQjVQ9ZxpB1BIPcEGCSLE5VDaFkEfAD6g2eO2fVsCL7Zi7aPAoAuMJzYM2wcNEgWfTiBkpuXn3hBtz0zG14TYvMHql9cqrM1u8jrIdMbOpxyJPijs8YKOUUPPL+Z2FjaPTLhtESXn/xCQD8mbWtqERcB27Ll+8ugjUpS8h6BOEeMmJWwvNkwggnbD7L4v+0kuTKdf7nN/vw599yB0+2Iw2cCtneu5JFgT6eS0Zman6AEE52aqbN3Ou6XVkPg6fBoz6bMWRc1VhkWsLDEPSQJY0fsJ3G3y7D3IBCbk31GbIwZtIwZHZnZuuFQcEz3f+f/OlOPHZoGsN9wZ4m0VzCbkCS3Eo/sYbdHAwNBAspaRgyWXIlw0Bnk8U4G+u5Ql5TGtjSdC6L/lq4GORB3QIfxK7wro+pqhm555IqhJiGmmlFmnqctX4JnvrgdThr/ZKOH3eG3oLr9CxgyLz9RFcVvPmKzS2rIGhfyikyu9+PTgUTMr6XvmbaOOyZzxyv1FHIKZHM1yXe3ExKJluRidOctLgesoWGLPLrEQQYspzCKt1/8F/34WWfviPyddWQpNGIsBkdKgYbL1tNyGzbaRgM7UoWG284Xrb4+OEp9m/+JuZNPQAgp84uO8TLj6LYOVqswpJFIFq2Ri6LfCDvjzKIYMhYMp3q0DN0Ea+/5ATceO5avOqCDQAadfJAOsmi2aW+SNqEj1eCQ4hHSkHzD5GMsVvIa8qsMWQbOZkMyYCjYDkOZMmX1nTSgHRJaF3tBeiccy0hDUPGr4VZQtY6eMkWmd3UzOh1gKRYGyghM2zGvotkWpmD7uKALEvo19XIHrJ2QUUzTZEEDJl7DfOqoJphManieNmIXSMofmU9xa24LHpS3krdgq7KPWu+0klkPWQ9ArLHBtzNsOgF8pbt4Bc7j0W+Lsy2WLZY9jZUCCdkrV3cvLNcwB1R8H5FLhkJO9QR3Dlk/neYbYYsMMw6YsMU9ZAVvKpmVFDuzyETMGQRfYEidjPD3KA/r+GDLzyN/V0S9DamkSwaEfdGu4iSNI9yDNlrLtyAZ5+6suOfHXdM7TRxN4NNy4IymXqMNNS2XVOPTZ60Jm70RLPoxeA4z812JNRMK7GSzq9/i6Ea3S1Q8bOgKYH1P2rYti9ZdPuZq6aF23cegyJLWNbfe5LYDLOHgYKGSU+R1ImxODyoiK6pMku8jkzVoKuyP++OWxN4hqxu2rG9a6QMomSylYSMBqxXDGtR9I8BGUPWMwhLFuM2RH4yewND5r1POLEZbEjIWvvpSa4I8C6L4uqfKMH59KvODvztVnP97zDbPWRBhiwiIfN+C74iFDXvhyCyvWfOmREMGUvIejDIW+wQ9ZClkiwKDG86Ab43bMVAHn9wzVb3ce4afdtVW7ouHeSR1xRm6tFtY5pNob6FmmHjgX0TzPSAB7ksUhL39LFy25//xdefh4/deEbb79MN5DWloa+ubtqJw575a2WxBEDdAO21uiYH9oyoPTevudIvGvj76MFpfPHO3XjpOWsbxl1kWFwocPJjNmS5Q2srxVqK5DNkR6frATUIXZOAq7Y4NOUXs+JiVCpg+glZ8/tQMeeaE1Xq1qIpEGUJWQ/gtseO4Kb/upf9nddkKLIUSBZ48I6MkQxZg8lG8O9WAyaqgAO8y6J4fljYjnW0T8fVJy0PPJb3qiAE0WDrbiLQQxYlWfQWq7xQsihmSQzLnT/Fb8I+qxEvc8xcFnsPoh6yNLb3Uexxu1AVmV0neU1mg5knOCa61MQ8vk6AZ8i6Pb5i/Ugx8PfDBydx/cd+jg9856GG57o9ZD5DtutY6w6zhIs2j+I5O1a1/T7dgB5aUwGvh6wJg5eovSdDMgYLLkudV5XAOY/uIVOwrF9n9+tff/8R5FQZv/+MLd0/2Aw9DV2TuYTMK9h2aD+hAoxpOwHbe950bd1IEbfddAUu2jyCqaqJ49z+EidZJP8AMvVo5ZiLORUzdXNRMWSZZLEH8Kp/+WXgb6pklnIqqka94fn80M+w/C3KqU/UU9AKhAxZhFwonJCJAgJdUwKDDWdqyTKwTiKwYUaZengLD39OaYEIu5kRDDvIjJy4coA11UcxZF4+NussYYZkiBKyqGSch9HF2XpkopHXFJaQ8Tr7JEak05hNhiyvKXjJ2Wugqwo+f8fTuPvpcQDAv93+NB4+OIWv/O4F7Lm2x5ANl3LYsXYIv91j84Y6DZGpRxqGLPweGVoDSRYbGLKI83/dqStx5rolgb3oWaeszOSKGZBXFSZLp2J7pxQXJFk0LDsgZy7pwXt/3UgRBU3FfeMTgcdjJYseQzbZhmSxpLvzFBcTQ5YlZD0ISlAKOQWYocf8eVf8ZhveeKMmo4eZtFab/WkoNP+eZoSTnBVyeBMFBOEkbWq2E7IUDBkdI68kTHJZ5JmR2266AktKGh4+4BqbRLksGhlD1rPgJYt3vPsqvOmLv8bYTN2dcRXze0U5kHYClJAVcgpOXzOEd169FS88aw0uuvmWrnxeEvKazGa1zcbohr958Q4cna7h83c8ze4tAPjlU2OB59m2LwP+xpsv6vpxzTXymtzQW+gyZOmDmsUSAHUDVLwJM2RRPWQvOXstALAZoUCjCVeGxYm8prDCX6d7yKhX3bKdgANrXrBO6JocKMYD8QqMvCZDlvx4rpX9oJhTYdkOjleMRbMeZbqEHgSlMXwFgu8x45OAMNtiRbgshqtzSVbRUSBJUr+ucqYetlAjHHbcFjJkocdmmyHjpTlRRieUtPEN/EUt3tTDPSfu89eNFNGf1xJNPcreaACRgUSGuQXPkPXlVeiqjLt2jeOm/7435lXRDqSdANll51UFsizhrVdtweqhubNh5wP+2TLnGe3TMVLK4Z49xyOfYzlOR50Vex26qjT0FjfLkC0WiVA3sKTkShYv374UsiyxXuokppzfC0WMfIbFB764YkbEdq2C4h3DcgJMrogdF8VuIudhgiRJKOVURi60kkSSU+Ox6dqiWY+yhKwX4TSyXHzFsxLDkBkRksUPvvBUvOL8dZGvi8OdTx7DPm/i+rRXJRnpy2G6ZuKm/7oXu46VhYsEMWTU5CxmyII3Whor8U6CNx5JmkPGn9ICY8gieshsp2EDjpIs3r7zGP7+R4+xZDQsGcgw99BVmd1TeVXGnR4L8z9374t9XbOBcDOg+6pXNqs0IyS6ga3L+9n6ROBt8O0EFnOhIa/JARbe9gbYN9NDtlgq0t3A6qECbnnnZfjDZ24H4O8fSQkZHwhnCVkGwC0GU3HFjHDQbhUD3v7B294D4oSMJweouJVUOKY+MlWWWnKjJZfuY9P1RSOhzhKyHgQxS3wPFu+aFUzIokw9gj/t6qEC3v+8UyJfF4eXfuoOXHTzLbhr1xijrUf7dNy75zj+69d7AYh1zXT8ZMUtcl0MDyudnmWGjF8okuaQSeAYsqQ5ZJbd8H6+y2LwNTd++g78/Y8eZ/R+thn3HiRJQl9ehaZIUBUZF24aAQDsWDMY+7q61b2EbNirxPdK8BxkyGYvAdowWmx4rMoVPchlcbEg7wVx5MZL6oqsh2z2sHFpH7vmSGGRlJDx1+hsG/Jk6E3oql9csSxxO0qreN3FJ+BtV23BK85fj5wis0RLZOjDu9oOF919J+kapYSt1bWXXj9VM2P71RYSsoSsB+F4okXe7IJnVar1aFMP3/a+8Sbgk49HD03hJ48cbuq4bvjk7bh/n9vYOVzKBSSJomTG9p4w5N3AaRiyzSE769lE1IZJ55Iv8lAQHJ2QOQ0LJ5MsRiTD1ACbbca9iT5dZYHqp155Ni7cNMJsfXk4joM/+K97ceeTx1IN5G0VvHkAjyu2LcVLvb6U2QR/HLM5T3BJMdfwGK8AsD2XxcUCXZXhOH4iRv9tzmVxcQRAswE67zk1/TUoGrORYfGBN+hhLosdKi7lNQVvv3or8poCibO+F937J60cYP+mQnucZBHwGbJWTa2KnFKoV4qO3UaWkPUgnrtjNYAgQ1ZtmiET37RvvXIzcooMy3bw2n+9q+lj2zteRp+uNsikRDfdW69ybXtXeX0tooBgoODf1G+6fBM++Yqzmj6mTiGqqk8/Ax/Uyd5Ygkqky2Kj0YnfQyZOyA57Qxm7bRmeoTX06SrbGEq6ii3L+gKN+ISKYeG/f70XL/3UHV2VLEYxZJ977bn46xefJnpJVxFgyGZRskjngQe/Xi5Ghgzw1xkqAGWSxbkBMQ7NrOt9mWw9A8hlMTSHrEtrK63fIobsxFV+QkaJ4WwxZO4xLY77IYv8egz3vO9qbFvRDyCckCX3kFUNCx/6waMAom+Cd16zDS86a43w9SLYIWeO/cer6M+rDU48omTmxnPXYdfNz8ZQTA8ZH0xdumUpBufQXSpqw2S/Q+grFnNqpPW5KRgFoGtiySLh8GQ1kyv2MMKFiOGSjsmqyVhpAu8uWutiQkbMc68k8IEesllMgMQMGSdZtLG4GDJvnaG13WfI0gc1UQZHGZoHnfdmWOPM2CkD4PWDmkHb+26trbR+i4oxA95sMl2VmdtjYkLm/f9Wj5eXKfZKn3S30Rs7eQYGPrjiJYu8axYfAPJsy7fu3Y9jXsU+blYFHziJKvw86qFg86CXNGxZ3oeTVw2w/rA4a2/6vJwgIOATsrkeRhpVeaKfIRzUFTQlUrJoCIZliySLDvcjH5qqZnLFHkZfXg1sVsMld5MaLwfvIT4hm6mbTTETzWCJV7xo1TG10+AD/tlkpJIYMtfUY9YOZ87BrzOO4+DTtz0JoLkeslaa8DOIwRiyTLKYoUnkNQWm7cC0bG7GbLfGqBBDJk5+bnnnZfjpTVcwpq4/IVahhKpVRo+PhYoZQ5ZhNhBmS/iELGjq4Qdd5KSYU+VA4FHkqmpxk9H5G67ZhAxwN4vXX7IR337rxey94iqq9BxRLw1f3Z7rKkgU00BJ5wmjpcDjJV1hVvVhmHbjQGBVliBLwQCan7t2eLKWJWQ9jDdetgnvuHor+3u4pANovIdMLiE7Xja61kNGbGqtxZmCnUbQZXEWe8gECRm/rtrO4uohy3NM/BOHp/Gvv9gFoDnJYobOgQLdZtaBTCmRAfDX1Kpps0JfXGzXDqiGFpWQbVzahxWDeRZ/ppUstppAlhYhQ5bd9XOMb96zP/A3n9jwakE+8SKGbCCvhmaS+f+OY8j4jfnodA2Aa72uKRLO3jAceG5dUH3v9+hrSZJY1TXupqMbXFQ055MW0UDC2UTUObtw0yg+99pzcMnm0cDjJV3FTKRk0WmoDLmNs0rgdzo6VWP/PjxVw/qRRse4DL2B8zeOBP4mZiackKUZiN4JsNELPZOQzY3L4nCSZNFxIC+mHjLveqsaNn6x8yh7PM11+LX/dyF2Hpnp2rEtRrTSQ5YV5jIAfjJfNSwYdrRhWydAu1bafq2k8Tx0DbeqlijqWQ9ZhlnEdM3ETf99X+AxXiryz688C2esGwIQlCwSdb2sP48xTi7FD1WOo4n5eJGCyb/67sP4G6//jIcwIeNuFFoc4j6PEsDwoOgw5roKEvcdrti2rKHq36erkYOsDauRIQNcJzqeITsWCuazyuj8QVRCZs5SQkYFjF5JyPhCz2yaegyVGvtOGySLi5AhqxoWbnvMT8jSnIIz1i3Bi7ke4wztg4Lq5kw9sn0gA8eQGVbXe8hIkJW2daRfj+/3p4St1b2Abw9Y2q+39B7zDVlCNoeIMoQgnLhyAP/w0jMABCu+xJCtGMwHgsEZjy37xMvPjF38abgz4A7dA1ym7Nh0reG5ooRs1VCe/VuRqfqXLFnk+6WEz5tjhqzZhaOYUzATKVlsdFkEXC00P2stfM6zyuj8QSRDZoUSMqU71/Upq90ZaC86szcC6CBDNntbi6iXobaI55DpHEPGD8yWwq5EGWYFupa8Rza8JpOXZkDQMbXbPWQ0biltHJbEkBVz7Zl68Gv2+SeMxDxz4SCL/uYQUfOoeNBizsvcqK9r+YCOXz41xh6fqZmQJODaU1bEvifP6hybqcNxHIzN1FE1Gm8wUQ/ZhZt86R5jyFJIFu2khCw3t5tQnMxThJKuRg6yNi0bqiBQHOnTAwH8dCihyyqj8wc0ByyckJG0hNAthmzFYB67bn52V967FfBB5GwmQCIDiiBDtrhcFvkesvFyHa84fx2uOWkFLtkymvDKDN0ABbiZqUqGZsFLFslMo1s9ZD5DljYhS3JZbN5dNApz6b49m8jKMHOIKPtzHnl2Q/pBHlVKlg/kMV0z2fvM1CyUcmriYs7LH49N11CuW6iZNsbLBsxQAkYMGV/dO+cEv8+MWKW46h8lbQmKxa6ZH6RFs30mfTE9ZIYlZshG+nKsbw9oZEkzhmz+QFNkDBa0Oesh6zWIzDVmC3/z4tMwWPA37aDt/eJyWaSAaqZuYaJiYLik49KtS7Mgf46gt9BDliEDwEsWbSaF77ZksZBQGKdiWxKLyxiyNhLIt121BZ94+Zktv36+IYv+5hAUNLz1ys342C1PCJ9Di/n7v/0QNi4t4Ypty2BYNiTJ19WOzdSxcrCAmZqZSCMDwLuetR2qLOOePeMYm6kHAsrxshHQ65L05zOvPgczNROPHJgMsDh+D1n0zUlxQFQP2bUnr8D3Hzw47wKGUkwPmWnbwsrQaJ+ORw5Msb/DDFvGkM0vjJRyjT1kYcniIknIzly3ZM4++yVnr8X4TB0f/N4jABb3YGgKlA5PVuE4wPAiqS73Knwn4uR14PZ3X4njZaPbh5RhnoAYspphMSl8tw2TkiSL33vbJbhn9/HEeI2Gm7ez9r6dczVeDFgckUKPgpitsLMhD74K8d37DgAg9kXGiGe7TX1g03Uz1UDJlYMFfOQlO7BqqIBjM/WAscQD+yfwjXv2sb95huy6U1fiHddsC7yXwiSL0Tcd3bhRksWPvewMPPDnz0w87m7h8m1LW3pdn67CsBz88MGD+MB3Hgr8P5HLIuAmZMdmaqyfrlyzAu6TZLGfYX5giSAhCzNk+iKpjPMM1Vzgd7xRHEBQBeA4zrwr9rQDSgAOTFQBzC1zmcHfw9P0kK0cLODElQPdPqQM8wS+7b3FGLJuF5f0BMni1uX9eMk5axPfhxiyZltBFjOycvwcghiyfEwFnQ8kRj3myrBsaLKEES94p4SqXDObkryNlHLYdWwGYzO+hO61n7sLAPDMk1dg73gZf/6tBwFE09OqnCzHYOtHBEOmKfKcyjk+9cqzW3KqozkZn7rtSdy3dwJ/8uyT2P8zBHPIADfhMiwHkxUTg0UNM14STfPIdqwdavFbZJgLDJdy2DNWDjxmzlIPWS/iDZduxC2PHJ6Tz5ZlCSevcoPZBsniIkrIyJ1sv2fosUQwFiDD7CFuDmeGDHFg/aCGDdO2ochS14pLVCRO67KYhFIHGLLFhiwhm0OQrCZtE+Vxz+LesGxoqsy5vLkJ1UzNYtPR02CkT8fYdJ0xbDxmaiZe9InbMVFx5RNRTnFKCtt7cvdKMvWYK+RUuaWgmZLfe/Ych2k7qJkWkxiYliNkDUkOevuTR6Gr7mDpku4nZFl1dH5hpJTDvXuOBx5brD1kAPDH152IP77uxDn7fHfWnxwYlu32kC2eoIACoT3jbqFgOGPI5hQ+Q7Z41oEMnQEbYeExZN1cx2jXKnRo5lcnesgWG7IVYg5B/Vl6QkXiTZdvAgAcmaKEzIEqyxjxNlpKqGbqZlM9SMOlHGbqFpO28JipWSwZA6KDyjQui1uX9wFoXRrYq6BzTVIC3gLfsBxhX91on5uQvfELd+O1/3oXZuomilzfX7Zpzy8sKeUwXq4HRjo0zCHLftNZRV5Tgi6LzuJyWVQVGXlNxp4xjyHLErI5BUnAtEVUmMnQGRBbVanbsCwHWjcTMm/bSpIspgXFR93ueVtIyBiyOQRjyBKaKP/o2u14YN8Ec+czLBs5RWIMTaVOLovNSRapX2nnkWloigSDMyMYLwdZs6iELE3FZsvyftz7vmswUFhYl1sxdK5naiarRpu2HemyGH5NKafi+79/yZzPYcvQPEZKrgR1qmZiIO/2UC1mhqwXoKvyonZZBIA+XWP7xZLM1GNO0UwPWYYMPCieK9fNWWDI3H2rUx9Bai0l6yFLjexMdQm27eALdzwdqNSGwXrIUlQkRko5HPOkiaYnWdQUGYossQb26ZqVymWRMOyZguwdr6CgKYE+sfv2TQSeG8mQeZtMOAgNY7CoLbjG+r7QuZ7iBm6bHosZBjFkhImKgWJOwfYVA9gwWurOgWboGoa8/pxxztijgSHLErJZRV5TAqYeluM0PdJivoPWJl2VOyZBytAamnFZzJCBB5m0TVVN17m5i9fQR244HWesG8LSUIzSKkoZQ9Y0FhZl0UP44UOH8J6vP4DdY+XIngpK1nRVxidfcWasrGakT8fRgGTRfW5BU1Cpu4ldOaXLov+ebjC5/3gFuqZAliUmo9w7HjQqiJJdUdIRNjJYDAizkfxMMsMSM2RLijnIkj8C4PBUDduW93f1ODN0D2TsUgn0LC1eU49egLsm8oOhF5epBwD05d21abiUW3CFsPmGQmbqkaFFKLKEUk7BdM3sei/sxVtGcXEHh8frqgxZynrImkG2QnQJNJ/q6FQt8jmU/OQ1BdeeshLXnLwi8rmjfToqhoVy3UTd8h388pqCimHBth2U602aenjyugMTVeQ1OSCZOzIZPO6kHrIkhmwhgpLf7SvchGqaZ8hsse29IkuMmQSAw5O1BuljhvmDPCVkdQtfvms3jk7XGueQZYHYrKKkKyjzCZnjLKoeMsBfm4Yyh8U5xyVbRvEn152IU1YPzvWhZJiH6MurmK6aMLvcQ9ZpSJLbVpMxZOmRRQpdAqnV4pwFeYYsCcMltw9gbKbuSha9IK+Qk1E1LNQtL7lrIiHjm711VUGBe+3hUCIZdYxUsQnLtBYDRvt0DJdyeM6OVQDAnBKrhgXLdpjLUOPr/PNet2zGsmSYf6Dq9+OHpvFHX70fb/7i3Q33Qpr7O0Pn0JfXMFUzcWiyCsdxXFOPRRYU9DOGLOsfm2vkNQW/c+nGReX0maFzKOkqpuseQzbP2KahohaIKzPEI4sUugSqyMalKVXTQk6VUwULBS+4rxqWNxialyxaqLGZZukvfr63QFflQC/b4amg82JUlf/8jSMAgE1L+1J/7kJBIafg1+95Bl545moAPit6vOy6Uw5FNNOT9T0hKnHL0Puge+h4xZUTH5mqZT1kc4x+XcW9e47jvL/6MX719DgALD7Jose6ZzPIMmSY3+jXXYbMsMV96b2Mf3zZmXjLlVvm+jDmDbJIsMuII45qhp26ek6BX6Vue/1JMnu8YlisiT3JQp+HO5DZdVfMa0rAujvMkEUljS86aw0u2DSCVUOF1J+7kCBJEgt+SLJIwXlUMDQSsqFuxoglQ2+Bqn/M0EXKesjmGvzoj4cPTAIANHVxJWSlLCHLkGFBoC+vYrpmoqQr845lPW3N0FwfwrxCFil0CSRVjJMs1kwr9VBo6g0r181AQpbXFDxxeBpf/80+AGCDidOCPl9X5QC1TCxPGizWZIxA/RrTYYasIGbIwk6LzYwqyNBboELJMc9lUQKyHrI5BhlaAL5SQZtnleV2Qecgm0GWIcP8Rp/u95Bl/VgLG4trl5pFkITQie0hs9ngvyRQ4lQx3IntJFnMawr2wq2mpwAAIABJREFUHa/gg997BEDz/SoFLiELyx0XmcqnZcicExLgJ2SDEZLF0ZBksZlh3hl6C3RfHpv2GeVsDtncgr+f6JdYbE5ffV6RaDibQZYhw7xGn64xl8XFto4tNmSRQpdADoox+RhqppWa0aLEqWpYqJv+PIrwjJm0jBt7X48Vy2tKgyFIMxb6ix3khAQAE55kMcrhbHOo327DSDZ/bL6C7p8xYsgkKeshm2P0cwwZ3ZOLbQZUxpBlyLAw0O9JFg3byYYsL3Bkv26XUPN6uuJdFtMzZAVu3pFh2UwGFXawaYchCyd3mTtOepATEpAsWbzqxGX49Xuewf7evGzxGaIsFOS9+42XLBJDtnIwDyCTLM42+IRssurei6KZgAsZmalHhgwLA326m5CZlp1JFhc4MgqkSyDJYpypR9WwUrsi8qYeYckij2YTMr+HTGmo5JdyCo409W6LFwN5DRNeIna8YkBTpMiZcJIkYYTrI1s+oAufl6H3oXrGOMSQAf4IiP98w/k4MlXLBvPOMvp0vxAyWXHvyfnmTtYuqE91hVcUyJAhw/xESVdh2Q5mambTCqgM8wuLa5eaJdy9exy3PuamMoZlRz6vZtqpXRELXA+ZESNZ1JuVLGokWZQb2LpCTsUlW0ax4v+3d+9Bkp3lfcd/T9/nvitptTddViAJIYQusIDMRcYSKAK7omCwAmVigklUcUCYFE5CbKeIXeXCOCmIqWAclbmZIlwC2BYUBagMiRRBhG5ICElEsiSklbQXaTU7M7szfTtP/jinu8/09OxM7/bp0zPn+6na2r6cmX2ndXS6f/O87/NO86a+lh3Tlfa+RwfmljQzVlr3B3E+sG9slWK+XRW1WJfF0ybL2rvnlDSHlkmTyypkYdU6a2svrjh/m75y/eU6f/tU2kMBcBJa17PZxXrmrmNZQ4UsAb/+Fz9s316sNVc9bqneXHVaW7dKKdf+mnrgyzaGXnZcH23vw6+PKmTFfLsjWfx7feE9r+rr+2XVjpmKbnvkWX32tsf1jbufWte6oQt2TOmCHXxg2ujGivl223tTZw3ZRmtRvFnEm3rMR1MWszZtNJ8zvSraIxLAxjUTfUY8MLeks1lvvqkRyBK2VF89kNUawboX/JfyOeUsDHhh2/toymKhe8piv23vc9HX5dofJHdMV7R/bum4YRLLbZ+uaL7a0N9E2w+sp3Pidz5wRdLDwhDE11rWmkG77T3z/dMRX0N2pDVlMWOBDMDm8PoXbdPZp47rF88d4z1lk+NdKmGLxwlk8f3E1mJm7U2g643O13Vv2NzvGrLW2opKMa/Wd2qtaWpvdos1tRo4PP7sUZ02WdaXr7885RFhWOLThhdrTSpkKYuv3WyvIWOqD4ANaLpS1F++8+WqFHM0WtvkqJAl7PiBzPtqiT1WigJZbD+KVnv9ln4DWeszY7mQ07GoL8H26YqkI+3fLmNt26N1dvPVhq69bBdrNzIkvtD6WK2hZhAonzPWBqZkJjYNvPVLpaxNWQSwebx457S+/juv1nSFfQU3M96lErZYW72pR62PCpkUfvBbqi1ve1/rDmR9NvVofWgsF3LtNWStcNHa6Bhr2xnrZsa+YtkSr5At1cMuqFTH0jNVKequP3yDXrxzut32nqk+ADayl+ya0ZmnjKc9DCSIQJaw460hC4PV+j8ojBXzWqg25N7Z6LQ7kFX6rJBZu0LWmbLY2kz0kjNm+vpeWbaDQJZZ3WvIqvVARQJAqk6dLGuynNdStP0Ia8gAAKOMKYsJW6w35e49py/VGv1VyMZK+c5vfKMg98pzTtFnbnusfUy/HzzinRXjY/zWDa/VGVvH+vpeWVYp5vWNf/1qffWOJ3X5C+luliXdW0/MLzWokI2AsVLn7S1rG0MDADYWfm2YsGbgqjd77w5dbwYq9lHRqhTzmltcvibimot26IcfuvKEx9f63Bi46y2X7dZEKa+3XLZbF+2e0Zbx0gl/3yx62Vlb9advvXhdHRaxeXTvJbhQrVORGQHjsaDczy++AAAYtjXfpcysYmY/NrN7zexnZvZHwxjYZtKrfbx7GNT6WWw+XsprvrpyTcTJbNzcqpAFLu05bUI/++NrdM5pTLkD1uvSM7dI6mwhQYVsNMSnklIhAwCMsvWkgaqkK939EkmXSrrGzOjp3YeF2srmGK2qWV9dFot5zR4LA1m8stbd+r4frVmKrt5VPADH91u/tEd3/uEb9JFff6mksBkOTSTSFw9kre09AAAYRWu+S3loIbpbjP7w6X0VQbDypZnr0T6+3gwXm/fzm9uxYr7dxnlQ0+KmojaqtIUGTtxpk2Vtjab4UiEbDfG1ff1MDQcAYNjW9anezPKS7pJ0rqRPuvvtPY65XtL1knTWWWcNcowbSq25ss19r0DW6o7Yz9qGyUrnP9f02GD2o/jAG87TVLmgt1y2eyDfD8iqVgCYX2posswGnmmLbxBN10sAwChbVxpw96a7XyrpDEmvNLOLehxzo7vvdfe927ZtG/Q4N4xqfWUg67XBcqdCtv5AFt/wdLoymArZeKmgG646jyYEwEkaj7r6zS/VqZCNgGVTFrm+AQBGWF/vUu4+K+kHkq5JZjgbX7XZaeDxL193jiRpbmnlGrJWJa2fqYLxQDbFju3ASBkrhf8vVxsBa5ZGQHzKYoGmHgCAEbaeLovbzGxLdHtM0hslPZT0wDaq1lTEP3vrxXrfr5wnabU1ZP039ZheFsiWV8gu2DGly87a0vd4AQxGfN8rKmTpi09ZZI0sAGCUrWfe205Jn4/WkeUkfdXdv5XssDauViArFXLtNV+tzZzjTmTK4nRl9QrZdz5wRd9jBTA4VGRGSyX+34OADAAYYWsGMne/T9JlQxjLplCNAlm5kFM+Z5oqF9qbOcd1mnqs/4NCfMriRImmAcAoGS8RAEbJOBVLAMAGwTyOAYtXyKRwmmGvph6tNWT9tGOOBzIzPmAAo6RcyLX39WMNWfpaAbmUz3G9BACMND41DFi7WUcUtKYqhd5TFhsn0NRjnEYewKgys/a0RSoy6WtNWWT6KABg1BHIBqzV9r5cCD8MzIwVB9fUY0Ct7gEko1WVIQSkr/3fgnAMABhxBLIBq0Vt7483ZdHd9dhzRyX1uTF0mUAGjLJ2VYYQkLr2lMU+fukFAEAaeKcasFrXVMTdW8a07/lFuXv7mC/e/oT+49/eL6m/ph6sgwBGWysEnDpZTnkkGGuHY97mAACjjXeqAat2NfV44bYJLVQbOjBXbR9zzxOz7dsnsj/OFedvO8lRAkhCa6ry6VMEsrSNMX0UALBBMAduwOJt7yXphadPSpIeObigHTMVScvbY/czZVGSHvvImwcxTAAJWKyHU5a3T1dSHglaFbJ+r7EAAAwb71QDVusKZOduCwPZPxxaaB8TD2T9rm8wM6YuAiNqPuqoun2aClnaCvmcSvlcX9PCAQBIA4FswLr3Ids2VdZUuaBHY4Fs7CQqZABG1/xSuAn86VTIRsJYKc8aMgDAyOOdasC69yEzM22dKC3rtBgPYSeyhgzAaDpWY8riKBkr5qmQAQBGHmlgwFr7kMWD1kS5oIVqs3NMVEWTpGKBDwvAZrONLosjYbyUZxYCAGDk8U41YLVmU/mcqRAPZKW8jlYbnWPigYwPC8Cm8Wdvu1iv2LOVva9GRKWYp8siAGDk0WVxwGqNYMU0xIlyQbPHasuOaWEDWWDzuG7vmbpu75lpDwORl+yaXrZmFwCAUUQgG7BqI1C5uDyQTZYL2vf8sfb9WrMzfZGOiQCQjP/8G5ekPQQAANbEvJoB610hy+tobA1ZvEIGAAAAILsIZANWawQr1o9MlAvtNWRPzy7q4HxVkvTS3TNDHx8AAACA0cGUxQGrNnsEslJBR2sNubte/afflySdd/qkvnnDa9MYIgAAAIARQYVswKr1QOXC8kXkE+WCApeW6p2pinRhAwAAAEAqGLBajwrZZDkMaAux1vcEMgAAAACkggGrNZoq92h7L2nZXmTdjT8AAAAAZA+pYICCwHu2vW8FMipkAAAAAOJIBQNSawR6we9/W/c8Mbuy7X0pDGTHap3W92UCGQAAAJB5pIIBuf/pI+3bK9veh2vIjlIhAwAAABBDKhiQOx473L69sqlHWCGbW6p3jmENGQAAAJB5pIIBuePx59u3u6cjttaQzR7rBLKmD2dcAAAAAEYXgWxAnjtabd9eOWVxZSBrNAMBAAAAyDYC2YBU45s+57s2hi6F92cXa+3H6gQyAAAAIPMIZAOy1Oh0UOyukBXyOZULuWUVshpzFgEAAIDMI5ANSLxC1qul/WS5oNljsQpZgwoZAAAAkHUEshM0e6ym/3dgvn2/GgtYvVraT5QLej6+hiwgkAEAAABZRyA7Qdd/4S5d/fFb2nuLVRvH3/R5olzQkUWmLAIAAADoIJCdoB9H+459/6GDkpZPWSz22GNsopRfNmVx63gx4RECAAAAGHUEshPg7hqPOife/MABBYGrFuua2AxWVr8mygXNRhWyqy44XR+77tLhDBYAAADAyCKQnYB9zy/qWC2covjE4WPLwpjUu6X9ZLkgj3Lau169R6dMlBIfJwAAAIDRRiA7AQ8fDJt5nH3quA7NV9vTFVtVs16BbKLc2ZuskLchjBIAAADAqCOQnYBnF8K1YBefsUUH55e0WA+rZZPlgqTeDTsmouckqdRjjRkAAACA7CEZrKLeDPSx7/1czy1UVzw3F60FO3fbpOpN1/65JUnSGVvHJEnTlcKKr5kodR4rEMgAAAAASFqZHCBJum/fEX3i+4/ofz/8rP7uva9Z9tzcYl1m0gu2TUiSnjx8TFK4NuytL2/our1nrvh+8QpZkSmLAAAAAEQgW9VSNA3x3idnVW00VS501oAdWaxrulLUjpmKJOnJ58NANl4q6NpLd/f8fpOxNWS92uIDAAAAyB6SwSrmlxrt288t1JY9N7fU0PRYQadPlSV1KmSV4uov52QlXiHjZQcAAABAIFvV/FK9fftotbHsuSOLdc2MFXX6VFQhO7woScuqaN2myp2NoAs5piwCAAAAIJCtaiEWwhZ6BLLpSlFjpbymygU9EVXIyoXVX87psU4gKx3nOAAAAADZQTJYRXzK4tFqc9lzc1GFTJJOny53AtlxpixOj8W6LFIhAwAAACAC2arWUyGT1J62KEmV401ZrHQqZEUqZAAAAABEIFtVvEJ2ZLGmP/ibn+qp2XCt2NxSXTPjnQpZy3ErZPGmHjledgAAAAC0vV/V/FI4LfHIYl23PfKcbrr3aX3x9if0uvNO01I9aAesVqdF6fhNPeIbQ7MPGQAAAACJCtmqFqoN7Yz2GWsEQfvxWx9+VpI0M16SJG2f7kxZPF5Tj1xs3VieNWQAAAAARCBb1fxSQ6dMlFTImQ4fra14fmcUxLYtq5Ct7+U0I5ABAAAAIJCtamGpoalKQRPlgp5dWBnIdm8dkyS9Ys8pkqRSPqcCGz4DAAAA6MOaa8jM7ExJfy1puySXdKO7/3nSA0vbQrWhyXJRk+WCnluorni+Fch2bRnTvR++WnOL9RXHAAAAAMDxrKepR0PSB939bjObknSXmd3s7g8kPLZUzS/VowpZvt1dMW461sZ+ZqzY3pcMAAAAANZrzTl27v6Mu98d3Z6X9KCk3UkPLG31pqtUyGmyTCNKAAAAAMnoK22Y2R5Jl0m6vcdz10u6XpLOOuusAQwtXc3Alc+ZJgYYyH74oSv1bI/pjwAAAACyad1pw8wmJX1d0gfcfa77eXe/UdKNkrR3714f2AhT0ggCFXK2rEL20/90tX782GGdPlU5zleubteWMe3aMjaoIQIAAADY4NYVyMysqDCMfdHdv5HskNIXBK7Aw/3Cpiqdl6hSzOuqF29PcWQAAAAANpM115BZuGnWpyU96O4fS35I6Wt6WOAr5KzdvCOfMxVpaw8AAABggNaTMF4j6Z9JutLMfhL9eXPC40pVoxkGsnwup+moe2Ihx2bOAAAAAAZrzSmL7v5/JGUqjTSCQFIYwsaKheixDb8sDgAAAMCIYQ5eD82gVSGzdoWsSSADAAAAMGAEsh5a1bBi3pZtAA0AAAAAg0Qg66FTIeusIQMAAACAQSOQ9dCqkBW62t4DAAAAwCARyHpoNleuIQMAAACAQSOQ9dDuspg3TVMhAwAAAJAQAlkP8S6LEyUCGQAAAIBkEMh6iK8hy7EhNAAAAICEUP7podHsdFmUpH9/zQV6ya7pNIcEAAAAYBMikPXQXkMWVcd+5/UvTHM4AAAAADYppiz2EF9DBgAAAABJIZD10F5DlieQAQAAAEgOgayHZrupBy8PAAAAgOSQOHpoMGURAAAAwBAQyHpodjX1AAAAAIAkEMh66LS9J5ABAAAASA6BrIcmTT0AAAAADAGBrId2l0UqZAAAAAASRCDrobUxdJ4uiwAAAAASROLoobWGjAoZAAAAgCQRyHpo0vYeAAAAwBAQyHpo0NQDAAAAwBAQyHpod1lkDRkAAACABJE4emgwZREAAADAEBDIemhGXRZp6gEAAAAgSQSyHqiQAQAAABgGAlkPTdreAwAAABgCAlkPVMgAAAAADAOBrIdGECifM5kRyAAAAAAkh0DWQyNwqmMAAAAAEkcg66HZdNaPAQAAAEgcgayHRkAgAwAAAJA8AlkPzcBVyPPSAAAAAEgWqaMH1pABAAAAGAYCWQ/NIGDKIgAAAIDEEch6oEIGAAAAYBgIZD00aeoBAAAAYAgIZD1QIQMAAAAwDASyHhrNQIUcLw0AAACAZJE6emhSIQMAAAAwBASyHhaqDY2X8mkPAwAAAMAmRyDr4ZkjS9q1ZSztYQAAAADY5AhkXYLA9cwsgQwAAABA8ghkXZ5dqKrWDLR7SyXtoQAAAADY5AhkXZ6aXZQk7d5KhQwAAABAsghkXVqBjCmLAAAAAJJGIOuy/8iSJGnnDIEMAAAAQLIIZF2O1ZqSpMlyIeWRAAAAANjsCGRdGs1AORMbQwMAAABI3JqBzMw+Y2YHzez+YQwobbWmq5gnpwIAAABI3nqSx+ckXZPwOEZGvRmoRCADAAAAMARrJg93v0XS4SGMZWi+ee/TOnKs3vO5ejNQsUAgAwAAAJC8zCWPp2YXdcOX7tH7vnR3z+frzUDFPOvHAAAAACRvYIHMzK43szvN7M5Dhw4N6tsOXCtq/Xz/fM/naw3WkAEAAAAYjoElD3e/0d33uvvebdu2DerbDpxHfx+tNno+zxoyAAAAAMOSueQRBGEkOxrtN9at3gxUYMoiAAAAgCFYT9v7L0n6kaQXmdk+M3tP8sNKTiPw4z4friHLXE4FAAAAkILCWge4+zuGMZBhaa4RyNiHDAAAAMCwZC55BL5GhazBGjIAAAAAw5G55NFormPKYoE1ZAAAAACSl7lAtmaFjDVkAAAAAIYkc8kj3tSj1ghWPM8aMgAAAADDkrnkEW/qMbdUX/E8+5ABAAAAGJbMJY94IDuy2DuQFdmHDAAAAMAQZDqQPTtfXfF8vcEaMgAAAADDkbnkEQ9kB3oEslrTVSxk7mUBAAAAkILMJY9mrMviwbmlFc+zhgwAAADAsGQueTSDTmfF/Ud6BzLWkAEAAAAYhkLaAxi2ZqzTfXzK4sMH5mXGPmQAAAAAhieDgSycsjhVKehAbMriGz9+S/t2gUAGAAAAYAgylzxagWzXzNiyQBZXYsoiAAAAgCHIXiCLmnrs2lLRgbkleazJRwtTFgEAAAAMQ+aSR6upx64tY1qqB5pbbKw4hkAGAAAAYBgylzxaTT12bRmTJB2YXzltkX3IAAAAAAxD5pJHq0K2uxXIonVkFls2xhoyAAAAAMOQwUAW/t2qkLX2IivmOi8FUxYBAAAADEPmkkerQrZzpiJJOjhfVTNw1WIblBHIAAAAAAxD5pJHq+39RLmgmbGiDswtqdpoLjumkGPKIgAAAIDkZS6QNaJAls+Ztk+X9fTskpbqwbJjDi1U0xgaAAAAgIzJXCALvBPIXnDapB49tKClelgh+9WX7pQk7Tl1IrXxAQAAAMiOQtoDGLbWUrFCznT+jil974H9mj1WlyS98cLt+uNrX6JTJ8spjhAAAABAVmSuQtZq6pEz0wU7phS4dP/TRyRJlWKOMAYAAABgaDIYyMK/CznT+dunJEn37ZuVJJWL+bSGBQAAACCDMhjIogpZzrTn1HGVCjnd+2RUISsQyAAAAAAMT/YCmXu7rX0hn9O52yb106c6UxYBAAAAYFgyl0AagSsX22fsgh1T7dsVpiwCAAAAGKLMBbIg8GUbP59PIAMAAACQkswFskbgyttqFbLMvRwAAAAAUpS5BBJ0TVm85Iwt7ds09QAAAAAwTJkLZI2uKYtbJ0rt20xZBAAAADBMmQtkgS+vkMWVC5l7OQAAAACkqJD2AIat2VUhk6Rvv/91uvXhQ6sGNQAAAABIQuYCWSNw5Wx58Lpw17Qu3DWd0ogAAAAAZFXm5ugFgauQpxIGAAAAIH2ZC2Tdbe8BAAAAIC2ZC2SBu/KsFQMAAAAwAjIXyBpNAhkAAACA0ZC5QEaFDAAAAMCoyFwgawQEMgAAAACjIXOBrNmj7T0AAAAApCGTgax7Y2gAAAAASEMmA1mOQAYAAABgBGQukAVOhQwAAADAaMhcIKOpBwAAAIBRkblAFhDIAAAAAIyIzAWyRuDK02URAAAAwAjIXCBrUiEDAAAAMCIyFcg++p2H9ND+eS1UG2kPBQAAAADWF8jM7Boz+7mZPWJmH0p6UEl48vAxfep//YMkqdoIUh4NAAAAAEiFtQ4ws7ykT0p6o6R9ku4ws5vc/YGkBzdIn73tcRXzpk+8/TK9eOd02sMBAAAAgLUDmaRXSnrE3R+VJDP7sqRrJW2YQHas1tD/vOtJveminXrTS3emPRwAAAAAkLS+KYu7JT0Zu78vemwZM7vezO40szsPHTo0qPENxP4jS9pz6oTeefnZaQ8FAAAAANrWUyFbF3e/UdKNkrR3714f1PcdhBdsm9Q3b3it3EdqWAAAAAAybj0VsqcknRm7f0b02IZj7D8GAAAAYISsJ5DdIek8MzvHzEqS3i7ppmSHBQAAAACb35pTFt29YWbvk/RdSXlJn3H3nyU+MgAAAADY5Na1hszdvy3p2wmPBQAAAAAyZV0bQwMAAAAABo9ABgAAAAApIZABAAAAQEoIZAAAAACQEgIZAAAAAKSEQAYAAAAAKSGQAQAAAEBKCGQAAAAAkBICGQAAAACkhEAGAAAAACkhkAEAAABASghkAAAAAJASAhkAAAAApIRABgAAAAApMXcf/Dc1OyTpFwP/xifvNEnPpj0IbFqcX0gS5xeSxjmGJHF+IUmjen6d7e7b1jookUA2qszsTnffm/Y4sDlxfiFJnF9IGucYksT5hSRt9POLKYsAAAAAkBICGQAAAACkJGuB7Ma0B4BNjfMLSeL8QtI4x5Akzi8kaUOfX5laQwYAAAAAoyRrFTIAAAAAGBkEMgAAAABISSYCmZldY2Y/N7NHzOxDaY8HG4+ZnWlmPzCzB8zsZ2b2u9Hjp5jZzWb2cPT31uhxM7NPROfcfWb2snR/AmwEZpY3s3vM7FvR/XPM7PboPPqKmZWix8vR/Uei5/ekOW5sDGa2xcy+ZmYPmdmDZvZLXMMwKGb2b6L3x/vN7EtmVuEahpNhZp8xs4Nmdn/ssb6vWWb2ruj4h83sXWn8LGvZ9IHMzPKSPinpTZIulPQOM7sw3VFhA2pI+qC7Xyjpcknvjc6jD0n6e3c/T9LfR/el8Hw7L/pzvaRPDX/I2IB+V9KDsfsflfRxdz9X0vOS3hM9/h5Jz0ePfzw6DljLn0v6jrtfIOkSheca1zCcNDPbLen9kva6+0WS8pLeLq5hODmfk3RN12N9XbPM7BRJH5b0KkmvlPThVogbJZs+kCl88R9x90fdvSbpy5KuTXlM2GDc/Rl3vzu6Pa/wg8xuhefS56PDPi/pn0S3r5X01x76v5K2mNnOIQ8bG4iZnSHpVyX9VXTfJF0p6WvRId3nV+u8+5qkq6LjgZ7MbEbSFZI+LUnuXnP3WXENw+AUJI2ZWUHSuKRnxDUMJ8Hdb5F0uOvhfq9Z/0jSze5+2N2fl3SzVoa81GUhkO2W9GTs/r7oMeCERFMrLpN0u6Tt7v5M9NR+Sduj25x36Nd/lfTvJAXR/VMlzbp7I7ofP4fa51f0/JHoeGA150g6JOmz0bTYvzKzCXENwwC4+1OS/oukJxQGsSOS7hLXMAxev9esDXEty0IgAwbGzCYlfV3SB9x9Lv6ch3tIsI8E+mZmvybpoLvflfZYsGkVJL1M0qfc/TJJR9WZ6iOJaxhOXDQF7FqFwX+XpAmNYBUCm8tmumZlIZA9JenM2P0zoseAvphZUWEY+6K7fyN6+EBrGk/098Hocc479OM1kv6xmT2ucFr1lQrX+2yJpv9Iy8+h9vkVPT8j6blhDhgbzj5J+9z99uj+1xQGNK5hGIQ3SHrM3Q+5e13SNxRe17iGYdD6vWZtiGtZFgLZHZLOizr9lBQuMr0p5TFhg4nmtn9a0oPu/rHYUzdJanXseZekv4s9/ltR15/LJR2JldiBZdz9P7j7Ge6+R+E16vvu/puSfiDpbdFh3edX67x7W3T8pvgtIZLh7vslPWlmL4oeukrSA+IahsF4QtLlZjYevV+2zi+uYRi0fq9Z35V0tZltjSq5V0ePjRTLwvlvZm9WuD4jL+kz7v4nKQ8JG4yZvVbSrZJ+qs4an99XuI7sq5LOkvQLSde5++HoDem/KZyycUzSu939zqEPHBuOmb1e0u+5+6+Z2QsUVsxOkXSPpHe6e9XMKpK+oHAt42FJb3f3R9MaMzYGM7tUYdOYkqRHJb1b4S9muYbhpJnZH0n6pwq7Et8j6V8oXKvDNQwnxMy+JOn1kk6TdEBht8S/VZ/XLDP7bYWf2SS4YMhSAAAChElEQVTpT9z9s8P8OdYjE4EMAAAAAEZRFqYsAgAAAMBIIpABAAAAQEoIZAAAAACQEgIZAAAAAKSEQAYAAAAAKSGQAQBGhpk1zewnZna/mX3TzLakNI49ZnZ/Gv82ACBbCGQAgFGy6O6XuvtFCvcneu8w/lEzyw/j3wEAoBuBDAAwqn6kcGNZSZKZ/Vszu8PM7os2oW099v7o9sfN7PvR7SvN7IvR7U+Z2Z1m9rPW10WPP25mHzWzuyX9hpm93MzuNbN7NaQgCAAAgQwAMHKiitVVkm6K7l8t6TxJr5R0qaSXm9kVkm6V9Lroy/ZKmjSzYvTYLdHjf+DueyVdLOmXzezi2D/1nLu/zN2/LOmzkm5w90uS/ekAAOggkAEARsmYmf1E0n5J2yXdHD1+dfTnHkl3S7pAYUC7S2E4m5ZUVVhV26swkN0afe11URXsHkkvkXRh7N/7iiRFa9W2uHsrxH0hkZ8OAIAuhbQHAABAzKK7X2pm45K+q3Dq4CckmaSPuPt/7/4CM3tM0j+X9ENJ90n6FUnnSnrQzM6R9HuSXuHuz5vZ5yRVYl9+NMGfBQCANVEhAwCMHHc/Jun9kj5oZgWF4ey3zWxSksxst5mdHh1+q8LQdUt0+19JusfdXdK0wtB1xMy2S3rTKv/erKRZM3tt9NBvJvOTAQCwHIEMADCS3P0ehRWvd7j79yT9D0k/MrOfSvqapKno0Fsl7ZT0I3c/IGkpekzufq/CqYoPRV9/23H+yXdL+mQ0ZdIG/xMBALCShb9ABAAAAAAMGxUyAAAAAEgJgQwAAAAAUkIgAwAAAICUEMgAAAAAICUEMgAAAABICYEMAAAAAFJCIAMAAACAlPx/2uTcW7MIF2IAAAAASUVORK5CYII=\n", + "image/png": "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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ - "from pandas import DataFrame\n", - "moving_average = lambda x, **kw: DataFrame(\n", - " {'x': np.asarray(x)}).x.ewm(**kw).mean().values\n", - "\n", - "horizon = 20\n", - "env = RiverSwimEnv(max_steps=horizon)\n", - "agent = PsrlAgent(env.n_states, env.n_actions, horizon=horizon)\n", - "rews = train_mdp_agent(agent, env, 1000)\n", - "\n", - "plt.figure(figsize=(15, 8))\n", - "plt.plot(moving_average(np.array(rews), alpha=0.1))\n", - "\n", - "plt.xlabel(\"Episode count\")\n", - "plt.ylabel(\"Reward\")\n", - "plt.show()" + "agent = QLearningAgent(\n", + " epsilon=.1, \n", + " alpha=0.5, \n", + " discount=.9, \n", + " get_legal_actions=lambda s: range(env.action_space.n)\n", + ")\n", + "\n", + "rnd = RandomNetworkDistilationModule(\n", + " np.prod(env.observation_space.shape), \n", + " np.prod(env.observation_space.shape), \n", + " 16\n", + ")\n", + "\n", + "train_with_reward(env, agent, rnd, n_episodes=2000, update_reward_period=100, batch_size=100, n_iter=25)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 333, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ - "plot_policy(agent)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Bonus 3.2 Bootstrapped DQN (10 points)\n", - "\n", - "Implement Bootstrapped DQN algorithm and compare it's performance with ordinary DQN on BeamRider Atari game. Links:\n", - "- https://arxiv.org/abs/1602.04621" + "test_agent(agent)" ] } ], "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "pygments_lexer": "ipython3" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" } }, "nbformat": 4, diff --git a/week06_policy_based/README.md b/week06_policy_based/README.md index 5f5ea046f..52b00bad8 100644 --- a/week06_policy_based/README.md +++ b/week06_policy_based/README.md @@ -1,7 +1,7 @@ ## Materials * [Slides](https://yadi.sk/i/keSzKSgA2oYuwQ) * Video lecture by D. Silver - [video](https://www.youtube.com/watch?v=KHZVXao4qXs) -* Our [lecture](https://yadi.sk/i/yPIPkO_f3TPsNK), [seminar(pytorch)](https://yadi.sk/i/flW8ezGk3TPsQ5), [seminar(theano)](https://yadi.sk/i/8f9NX_E73GKBkT) +* Our [lecture](https://yadi.sk/i/yPIPkO_f3TPsNK), [seminar(pytorch)](https://yadi.sk/i/flW8ezGk3TPsQ5) * Alternative lecture by J. Schulman part 1 - [video](https://www.youtube.com/watch?v=BB-BhTn6DCM) * Alternative lecture by J. Schulman part 2 - [video](https://www.youtube.com/watch?v=Wnl-Qh2UHGg) * Andrej Karpathy's [post](http://karpathy.github.io/2016/05/31/rl/) on policy gradients diff --git a/week06_policy_based/a2c-optional.ipynb b/week06_policy_based/a2c-optional.ipynb index 4cb4186ad..2ffe4deaf 100644 --- a/week06_policy_based/a2c-optional.ipynb +++ b/week06_policy_based/a2c-optional.ipynb @@ -1,298 +1,409 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "if 'google.colab' in sys.modules:\n", - " import os\n", - "\n", - " os.system('apt-get install -y xvfb')\n", - " os.system('wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/xvfb -O ../xvfb')\n", - " os.system('apt-get install -y python-opengl ffmpeg')\n", - " os.system('pip install pyglet==1.2.4')\n", - "\n", - " os.system('python -m pip install -U pygame --user')\n", - "\n", - " print('setup complete')\n", - "\n", - "# XVFB will be launched if you run on a server\n", - "import os\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "o4vBVdNx2EPr" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting virtual X frame buffer: Xvfb../xvfb: line 24: start-stop-daemon: command not found\n", + ".\n" + ] + } + ], + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " # Install xvfb and our launcher script for it\n", + " !apt-get install -y xvfb\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/xvfb -O ../xvfb\n", + "\n", + " # Download dependencies from Github\n", + " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week06_policy_based/atari_wrappers.py\n", + " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week06_policy_based/env_batch.py\n", + " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week06_policy_based/runners.py\n", + "\n", + " # Update the gym environment to be compatible with the Atari environment\n", + " !pip install -q gymnasium[atari,accept-rom-license]\n", + " !pip install -q tensorboardX\n", + "\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display to draw game images on.\n", + "# It will have no effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "O_iJbFWQ2EPs" + }, + "source": [ + "# Implementing Advantage-Actor Critic (A2C)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "16ownLDJ2EPs" + }, + "source": [ + "In this notebook you will implement Advantage Actor Critic algorithm that trains on a batch of Atari 2600 environments running in parallel.\n", + "\n", + "Firstly, we will use environment wrappers implemented in file `atari_wrappers.py`. These wrappers preprocess observations (resize, grayscale, take max between frames, skip frames and stack them together) and rewards. Some of the wrappers help to reset the environment and pass `done` flag equal to `True` when agent dies.\n", + "File `env_batch.py` includes implementation of `ParallelEnvBatch` class that allows to run multiple environments in parallel. To create an environment we can use `nature_dqn_env` function. Note that if you are using\n", + "PyTorch and not using `tensorboardX` you will need to implement a wrapper that will log **raw** total rewards that the *unwrapped* environment returns and redefine the implemention of `nature_dqn_env` function here.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uScP-zu12EPt" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import gymnasium as gym\n", + "from atari_wrappers import nature_dqn_env\n", + "\n", + "\n", + "env_name = \"SpaceInvadersNoFrameskip-v4\"\n", + "nenvs = 8 # change this if you have more than 8 CPU ;)\n", + "summaries = \"Tensorboard\"\n", + "\n", + "env = nature_dqn_env(env_name, nenvs=nenvs, summaries=summaries)\n", + "obs, _ = env.reset()\n", + "assert obs.shape == (nenvs, 4, 84, 84)\n", + "assert obs.dtype == np.float32\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jiWeYgmd2EPt" + }, + "source": [ + "Next, we will need to implement a model that predicts logits and values. It is suggested that you use the same model as in [Nature DQN paper](https://www.nature.com/articles/nature14236) with a modification that instead of having a single output layer, it will have two output layers taking as input the output of the last hidden layer. **Note** that this model is different from the model you used in homework where you implemented DQN. You can use your favorite deep learning framework here. We suggest that you use orthogonal initialization with parameter $\\sqrt{2}$ for kernels and initialize biases with zeros." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "id": "FIkJ7z7TiWS4" + }, + "outputs": [], + "source": [ + "# import tensorflow as torch\n", + "# import torch as tf\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pA2VlyZ32EPt" + }, + "source": [ + "You will also need to define and use a policy that wraps the model. While the model computes logits for all actions, the policy will sample actions and also compute their log probabilities. `policy.act` should return a dictionary of all the arrays that are needed to interact with an environment and train the model.\n", + " Note that actions must be an `np.ndarray` while the other\n", + "tensors need to have the type determined by your deep learning framework." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "id": "dtHP-Fo72EPt" + }, + "outputs": [], + "source": [ + "class Policy:\n", + " def __init__(self, model):\n", + " self.model = model\n", + "\n", + " def act(self, inputs):\n", + " # Implement a policy by calling the model, sampling actions and computing their log probs.\n", + " # Should return a dict containing keys ['actions', 'logits', 'log_probs', 'values'].\n", + "\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2oPCQwsd2EPt" + }, + "source": [ + "Next will pass the environment and policy to a runner that collects partial trajectories from the environment.\n", + "The class that does is is already implemented for you." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "id": "fj-fKr_A2EPt" + }, + "outputs": [], + "source": [ + "from runners import EnvRunner" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_9JehIbH2EPt" + }, + "source": [ + "This runner interacts with the environment for a given number of steps and returns a dictionary containing\n", + "keys\n", + "\n", + "* 'observations'\n", + "* 'rewards'\n", + "* 'resets'\n", + "* 'actions'\n", + "* all other keys that you defined in `Policy`\n", + "\n", + "under each of these keys there is a python `list` of interactions with the environment. This list has length $T$ that is size of partial trajectory. Partial trajectory for given moment `t` is part of `ComputeValueTargets.__call__` input argument `trajectory` from moment `t` to the end (i.e. it's different at each iteration in the algorithm)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iY7FB6s72EPu" + }, + "source": [ + "To train the part of the model that predicts state values you will need to compute the value targets.\n", + "Any callable could be passed to `EnvRunner` to be applied to each partial trajectory after it is collected.\n", + "Thus, we can implement and use `ComputeValueTargets` callable.\n", + "The formula for the value targets is simple:\n", + "\n", + "$$\n", + "\\hat v(s_t) = \\left( \\sum_{t'=0}^{T - 1} \\gamma^{t'}r_{t+t'} \\right) + \\gamma^T \\hat{v}(s_{t+T}),\n", + "$$\n", + "\n", + "In implementation, however, do not forget to use\n", + "`trajectory['resets']` flags to check if you need to add the value targets at the next step when\n", + "computing value targets for the current step. You can access `trajectory['state']['latest_observation']`\n", + "to get last observations in partial trajectory — $s_{t+T}$." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "id": "4CbDi3GZ2EPu" + }, + "outputs": [], + "source": [ + "class ComputeValueTargets:\n", + " def __init__(self, policy, gamma=0.99):\n", + " self.policy = policy\n", + " self.gamma = gamma\n", + "\n", + " def __call__(self, trajectory):\n", + " \"\"\"Compute value targets for a given partial trajectory.\"\"\"\n", + "\n", + " # This method should modify trajectory inplace by adding\n", + " # an item with key 'value_targets' to it.\n", + "\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9_d9OYyz2EPu" + }, + "source": [ + "After computing value targets we will transform lists of interactions into tensors\n", + "with the first dimension `batch_size` which is equal to `env_steps * num_envs`, i.e. you essentially need\n", + "to flatten the first two dimensions." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "id": "IEnqWlHh2EPu" + }, + "outputs": [], + "source": [ + "class MergeTimeBatch:\n", + " \"\"\" Merges first two axes typically representing time and env batch. \"\"\"\n", + " def __call__(self, trajectory):\n", + " # Modify trajectory inplace.\n", + "\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "id": "-2CwwzLl2EPu" + }, + "outputs": [], + "source": [ + "model = \n", + "policy = Policy(model)\n", + "runner = EnvRunner(\n", + " env=env,\n", + " policy=policy,\n", + " nsteps=5,\n", + " transforms=[\n", + " ComputeValueTargets(policy),\n", + " MergeTimeBatch(),\n", + " ],\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IuYy-8Ri2EPu" + }, + "source": [ + "Now is the time to implement the advantage actor critic algorithm itself. You can look into your lecture,\n", + "[Mnih et al. 2016](https://arxiv.org/abs/1602.01783) paper, and [lecture](https://www.youtube.com/watch?v=Tol_jw5hWnI&list=PLkFD6_40KJIxJMR-j5A1mkxK26gh_qg37&index=20) by Sergey Levine." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "id": "hxFLzyRX2EPu" + }, + "outputs": [], + "source": [ + "class A2C:\n", + " def __init__(self,\n", + " policy,\n", + " optimizer,\n", + " value_loss_coef=0.25,\n", + " entropy_coef=0.01,\n", + " max_grad_norm=0.5):\n", + " self.policy = policy\n", + " self.optimizer = optimizer\n", + " self.value_loss_coef = value_loss_coef\n", + " self.entropy_coef = entropy_coef\n", + " self.max_grad_norm = max_grad_norm\n", + "\n", + " def policy_loss(self, trajectory):\n", + " # You will need to compute advantages here.\n", + " \n", + "\n", + " def value_loss(self, trajectory):\n", + " \n", + "\n", + " def loss(self, trajectory):\n", + " \n", + "\n", + " def step(self, trajectory):\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JIMtFZuG2EPu" + }, + "source": [ + "Now you can train your model. With reasonable hyperparameters training on a single GTX1080 for 10 million steps across all batched environments (which translates to about 5 hours of wall clock time)\n", + "it should be possible to achieve *average raw reward over last 100 episodes* (the average is taken over 100 last\n", + "episodes in each environment in the batch) of about 600. You should plot this quantity with respect to\n", + "`runner.step_var` — the number of interactions with all environments. It is highly\n", + "encouraged to also provide plots of the following quantities (these are useful for debugging as well):\n", + "\n", + "* [Coefficient of Determination](https://en.wikipedia.org/wiki/Coefficient_of_determination) between\n", + "value targets and value predictions\n", + "* Entropy of the policy $\\pi$\n", + "* Value loss\n", + "* Policy loss\n", + "* Value targets\n", + "* Value predictions\n", + "* Gradient norm\n", + "* Advantages\n", + "* A2C loss\n", + "\n", + "For optimization we suggest you use RMSProp with learning rate starting from 7e-4 and linearly decayed to 0, smoothing constant (alpha in PyTorch and decay in TensorFlow) equal to 0.99 and epsilon equal to 1e-5." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#if you use TensorboardSummaries\n", + "%load_ext tensorboard\n", + "%tensorboard --logdir logs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a2c = \n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZDbgUdMq2EPu" + }, + "source": [ + "### Target networks?\n", + "\n", + "You may recall a technique called \"target networks\" we used a few weeks ago when we trained a DQN agent to play Atari Breakout and wonder why we have not suggested using them here. The answer is that this is more historical than practical.\n", + "\n", + "While the \"chasing the target\" problem is still present in actor-critic value estimation and target networks do show up in follow-up papers, the original A3C/A2C papers do not mention them and do not explain this omission.\n", + "\n", + "The hypothesis why this may not be a big deal (compared to Q-learning) goes like this. An A3C/A2C agent selects actions based on policy, not an epsilon greedy exploration function, for which the argmax can change drastically due to tiny errors in function approximation. Therefore, errors in the value target caused by target chasing will cause less damage.\n", + "\n", + "Also, the actor-critic gradient relies on the advantage function $A(s_t, a_t) = Q(s_t, a_t) - V(s_t)$. Compare this to the $Q$-function $Q(s_t, a_t) = r(s_t, a_t) + \\gamma \\cdot \\mathbb{E}_{s_{t+1} \\mid s_t, a_t} V(s_{t+1})$ used in Q-learning and SARSA: we would expect that any bias in $V$-function approximation will be carried over from $V(s_{t+1})$ to $V(s_t)$ by gradient updates. However, in the formula for the advantage function the two approximations ($Q$-function and $V$-function) come with opposite signs, and thus the errors will cancel out.\n", + "\n", + "The last reason may be computational. Authors were concerned to beat existent algorithms in the wall-clock learning time, and any overhead of parameter copying (target network update) counted against this goal." + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Implementing Advantage-Actor Critic (A2C)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this notebook you will implement Advantage Actor Critic algorithm that trains on a batch of Atari 2600 environments running in parallel. \n", - "\n", - "Firstly, we will use environment wrappers implemented in file `atari_wrappers.py`. These wrappers preprocess observations (resize, grayscal, take max between frames, skip frames and stack them together) and rewards. Some of the wrappers help to reset the environment and pass `done` flag equal to `True` when agent dies.\n", - "File `env_batch.py` includes implementation of `ParallelEnvBatch` class that allows to run multiple environments in parallel. To create an environment we can use `nature_dqn_env` function. Note that if you are using \n", - "PyTorch and not using `tensorboardX` you will need to implement a wrapper that will log **raw** total rewards that the *unwrapped* environment returns and redefine the implemention of `nature_dqn_env` function here. \n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "from atari_wrappers import nature_dqn_env, NumpySummaries\n", - "\n", - "\n", - "env = nature_dqn_env(\"SpaceInvadersNoFrameskip-v4\", nenvs=8, summaries='Numpy')\n", - "obs = env.reset()\n", - "assert obs.shape == (8, 84, 84, 4)\n", - "assert obs.dtype == np.uint8" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will need to implement a model that predicts logits and values. It is suggested that you use the same model as in [Nature DQN paper](https://web.stanford.edu/class/psych209/Readings/MnihEtAlHassibis15NatureControlDeepRL.pdf) with a modification that instead of having a single output layer, it will have two output layers taking as input the output of the last hidden layer. **Note** that this model is different from the model you used in homework where you implemented DQN. You can use your favorite deep learning framework here. We suggest that you use orthogonal initialization with parameter $\\sqrt{2}$ for kernels and initialize biases with zeros. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# import tensorflow as torch\n", - "# import torch as tf\n", - "\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You will also need to define and use a policy that wraps the model. While the model computes logits for all actions, the policy will sample actions and also compute their log probabilities. `policy.act` should return a dictionary of all the arrays that are needed to interact with an environment and train the model.\n", - " Note that actions must be an `np.ndarray` while the other\n", - "tensors need to have the type determined by your deep learning framework. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class Policy:\n", - " def __init__(self, model):\n", - " self.model = model\n", - " \n", - " def act(self, inputs):\n", - " \n", - " # Should return a dict containing keys ['actions', 'logits', 'log_probs', 'values']." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next will pass the environment and policy to a runner that collects partial trajectories from the environment. \n", - "The class that does is is already implemented for you." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from runners import EnvRunner" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This runner interacts with the environment for a given number of steps and returns a dictionary containing\n", - "keys \n", - "\n", - "* 'observations' \n", - "* 'rewards' \n", - "* 'resets'\n", - "* 'actions'\n", - "* all other keys that you defined in `Policy`\n", - "\n", - "under each of these keys there is a python `list` of interactions with the environment of specified length $T$ — the size of partial trajectory. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To train the part of the model that predicts state values you will need to compute the value targets. \n", - "Any callable could be passed to `EnvRunner` to be applied to each partial trajectory after it is collected. \n", - "Thus, we can implement and use `ComputeValueTargets` callable. \n", - "The formula for the value targets is simple:\n", - "\n", - "$$\n", - "\\hat v(s_t) = \\left( \\sum_{t'=0}^{T - 1 - t} \\gamma^{t'}r_{t+t'} \\right) + \\gamma^T \\hat{v}(s_{t+T}),\n", - "$$\n", - "\n", - "In implementation, however, do not forget to use \n", - "`trajectory['resets']` flags to check if you need to add the value targets at the next step when \n", - "computing value targets for the current step. You can access `trajectory['state']['latest_observation']`\n", - "to get last observations in partial trajectory — $s_{t+T}$." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class ComputeValueTargets:\n", - " def __init__(self, policy, gamma=0.99):\n", - " self.policy = policy\n", - " \n", - " def __call__(self, trajectory):\n", - " # This method should modify trajectory inplace by adding\n", - " # an item with key 'value_targets' to it.\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "After computing value targets we will transform lists of interactions into tensors\n", - "with the first dimension `batch_size` which is equal to `T * nenvs`, i.e. you essentially need\n", - "to flatten the first two dimensions. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class MergeTimeBatch:\n", - " \"\"\" Merges first two axes typically representing time and env batch. \"\"\"\n", - " def __call__(self, trajectory):\n", - " # Modify trajectory inplace.\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "model = \n", - "policy = Policy(model)\n", - "runner = EnvRunner(\n", - " env, policy, nsteps=5,\n", - " transforms=[\n", - " ComputeValueTargets(),\n", - " MergeTimeBatch(),\n", - " ])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now is the time to implement the advantage actor critic algorithm itself. You can look into your lecture,\n", - "[Mnih et al. 2016](https://arxiv.org/abs/1602.01783) paper, and [lecture](https://www.youtube.com/watch?v=Tol_jw5hWnI&list=PLkFD6_40KJIxJMR-j5A1mkxK26gh_qg37&index=20) by Sergey Levine." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class A2C:\n", - " def __init__(self,\n", - " policy,\n", - " optimizer,\n", - " value_loss_coef=0.25,\n", - " entropy_coef=0.01,\n", - " max_grad_norm=0.5):\n", - " self.policy = policy\n", - " self.optimizer = optimizer\n", - " self.value_loss_coef = value_loss_coef\n", - " self.entropy_coef = entropy_coef\n", - " self.max_grad_norm = max_grad_norm\n", - " \n", - " def policy_loss(self, trajectory):\n", - " # You will need to compute advantages here.\n", - " \n", - " \n", - " def value_loss(self, trajectory):\n", - " \n", - " \n", - " def loss(self, trajectory):\n", - " \n", - " \n", - " def step(self, trajectory):\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now you can train your model. With reasonable hyperparameters training on a single GTX1080 for 10 million steps across all batched environments (which translates to about 5 hours of wall clock time)\n", - "it should be possible to achieve *average raw reward over last 100 episodes* (the average is taken over 100 last \n", - "episodes in each environment in the batch) of about 600. You should plot this quantity with respect to \n", - "`runner.step_var` — the number of interactions with all environments. It is highly \n", - "encouraged to also provide plots of the following quantities (these are useful for debugging as well):\n", - "\n", - "* [Coefficient of Determination](https://en.wikipedia.org/wiki/Coefficient_of_determination) between \n", - "value targets and value predictions\n", - "* Entropy of the policy $\\pi$\n", - "* Value loss\n", - "* Policy loss\n", - "* Value targets\n", - "* Value predictions\n", - "* Gradient norm\n", - "* Advantages\n", - "* A2C loss\n", - "\n", - "For optimization we suggest you use RMSProp with learning rate starting from 7e-4 and linearly decayed to 0, smoothing constant (alpha in PyTorch and decay in TensorFlow) equal to 0.99 and epsilon equal to 1e-5." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "a2c = \n", - "\n", - "" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/week06_policy_based/atari_wrappers.py b/week06_policy_based/atari_wrappers.py index b1a9234de..ffd0ce25f 100644 --- a/week06_policy_based/atari_wrappers.py +++ b/week06_policy_based/atari_wrappers.py @@ -2,139 +2,149 @@ from collections import defaultdict, deque import cv2 -import gym -import gym.spaces as spaces -from gym.envs import atari +import gymnasium as gym import numpy as np +from gymnasium import ObservationWrapper, RewardWrapper, Wrapper +from gymnasium.spaces import Box +from gymnasium.wrappers import RecordVideo +from shimmy.atari_env import AtariEnv +from tensorboardX import SummaryWriter from env_batch import ParallelEnvBatch + cv2.ocl.setUseOpenCL(False) -class EpisodicLife(gym.Wrapper): - """ Sets done flag to true when agent dies. """ +class EpisodicLife(Wrapper): + """Sets done flag to true when agent dies.""" def __init__(self, env): - super(EpisodicLife, self).__init__(env) + super().__init__(env) self.lives = 0 self.real_done = True def step(self, action): - obs, rew, done, info = self.env.step(action) - self.real_done = done - info["real_done"] = done + obs, reward, terminated, truncated, info = self.env.step(action) + self.real_done = terminated or truncated + info["real_done"] = self.real_done lives = self.env.unwrapped.ale.lives() if 0 < lives < self.lives: - done = True + terminated = True self.lives = lives - return obs, rew, done, info + return obs, reward, terminated, truncated, info def reset(self, **kwargs): if self.real_done: - obs = self.env.reset(**kwargs) + obs, info = self.env.reset(**kwargs) else: - obs, _, _, _ = self.env.step(0) + obs, _, terminated, truncated, info = self.env.step(0) + if terminated or truncated: + obs, info = self.env.reset(**kwargs) self.lives = self.env.unwrapped.ale.lives() - return obs + return obs, info -class FireReset(gym.Wrapper): - """ Makes fire action when reseting environment. +class FireReset(Wrapper): + """Makes fire action when reseting environment. Some environments are fixed until the agent makes the fire action, this wrapper makes this action so that the epsiode starts automatically. """ def __init__(self, env): - super(FireReset, self).__init__(env) + super().__init__(env) action_meanings = env.unwrapped.get_action_meanings() if len(action_meanings) < 3: raise ValueError( "env.unwrapped.get_action_meanings() must be of length >= 3" - f"but is of length {len(action_meanings)}") + f"but is of length {len(action_meanings)}" + ) if env.unwrapped.get_action_meanings()[1] != "FIRE": raise ValueError( "env.unwrapped.get_action_meanings() must have 'FIRE' " - f"under index 1, but is {action_meanings}") + f"under index 1, but is {action_meanings}" + ) def step(self, action): return self.env.step(action) def reset(self, **kwargs): self.env.reset(**kwargs) - obs, _, done, _ = self.env.step(1) - if done: + obs, _, terminated, truncated, _ = self.env.step(1) + if terminated or truncated: self.env.reset(**kwargs) - obs, _, done, _ = self.env.step(2) - if done: + obs, _, terminated, truncated, _ = self.env.step(2) + if terminated or truncated: self.env.reset(**kwargs) - return obs + return obs, {} -class StartWithRandomActions(gym.Wrapper): - """ Makes random number of random actions at the beginning of each - episode. """ +class StartWithRandomActions(Wrapper): + """Makes random number of random actions at the beginning of each + episode.""" def __init__(self, env, max_random_actions=30): - super(StartWithRandomActions, self).__init__(env) + super().__init__(env) self.max_random_actions = max_random_actions self.real_done = True def step(self, action): - obs, rew, done, info = self.env.step(action) + obs, reward, terminated, truncated, info = self.env.step(action) self.real_done = info.get("real_done", True) - return obs, rew, done, info + return obs, reward, terminated, truncated, info def reset(self, **kwargs): - obs = self.env.reset() + obs, info = self.env.reset(**kwargs) if self.real_done: - num_random_actions = np.random.randint(self.max_random_actions + 1) + num_random_actions = self.unwrapped.np_random.integers( + low=1, high=self.max_random_actions + 1 + ) for _ in range(num_random_actions): - obs, _, _, _ = self.env.step(self.env.action_space.sample()) + obs, _, _, _, info = self.env.step(self.env.action_space.sample()) self.real_done = False - return obs + return obs, info -class ImagePreprocessing(gym.ObservationWrapper): - """ Preprocesses image-observations by possibly grayscaling and resizing. """ +class ImagePreprocessing(ObservationWrapper): + """Preprocesses image-observations by possibly grayscaling and resizing.""" - def __init__(self, env, width=84, height=84, grayscale=True): - super(ImagePreprocessing, self).__init__(env) - self.width = width + def __init__(self, env, height=84, width=84, grayscale=True): + super().__init__(env) self.height = height + self.width = width self.grayscale = grayscale ospace = self.env.observation_space low, high, dtype = ospace.low.min(), ospace.high.max(), ospace.dtype if self.grayscale: - self.observation_space = spaces.Box( + self.observation_space = Box( low=low, high=high, - shape=(width, height), + shape=(height, width), dtype=dtype, ) else: - obs_shape = (width, height) + self.observation_space.shape[2:] - self.observation_space = spaces.Box(low=low, high=high, - shape=obs_shape, dtype=dtype) + self.observation_space = Box( + low=low, + high=high, + shape=(height, width, *self.observation_space.shape[2:]), + dtype=dtype, + ) def observation(self, observation): - """ Performs image preprocessing. """ + """Performs image preprocessing.""" if self.grayscale: observation = cv2.cvtColor(observation, cv2.COLOR_RGB2GRAY) - observation = cv2.resize(observation, (self.width, self.height), - cv2.INTER_AREA) + observation = cv2.resize(observation, (self.width, self.height), cv2.INTER_AREA) return observation -class MaxBetweenFrames(gym.ObservationWrapper): - """ Takes maximum between two subsequent frames. """ +class MaxBetweenFrames(ObservationWrapper): + """Takes maximum between two subsequent frames.""" def __init__(self, env): - if (isinstance(env.unwrapped, atari.AtariEnv) and - "NoFrameskip" not in env.spec.id): - raise ValueError( - "MaxBetweenFrames requires NoFrameskip in Atari env id") - super(MaxBetweenFrames, self).__init__(env) + if isinstance(env.unwrapped, AtariEnv) and "NoFrameskip" not in env.spec.id: + raise ValueError("MaxBetweenFrames requires NoFrameskip in atari env id") + super().__init__(env) self.last_obs = None def observation(self, observation): @@ -143,15 +153,15 @@ def observation(self, observation): return obs def reset(self, **kwargs): - self.last_obs = self.env.reset() - return self.last_obs + self.last_obs, info = self.env.reset(**kwargs) + return self.last_obs, info -class QueueFrames(gym.ObservationWrapper): - """ Queues specified number of frames together along new dimension. """ +class QueueFrames(ObservationWrapper): + """Queues specified number of frames together along new dimension.""" def __init__(self, env, nframes, concat=False): - super(QueueFrames, self).__init__(env) + super().__init__(env) self.obs_queue = deque([], maxlen=nframes) self.concat = concat ospace = self.observation_space @@ -159,110 +169,143 @@ def __init__(self, env, nframes, concat=False): oshape = ospace.shape[:-1] + (ospace.shape[-1] * nframes,) else: oshape = ospace.shape + (nframes,) - self.observation_space = spaces.Box( - ospace.low.min(), ospace.high.max(), oshape, ospace.dtype) + self.observation_space = Box( + ospace.low.min(), ospace.high.max(), oshape, ospace.dtype + ) def observation(self, observation): self.obs_queue.append(observation) - return (np.concatenate(self.obs_queue, -1) if self.concat - else np.dstack(self.obs_queue)) + return ( + np.concatenate(self.obs_queue, -1) + if self.concat + else np.dstack(self.obs_queue) + ) def reset(self, **kwargs): - obs = self.env.reset() + obs, info = self.env.reset(**kwargs) for _ in range(self.obs_queue.maxlen - 1): self.obs_queue.append(obs) - return self.observation(obs) + return self.observation(obs), info -class SkipFrames(gym.Wrapper): - """ Performs the same action for several steps and returns the final result. - """ +class SkipFrames(Wrapper): + """Performs the same action for several steps and returns the final result.""" def __init__(self, env, nskip=4): - super(SkipFrames, self).__init__(env) - if (isinstance(env.unwrapped, atari.AtariEnv) and - "NoFrameskip" not in env.spec.id): - raise ValueError("SkipFrames requires NoFrameskip in Atari env id") + super().__init__(env) + if isinstance(env.unwrapped, AtariEnv) and "NoFrameskip" not in env.spec.id: + raise ValueError("SkipFrames requires NoFrameskip in atari env id") self.nskip = nskip def step(self, action): total_reward = 0.0 for _ in range(self.nskip): - obs, rew, done, info = self.env.step(action) - total_reward += rew - if done: + obs, reward, terminated, truncated, info = self.env.step(action) + total_reward += reward + if terminated or truncated: break - return obs, total_reward, done, info + return obs, total_reward, terminated, truncated, info def reset(self, **kwargs): return self.env.reset(**kwargs) -class ClipReward(gym.RewardWrapper): - """ Modifes reward to be in {-1, 0, 1} by taking sign of it. """ +class ClipReward(RewardWrapper): + """Modifes reward to be in {-1, 0, 1} by taking sign of it.""" def reward(self, reward): return np.sign(reward) -class SummariesBase(gym.Wrapper): - """ Env summaries writer base.""" +class SwapImageAxes(ObservationWrapper): + """ + Image shape to num_channels x height x width and normalization + """ - def __init__(self, env, prefix=None, running_mean_size=100): + def __init__(self, env): + super().__init__(env) + old_shape = self.observation_space.shape + self.observation_space = Box( + low=0.0, + high=1.0, + shape=(old_shape[-1], old_shape[0], old_shape[1]), + dtype=np.float32, + ) + + def observation(self, observation): + return np.transpose(observation, (2, 0, 1)).astype(np.float32) / 255.0 + + +class SummariesBase(Wrapper): + """Env summaries writer base.""" + + def __init__(self, env, prefix=None, running_mean_size=100, step_var=None): super().__init__(env) self.episode_counter = 0 self.prefix = prefix or self.env.spec.id + self.step_var = step_var or 0 - nenvs = getattr(self.env.unwrapped, "nenvs", 1) - self.rewards = np.zeros(nenvs) - self.had_ended_episodes = np.zeros(nenvs, dtype=np.bool) - self.episode_lengths = np.zeros(nenvs) - self.reward_queues = [deque([], maxlen=running_mean_size) - for _ in range(nenvs)] + self.nenvs = getattr(self.env.unwrapped, "nenvs", 1) + self.rewards = np.zeros(self.nenvs) + self.had_ended_episodes = np.zeros(self.nenvs, dtype=bool) + self.episode_lengths = np.zeros(self.nenvs) + self.reward_queues = [ + deque([], maxlen=running_mean_size) for _ in range(self.nenvs) + ] def should_write_summaries(self): - """ Returns true if it's time to write summaries. """ + """Returns true if it's time to write summaries.""" return np.all(self.had_ended_episodes) def add_summaries(self): - """ Writes summaries. """ - self.add_summary_scalar( - f"{self.prefix}/total_reward", - np.mean([q[-1] for q in self.reward_queues])) - self.add_summary_scalar( - f"{self.prefix}/reward_mean_{self.reward_queues[0].maxlen}", - np.mean([np.mean(q) for q in self.reward_queues])) - self.add_summary_scalar( - f"{self.prefix}/episode_length", - np.mean(self.episode_lengths)) + """Writes summaries.""" + self.add_summary( + f"Episodes/total_reward", np.mean([q[-1] for q in self.reward_queues]) + ) + self.add_summary( + f"Episodes/reward_mean_{self.reward_queues[0].maxlen}", + np.mean([np.mean(q) for q in self.reward_queues]), + ) + self.add_summary(f"Episodes/episode_length", np.mean(self.episode_lengths)) if self.had_ended_episodes.size > 1: - self.add_summary_scalar( - f"{self.prefix}/min_reward", - min(q[-1] for q in self.reward_queues)) - self.add_summary_scalar( - f"{self.prefix}/max_reward", - max(q[-1] for q in self.reward_queues)) + self.add_summary( + f"Episodes/min_reward", + min(q[-1] for q in self.reward_queues), + ) + self.add_summary( + f"Episodes/max_reward", + max(q[-1] for q in self.reward_queues), + ) self.episode_lengths.fill(0) self.had_ended_episodes.fill(False) def step(self, action): - obs, rew, done, info = self.env.step(action) + obs, rew, terminated, truncated, info = self.env.step(action) self.rewards += rew self.episode_lengths[~self.had_ended_episodes] += 1 info_collection = [info] if isinstance(info, dict) else info - done_collection = [done] if isinstance(done, bool) else done - done_indices = [i for i, info in enumerate(info_collection) - if info.get("real_done", done_collection[i])] + terminated_collection = ( + [terminated] if isinstance(terminated, bool) else terminated + ) + truncated_collection = [truncated] if isinstance(truncated, bool) else truncated + done_indices = [ + i + for i, info in enumerate(info_collection) + if info.get( + "real_done", terminated_collection[i] or truncated_collection[i] + ) + ] for i in done_indices: if not self.had_ended_episodes[i]: self.had_ended_episodes[i] = True self.reward_queues[i].append(self.rewards[i]) self.rewards[i] = 0 + self.step_var += self.nenvs if self.should_write_summaries(): self.add_summaries() - return obs, rew, done, info + return obs, rew, terminated, truncated, info def reset(self, **kwargs): self.rewards.fill(0) @@ -271,30 +314,23 @@ def reset(self, **kwargs): return self.env.reset(**kwargs) -class TFSummaries(SummariesBase): - """ Writes env summaries using TensorFlow.""" +class TensorboardSummaries(SummariesBase): + """Writes env summaries using Tensorboard.""" def __init__(self, env, prefix=None, running_mean_size=100, step_var=None): + super().__init__(env, prefix, running_mean_size, step_var) + self.writer = SummaryWriter(f"logs/{self.prefix}") - super().__init__(env, prefix, running_mean_size) - - import tensorflow as tf - self.step_var = (step_var if step_var is not None - else tf.train.get_global_step()) - - def add_summary_scalar(self, name, value): - import tensorflow as tf - tf.contrib.summary.scalar(name, value, step = self.step_var) + def add_summary(self, name, value): + if isinstance(value, dict): + self.writer.add_scalars(name, value, self.step_var) + else: + self.writer.add_scalar(name, value, self.step_var) class NumpySummaries(SummariesBase): _summaries = defaultdict(list) - _summary_step = None - - @classmethod - def set_step(cls, step): - cls._summary_step = step @classmethod def get_values(cls, name): @@ -304,16 +340,44 @@ def get_values(cls, name): def clear(cls): cls._summaries = defaultdict(list) - def __init__(self, env, prefix = None, running_mean_size = 100): - super().__init__(env, prefix, running_mean_size) + def __init__(self, env, prefix=None, running_mean_size=100, step_var=None): + super().__init__(env, prefix, running_mean_size, step_var) + + def add_summary(self, name, value): + self._summaries[name].append((self.step_var, value)) + + +def get_summaries_class(summaries): + summaries_class_map = { + "Numpy": NumpySummaries, + "Tensorboard": TensorboardSummaries, + } + if summaries in summaries_class_map: + return summaries_class_map[summaries] + + raise NotImplementedError( + f"Unknown summaries: {summaries}. Supported summaries: {summaries_class_map.keys()}" + ) - def add_summary_scalar(self, name, value): - self._summaries[name].append((self._summary_step, value)) +# magic for parallel launching of environments +class _thunk: + def __init__(self, i, env_id, **kwargs): + self.env_id = env_id + self.i = i + self.kwargs = kwargs -def nature_dqn_env(env_id, nenvs=None, seed=None, - summaries='TensorFlow', clip_reward=True): - """ Wraps env as in Nature DQN paper. """ + def __call__(self): + return nature_dqn_env( + self.env_id, + summaries=False, + clip_reward=False, + **self.kwargs, + ) + + +def nature_dqn_env(env_id, nenvs=None, seed=None, summaries="Numpy", clip_reward=True): + """Wraps env as in Nature DQN paper.""" if "NoFrameskip" not in env_id: raise ValueError(f"env_id must have 'NoFrameskip' but is {env_id}") if nenvs is not None: @@ -322,25 +386,24 @@ def nature_dqn_env(env_id, nenvs=None, seed=None, if isinstance(seed, int): seed = [seed] * nenvs if len(seed) != nenvs: - raise ValueError(f"seed has length {len(seed)} but must have " - f"length equal to nenvs which is {nenvs}") - - env = ParallelEnvBatch([ - lambda i=i, env_seed=env_seed: nature_dqn_env( - env_id, seed=env_seed, summaries=False, clip_reward=False) - for i, env_seed in enumerate(seed) - ]) + raise ValueError( + f"seed has length {len(seed)} but must have " + f"length equal to nenvs which is {nenvs}" + ) + + thunks = [_thunk(i, env_id) for i in range(nenvs)] + env = ParallelEnvBatch(make_env=thunks, seeds=seed) + if summaries: - summaries_class = NumpySummaries if summaries == 'Numpy' else TFSummaries + summaries_class = get_summaries_class(summaries) env = summaries_class(env, prefix=env_id) if clip_reward: env = ClipReward(env) return env - env = gym.make(env_id) - env.seed(seed) + env = gym.make(env_id, render_mode="rgb_array") if summaries: - env = TFSummaries(env) + env = TensorboardSummaries(env) env = EpisodicLife(env) if "FIRE" in env.unwrapped.get_action_meanings(): env = FireReset(env) @@ -349,6 +412,7 @@ def nature_dqn_env(env_id, nenvs=None, seed=None, env = SkipFrames(env, 4) env = ImagePreprocessing(env, width=84, height=84, grayscale=True) env = QueueFrames(env, 4) + env = SwapImageAxes(env) if clip_reward: env = ClipReward(env) return env diff --git a/week06_policy_based/env_batch.py b/week06_policy_based/env_batch.py index 1e23913e9..b2bd163ac 100644 --- a/week06_policy_based/env_batch.py +++ b/week06_policy_based/env_batch.py @@ -1,8 +1,9 @@ # pylint: skip-file -from multiprocessing import Process, Pipe +from multiprocessing import Pipe, Process -from gym import Env, Wrapper, Space import numpy as np +from gymnasium import Env, Wrapper +from gymnasium.spaces import Space class SpaceBatch(Space): @@ -12,18 +13,26 @@ def __init__(self, spaces): first_dtype = spaces[0].dtype for space in spaces: if not isinstance(space, first_type): - raise TypeError("spaces have different types: {}, {}" - .format(first_type, type(space))) + raise TypeError( + "spaces have different types: {}, {}".format( + first_type, type(space) + ) + ) if first_shape != space.shape: - raise ValueError("spaces have different shapes: {}, {}" - .format(first_shape, space.shape)) + raise ValueError( + "spaces have different shapes: {}, {}".format( + first_shape, space.shape + ) + ) if first_dtype != space.dtype: - raise ValueError("spaces have different data types: {}, {}" - .format(first_dtype, space.dtype)) + raise ValueError( + "spaces have different data types: {}, {}".format( + first_dtype, space.dtype + ) + ) self.spaces = spaces - super(SpaceBatch, self).__init__(shape=self.spaces[0].shape, - dtype=self.spaces[0].dtype) + super().__init__(shape=self.spaces[0].shape, dtype=self.spaces[0].dtype) def sample(self): return np.stack([space.sample() for space in self.spaces]) @@ -39,16 +48,15 @@ def __init__(self, make_env, nenvs=None): self._nenvs = len(self.envs) # self.observation_space = SpaceBatch([env.observation_space # for env in self._envs]) - self.action_space = SpaceBatch([env.action_space - for env in self._envs]) + self.action_space = SpaceBatch([env.action_space for env in self._envs]) def _get_make_env_functions(self, make_env, nenvs): if nenvs is None and not isinstance(make_env, list): - raise ValueError("When nenvs is None make_env" - " must be a list of callables") - if nenvs is not None and not callable(make_env): raise ValueError( - "When nenvs is not None make_env must be callable") + "When nenvs is None make_env" " must be a list of callables" + ) + if nenvs is not None and not callable(make_env): + raise ValueError("When nenvs is not None make_env must be callable") if nenvs is not None: make_env = [make_env for _ in range(nenvs)] @@ -66,29 +74,41 @@ def _check_actions(self, actions): if not len(actions) == self.nenvs: raise ValueError( "number of actions is not equal to number of envs: " - "len(actions) = {}, nenvs = {}" - .format(len(actions), self.nenvs)) + "len(actions) = {}, nenvs = {}".format(len(actions), self.nenvs) + ) def step(self, actions): self._check_actions(actions) - obs, rews, resets, infos = [], [], [], [] + observations, rewards, terminated_list, truncated_list, infos = [], [], [], [], [] for env, action in zip(self._envs, actions): - ob, rew, done, info = env.step(action) - if done: - ob = env.reset() - obs.append(ob) - rews.append(rew) - resets.append(done) + obs, rew, terminated, truncated, info = env.step(action) + if terminated or truncated: + obs, info = env.reset() + observations.append(obs) + rewards.append(rew) + terminated_list.append(terminated) + truncated_list.append(truncated) infos.append(info) - return np.stack(obs), np.stack(rews), np.stack(resets), infos + return ( + np.stack(observations), + np.stack(rewards), + np.stack(terminated_list), + np.stack(truncated_list), + infos, + ) - def reset(self): - return np.stack([env.reset() for env in self.envs]) + def reset(self, **kwargs): + observations, infos = [], [] + for env in self.envs: + obs, info = env.reset(**kwargs) + observations.append(obs) + infos.append(info) + return np.stack(observations), infos class SingleEnvBatch(Wrapper, EnvBatch): def __init__(self, env): - super(SingleEnvBatch, self).__init__(env) + super().__init__(env) self.observation_space = SpaceBatch([self.env.observation_space]) self.action_space = SpaceBatch([self.env.action_space]) @@ -102,37 +122,38 @@ def envs(self): def step(self, actions): self._check_actions(actions) - ob, rew, done, info = self.env.step(actions[0]) - if done: - ob = self.env.reset() + obs, rew, terminated, truncated, info = self.env.step(actions[0]) + if terminated or truncated: + obs, info = self.env.reset() return ( - ob[None], + obs[None], np.expand_dims(rew, 0), - np.expand_dims(done, 0), + np.expand_dims(terminated, 0), + np.expand_dims(truncated, 0), [info], ) - def reset(self): - return self.env.reset()[None] + def reset(self, **kwargs): + obs, info = self.env.reset(**kwargs) + return obs[None], info -def worker(parent_connection, worker_connection, make_env_function, - send_spaces=True): +def worker(parent_connection, worker_connection, make_env_function, send_spaces=True): # Adapted from SubprocVecEnv github.com/openai/baselines parent_connection.close() env = make_env_function() if send_spaces: worker_connection.send((env.observation_space, env.action_space)) while True: - cmd, action = worker_connection.recv() + cmd, data = worker_connection.recv() if cmd == "step": - ob, rew, done, info = env.step(action) - if done: - ob = env.reset() - worker_connection.send((ob, rew, done, info)) + obs, rew, terminated, truncated, info = env.step(data) + if terminated or truncated: + obs, info = env.reset() + worker_connection.send((obs, rew, terminated, truncated, info)) elif cmd == "reset": - ob = env.reset() - worker_connection.send(ob) + obs, info = env.reset(seed=data) + worker_connection.send((obs, info)) elif cmd == "close": env.close() worker_connection.close() @@ -146,22 +167,26 @@ class ParallelEnvBatch(EnvBatch): An abstract batch of environments. """ - def __init__(self, make_env, nenvs=None): + def __init__(self, make_env, nenvs=None, seeds=None): make_env_functions = self._get_make_env_functions(make_env, nenvs) self._nenvs = len(make_env_functions) - self._parent_connections, self._worker_connections = zip(*[ - Pipe() for _ in range(self._nenvs) - ]) + self._parent_connections, self._worker_connections = zip( + *[Pipe() for _ in range(self._nenvs)] + ) + self._seeds = seeds or list(range(self._envs)) self._processes = [ Process( target=worker, args=(parent_connection, worker_connection, make_env), - daemon=True + daemon=True, + ) + for i, (parent_connection, worker_connection, make_env) in enumerate( + zip( + self._parent_connections, + self._worker_connections, + make_env_functions, + ) ) - for i, (parent_connection, worker_connection, make_env) - in enumerate(zip(self._parent_connections, - self._worker_connections, - make_env_functions)) ] for p in self._processes: p.start() @@ -187,13 +212,23 @@ def step(self, actions): for conn, a in zip(self._parent_connections, actions): conn.send(("step", a)) results = [conn.recv() for conn in self._parent_connections] - obs, rews, dones, infos = zip(*results) - return np.stack(obs), np.stack(rews), np.stack(dones), infos + obs, rews, terminated, truncated, infos = zip(*results) + return ( + np.stack(obs), + np.stack(rews), + np.stack(terminated), + np.stack(truncated), + infos, + ) - def reset(self): - for conn in self._parent_connections: - conn.send(("reset", None)) - return np.stack([conn.recv() for conn in self._parent_connections]) + def reset(self, **kwargs): + for env_idx, conn in enumerate(self._parent_connections): + conn.send(("reset", self._seeds[env_idx])) + + results = [remote.recv() for remote in self._parent_connections] + observations, infos = zip(*results) + + return np.stack(observations), infos def close(self): if self._closed: diff --git a/week06_policy_based/reinforce_lasagne.ipynb b/week06_policy_based/reinforce_lasagne.ipynb deleted file mode 100644 index 3dcb9cefe..000000000 --- a/week06_policy_based/reinforce_lasagne.ipynb +++ /dev/null @@ -1,451 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# REINFORCE in lasagne\n", - "\n", - "Just like we did before for q-learning, this time we'll design a lasagne network to learn `CartPole-v0` via policy gradient (REINFORCE).\n", - "\n", - "Most of the code in this notebook is taken from approximate qlearning, so you'll find it more or less familiar and even simpler." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "__Frameworks__ - we'll accept this homework in any deep learning framework. For example, it translates to TensorFlow almost line-to-line. However, we recommend you to stick to theano/lasagne unless you're certain about your skills in the framework of your choice." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "env: THEANO_FLAGS='floatX=float32'\n" - ] - } - ], - "source": [ - "%env THEANO_FLAGS = 'floatX=float32'\n", - "import os\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[2017-03-14 19:35:59,320] Making new env: CartPole-v0\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\nqSX+P7qsoBUsM5jGAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import gym\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "\n", - "env = gym.make(\"CartPole-v0\").env\n", - "env.reset()\n", - "n_actions = env.action_space.n\n", - "state_dim = env.observation_space.shape\n", - "\n", - "plt.imshow(env.render(\"rgb_array\"))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Building the network for REINFORCE" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For REINFORCE algorithm, we'll need a model that predicts action probabilities given states." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import theano\n", - "import theano.tensor as T\n", - "\n", - "# create input variables. We'll support multiple states at once\n", - "\n", - "states = T.matrix(\"states[batch,units]\")\n", - "actions = T.ivector(\"action_ids[batch]\")\n", - "cumulative_rewards = T.vector(\"G[batch] = r + gamma*r' + gamma^2*r'' + ...\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import lasagne\n", - "from lasagne.layers import *\n", - "\n", - "# input layer\n", - "l_states = InputLayer((None,)+state_dim, input_var=states)\n", - "\n", - "\n", - "\n", - "\n", - "# output layer\n", - "# this time we need to predict action probabilities,\n", - "# so make sure your nonlinearity forces p>0 and sum_p = 1\n", - "l_action_probas = DenseLayer( ,\n", - " num_units= ,\n", - " nonlinearity= )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Predict function" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get probabilities of actions\n", - "predicted_probas = get_output(l_action_probas)\n", - "\n", - "# predict action probability given state\n", - "# if you use float32, set allow_input_downcast=True\n", - "predict_proba = " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Loss function and updates\n", - "\n", - "We now need to define objective and update over policy gradient.\n", - "\n", - "Our objective function is\n", - "\n", - "$$ J \\approx { 1 \\over N } \\sum_{s_i,a_i} G(s_i,a_i) $$\n", - "\n", - "\n", - "Following the REINFORCE algorithm, we can define our objective as follows: \n", - "\n", - "$$ \\hat J \\approx { 1 \\over N } \\sum_{s_i,a_i} \\log \\pi_\\theta (a_i \\mid s_i) \\cdot G(s_i,a_i) $$\n", - "\n", - "When you compute gradient of that function over network weights $ \\theta $, it will become exactly the policy gradient." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# select probabilities for chosen actions, pi(a_i|s_i)\n", - "predicted_probas_for_actions = predicted_probas[T.arange(\n", - " actions.shape[0]), actions]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# REINFORCE objective function\n", - "J = # " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# all network weights\n", - "all_weights = \n", - "\n", - "# weight updates. maximize J = minimize -J\n", - "updates = lasagne.updates.sgd(-J, all_weights, learning_rate=0.01)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "train_step = theano.function([states, actions, cumulative_rewards], updates=updates,\n", - " allow_input_downcast=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Computing cumulative rewards" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "\n", - "def get_cumulative_rewards(rewards, # rewards at each step\n", - " gamma=0.99 # discount for reward\n", - " ):\n", - " \"\"\"\n", - " take a list of immediate rewards r(s,a) for the whole session \n", - " compute cumulative returns (a.k.a. G(s,a) in Sutton '16)\n", - " G_t = r_t + gamma*r_{t+1} + gamma^2*r_{t+2} + ...\n", - "\n", - " The simple way to compute cumulative rewards is to iterate from last to first time tick\n", - " and compute G_t = r_t + gamma*G_{t+1} recurrently\n", - "\n", - " You must return an array/list of cumulative rewards with as many elements as in the initial rewards.\n", - " \"\"\"\n", - "\n", - " \n", - "\n", - " return " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert len(get_cumulative_rewards(range(100))) == 100\n", - "assert np.allclose(get_cumulative_rewards([0, 0, 1, 0, 0, 1, 0], gamma=0.9), [\n", - " 1.40049, 1.5561, 1.729, 0.81, 0.9, 1.0, 0.0])\n", - "assert np.allclose(get_cumulative_rewards(\n", - " [0, 0, 1, -2, 3, -4, 0], gamma=0.5), [0.0625, 0.125, 0.25, -1.5, 1.0, -4.0, 0.0])\n", - "assert np.allclose(get_cumulative_rewards(\n", - " [0, 0, 1, 2, 3, 4, 0], gamma=0), [0, 0, 1, 2, 3, 4, 0])\n", - "print(\"looks good!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Playing the game" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def generate_session(t_max=1000):\n", - " \"\"\"play env with REINFORCE agent and train at the session end\"\"\"\n", - "\n", - " # arrays to record session\n", - " states, actions, rewards = [], [], []\n", - "\n", - " s = env.reset()\n", - "\n", - " for t in range(t_max):\n", - "\n", - " # action probabilities array aka pi(a|s)\n", - " action_probas = predict_proba([s])[0]\n", - "\n", - " a = \n", - "\n", - " new_s, r, done, info = env.step(a)\n", - "\n", - " # record session history to train later\n", - " states.append(s)\n", - " actions.append(a)\n", - " rewards.append(r)\n", - "\n", - " s = new_s\n", - " if done:\n", - " break\n", - "\n", - " cumulative_rewards = get_cumulative_rewards(rewards)\n", - " train_step(states, actions, cumulative_rewards)\n", - "\n", - " return sum(rewards)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "mean reward:20.900\n", - "mean reward:35.860\n", - "mean reward:50.820\n", - "mean reward:88.550\n", - "mean reward:132.080\n", - "mean reward:165.890\n", - "mean reward:193.790\n", - "mean reward:166.510\n", - "mean reward:120.910\n", - "mean reward:98.450\n", - "mean reward:236.340\n", - "mean reward:280.410\n", - "mean reward:317.610\n", - "You Win!\n" - ] - } - ], - "source": [ - "for i in range(100):\n", - "\n", - " rewards = [generate_session() for _ in range(100)] # generate new sessions\n", - "\n", - " print(\"mean reward:%.3f\" % (np.mean(rewards)))\n", - "\n", - " if np.mean(rewards) > 300:\n", - " print(\"You Win!\")\n", - " break" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Video" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[2017-03-14 19:36:45,862] Making new env: CartPole-v0\n", - "[2017-03-14 19:36:45,870] DEPRECATION WARNING: env.spec.timestep_limit has been deprecated. Replace your call to `env.spec.timestep_limit` with `env.spec.tags.get('wrapper_config.TimeLimit.max_episode_steps')`. This change was made 12/28/2016 and is included in version 0.7.0\n", - "[2017-03-14 19:36:45,873] Clearing 12 monitor files from previous run (because force=True was provided)\n", - "[2017-03-14 19:36:45,894] Starting new video recorder writing to /home/jheuristic/Downloads/Practical_RL/week6/videos/openaigym.video.0.7776.video000000.mp4\n", - "[2017-03-14 19:36:51,516] Starting new video recorder writing to /home/jheuristic/Downloads/Practical_RL/week6/videos/openaigym.video.0.7776.video000001.mp4\n", - "[2017-03-14 19:36:57,580] Starting new video recorder writing to /home/jheuristic/Downloads/Practical_RL/week6/videos/openaigym.video.0.7776.video000008.mp4\n", - "[2017-03-14 19:37:05,049] Starting new video recorder writing to /home/jheuristic/Downloads/Practical_RL/week6/videos/openaigym.video.0.7776.video000027.mp4\n", - "[2017-03-14 19:37:08,785] Starting new video recorder writing to /home/jheuristic/Downloads/Practical_RL/week6/videos/openaigym.video.0.7776.video000064.mp4\n", - "[2017-03-14 19:37:11,505] Finished writing results. You can upload them to the scoreboard via gym.upload('/home/jheuristic/Downloads/Practical_RL/week6/videos')\n" - ] - } - ], - "source": [ - "# record sessions\n", - "import gym.wrappers\n", - "env = gym.wrappers.Monitor(gym.make(\"CartPole-v0\"),\n", - " directory=\"videos\", force=True)\n", - "sessions = [generate_session() for _ in range(100)]\n", - "env.close()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# show video\n", - "from IPython.display import HTML\n", - "import os\n", - "\n", - "video_names = list(\n", - " filter(lambda s: s.endswith(\".mp4\"), os.listdir(\"./videos/\")))\n", - "\n", - "HTML(\"\"\"\n", - "\n", - "\"\"\".format(\"./videos/\" + video_names[-1])) # this may or may not be _last_ video. Try other indices" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week06_policy_based/reinforce_pytorch.ipynb b/week06_policy_based/reinforce_pytorch.ipynb index 5f2989998..0130118d5 100644 --- a/week06_policy_based/reinforce_pytorch.ipynb +++ b/week06_policy_based/reinforce_pytorch.ipynb @@ -19,7 +19,11 @@ "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !pip install -q gymnasium\n", + " !pip install moviepy\n", + " !apt install ffmpeg\n", + " !pip install imageio-ffmpeg\n", " !touch .setup_complete\n", "\n", "# This code creates a virtual display to draw game images on.\n", @@ -35,12 +39,22 @@ "metadata": {}, "outputs": [], "source": [ - "import gym\n", + "import gymnasium as gym\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# also you need to install ffmpeg if not installed\n", + "# for MacOS: ! brew install ffmpeg" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -54,7 +68,7 @@ "metadata": {}, "outputs": [], "source": [ - "env = gym.make(\"CartPole-v0\")\n", + "env = gym.make(\"CartPole-v1\", render_mode=\"rgb_array\")\n", "\n", "# gym compatibility: unwrap TimeLimit\n", "if hasattr(env, '_max_episode_steps'):\n", @@ -64,7 +78,7 @@ "n_actions = env.action_space.n\n", "state_dim = env.observation_space.shape\n", "\n", - "plt.imshow(env.render(\"rgb_array\"))" + "plt.imshow(env.render())" ] }, { @@ -91,7 +105,8 @@ "outputs": [], "source": [ "import torch\n", - "import torch.nn as nn" + "import torch.nn as nn\n", + "import torch.nn.functional as F" ] }, { @@ -155,7 +170,7 @@ "metadata": {}, "outputs": [], "source": [ - "test_states = np.array([env.reset() for _ in range(5)])\n", + "test_states = np.array([env.reset()[0] for _ in range(5)])\n", "test_probas = predict_probs(test_states)\n", "assert isinstance(test_probas, np.ndarray), \\\n", " \"you must return np array and not %s\" % type(test_probas)\n", @@ -180,13 +195,14 @@ "outputs": [], "source": [ "def generate_session(env, t_max=1000):\n", - " \"\"\" \n", + " \"\"\"\n", " Play a full session with REINFORCE agent.\n", " Returns sequences of states, actions, and rewards.\n", " \"\"\"\n", " # arrays to record session\n", " states, actions, rewards = [], [], []\n", - " s = env.reset()\n", + "\n", + " s = env.reset()[0]\n", "\n", " for t in range(t_max):\n", " # action probabilities array aka pi(a|s)\n", @@ -194,7 +210,8 @@ "\n", " # Sample action with given probabilities.\n", " a = \n", - " new_s, r, done, info = env.step(a)\n", + "\n", + " new_s, r, terminated, truncated, info = env.step(a)\n", "\n", " # record session history to train later\n", " states.append(s)\n", @@ -202,7 +219,7 @@ " rewards.append(r)\n", "\n", " s = new_s\n", - " if done:\n", + " if terminated or truncated:\n", " break\n", "\n", " return states, actions, rewards" @@ -300,20 +317,6 @@ "When you compute the gradient of that function with respect to network weights $\\theta$, it will become exactly the policy gradient." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def to_one_hot(y_tensor, ndims):\n", - " \"\"\" helper: take an integer vector and convert it to 1-hot matrix. \"\"\"\n", - " y_tensor = y_tensor.type(torch.LongTensor).view(-1, 1)\n", - " y_one_hot = torch.zeros(\n", - " y_tensor.size()[0], ndims).scatter_(1, y_tensor, 1)\n", - " return y_one_hot" - ] - }, { "cell_type": "code", "execution_count": null, @@ -333,7 +336,7 @@ "\n", " # cast everything into torch tensors\n", " states = torch.tensor(states, dtype=torch.float32)\n", - " actions = torch.tensor(actions, dtype=torch.int32)\n", + " actions = torch.tensor(actions, dtype=torch.int64)\n", " cumulative_returns = np.array(get_cumulative_rewards(rewards, gamma))\n", " cumulative_returns = torch.tensor(cumulative_returns, dtype=torch.float32)\n", "\n", @@ -347,7 +350,7 @@ "\n", " # select log-probabilities for chosen actions, log pi(a_i|s_i)\n", " log_probs_for_actions = torch.sum(\n", - " log_probs * to_one_hot(actions, env.action_space.n), dim=1)\n", + " log_probs * F.one_hot(actions, env.action_space.n), dim=1)\n", " \n", " # Compute loss here. Don't forgen entropy regularization with `entropy_coef` \n", " entropy = \n", @@ -376,7 +379,7 @@ "for i in range(100):\n", " rewards = [train_on_session(*generate_session(env)) for _ in range(100)] # generate new sessions\n", " \n", - " print(\"mean reward:%.3f\" % (np.mean(rewards)))\n", + " print(\"mean reward: %.3f\" % (np.mean(rewards)))\n", " \n", " if np.mean(rewards) > 500:\n", " print(\"You Win!\") # but you can train even further\n", @@ -398,10 +401,12 @@ "source": [ "# Record sessions\n", "\n", - "import gym.wrappers\n", + "from gymnasium.wrappers import RecordVideo\n", "\n", - "with gym.wrappers.Monitor(gym.make(\"CartPole-v0\"), directory=\"videos\", force=True) as env_monitor:\n", - " sessions = [generate_session(env_monitor) for _ in range(100)]" + "with gym.make(\"CartPole-v1\", render_mode=\"rgb_array\") as env, RecordVideo(\n", + " env=env, video_folder=\"./videos\"\n", + ") as env_monitor:\n", + " sessions = [generate_session(env_monitor) for _ in range(10)]\n" ] }, { @@ -414,22 +419,45 @@ "# work for you, you can download the videos and view them locally.\n", "\n", "from pathlib import Path\n", + "from base64 import b64encode\n", "from IPython.display import HTML\n", "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", "\n", "HTML(\"\"\"\n", "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" + "\"\"\".format(data_url))" ] } ], "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "pygments_lexer": "ipython3" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" } }, "nbformat": 4, diff --git a/week06_policy_based/reinforce_tensorflow.ipynb b/week06_policy_based/reinforce_tensorflow.ipynb index 077350874..644340cb4 100644 --- a/week06_policy_based/reinforce_tensorflow.ipynb +++ b/week06_policy_based/reinforce_tensorflow.ipynb @@ -22,7 +22,8 @@ " %tensorflow_version 1.x\n", " \n", " if not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !pip install -q gym[classic_control]==0.18.0\n", " !touch .setup_complete\n", "\n", "# This code creates a virtual display to draw game images on.\n", @@ -425,15 +426,25 @@ "# work for you, you can download the videos and view them locally.\n", "\n", "from pathlib import Path\n", + "from base64 import b64encode\n", "from IPython.display import HTML\n", "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", "\n", "HTML(\"\"\"\n", "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" + "\"\"\".format(data_url))" ] } ], diff --git a/week06_policy_based/runners.py b/week06_policy_based/runners.py index 120c42484..2d608aa68 100644 --- a/week06_policy_based/runners.py +++ b/week06_policy_based/runners.py @@ -1,11 +1,10 @@ -""" RL env runner """ from collections import defaultdict import numpy as np class EnvRunner: - """ Reinforcement learning runner in an environment with given policy """ + """Reinforcement learning runner in an environment with given policy""" def __init__(self, env, policy, nsteps, transforms=None, step_var=None): self.env = env @@ -13,20 +12,25 @@ def __init__(self, env, policy, nsteps, transforms=None, step_var=None): self.nsteps = nsteps self.transforms = transforms or [] self.step_var = step_var if step_var is not None else 0 - self.state = {"latest_observation": self.env.reset()} + self.state = {"latest_observation": self.env.reset()[0]} @property def nenvs(self): - """ Returns number of batched envs or `None` if env is not batched """ + """Returns number of batched envs or `None` if env is not batched""" return getattr(self.env.unwrapped, "nenvs", None) - def reset(self): - """ Resets env and runner states. """ - self.state["latest_observation"] = self.env.reset() + def reset(self, **kwargs): + """Resets env and runner states.""" + self.state["latest_observation"] = self.env.reset(**kwargs)[0] self.policy.reset() + def add_summary(self, name, val): + """Writes logs""" + add_summary = self.env.get_wrapper_attr("add_summary") + add_summary(name, val) + def get_next(self): - """ Runs the agent in the environment. """ + """Runs the agent in the environment.""" trajectory = defaultdict(list, {"actions": []}) observations = [] rewards = [] @@ -37,27 +41,29 @@ def get_next(self): observations.append(self.state["latest_observation"]) act = self.policy.act(self.state["latest_observation"]) if "actions" not in act: - raise ValueError("result of policy.act must contain 'actions' " - f"but has keys {list(act.keys())}") + raise ValueError( + "result of policy.act must contain 'actions' " + f"but has keys {list(act.keys())}" + ) for key, val in act.items(): trajectory[key].append(val) - obs, rew, done, _ = self.env.step(trajectory["actions"][-1]) + obs, rew, terminated, truncated, _ = self.env.step( + trajectory["actions"][-1] + ) self.state["latest_observation"] = obs rewards.append(rew) - resets.append(done) + reset = np.logical_or(terminated, truncated) + resets.append(reset) self.step_var += self.nenvs or 1 # Only reset if the env is not batched. Batched envs should # auto-reset. - if not self.nenvs and np.all(done): + if not self.nenvs and np.all(reset): self.state["env_steps"] = i + 1 - self.state["latest_observation"] = self.env.reset() + self.state["latest_observation"] = self.env.reset()[0] - trajectory.update( - observations=observations, - rewards=rewards, - resets=resets) + trajectory.update(observations=observations, rewards=rewards, resets=resets) trajectory["state"] = self.state for transform in self.transforms: diff --git a/week07_[recap]_rnn/README.md b/week07_[recap]_rnn/README.md index 4b187b0f2..2e98665f6 100644 --- a/week07_[recap]_rnn/README.md +++ b/week07_[recap]_rnn/README.md @@ -1,7 +1,7 @@ ## Materials * [Slides](https://yadi.sk/i/-Iqdhg483GDyoN) * CS231 lecture on RNNs - [video](https://www.youtube.com/watch?v=iX5V1WpxxkY) -* Our [lecture](https://yadi.sk/i/XHmT5hO53GcCKV), [seminar(pytorch)](https://yadi.sk/i/nCch5I8S3TsXh5), [seminar(theano)](https://yadi.sk/i/19twHESN3GcGKQ) (both russian) +* Our [lecture](https://yadi.sk/i/XHmT5hO53GcCKV), [seminar (PyTorch)](https://yadi.sk/i/nCch5I8S3TsXh5) (in russian) * [alternative] Brief lecture on RNN by nervana - [video](https://www.youtube.com/watch?v=Ukgii7Yd_cU) * [alternative] More detailed lecture by Y. Bengio - [video](https://www.youtube.com/watch?v=xK-bzjIQkmM) * Great reading by Karpathy - [blog post](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) @@ -15,6 +15,4 @@ # Homework description [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week07_%5Brecap%5D_rnn/seminar_pytorch.ipynb) -This week's practice gets you acquainted with basics of recurrent neural networks. For simplicity, we'll train them on character language modelling task. Pick any one of `seminar_lasagne`, `seminar_lasagne_ingraph` or `seminar_tf`. - -As for difference btwn `seminar_lasagne` and `seminar_lasagne_ingraph` - ingraph version shows a lower-level interface to recurrent neural networks. It also requires you to install `pip install https://github.com/yandexdataschool/agentnet/archive/master.zip`. Out-of-graph version cover higher-level syntax from native lasagne. +This week's practice gets you acquainted with basics of recurrent neural networks. For simplicity, we'll train them on character language modelling task. You'll need `seminar_pytorch.ipynb` or `seminar_tf.ipynb`. diff --git a/week07_[recap]_rnn/seminar_lasagne.ipynb b/week07_[recap]_rnn/seminar_lasagne.ipynb deleted file mode 100644 index 5fdbeddcf..000000000 --- a/week07_[recap]_rnn/seminar_lasagne.ipynb +++ /dev/null @@ -1,488 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Generating names with recurrent neural networks (5 points)\n", - "\n", - "This time you'll find yourself delving into the heart (and other intestines) of recurrent neural networks on a class of toy problems.\n", - "\n", - "Struggle to find a name for the variable? Let's see how you'll come up with a name for your son/daughter. Surely no human has expertize over what is a good child name, so let us train RNN instead;\n", - "\n", - "It's dangerous to go alone, take these:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import theano\n", - "import theano.tensor as T\n", - "import lasagne\n", - "import os\n", - "#thanks @keskarnitish" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "start_token = \" \"\n", - "\n", - "with open(\"names\") as f:\n", - " names = f.read()[:-1].split('\\n')\n", - " names = [start_token+name for name in names]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print('n samples = ', len(names))\n", - "for x in names[::1000]:\n", - " print(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Text processing\n", - "\n", - "First we need next to collect a \"vocabulary\" of all unique tokens i.e. unique characters. We can then encode inputs as a sequence of character ids." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# all unique characters go here\n", - "tokens = \n", - "\n", - "tokens = list(tokens)\n", - "print('n_tokens = ', len(tokens))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Theano is built for numbers, not strings of characters.\n", - "We'll feed our recurrent neural network with ids of characters from our dictionary.\n", - "\n", - "To create such dictionary, let's assign each character with it's index in tokens list." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "token_to_id = its identifier (index in tokens list)>\n", - "\n", - "id_to_token = symbol itself>" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "plt.hist(list(map(len, names)), bins=25)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# truncate names longer than MAX_LEN characters.\n", - "MAX_LEN = ?!\n", - "\n", - "# you will likely need to change this for any dataset different from \"names\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Cast everything from symbols into identifiers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "names_ix = list(map(lambda name: list(map(token_to_id.get, name)), names))\n", - "\n", - "\n", - "# crop long names and pad short ones\n", - "for i in range(len(names_ix)):\n", - " names_ix[i] = names_ix[i][:MAX_LEN] # crop too long\n", - "\n", - " if len(names_ix[i]) < MAX_LEN:\n", - " names_ix[i] += [token_to_id[\" \"]] * \\\n", - " (MAX_LEN - len(names_ix[i])) # pad too short\n", - "\n", - "assert len(set(map(len, names_ix))) == 1\n", - "\n", - "names_ix = np.array(names_ix)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Input variables" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "input_sequence = T.matrix('token sequencea', 'int32')\n", - "target_values = T.matrix('actual next token', 'int32')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Build NN\n", - "\n", - "You will be building a model that takes token sequence and predicts next token\n", - "\n", - "\n", - "* iput sequence\n", - "* one-hot / embedding\n", - "* recurrent layer(s)\n", - "* otput layer(s) that predict output probabilities\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from lasagne.layers import InputLayer, DenseLayer, EmbeddingLayer\n", - "from lasagne.layers import RecurrentLayer, LSTMLayer, GRULayer, CustomRecurrentLayer" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "l_in = lasagne.layers.InputLayer(shape=(None, None), input_var=input_sequence)\n", - "\n", - "#!\n", - "l_emb = \n", - "\n", - "l_rnn = \n", - "\n", - "# flatten batch and time to be compatible with feedforward layers (will un-flatten later)\n", - "l_rnn_flat = lasagne.layers.reshape(l_rnn, (-1, l_rnn.output_shape[-1]))\n", - "\n", - "l_out = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Model weights\n", - "weights = lasagne.layers.get_all_params(l_out, trainable=True)\n", - "print(weights)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "network_output = \n", - "# If you use dropout do not forget to create deterministic version for evaluation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "predicted_probabilities_flat = network_output\n", - "correct_answers_flat = target_values.ravel()\n", - "\n", - "\n", - "loss = \n", - "\n", - "updates = " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Compiling it" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# training\n", - "train = theano.function([input_sequence, target_values],\n", - " loss, updates=updates, allow_input_downcast=True)\n", - "\n", - "# computing loss without training\n", - "compute_cost = theano.function(\n", - " [input_sequence, target_values], loss, allow_input_downcast=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# generation\n", - "\n", - "Simple: \n", - "* get initial context(seed), \n", - "* predict next token probabilities,\n", - "* sample next token, \n", - "* add it to the context\n", - "* repeat from step 2\n", - "\n", - "You'll get a more detailed info on how it works in the homework section." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# compile the function that computes probabilities for next token given previous text.\n", - "\n", - "# reshape back into original shape\n", - "next_word_probas = network_output.reshape(\n", - " (input_sequence.shape[0], input_sequence.shape[1], len(tokens)))\n", - "# predictions for next tokens (after sequence end)\n", - "last_word_probas = next_word_probas[:, -1]\n", - "probs = theano.function(\n", - " [input_sequence], last_word_probas, allow_input_downcast=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "def generate_sample(seed_phrase=None, N=MAX_LEN, t=1, n_snippets=1):\n", - " '''\n", - " The function generates text given a phrase of length at least SEQ_LENGTH.\n", - "\n", - " parameters:\n", - " sample_fun - max_ or proportional_sample_fun or whatever else you implemented\n", - "\n", - " The phrase is set using the variable seed_phrase\n", - "\n", - " The optional input \"N\" is used to set the number of characters of text to predict. \n", - " '''\n", - " if seed_phrase is None:\n", - " seed_phrase = start_token\n", - " if len(seed_phrase) > MAX_LEN:\n", - " seed_phrase = seed_phrase[-MAX_LEN:]\n", - " assert type(seed_phrase) is str\n", - "\n", - " snippets = []\n", - " for _ in range(n_snippets):\n", - " sample_ix = []\n", - " x = list(map(lambda c: token_to_id.get(c, 0), seed_phrase))\n", - " x = np.array([x])\n", - "\n", - " for i in range(N):\n", - " # Pick the character that got assigned the highest probability\n", - " p = probs(x).ravel()\n", - " p = p**t / np.sum(p**t)\n", - " ix = np.random.choice(np.arange(len(tokens)), p=p)\n", - " sample_ix.append(ix)\n", - "\n", - " x = np.hstack((x[-MAX_LEN+1:], [[ix]]))\n", - "\n", - " random_snippet = seed_phrase + \\\n", - " ''.join(id_to_token[ix] for ix in sample_ix)\n", - " snippets.append(random_snippet)\n", - "\n", - " print(\"----\\n %s \\n----\" % '; '.join(snippets))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model training\n", - "\n", - "Here you can tweak parameters or insert your generation function\n", - "\n", - "\n", - "__Once something word-like starts generating, try increasing seq_length__\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def sample_batch(data, batch_size):\n", - "\n", - " rows = data[np.random.randint(0, len(data), size=batch_size)]\n", - "\n", - " return rows[:, :-1], rows[:, 1:]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "print(\"Training ...\")\n", - "\n", - "\n", - "# total N iterations\n", - "n_epochs = 100\n", - "\n", - "# how many minibatches are there in the epoch\n", - "batches_per_epoch = 500\n", - "\n", - "# how many training sequences are processed in a single function call\n", - "batch_size = 10\n", - "\n", - "\n", - "for epoch in range(n_epochs):\n", - "\n", - " print(\"Generated names\")\n", - " generate_sample(n_snippets=10)\n", - "\n", - " avg_cost = 0\n", - "\n", - " for _ in range(batches_per_epoch):\n", - "\n", - " x, y = sample_batch(names_ix, batch_size)\n", - " avg_cost += train(x, y)\n", - "\n", - " print(\"Epoch {} average loss = {}\".format(\n", - " epoch, avg_cost / batches_per_epoch))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "generate_sample(n_snippets=100)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "generate_sample(seed_phrase=\" A\", n_snippets=10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "generate_sample(seed_phrase= , n_snippets=10, t=1.0)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Bonus: try it out!\n", - "You've just implemented a recurrent language model that can be tasked with generating any kind of sequence, so there's plenty of data you can try it on:\n", - "\n", - "* Novels/poems/songs of your favorite author\n", - "* News titles/clickbait titles\n", - "* Source code of Linux or Tensorflow\n", - "* Molecules in [smiles](https://en.wikipedia.org/wiki/Simplified_molecular-input_line-entry_system) format\n", - "* Melody in notes/chords format\n", - "* Ikea catalog titles\n", - "* Pokemon names\n", - "* Cards from Magic, the Gathering / Hearthstone\n", - "\n", - "If you're willing to give it a try, here's what you wanna look at:\n", - "* Current data format is a sequence of lines, so a novel can be formatted as a list of sentences. Alternatively, you can change data preprocessing altogether.\n", - "* While some datasets are readily available, others can only be scraped from the web. Try `Selenium` or `Scrapy` for that.\n", - "* Make sure MAX_LENGTH is adjusted for longer datasets. There's also a bonus section about dynamic RNNs at the bottom.\n", - "* More complex tasks require larger RNN architecture, try more neurons or several layers. It would also require more training iterations.\n", - "* Long-term dependencies in music, novels or molecules are better handled with LSTM or GRU\n", - "\n", - "__Good hunting!__" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week07_[recap]_rnn/seminar_lasagne_ingraph.ipynb b/week07_[recap]_rnn/seminar_lasagne_ingraph.ipynb deleted file mode 100644 index 5a7b55f79..000000000 --- a/week07_[recap]_rnn/seminar_lasagne_ingraph.ipynb +++ /dev/null @@ -1,439 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import theano\n", - "import theano.tensor as T\n", - "import lasagne\n", - "import os" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generate names\n", - "* Struggle to find a name for the variable? Let's see how you'll come up with a name for your son/daughter. Surely no human has expertize over what is a good child name, so let us train NN instead.\n", - "* Dataset contains ~8k human names from different cultures[in latin transcript]\n", - "* Objective (toy problem): learn a generative model over names." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "start_token = \" \"\n", - "\n", - "with open(\"names\") as f:\n", - " names = f.read()[:-1].split('\\n')\n", - " names = [start_token+name for name in names]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print('n samples = ', len(names))\n", - "for x in names[::1000]:\n", - " print(x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Text processing\n", - "First we need next to collect a \"vocabulary\" of all unique tokens i.e. unique characters. We can then encode inputs as a sequence of character ids." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# all unique characters go here\n", - "token_set = \n", - "\n", - "tokens = list(token_set)\n", - "print('n_tokens = ', len(tokens))\n", - "assert 54 < len(tokens) < 56" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Theano is built for numbers, not strings of characters.\n", - "We'll feed our recurrent neural network with ids of characters from our dictionary.\n", - "\n", - "To create such dictionary, let's assign each character with it's index in tokens list." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "token_to_id = its identifier (index in tokens list)>\n", - "\n", - "id_to_token = symbol itself>" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "plt.hist(list(map(len, names)), bins=25)\n", - "\n", - "# truncate names longer than MAX_LEN characters.\n", - "MAX_LEN = min([60, max(list(map(len, names)))])\n", - "# ADJUST IF YOU ARE UP TO SOMETHING SERIOUS" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Cast everything from symbols into identifiers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "names_ix = list(map(lambda name: list(map(token_to_id.get, name)), names))\n", - "\n", - "\n", - "# crop long names and pad short ones\n", - "for i in range(len(names_ix)):\n", - " names_ix[i] = names_ix[i][:MAX_LEN] # crop too long\n", - "\n", - " if len(names_ix[i]) < MAX_LEN:\n", - " names_ix[i] += [token_to_id[\" \"]] * \\\n", - " (MAX_LEN - len(names_ix[i])) # pad too short\n", - "\n", - "assert len(set(map(len, names_ix))) == 1\n", - "\n", - "names_ix = np.array(names_ix)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Input variables" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet import Recurrence\n", - "from lasagne.layers import *\n", - "from agentnet.memory import *\n", - "from agentnet.resolver import ProbabilisticResolver" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sequence = T.matrix('token sequence', 'int64')\n", - "\n", - "inputs = sequence[:, :-1]\n", - "targets = sequence[:, 1:]\n", - "\n", - "\n", - "l_input_sequence = InputLayer(shape=(None, None), input_var=inputs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Build NN\n", - "\n", - "You'll be building a model that takes token sequence and predicts next tokens at each tick\n", - "\n", - "This is basically equivalent to how rnn step was described in the lecture" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# One step of rnn\n", - "class step:\n", - "\n", - " # inputs\n", - " inp = InputLayer((None,), name='current character')\n", - " h_prev = InputLayer((None, 10), name='previous rnn state')\n", - "\n", - " # recurrent part\n", - " emb = EmbeddingLayer(inp, len(tokens), 30, name='emb')\n", - "\n", - " h_new = \n", - "\n", - " next_token_probas = \n", - "\n", - " # pick next token from predicted probas\n", - " next_token = ProbabilisticResolver(next_token_probas)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_loop = Recurrence(\n", - " state_variables={step.h_new: step.h_prev},\n", - " input_sequences={step.inp: l_input_sequence},\n", - " tracked_outputs=[step.next_token_probas, ],\n", - " unroll_scan=False,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Model weights\n", - "weights = lasagne.layers.get_all_params(training_loop, trainable=True)\n", - "print(weights)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "predicted_probabilities = lasagne.layers.get_output(\n", - " training_loop[step.next_token_probas])\n", - "# If you use dropout do not forget to create deterministic version for evaluation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "loss = # \n", - "\n", - "updates = lasagne.updates.adam(loss, weights)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Compiling it" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# training\n", - "train_step = theano.function([sequence], loss,\n", - " updates=training_loop.get_automatic_updates()+updates)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# generation\n", - "\n", - "here we re-wire the recurrent network so that it's output is fed back to it's input. \n", - "\n", - "We also make sure to feed id of `\" \"` as initial token." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n_steps = T.scalar(dtype='int32')\n", - "x0 = InputLayer([None], theano.shared(np.int32([token_to_id[' ']])))\n", - "\n", - "feedback_loop = Recurrence(\n", - " state_variables={step.h_new: step.h_prev,\n", - " step.next_token: step.inp},\n", - " tracked_outputs=[step.next_token_probas, ],\n", - " state_init={step.next_token: x0},\n", - " batch_size=theano.shared(1),\n", - " n_steps=n_steps,\n", - " unroll_scan=False,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "generated_tokens = get_output(feedback_loop[step.next_token])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "generate_sample = theano.function(\n", - " [n_steps], generated_tokens, updates=feedback_loop.get_automatic_updates())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def generate_string(length=MAX_LEN):\n", - " output_indices = generate_sample(length)[0]\n", - "\n", - " return ''.join(tokens[i] for i in output_indices)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "generate_string()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model training\n", - "\n", - "Here you can tweak parameters or insert your generation function\n", - "\n", - "\n", - "__Once something word-like starts generating, try increasing seq_length__\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def sample_batch(data, batch_size):\n", - "\n", - " rows = data[np.random.randint(0, len(data), size=batch_size)]\n", - "\n", - " return rows" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "print(\"Training ...\")\n", - "\n", - "\n", - "# total N iterations\n", - "n_epochs = 100\n", - "\n", - "# how many minibatches are there in the epoch\n", - "batches_per_epoch = 500\n", - "\n", - "# how many training sequences are processed in a single function call\n", - "batch_size = 10\n", - "\n", - "\n", - "for epoch in xrange(n_epochs):\n", - "\n", - " avg_cost = 0\n", - " for _ in range(batches_per_epoch):\n", - "\n", - " avg_cost += train_step(sample_batch(names_ix, batch_size))\n", - "\n", - " print(\"\\n\\nEpoch {} average loss = {}\".format(\n", - " epoch, avg_cost / batches_per_epoch))\n", - "\n", - " print(\"Generated names\")\n", - " for i in range(10):\n", - " print(generate_string(),)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# And now,\n", - "* try lstm/gru\n", - "* try several layers\n", - "* try mtg cards\n", - "* try your own dataset of any kind" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week07_seq2seq/README.md b/week07_seq2seq/README.md index b3eb52b5a..05d9f8a12 100644 --- a/week07_seq2seq/README.md +++ b/week07_seq2seq/README.md @@ -13,19 +13,18 @@ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week07_seq2seq/practice_torch.ipynb) -As usual, go to practice_{your framework}.ipynb above and follow instructions from there. [pytorch](./practice_torch.ipynb), [tensorflow](./practice_tf.ipynb), [theano](./practice_theano.ipynb) +As usual, go to practice_{your framework}.ipynb above and follow instructions from there. [PyTorch](./practice_torch.ipynb), [Tensorflow](./practice_tf.ipynb) ## More materials * An [awesome post](http://distill.pub/2016/augmented-rnns/) explaining attention and long-term memory models. * [BLEU](http://www.aclweb.org/anthology/P02-1040.pdf) and [CIDEr](https://arxiv.org/pdf/1411.5726.pdf) articles. * Image captioning - * MSCOCO captioning [challenge](http://mscoco.org/dataset/#captions-challenge2015) + * MSCOCO captioning [challenge](https://cocodataset.org/#captions-2015) * Captioning tutorial [notebook](https://github.com/yandexdataschool/Practical_DL/tree/980121c7b3147ed28a7c1360df5038d3432b8cc3/week07_seq2seq) -* Other articles on reinforcement learning for natural language: +* Other articles on reinforcement learning for natural language: * [task-oriented conversation system](https://arxiv.org/abs/1703.07055) * [generating dialogues](https://arxiv.org/abs/1606.01541) * [sequential adversarial networks](https://arxiv.org/abs/1609.05473) (a.k.a. SeqGAN) * A large overview for machine translation (touching on RL, including RL failures) - [arxiv](https://arxiv.org/abs/1609.08144) * How _not_ to evaluate conversation models - [arxiv](https://arxiv.org/abs/1603.08023) * Overview of other non-games applications ("that article again") - [arxiv](https://arxiv.org/abs/1701.07274) - diff --git a/week07_seq2seq/basic_model_theano.py b/week07_seq2seq/basic_model_theano.py deleted file mode 100644 index 951b2dff9..000000000 --- a/week07_seq2seq/basic_model_theano.py +++ /dev/null @@ -1,214 +0,0 @@ -# code by https://github.com/deniskamazur - -from lasagne.layers import * -import theano.tensor as T -import theano - -from agentnet.memory import LSTMCell, GRUCell, AttentionLayer -from agentnet import Recurrence -from agentnet.learning.generic import get_mask_by_eos -from agentnet.resolver import ProbabilisticResolver -from agentnet.utils import reapply - - -class BasicTranslationModel: - def __init__(self, inp_voc, out_voc, emb_size, hid_size, **kwargs): - """ - A simple interface for mt - :param emb_size: Embedding size - :param hid_size: Number of LSTM units - :param bidereactional: If the nLSTM layers should be bidirectional - :param input_dropout: Dropout after embedding layer - :param recurrent_dropout: Dropout after each LSTM iteration - :param rdo_size: If int - use dense layer after neck in decoder, if none don't - :param peepholes: http://colah.github.io/posts/2015-08-Understanding-LSTMs/img/LSTM3-var-peepholes.png - :param kwargs: recurrence flags - """ - self.inp_voc = inp_voc - self.out_voc = out_voc - # encode input sequence - - class encoder: - # intput layers - inp = InputLayer((None, None)) - mask = ExpressionLayer( - inp, - lambda x: get_mask_by_eos(T.eq(x, self.out_voc.eos_ix)), - ) - - # embed the tokens - emb = EmbeddingLayer( - inp, - input_size=len(inp_voc), - output_size=emb_size, - ) - - rnn_fw = GRULayer( - emb, - num_units=hid_size, - mask_input=mask, - only_return_final=True, - ) - - dec_start = DenseLayer(rnn_fw, hid_size, nonlinearity=None) - - # make encoder a public field - self.encoder = encoder - - # decoder the encoded sequence - class decoder: - # decoder previous memory and tokens - prev_hid = InputLayer((None, hid_size), name='prev hidden state') - inp = InputLayer((None,), name="prev phoneme") - - emb = EmbeddingLayer(inp, len(out_voc), emb_size) - - new_hid = GRUCell(prev_hid, emb) - - logits = DenseLayer(new_hid, len(out_voc), nonlinearity=None) - - probs = NonlinearityLayer(logits, nonlinearity=T.nnet.softmax) - logprobs = NonlinearityLayer( - logits, - nonlinearity=T.nnet.logsoftmax, - ) - out = ProbabilisticResolver(probs, assume_normalized=True) - - state_dict = { - new_hid: prev_hid, - # ^^^ this reads "at next step, new_hid will become prev_hid" - # if you add any more recurrent memory units, - # please make sure they're here - } - - init_dict = { - new_hid: encoder.dec_start - # ^^^ this reads "before first step, new_hid is set to outputs of dec_start" - # if you add any more recurrent memory units with non-zero init - # please make sure they're here - } - - nonseq_dict = { - # here you can add anything encoder needs that's gonna be same - # across time-steps - } - - self.decoder = decoder - - top_layers = [encoder.dec_start, decoder.out] + \ - list(decoder.state_dict.keys()) - self.weights = get_all_params(top_layers, trainable=True) - - def symbolic_score(self, inp, out, eps=1e-30, **flags): - """ - Takes symbolic int32 matrices of hebrew words and their english translations. - Computes the log-probabilities of all possible english characters given english prefices and hebrew word. - :param inp: input sequence, int32 matrix of shape [batch,time] - :param out: output sequence, int32 matrix of shape [batch,time] - :return: log-probabilities of all possible english characters of shape [bath,time,n_tokens] - - NOTE: log-probabilities time axis is synchronized with out - In other words, logp are probabilities of __current__ output at each tick, not the next one - therefore you can get likelihood as logprobas * tf.one_hot(out,n_tokens) - """ - - l_output_sequence = InputLayer([None, None]) - - # Defining custom recurrent layer out of decoder - rec = Recurrence( - state_variables=self.decoder.state_dict, - state_init=self.decoder.init_dict, - input_sequences={self.decoder.inp: l_output_sequence}, - input_nonsequences=self.decoder.nonseq_dict, - tracked_outputs=self.decoder.logprobs, - unroll_scan=False - ) - - feed_dict = { - self.encoder.inp: inp, - l_output_sequence: out - } - logprobs = get_output(rec[self.decoder.logprobs], feed_dict, - recurrence_flags=flags, **flags) - - self.auto_updates = rec.get_automatic_updates() - if len(self.auto_updates) != 0: - print( - "symbolic_score: Please collect auto_updates of random states " - "after you called symbolic_score (available at model.auto_updates)!") - - first_logprobs = T.zeros_like(logprobs[:, :1]) - logprobs = T.concatenate([first_logprobs, logprobs[:, :-1]], axis=1) - - return logprobs - - def symbolic_translate(self, inp, greedy=False, max_len=None, - unroll_scan=False, eps=1e-30, **flags): - """ - takes symbolic int32 matrix of hebrew words, produces output tokens sampled - from the model and output log-probabilities for all possible tokens at each tick. - :param inp: input sequence, int32 matrix of shape [batch,time] - :param greedy: if greedy, takes token with highest probablity at each tick. - Otherwise samples proportionally to probability. - :param max_len: max length of output, defaults to 2 * input length - :param unroll_scan: if True, compiles longer but runs faster. - requires max_len to be constant - :return: output tokens int32[batch,time] and - log-probabilities of all tokens at each tick, [batch,time,n_tokens] - """ - if unroll_scan: - assert isinstance( - max_len, int), "if scan is unrolled, max_len must be a constant integer" - - max_len = max_len if max_len is not None else 2 * inp.shape[1] - - # initial output tokens (BOS) - bos = T.zeros_like(inp[:, 0]) + self.out_voc.bos_ix - l_start = InputLayer((None,), bos) - - # Defining custom recurrent layer out of decoder - rec = Recurrence( - state_variables=merge_dicts(self.decoder.state_dict, - {self.decoder.out: self.decoder.inp}), - state_init=merge_dicts(self.decoder.init_dict, {self.decoder.out: l_start}), - input_nonsequences=self.decoder.nonseq_dict, - tracked_outputs=(self.decoder.out, self.decoder.probs, self.decoder.logprobs), - n_steps=max_len, - unroll_scan=unroll_scan - ) - - translations, logprobs = get_output(rec[self.decoder.out, self.decoder.logprobs], - {self.encoder.inp: inp, - l_start: bos}, - recurrence_flags=dict(flags, greedy=greedy), - **flags) - - self.auto_updates = rec.get_automatic_updates() - if len(self.auto_updates) != 0: - print( - "symbolic_translate: Please collect auto_updates of random states " - "after you called symbolic_translate (available at model.auto_updates)!") - - # add first step (bos) - translations = T.concatenate([bos[:, None], translations], axis=1) - first_logprobs = T.zeros_like(logprobs[:, :1]) - logprobs = T.concatenate([first_logprobs, logprobs], axis=1) - - return translations, logprobs - - -def merge_dicts(*dicts, **kwargs): - """ - Melts several dicts into one. Useful when messing with feed dicts - :param dicts: dictionaries - :param check_conflicts: if True, raises error if several dicts have the same key - Otherwise uses the key from the latest dict in *dicts - :return: a dict that contains k-v pairs from all *dicts - """ - merged_dict = {} - for d in dicts: - merged_dict.update(d) - if kwargs.get('check_conflicts'): - assert len(merged_dict) == sum( - map(len, dicts)), 'dicts have duplicate keys' - return merged_dict diff --git a/week07_seq2seq/basic_model_torch.py b/week07_seq2seq/basic_model_torch.py index 586482ffb..25700da42 100644 --- a/week07_seq2seq/basic_model_torch.py +++ b/week07_seq2seq/basic_model_torch.py @@ -2,8 +2,8 @@ import torch.nn as nn import torch.nn.functional as F -# Note: unlike official pytorch tutorial, this model doesn't process one sample at a time -# because it's slow on GPU. instead it uses masks just like ye olde theano/tensorflow. +# Note: unlike official PyTorch tutorial, this model doesn't process one sample at a time +# because it's slow on GPU. Instead it uses masks just like ye olde Tensorflow. # it doesn't use torch.nn.utils.rnn.pack_paded_sequence because reasons. @@ -24,7 +24,7 @@ def __init__(self, inp_voc, out_voc, def encode(self, inp, **flags): """ Takes symbolic input sequence, computes initial state - :param inp: a vector of input tokens (Variable, int64, 1d) + :param inp: input tokens, int64 vector of shape [batch] :return: a list of initial decoder state tensors """ inp_emb = self.emb_inp(inp) diff --git a/week07_seq2seq/bonus.ipynb b/week07_seq2seq/bonus.ipynb deleted file mode 100644 index 1acb2ead1..000000000 --- a/week07_seq2seq/bonus.ipynb +++ /dev/null @@ -1,247 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Week8 bonus descriptions\n", - "\n", - "Here are some cool mini-projects you can try to dive deeper into the topic.\n", - "\n", - "## More metrics: BLEU (5+ pts)\n", - "\n", - "Pick BLEU or any other relevant metric, e.g. BLEU (e.g. from `nltk.bleu_score`).\n", - "* Train model to maximize BLEU directly\n", - "* How does levenshtein behave when maximizing BLEU and vice versa?\n", - "* Compare this with how they behave when optimizing likelihood. \n", - "\n", - "(use default parameters for bleu: 4-gram, uniform weights)\n", - "\n", - "## Actor-critic (5+++ pts)\n", - "\n", - "While self-critical training provides a large reduction of gradient variance, it has a few drawbacks:\n", - "- It requires a lot of additional computation during training\n", - "- It doesn't adjust V(s) between decoder steps. (one value per sequence)\n", - "\n", - "There's a more general way of doing the same thing: learned baselines, also known as __advantage actor-critic__.\n", - "\n", - "There are two main ways to apply that:\n", - "- __naive way__: compute V(s) once per training example.\n", - " - This only requires additional 1-unit linear dense layer that grows out of encoder, estimating V(s)\n", - " - (implement this to get main points)\n", - "- __every step__: compute V(s) on each decoder step\n", - " - Again it's just an 1-unit dense layer (no nonlinearity), but this time it's inside decoder recurrence.\n", - " - (+3 pts additional for this guy)\n", - "\n", - "In both cases, you should train V(s) to minimize squared error $(V(s) - R(s,a))^2$ with R being actual levenshtein.\n", - "You can then use $ A(s,a) = (R(s,a) - const(V(s))) $ for policy gradient.\n", - "\n", - "There's also one particularly interesting approach (+5 additional pts):\n", - "- __combining SCST and actor-critic__:\n", - " - compute baseline $V(s)$ via self-critical sequence training (just like in main assignment)\n", - " - learn correction $ C(s,a_{:t}) = R(s,a) - V(s) $ by minimizing $(R(s,a) - V(s) - C(s,a_{:t}))^2 $\n", - " - use $ A(s,a_{:t}) = R(s,a) - V(s) - const(C(s,a_{:t})) $\n", - "\n", - "\n", - "\n", - "## Implement attention (5+++ pts)\n", - "\n", - "Some seq2seq tasks can benefit from the attention mechanism. In addition to taking the _last_ time-step of encoder hidden state, we can allow decoder to peek on any time-step of his choice.\n", - "\n", - "![img](https://xiandong79.github.io/downloads/nmt-model-fast.gif)\n", - "\n", - "\n", - "#### Recommended steps:\n", - "__1)__ Modify encoder-decoder\n", - "\n", - "Learn to feed the entire encoder into the decoder. You can do so by sending encoder rnn layer directly into decoder (make sure there's no `only_return_final=True` for encoder rnn layer).\n", - "\n", - "```\n", - "class decoder:\n", - " ...\n", - " encoder_rnn_input = InputLayer(encoder.rnn.output_shape, name='encoder rnn input for decoder')\n", - " ...\n", - " \n", - "#decoder Recurrence\n", - "rec = Recurrence(...,\n", - " input_nonsequences = {decoder.encoder_rnn_input: encoder.rnn},\n", - " )\n", - "\n", - "```\n", - "\n", - "For starters, you can take it's last tick (via SliceLayer) inside the decoder step and feed it as input to make sure it works.\n", - "\n", - "__2)__ Implement attention mechanism\n", - "\n", - "Next thing we'll need is to implement the math of attention.\n", - "\n", - "The simplest way to do so is to write a special layer. We gave you a prototype and some tests below.\n", - "\n", - "__3)__ Use attention inside decoder\n", - "\n", - "That's almost it! Now use `AttentionLayer` inside the decoder and feed it to back to lstm/gru/rnn (see code demo below).\n", - "\n", - "Train the full network just like you did before attention.\n", - "\n", - "__More points__ will be awwarded for comparing learning results of attention Vs no attention.\n", - "\n", - "__Bonus bonus:__ visualize attention vectors (>= +3 points)\n", - "\n", - "The best way to make sure your attention actually works is to visualize it.\n", - "\n", - "A simple way to do so is to obtain attention vectors from each tick (values __right after softmax__, not the layer outputs) and drawing those as images.\n", - "\n", - "#### step-by-step guide:\n", - "- split AttentionLayer into two layers: _\"from start to softmax\"_ and _\"from softmax to output\"_\n", - "- add outputs of the first layer to recurrence's `tracked_outputs`\n", - "- compile a function that computes them\n", - "- plt.imshow(them)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import theano\n", - "import lasagne\n", - "import theano.tensor as T\n", - "from lasagne import init\n", - "from lasagne.layers import *" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class AttentionLayer(MergeLayer):\n", - " def __init__(self, decoder_h, encoder_rnn):\n", - " # sanity checks\n", - " assert len(\n", - " decoder_h.output_shape) == 2, \"please feed decoder 1 step activation as first param \"\n", - " assert len(\n", - " encoder_rnn.output_shape) == 3, \"please feed full encoder rnn sequence as second param\"\n", - "\n", - " self.decoder_num_units = decoder_h.output_shape[-1]\n", - " self.encoder_num_units = encoder.output_shape[-1]\n", - "\n", - " # Here you should initialize all trainable parameters.\n", - " #\n", - "\n", - " # use this syntax:\n", - " self.add_param(spec=init.Normal(std=0.01), # or other initializer\n", - " shape= ,\n", - " name='')\n", - "\n", - " MergeLayer.__init__(self, [decoder_h, encoder_rnn], name=\"attention\")\n", - "\n", - " def get_output_shape_for(self, input_shapes, **kwargs):\n", - " \"\"\"return matrix of shape [batch_size, encoder num units]\"\"\"\n", - " return (None, self.encoder_num_units)\n", - "\n", - " def get_output_for(self, inputs, **kwargs):\n", - " \"\"\"\n", - " takes (decoder_h, encoder_seq)\n", - " decoder_h has shape [batch_size, decoder num_units]\n", - " encoder_seq has shape [batch_size, sequence_length, encoder num_units]\n", - "\n", - " returns attention output: matrix of shape [batch_size, encoder num units]\n", - "\n", - " please read comments carefully before you start implementing\n", - " \"\"\"\n", - " decoder_h, encoder_seq = inputs\n", - "\n", - " # get symbolic batch-size / seq length. Also don't forget self.decoder_num_units above\n", - " batch_size, seq_length, _ = tuple(encoder_seq.shape)\n", - "\n", - " # here's a recommended step-by-step guide for attention mechanism.\n", - " # You are free to ignore it alltogether if you so wish\n", - "\n", - " # we repeat decoder activations to allign with encoder\n", - " decoder_h_repeated = \n", - " \n", - " # ^--shape=[batch,seq_length,decoder_n_units]\n", - " \n", - " encoder_and_decoder_together = \n", - " # ^--shape=[batch,seq_length,enc_n_units+dec_n_units]\n", - " \n", - " # here we flatten the tensor to simplify\n", - " encoder_and_decoder_flat = T.reshape(encoder_and_decoder_together,(-1,encoder_and_decoder_together.shape[-1]))\n", - " # ^--shape=[batch*seq_length,enc_n_units+dec_n_units]\n", - " \n", - " # here you use encoder_and_decoder_flat and some learned weights to predict attention logits\n", - " # don't use softmax yet\n", - " \n", - " attention_logits_flat = \n", - " # ^--shape=[batch*seq_length,1]\n", - " \n", - " \n", - " # here we reshape flat logits back into correct form\n", - " assert attention_logits_flat.ndim==2\n", - " attention_logits = attention_logits_flat.reshape((batch_size,seq_length))\n", - " # ^--shape=[batch,seq_length]\n", - " \n", - " # here we apply softmax :)\n", - " attention = T.nnet.softmax(attention_logits)\n", - " # ^--shape=[batch,seq_length]\n", - " \n", - " # here we compute output\n", - " output = (attention[:,:,None]*encoder_seq).sum(axis=1) #sum over seq_length\n", - " # ^--shape=[batch,enc_n_units]\n", - " \n", - " return output" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# demo code\n", - "\n", - "from numpy.random import randn\n", - "\n", - "dec_h_prev = InputLayer((None, 50), T.constant(\n", - " randn(5, 50)), name='decoder h mock')\n", - "\n", - "enc = InputLayer((None, None, 32), T.constant(\n", - " randn(5, 20, 32)), name='encoder sequence mock')\n", - "\n", - "attention = AttentionLayer(dec_h_prev, enc)\n", - "\n", - "# now you can use attention as additonal input to your decoder\n", - "# LSTMCell(prev_cell,prev_out,input_or_inputs=(usual_input,attention))\n", - "\n", - "\n", - "# sanity check\n", - "demo_output = get_output(attention).eval()\n", - "print 'actual shape:', demo_output.shape\n", - "assert demo_output.shape == (5, 32)\n", - "assert np.isfinite(demo_output)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/week07_seq2seq/practice_tf.ipynb b/week07_seq2seq/practice_tf.ipynb index c561d7b11..8d5a1520b 100644 --- a/week07_seq2seq/practice_tf.ipynb +++ b/week07_seq2seq/practice_tf.ipynb @@ -7,19 +7,20 @@ "outputs": [], "source": [ "import sys, os\n", - "if 'google.colab' in sys.modules:\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", " # https://github.com/yandexdataschool/Practical_RL/issues/256\n", - " !pip install tensorflow-gpu==1.13.1\n", - " \n", - " if not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " # https://stackoverflow.com/a/62482183\n", + " !pip uninstall -y tensorflow\n", + " !pip install tensorflow-gpu==1.13.1 keras==2.3.1\n", "\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week07_seq2seq/basic_model_tf.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week07_seq2seq/he-pron-wiktionary.txt\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week07_seq2seq/main_dataset.txt\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week07_seq2seq/voc.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", "\n", - " !touch .setup_complete\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week07_seq2seq/basic_model_tf.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week07_seq2seq/he-pron-wiktionary.txt\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week07_seq2seq/main_dataset.txt\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week07_seq2seq/voc.py\n", + "\n", + " !touch .setup_complete\n", "\n", "# This code creates a virtual display to draw game images on.\n", "# It will have no effect if your machine has a monitor.\n", @@ -34,7 +35,7 @@ "source": [ "## Reinforcement Learning for seq2seq\n", "\n", - "This time we'll solve a problem of transribing hebrew words in english, also known as g2p (grapheme2phoneme)\n", + "This time we'll solve a problem of transcribing Hebrew words in English, also known as g2p (grapheme2phoneme)\n", "\n", " * word (sequence of letters in source language) -> translation (sequence of letters in target language)\n", "\n", @@ -43,19 +44,19 @@ "\n", "### About the task\n", "\n", - "One notable property of Hebrew is that it's consonant language. That is, there are no wovels in the written language. One could represent wovels with diacritics above consonants, but you don't expect people to do that in everyay life.\n", + "One notable property of Hebrew is that it's a consonant language. That is, there are no vowels in the written language. One could represent vowels with diacritics above consonants, but you don't expect people to do that in everyday life.\n", "\n", - "Therefore, some hebrew characters will correspond to several english letters and others - to none, so we should use encoder-decoder architecture to figure that out.\n", + "Therefore, some Hebrew characters will correspond to several English letters and others - to none, so we should use encoder-decoder architecture to figure that out.\n", "\n", "![img](https://esciencegroup.files.wordpress.com/2016/03/seq2seq.jpg)\n", "_(img: esciencegroup.files.wordpress.com)_\n", "\n", "Encoder-decoder architectures are about converting anything to anything, including\n", " * Machine translation and spoken dialogue systems\n", - " * [Image captioning](http://mscoco.org/dataset/#captions-challenge2015) and [image2latex](https://openai.com/requests-for-research/#im2latex) (convolutional encoder, recurrent decoder)\n", + " * [Image captioning](https://cocodataset.org/#captions-2015) and [image2latex](https://openai.com/requests-for-research/#im2latex) (convolutional encoder, recurrent decoder)\n", " * Generating [images by captions](https://arxiv.org/abs/1511.02793) (recurrent encoder, convolutional decoder)\n", " * Grapheme2phoneme - convert words to transcripts\n", - " \n", + "\n", "We chose simplified __Hebrew->English__ machine translation for words and short phrases (character-level), as it is relatively quick to train even without a gpu cluster." ] }, @@ -87,10 +88,7 @@ "\n", "This is mostly due to the fact that many words have several correct translations.\n", "\n", - "We have implemented this thing for you so that you can focus on more interesting parts.\n", - "\n", - "\n", - "__Attention python2 users!__ You may want to cast everything to unicode later during homework phase, just make sure you do it _everywhere_." + "We have implemented this thing for you so that you can focus on more interesting parts." ] }, { @@ -163,7 +161,7 @@ "source": [ "### Building vocabularies\n", "\n", - "We now need to build vocabularies that map strings to token ids and vice versa. We're gonna need these fellas when we feed training data into model or convert output matrices into english words." + "We now need to build vocabularies that map strings to token ids and vice versa. We're gonna need these fellas when we feed training data into the model or convert output matrices into English words." ] }, { @@ -233,13 +231,13 @@ "* Encoder reads words character by character and outputs code vector (usually a function of last RNN state)\n", "* Decoder takes that code vector and produces translations character by character\n", "\n", - "Than it gets fed into a model that follows this simple interface:\n", - "* __`model.symbolic_translate(inp, **flags) -> out, logp`__ - takes symbolic int32 matrix of hebrew words, produces output tokens sampled from the model and output log-probabilities for all possible tokens at each tick.\n", - " * if given flag __`greedy=True`__, takes most likely next token at each iteration. Otherwise samples with next token probabilities predicted by model.\n", - "* __`model.symbolic_score(inp, out, **flags) -> logp`__ - takes symbolic int32 matrices of hebrew words and their english translations. Computes the log-probabilities of all possible english characters given english prefices and hebrew word.\n", - "* __`model.weights`__ - weights from all model layers [a list of variables]\n", + "Then it gets fed into a model that follows this simple interface:\n", + "* __`model.symbolic_translate(inp, **flags) -> out, logp`__ - takes symbolic int32 matrix of Hebrew words, produces output tokens sampled from the model and output log-probabilities for all possible tokens at each tick.\n", + " * if given flag __`greedy=True`__, takes most likely next token at each iteration. Otherwise, samples with next token probabilities predicted by model.\n", + "* __`model.symbolic_score(inp, out, **flags) -> logp`__ - takes symbolic int32 matrices of Hebrew words and their English translations. Computes the log-probabilities of all possible English characters given English prefixes and Hebrew word.\n", + "* __`model.weights`__ - weights from all model layers, [a list of variables]\n", "\n", - "That's all! It's as hard as it gets. With those two methods alone you can implement all kinds of prediction and training." + "That's all! It's as hard as it gets. With those two methods alone, you can implement all kinds of prediction and training." ] }, { @@ -311,7 +309,7 @@ "\n", "def translate(lines):\n", " \"\"\"\n", - " You are given a list of input lines. \n", + " You are given a list of input lines.\n", " Make your neural network translate them.\n", " :return: a list of output lines\n", " \"\"\"\n", @@ -350,7 +348,7 @@ "### Scoring function\n", "\n", "LogLikelihood is a poor estimator of model performance.\n", - "* If we predict zero probability once, it shouldn't ruin entire model.\n", + "* If we predict zero probability once, it shouldn't ruin the entire model.\n", "* It is enough to learn just one translation if there are several correct ones.\n", "* What matters is how many mistakes model's gonna make when it translates!\n", "\n", @@ -594,7 +592,7 @@ "\n", " Params:\n", " - words_ix - a matrix of letter indices, shape=[batch_size,word_length]\n", - " - words_mask - a matrix of zeros/ones, \n", + " - words_mask - a matrix of zeros/ones,\n", " 1 means \"word is still not finished\"\n", " 0 means \"word has already finished and this is padding\"\n", "\n", @@ -704,7 +702,7 @@ "\n", "* You may now want to __remove/comment asserts__ from function code for a slight speed-up.\n", "\n", - "* There's a more detailed tutorial on custom tensorflow ops: [`py_func`](https://www.tensorflow.org/api_docs/python/tf/py_func), [`low-level`](https://www.tensorflow.org/api_docs/python/tf/py_func)." + "* There's a more detailed tutorial on custom tensorflow ops: [`py_func`](https://www.tensorflow.org/api_docs/python/tf/compat/v1/py_func), [`low-level`](https://www.tensorflow.org/lite/guide/ops_custom)." ] }, { @@ -715,7 +713,7 @@ "\n", "In this section you'll implement algorithm called self-critical sequence training (here's an [article](https://arxiv.org/abs/1612.00563)).\n", "\n", - "The algorithm is a vanilla policy gradient with a special baseline. \n", + "The algorithm is a vanilla policy gradient with a special baseline.\n", "\n", "$$ \\nabla J = E_{x \\sim p(s)} E_{y \\sim \\pi(y|x)} \\nabla log \\pi(y|x) \\cdot (R(x,y) - b(x)) $$\n", "\n", @@ -865,7 +863,7 @@ "## Step 6: Make it actually work (5++ pts)\n", "\n", "\n", - "In this section we want you to finally __restart with EASY_MODE=False__ and experiment to find a good model/curriculum for that task.\n", + "In this section, we want you to finally __restart with EASY_MODE=False__ and experiment to find a good model/curriculum for that task.\n", "\n", "We recommend you to start with the following architecture\n", "\n", @@ -881,24 +879,24 @@ "input y_prev\n", "```\n", "\n", - "__Note:__ you can fit all 4 state tensors of both LSTMs into a in a single state - just assume that it contains, for example, [h0, c0, h1, c1] - pack it in encode and update in decode.\n", + "__Note:__ you can fit all 4 state tensors of both LSTMs into in a single state - just assume that it contains, for example, [h0, c0, h1, c1] - pack it in encode and update in decode.\n", "\n", "\n", "Here are some cool ideas on what you can do then.\n", "\n", "__General tips & tricks:__\n", - "* In some tensorflow versions and for some layers, it is required that each rnn/gru/lstm cell gets it's own `tf.variable_scope(unique_name, reuse=False)`.\n", - " * Otherwise it will complain about wrong tensor sizes because it tries to reuse weights from one rnn to the other.\n", + "* In some tensorflow versions and for some layers, it is required that each rnn/gru/lstm cell gets its own `tf.variable_scope(unique_name, reuse=False)`.\n", + " * Otherwise, it will complain about wrong tensor sizes because it tries to reuse weights from one rnn to the other.\n", "* You will likely need to adjust pre-training time for such a network.\n", "* Supervised pre-training may benefit from clipping gradients somehow.\n", "* SCST may indulge a higher learning rate in some cases and changing entropy regularizer over time.\n", - "* It's often useful to save pre-trained model parameters to not re-train it every time you want new policy gradient parameters. \n", + "* It's often useful to save pre-trained model parameters to not re-train it every time you want new policy gradient parameters.\n", "* When leaving training for nighttime, try setting REPORT_FREQ to a larger value (e.g. 500) not to waste time on it.\n", "\n", "__Formal criteria:__\n", - "To get 5 points we want you to build an architecture that:\n", + "To get 5 points, we want you to build an architecture that:\n", "* _doesn't consist of single GRU_\n", - "* _works better_ than single GRU baseline. \n", + "* _works better_ than single GRU baseline.\n", "* We also want you to provide either learning curve or trained model, preferably both\n", "* ... and write a brief report or experiment log describing what you did and how it fared.\n", "\n", @@ -907,7 +905,7 @@ " * __Vanilla:__ layer_i of encoder last state goes to layer_i of decoder initial state\n", " * __Every tick:__ feed encoder last state _on every iteration_ of decoder.\n", " * __Attention:__ allow decoder to \"peek\" at one (or several) positions of encoded sequence on every tick.\n", - " \n", + "\n", "The most effective (and cool) of those is, of course, attention.\n", "You can read more about attention [in this nice blog post](https://distill.pub/2016/augmented-rnns/). The easiest way to begin is to use \"soft\" attention with \"additive\" or \"dot-product\" intermediate layers.\n", "\n", @@ -915,8 +913,8 @@ "* Model usually generalizes better if you no longer allow decoder to see final encoder state\n", "* Once your model made it through several epochs, it is a good idea to visualize attention maps to understand what your model has actually learned\n", "\n", - "* There's more stuff [here](https://github.com/yandexdataschool/Practical_RL/blob/master/week8_scst/bonus.ipynb)\n", - "* If you opted for hard attention, we recommend [gumbel-softmax](https://blog.evjang.com/2016/11/tutorial-categorical-variational.html) instead of sampling. Also please make sure soft attention works fine before you switch to hard.\n", + "* There's more stuff [here](bonus.ipynb)\n", + "* If you opted for hard attention, we recommend [gumbel-softmax](https://blog.evjang.com/2016/11/tutorial-categorical-variational.html) instead of sampling. Also, please make sure soft attention works fine before you switch to hard.\n", "\n", "### UREX\n", "* This is a way to improve exploration in policy-based settings. The main idea is that you find and upweight under-appreciated actions.\n", @@ -927,8 +925,8 @@ "\n", "### Some additional ideas:\n", "* (advanced deep learning) It may be a good idea to first train on small phrases and then adapt to larger ones (a.k.a. training curriculum).\n", - "* (advanced nlp) You may want to switch from raw utf8 to something like unicode or even syllables to make task easier.\n", - "* (advanced nlp) Since hebrew words are written __with vowels omitted__, you may want to use a small Hebrew vowel markup dataset at `he-pron-wiktionary.txt`.\n", + "* (advanced nlp) You may want to switch from raw utf8 to something like unicode or even syllables to make the task easier.\n", + "* (advanced nlp) Since Hebrew words are written __with vowels omitted__, you may want to use a small Hebrew vowel markup dataset at `he-pron-wiktionary.txt`.\n", "\n" ] }, @@ -936,7 +934,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Bonus hints: [here](https://github.com/yandexdataschool/Practical_RL/blob/master/week8_scst/bonus.ipynb)" + "### Bonus hints: [here](bonus.ipynb)" ] }, { diff --git a/week07_seq2seq/practice_theano.ipynb b/week07_seq2seq/practice_theano.ipynb deleted file mode 100644 index 790ebe158..000000000 --- a/week07_seq2seq/practice_theano.ipynb +++ /dev/null @@ -1,939 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Reinforcement Learning for seq2seq\n", - "\n", - "This time we'll solve a problem of transribing hebrew words in english, also known as g2p (grapheme2phoneme)\n", - "\n", - " * word (sequence of letters in source language) -> translation (sequence of letters in target language)\n", - "\n", - "Unlike what most deep learning researchers do, we won't only train it to maximize likelihood of correct translation, but also employ reinforcement learning to actually teach it to translate with as few errors as possible.\n", - "\n", - "\n", - "### About the task\n", - "\n", - "One notable property of Hebrew is that it's consonant language. That is, there are no wovels in the written language. One could represent wovels with diacritics above consonants, but you don't expect people to do that in everyay life.\n", - "\n", - "Therefore, some hebrew characters will correspond to several english letters and others - to none, so we should use encoder-decoder architecture to figure that out.\n", - "\n", - "![img](https://esciencegroup.files.wordpress.com/2016/03/seq2seq.jpg)\n", - "_(img: esciencegroup.files.wordpress.com)_\n", - "\n", - "Encoder-decoder architectures are about converting anything to anything, including\n", - " * Machine translation and spoken dialogue systems\n", - " * [Image captioning](http://mscoco.org/dataset/#captions-challenge2015) and [image2latex](https://openai.com/requests-for-research/#im2latex) (convolutional encoder, recurrent decoder)\n", - " * Generating [images by captions](https://arxiv.org/abs/1511.02793) (recurrent encoder, convolutional decoder)\n", - " * Grapheme2phoneme - convert words to transcripts\n", - " \n", - "We chose simplified __Hebrew->English__ machine translation for words and short phrases (character-level), as it is relatively quick to train even without a gpu cluster." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# If True, only translates phrases shorter than 20 characters (way easier).\n", - "EASY_MODE = True\n", - "# Please keep it until you're done debugging your code\n", - "# If false, works with all phrases (please switch to this mode for homework assignment)\n", - "\n", - "# way we translate. Either \"he-to-en\" or \"en-to-he\"\n", - "MODE = \"he-to-en\"\n", - "# maximal length of _generated_ output, does not affect training\n", - "MAX_OUTPUT_LENGTH = 50 if not EASY_MODE else 20\n", - "REPORT_FREQ = 100 # how often to evaluate validation score" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 1: preprocessing\n", - "\n", - "We shall store dataset as a dictionary\n", - "`{ word1:[translation1,translation2,...], word2:[...],...}`.\n", - "\n", - "This is mostly due to the fact that many words have several correct translations.\n", - "\n", - "We have implemented this thing for you so that you can focus on more interesting parts.\n", - "\n", - "\n", - "__Attention python2 users!__ You may want to cast everything to unicode later during homework phase, just make sure you do it _everywhere_." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "from collections import defaultdict\n", - "word_to_translation = defaultdict(list) # our dictionary\n", - "\n", - "bos = '_'\n", - "eos = ';'\n", - "\n", - "with open(\"main_dataset.txt\", encoding='utf8') as fin:\n", - " for line in fin:\n", - "\n", - " en, he = line[:-1].lower().replace(bos, ' ').replace(eos,\n", - " ' ').split('\\t')\n", - " word, trans = (he, en) if MODE == 'he-to-en' else (en, he)\n", - "\n", - " if len(word) < 3:\n", - " continue\n", - " if EASY_MODE:\n", - " if max(len(word), len(trans)) > 20:\n", - " continue\n", - "\n", - " word_to_translation[word].append(trans)\n", - "\n", - "print(\"size = \", len(word_to_translation))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get all unique lines in source language\n", - "all_words = np.array(list(word_to_translation.keys()))\n", - "# get all unique lines in translation language\n", - "all_translations = np.array(\n", - " [ts for all_ts in word_to_translation.values() for ts in all_ts])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### split the dataset\n", - "\n", - "We hold out 10% of all words to be used for validation.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.model_selection import train_test_split\n", - "train_words, test_words = train_test_split(\n", - " all_words, test_size=0.1, random_state=42)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Building vocabularies\n", - "\n", - "We now need to build vocabularies that map strings to token ids and vice versa. We're gonna need these fellas when we feed training data into model or convert output matrices into english words." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from voc import Vocab\n", - "inp_voc = Vocab.from_lines(''.join(all_words), bos=bos, eos=eos, sep='')\n", - "out_voc = Vocab.from_lines(''.join(all_translations), bos=bos, eos=eos, sep='')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Here's how you cast lines into ids and backwards.\n", - "batch_lines = all_words[:5]\n", - "batch_ids = inp_voc.to_matrix(batch_lines)\n", - "batch_lines_restored = inp_voc.to_lines(batch_ids)\n", - "\n", - "print(\"lines\")\n", - "print(batch_lines)\n", - "print(\"\\nwords to ids (0 = bos, 1 = eos):\")\n", - "print(batch_ids)\n", - "print(\"\\nback to words\")\n", - "print(batch_lines_restored)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Draw word/translation length distributions to estimate the scope of the task." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "plt.figure(figsize=[8, 4])\n", - "plt.subplot(1, 2, 1)\n", - "plt.title(\"words\")\n", - "plt.hist(list(map(len, all_words)), bins=20)\n", - "\n", - "plt.subplot(1, 2, 2)\n", - "plt.title('translations')\n", - "plt.hist(list(map(len, all_translations)), bins=20)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 3: deploy encoder-decoder (1 point)\n", - "\n", - "__assignment starts here__\n", - "\n", - "Our architecture consists of two main blocks:\n", - "* Encoder reads words character by character and outputs code vector (usually a function of last RNN state)\n", - "* Decoder takes that code vector and produces translations character by character\n", - "\n", - "Than it gets fed into a model that follows this simple interface:\n", - "* __`model.symbolic_translate(inp, **flags) -> out, logp`__ - takes symbolic int32 matrix of hebrew words, produces output tokens sampled from the model and output log-probabilities for all possible tokens at each tick.\n", - " * if given flag __`greedy=True`__, takes most likely next token at each iteration. Otherwise samples with next token probabilities predicted by model.\n", - "* __`model.symbolic_score(inp, out, **flags) -> logp`__ - takes symbolic int32 matrices of hebrew words and their english translations. Computes the log-probabilities of all possible english characters given english prefices and hebrew word.\n", - "\n", - "That's all! It's as hard as it gets. With those two methods alone you can implement all kinds of prediction and training." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# set flags here if necessary\n", - "import theano\n", - "theano.config.floatX = 'float32'\n", - "import theano.tensor as T\n", - "import lasagne" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from basic_model_theano import BasicTranslationModel\n", - "model = BasicTranslationModel(inp_voc, out_voc,\n", - " emb_size=64, hid_size=128)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Play around with symbolic_translate and symbolic_score\n", - "inp = T.constant(np.random.randint(0, 10, [3, 5], dtype='int32'))\n", - "out = T.constant(np.random.randint(0, 10, [3, 5], dtype='int32'))\n", - "\n", - "# translate inp (with untrained model)\n", - "sampled_out, logp = model.symbolic_translate(inp, greedy=False)\n", - "dummy_translate = theano.function([], sampled_out, updates=model.auto_updates)\n", - "\n", - "print(\"\\nSymbolic_translate output:\\n\", sampled_out, logp)\n", - "print(\"\\nSample translations:\\n\", dummy_translate())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# score logp(out | inp) with untrained input\n", - "logp = model.symbolic_score(inp, out)\n", - "dummy_score = theano.function([], logp)\n", - "\n", - "print(\"\\nSymbolic_score output:\\n\", logp)\n", - "print(\"\\nLog-probabilities (clipped):\\n\", dummy_score()[:, :2, :5])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare any operations you want here\n", - "\n", - "inp = T.imatrix(\"input tokens [batch,time]\")\n", - "trans, _ = \n", - "translate_fun = theano.function([inp], trans, updates=model.auto_updates)\n", - "\n", - "\n", - "def translate(lines):\n", - " \"\"\"\n", - " You are given a list of input lines. \n", - " Make your neural network translate them.\n", - " :return: a list of output lines\n", - " \"\"\"\n", - " # Convert lines to a matrix of indices\n", - " lines_ix = \n", - "\n", - " # Compute translations in form of indices (call your function)\n", - " trans_ix = \n", - "\n", - " # Convert translations back into strings\n", - " return out_voc.to_lines(trans_ix)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Sample inputs:\", all_words[:3])\n", - "print(\"Dummy translations:\", translate(all_words[:3]))\n", - "\n", - "assert trans.ndim == 2 and trans.dtype.startswith(\n", - " 'int'), \"trans must be a tensor of integers (token ids)\"\n", - "assert translate(all_words[:3]) == translate(\n", - " all_words[:3]), \"make sure translation is deterministic (use greedy=True and disable any noise layers)\"\n", - "assert type(translate(all_words[:3])) is list and (type(translate(all_words[:1])[0]) is str or type(\n", - " translate(all_words[:1])[0]) is unicode), \"translate(lines) must return a sequence of strings!\"\n", - "print(\"Tests passed!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Scoring function\n", - "\n", - "LogLikelihood is a poor estimator of model performance.\n", - "* If we predict zero probability once, it shouldn't ruin entire model.\n", - "* It is enough to learn just one translation if there are several correct ones.\n", - "* What matters is how many mistakes model's gonna make when it translates!\n", - "\n", - "Therefore, we will use minimal Levenshtein distance. It measures how many characters do we need to add/remove/replace from model translation to make it perfect. Alternatively, one could use character-level BLEU/RougeL or other similar metrics.\n", - "\n", - "The catch here is that Levenshtein distance is not differentiable: it isn't even continuous. We can't train our neural network to maximize it by gradient descent." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import editdistance # !pip install editdistance\n", - "\n", - "\n", - "def get_distance(word, trans):\n", - " \"\"\"\n", - " A function that takes word and predicted translation\n", - " and evaluates (Levenshtein's) edit distance to closest correct translation\n", - " \"\"\"\n", - " references = word_to_translation[word]\n", - " assert len(references) != 0, \"wrong/unknown word\"\n", - " return min(editdistance.eval(trans, ref) for ref in references)\n", - "\n", - "\n", - "def score(words, bsize=100):\n", - " \"\"\"a function that computes levenshtein distance for bsize random samples\"\"\"\n", - " assert isinstance(words, np.ndarray)\n", - "\n", - " batch_words = np.random.choice(words, size=bsize, replace=False)\n", - " batch_trans = translate(batch_words)\n", - "\n", - " distances = list(map(get_distance, batch_words, batch_trans))\n", - "\n", - " return np.array(distances, dtype='float32')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# should be around 5-50 and decrease rapidly after training :)\n", - "[score(test_words, 10).mean() for _ in range(5)]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 2: Supervised pre-training\n", - "\n", - "Here we define a function that trains our model through maximizing log-likelihood a.k.a. minimizing crossentropy." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.learning.generic import get_values_for_actions, get_mask_by_eos\n", - "\n", - "\n", - "class llh_trainer:\n", - "\n", - " # variable for correct answers\n", - " input_sequence = T.imatrix(\"input sequence [batch,time]\")\n", - " reference_answers = T.imatrix(\"reference translations [batch, time]\")\n", - "\n", - " # Compute log-probabilities of all possible tokens at each step. Use model interface.\n", - " logprobs_seq = \n", - "\n", - " # compute mean crossentropy\n", - " crossentropy = - get_values_for_actions(logprobs_seq, reference_answers)\n", - "\n", - " mask = get_mask_by_eos(T.eq(reference_answers, out_voc.eos_ix))\n", - "\n", - " loss = T.sum(crossentropy * mask)/T.sum(mask)\n", - "\n", - " # Build weight updates. Use model.weights to get all trainable params.\n", - " updates = \n", - "\n", - " train_step = theano.function(\n", - " [input_sequence, reference_answers], loss, updates=updates)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Actually run training on minibatches" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "\n", - "\n", - "def sample_batch(words, word_to_translation, batch_size):\n", - " \"\"\"\n", - " sample random batch of words and random correct translation for each word\n", - " example usage:\n", - " batch_x,batch_y = sample_batch(train_words, word_to_translations,10)\n", - " \"\"\"\n", - " # choose words\n", - " batch_words = np.random.choice(words, size=batch_size)\n", - "\n", - " # choose translations\n", - " batch_trans_candidates = list(map(word_to_translation.get, batch_words))\n", - " batch_trans = list(map(random.choice, batch_trans_candidates))\n", - "\n", - " return inp_voc.to_matrix(batch_words), out_voc.to_matrix(batch_trans)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "bx, by = sample_batch(train_words, word_to_translation, batch_size=3)\n", - "print(\"Source:\")\n", - "print(bx)\n", - "print(\"Target:\")\n", - "print(by)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import clear_output\n", - "from tqdm import tqdm, trange # or use tqdm_notebook,tnrange\n", - "\n", - "loss_history = []\n", - "editdist_history = []\n", - "\n", - "for i in trange(25000):\n", - " loss = llh_trainer.train_step(\n", - " *sample_batch(train_words, word_to_translation, 32))\n", - " loss_history.append(loss)\n", - "\n", - " if (i+1) % REPORT_FREQ == 0:\n", - " clear_output(True)\n", - " current_scores = score(test_words)\n", - " editdist_history.append(current_scores.mean())\n", - " plt.figure(figsize=(12, 4))\n", - " plt.subplot(131)\n", - " plt.title('train loss / traning time')\n", - " plt.plot(loss_history)\n", - " plt.grid()\n", - " plt.subplot(132)\n", - " plt.title('val score distribution')\n", - " plt.hist(current_scores, bins=20)\n", - " plt.subplot(133)\n", - " plt.title('val score / traning time')\n", - " plt.plot(editdist_history)\n", - " plt.grid()\n", - " plt.show()\n", - " print(\"llh=%.3f, mean score=%.3f\" %\n", - " (np.mean(loss_history[-10:]), np.mean(editdist_history[-10:])))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for word in train_words[:10]:\n", - " print(\"%s -> %s\" % (word, translate([word])[0]))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "test_scores = []\n", - "for start_i in trange(0, len(test_words), 32):\n", - " batch_words = test_words[start_i:start_i+32]\n", - " batch_trans = translate(batch_words)\n", - " distances = list(map(get_distance, batch_words, batch_trans))\n", - " test_scores.extend(distances)\n", - "\n", - "print(\"Supervised test score:\", np.mean(test_scores))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Preparing for reinforcement learning (2 points)\n", - "\n", - "First we need to define loss function as a custom theano operation.\n", - "\n", - "The simple way to do so is\n", - "```\n", - "@theano.compile.as_op(input_types,output_type(s),infer_shape)\n", - "def my_super_function(inputs):\n", - " return outputs\n", - "```\n", - "\n", - "\n", - "\n", - "\n", - "__Your task__ is to implement `_compute_levenshtein` function that takes matrices of words and translations, along with input masks, then converts those to actual words and phonemes and computes min-levenshtein via __get_distance__ function above.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "@theano.compile.as_op([T.imatrix]*2, [T.fvector], lambda _, shapes: [shapes[0][:1]])\n", - "def _compute_levenshtein(words_ix, trans_ix):\n", - " \"\"\"\n", - " A custom theano operation that computes levenshtein loss for predicted trans.\n", - "\n", - " Params:\n", - " - words_ix - a matrix of letter indices, shape=[batch_size,word_length]\n", - " - words_mask - a matrix of zeros/ones, \n", - " 1 means \"word is still not finished\"\n", - " 0 means \"word has already finished and this is padding\"\n", - "\n", - " - trans_mask - a matrix of output letter indices, shape=[batch_size,translation_length]\n", - " - trans_mask - a matrix of zeros/ones, similar to words_mask but for trans_ix\n", - "\n", - "\n", - " Please implement the function and make sure it passes tests from the next cell.\n", - "\n", - " \"\"\"\n", - "\n", - " # convert words to strings\n", - " words = \n", - "\n", - " assert type(words) is list and type(\n", - " words[0]) is str and len(words) == len(words_ix)\n", - "\n", - " # convert translations to lists\n", - " translations = \n", - "\n", - " assert type(distances) in (list, tuple, np.ndarray) and len(\n", - " distances) == len(words_ix)\n", - "\n", - " distances = np.array(list(distances), dtype='float32')\n", - " return distances\n", - "\n", - "\n", - "# forbid gradient\n", - "from theano.gradient import disconnected_grad\n", - "\n", - "\n", - "def compute_levenshtein(*args):\n", - " return disconnected_grad(_compute_levenshtein(*[arg.astype('int32') for arg in args]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Simple test suite to make sure your implementation is correct. Hint: if you run into any bugs, feel free to use print from inside _compute_levenshtein." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# test suite\n", - "# sample random batch of (words, correct trans, wrong trans)\n", - "batch_words = np.random.choice(train_words, size=100)\n", - "batch_trans = list(map(random.choice, map(\n", - " word_to_translation.get, batch_words)))\n", - "batch_trans_wrong = np.random.choice(all_translations, size=100)\n", - "\n", - "batch_words_ix = T.constant(inp_voc.to_matrix(batch_words))\n", - "batch_trans_ix = T.constant(out_voc.to_matrix(batch_trans))\n", - "batch_trans_wrong_ix = T.constant(out_voc.to_matrix(batch_trans_wrong))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# assert compute_levenshtein is zero for ideal translations\n", - "correct_answers_score = compute_levenshtein(\n", - " batch_words_ix, batch_trans_ix).eval()\n", - "\n", - "assert np.all(correct_answers_score ==\n", - " 0), \"a perfect translation got nonzero levenshtein score!\"\n", - "\n", - "print(\"Everything seems alright!\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# assert compute_levenshtein matches actual scoring function\n", - "wrong_answers_score = compute_levenshtein(\n", - " batch_words_ix, batch_trans_wrong_ix).eval()\n", - "\n", - "true_wrong_answers_score = np.array(\n", - " list(map(get_distance, batch_words, batch_trans_wrong)))\n", - "\n", - "assert np.all(wrong_answers_score ==\n", - " true_wrong_answers_score), \"for some word symbolic levenshtein is different from actual levenshtein distance\"\n", - "\n", - "print(\"Everything seems alright!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Once you got it working...\n", - "\n", - "\n", - "* You may now want to __remove/comment asserts__ from function code for a slight speed-up.\n", - "\n", - "* There's a more detailed tutorial on custom theano ops here: [docs](http://deeplearning.net/software/theano/extending/extending_theano.html), [example](https://gist.github.com/justheuristic/9f4ffef6162a8089c3260fc3bbacbf46)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Self-critical policy gradient (2 points)\n", - "\n", - "In this section you'll implement algorithm called self-critical sequence training (here's an [article](https://arxiv.org/abs/1612.00563)).\n", - "\n", - "The algorithm is a vanilla policy gradient with a special baseline. \n", - "\n", - "$$ \\nabla J = E_{x \\sim p(s)} E_{y \\sim \\pi(y|x)} \\nabla log \\pi(y|x) \\cdot (R(x,y) - b(x)) $$\n", - "\n", - "Here reward R(x,y) is a __negative levenshtein distance__ (since we minimize it). The baseline __b(x)__ represents how well model fares on word __x__.\n", - "\n", - "In practice, this means that we compute baseline as a score of greedy translation, $b(x) = R(x,y_{greedy}(x)) $.\n", - "![img](https://github.com/yandexdataschool/Practical_RL/raw/master/yet_another_week/_resource/scheme.png)\n", - "\n", - "Luckily, we already obtained the required outputs: `model.greedy_translations, model.greedy_mask` and we only need to compute levenshtein using `compute_levenshtein` function.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "class trainer:\n", - "\n", - " input_sequence = T.imatrix(\"input tokens [batch,time]\")\n", - "\n", - " # use model to __sample__ symbolic translations given input_sequence\n", - " sample_translations, sample_logp = \n", - " auto_updates = model.auto_updates\n", - " # use model to __greedy__ symbolic translations given input_sequence\n", - " greedy_translations, greedy_logp = \n", - " greedy_auto_updates = model.auto_updates\n", - "\n", - " # Note: you can use model.symbolic_translate(...,unroll_scan=True,max_len=MAX_OUTPUT_LENGTH)\n", - " # to run much faster at a cost of longer compilation\n", - "\n", - " rewards = - compute_levenshtein(input_sequence, sample_translations)\n", - "\n", - " baseline = \n", - "\n", - " # compute advantage using rewards and baseline\n", - " advantage = \n", - "\n", - " # compute log_pi(a_t|s_t), shape = [batch, seq_length]\n", - " logprobs_phoneme = get_values_for_actions(sample_logp, sample_translations)\n", - "\n", - " # policy gradient\n", - " J = logprobs_phoneme*advantage[:, None]\n", - "\n", - " mask = get_mask_by_eos(T.eq(sample_translations, out_voc.eos_ix))\n", - " loss = - T.sum(J*mask) / T.sum(mask)\n", - "\n", - " # regularize with negative entropy. Don't forget the sign!\n", - " # note: for entropy you need probabilities for all tokens (sample_logp), not just phoneme_logprobs\n", - " entropy = \n", - "\n", - " assert entropy.ndim == 2, \"please make sure elementwise entropy is of shape [batch,time]\"\n", - "\n", - " loss -= 0.01*T.sum(entropy*mask) / T.sum(mask)\n", - "\n", - " # compute weight updates, clip by norm\n", - " grads = T.grad(loss, model.weights)\n", - " grads = lasagne.updates.total_norm_constraint(grads, 50)\n", - "\n", - " updates = lasagne.updates.adam(grads, model.weights, learning_rate=1e-5)\n", - "\n", - " train_step = theano.function([input_sequence], loss,\n", - " updates=auto_updates+greedy_auto_updates+updates)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Policy gradient training\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for i in trange(100000):\n", - " loss_history.append(\n", - " trainer.train_step(sample_batch(\n", - " train_words, word_to_translation, 32)[0])\n", - " )\n", - "\n", - " if (i+1) % REPORT_FREQ == 0:\n", - " clear_output(True)\n", - " current_scores = score(test_words)\n", - " editdist_history.append(current_scores.mean())\n", - " plt.figure(figsize=(8, 4))\n", - " plt.subplot(121)\n", - " plt.title('val score distribution')\n", - " plt.hist(current_scores, bins=20)\n", - " plt.subplot(122)\n", - " plt.title('val score / traning time')\n", - " plt.plot(editdist_history)\n", - " plt.grid()\n", - " plt.show()\n", - " print(\"J=%.3f, mean score=%.3f\" %\n", - " (np.mean(loss_history[-10:]), np.mean(editdist_history[-10:])))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "model.translate(\"EXAMPLE;\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for word in train_words[:10]:\n", - " print(\"%s -> %s\" % (word, translate([word])[0]))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "test_scores = []\n", - "for start_i in trange(0, len(test_words), 32):\n", - " batch_words = test_words[start_i:start_i+32]\n", - " batch_trans = translate(batch_words)\n", - " distances = list(map(get_distance, batch_words, batch_trans))\n", - " test_scores.extend(distances)\n", - "print(\"Supervised test score:\", np.mean(test_scores))\n", - "\n", - "# ^^ If you get Out Of Memory, please replace this with batched computation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 6: Make it actually work (5++ pts)\n", - "\n", - "\n", - "\n", - "In this section we want you to finally __restart with EASY_MODE=False__ and experiment to find a good model/curriculum for that task.\n", - "\n", - "We recommend you to start with the following architecture\n", - "\n", - "```\n", - "encoder---decoder\n", - "\n", - " P(y|h)\n", - " ^\n", - " LSTM -> LSTM\n", - " ^ ^\n", - " biLSTM -> LSTM\n", - " ^ ^\n", - "input y_prev\n", - "```\n", - "\n", - "__Note:__ you can fit all 4 state tensors of both LSTMs into a in a single state - just assume that it contains, for example, [h0, c0, h1, c1] - pack it in encode and update in decode.\n", - "\n", - "\n", - "Here are some cool ideas on what you can do then.\n", - "\n", - "__General tips & tricks:__\n", - "* In some tensorflow versions and for some layers, it is required that each rnn/gru/lstm cell gets it's own `tf.variable_scope(unique_name, reuse=False)`.\n", - " * Otherwise it will complain about wrong tensor sizes because it tries to reuse weights from one rnn to the other.\n", - "* You will likely need to adjust pre-training time for such a network.\n", - "* Supervised pre-training may benefit from clipping gradients somehow.\n", - "* SCST may indulge a higher learning rate in some cases and changing entropy regularizer over time.\n", - "* It's often useful to save pre-trained model parameters to not re-train it every time you want new policy gradient parameters. \n", - "* When leaving training for nighttime, try setting REPORT_FREQ to a larger value (e.g. 500) not to waste time on it.\n", - "\n", - "__Formal criteria:__\n", - "To get 5 points we want you to build an architecture that:\n", - "* _doesn't consist of single GRU_\n", - "* _works better_ than single GRU baseline. \n", - "* We also want you to provide either learning curve or trained model, preferably both\n", - "* ... and write a brief report or experiment log describing what you did and how it fared.\n", - "\n", - "### Attention\n", - "There's more than one way to connect decoder to encoder\n", - " * __Vanilla:__ layer_i of encoder last state goes to layer_i of decoder initial state\n", - " * __Every tick:__ feed encoder last state _on every iteration_ of decoder.\n", - " * __Attention:__ allow decoder to \"peek\" at one (or several) positions of encoded sequence on every tick.\n", - " \n", - "The most effective (and cool) of those is, of course, attention.\n", - "You can read more about attention [in this nice blog post](https://distill.pub/2016/augmented-rnns/). The easiest way to begin is to use \"soft\" attention with \"additive\" or \"dot-product\" intermediate layers.\n", - "\n", - "__Tips__\n", - "* Model usually generalizes better if you no longer allow decoder to see final encoder state\n", - "* Once your model made it through several epochs, it is a good idea to visualize attention maps to understand what your model has actually learned\n", - "\n", - "* There's more stuff [here](https://github.com/yandexdataschool/Practical_RL/blob/master/week8_scst/bonus.ipynb)\n", - "* If you opted for hard attention, we recommend [gumbel-softmax](https://blog.evjang.com/2016/11/tutorial-categorical-variational.html) instead of sampling. Also please make sure soft attention works fine before you switch to hard.\n", - "\n", - "### UREX\n", - "* This is a way to improve exploration in policy-based settings. The main idea is that you find and upweight under-appreciated actions.\n", - "* Here's [video](https://www.youtube.com/watch?v=fZNyHoXgV7M&feature=youtu.be&t=3444)\n", - " and an [article](https://arxiv.org/abs/1611.09321).\n", - "* You may want to reduce batch size 'cuz UREX requires you to sample multiple times per source sentence.\n", - "* Once you got it working, try using experience replay with importance sampling instead of (in addition to) basic UREX.\n", - "\n", - "### Some additional ideas:\n", - "* (advanced deep learning) It may be a good idea to first train on small phrases and then adapt to larger ones (a.k.a. training curriculum).\n", - "* (advanced nlp) You may want to switch from raw utf8 to something like unicode or even syllables to make task easier.\n", - "* (advanced nlp) Since hebrew words are written __with vowels omitted__, you may want to use a small Hebrew vowel markup dataset at `he-pron-wiktionary.txt`.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert not EASY_MODE, \"make sure you set EASY_MODE = False at the top of the notebook.\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`[your report/log here or anywhere you please]`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "__Contributions:__ This notebook is brought to you by\n", - "* Yandex [MT team](https://tech.yandex.com/translate/)\n", - "* Denis Mazur ([DeniskaMazur](https://github.com/DeniskaMazur)), Oleg Vasilev ([Omrigan](https://github.com/Omrigan/)), Dmitry Emelyanenko ([TixFeniks](https://github.com/tixfeniks)) and Fedor Ratnikov ([justheuristic](https://github.com/justheuristic/))\n", - "* Dataset is parsed from [Wiktionary](https://en.wiktionary.org), which is under CC-BY-SA and GFDL licenses.\n" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week07_seq2seq/practice_torch.ipynb b/week07_seq2seq/practice_torch.ipynb index d0b596764..97bc2ebbe 100644 --- a/week07_seq2seq/practice_torch.ipynb +++ b/week07_seq2seq/practice_torch.ipynb @@ -6,28 +6,28 @@ "source": [ "## Reinforcement Learning for seq2seq\n", "\n", - "This time we'll solve a problem of transribing hebrew words in english, also known as g2p (grapheme2phoneme)\n", + "This time we'll solve a problem of transсribing Hebrew words in English, also known as g2p (grapheme2phoneme)\n", "\n", " * word (sequence of letters in source language) -> translation (sequence of letters in target language)\n", "\n", - "Unlike what most deep learning practicioners do, we won't only train it to maximize likelihood of correct translation, but also employ reinforcement learning to actually teach it to translate with as few errors as possible.\n", + "Unlike what most deep learning practitioners do, we won't only train it to maximize likelihood of correct translation, but also employ reinforcement learning to actually teach it to translate with as few errors as possible.\n", "\n", "\n", "### About the task\n", "\n", - "One notable property of Hebrew is that it's consonant language. That is, there are no wovels in the written language. One could represent wovels with diacritics above consonants, but you don't expect people to do that in everyay life.\n", + "One notable property of Hebrew is that it's a consonant language. That is, there are no vowels in the written language. One could represent vowels with diacritics above consonants, but you don't expect people to do that in everyday life.\n", "\n", - "Therefore, some hebrew characters will correspond to several english letters and others - to none, so we should use encoder-decoder architecture to figure that out.\n", + "Therefore, some Hebrew characters will correspond to several English letters and others - to none, so we should use encoder-decoder architecture to figure that out.\n", "\n", "![img](https://esciencegroup.files.wordpress.com/2016/03/seq2seq.jpg)\n", "_(img: esciencegroup.files.wordpress.com)_\n", "\n", "Encoder-decoder architectures are about converting anything to anything, including\n", " * Machine translation and spoken dialogue systems\n", - " * [Image captioning](http://mscoco.org/dataset/#captions-challenge2015) and [image2latex](https://htmlpreview.github.io/?https://github.com/openai/requests-for-research/blob/master/_requests_for_research/im2latex.html) (convolutional encoder, recurrent decoder)\n", + " * [Image captioning](https://cocodataset.org/#captions-2015) and [image2latex](https://htmlpreview.github.io/?https://github.com/openai/requests-for-research/blob/master/_requests_for_research/im2latex.html) (convolutional encoder, recurrent decoder)\n", " * Generating [images by captions](https://arxiv.org/abs/1511.02793) (recurrent encoder, convolutional decoder)\n", " * Grapheme2phoneme - convert words to transcripts\n", - " \n", + "\n", "We chose simplified __Hebrew->English__ machine translation for words and short phrases (character-level), as it is relatively quick to train even without a gpu cluster." ] }, @@ -39,9 +39,9 @@ "source": [ "import sys\n", "if 'google.colab' in sys.modules:\n", - " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week07_seq2seq/basic_model_torch.py -O basic_model_torch.py\n", - " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week07_seq2seq/main_dataset.txt -O main_dataset.txt\n", - " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week07_seq2seq/voc.py -O voc.py\n", + " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week07_seq2seq/basic_model_torch.py -O basic_model_torch.py\n", + " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week07_seq2seq/main_dataset.txt -O main_dataset.txt\n", + " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week07_seq2seq/voc.py -O voc.py\n", " !pip3 install torch==1.0.0 nltk editdistance" ] }, @@ -74,10 +74,7 @@ "\n", "This is mostly due to the fact that many words have several correct translations.\n", "\n", - "We have implemented this thing for you so that you can focus on more interesting parts.\n", - "\n", - "\n", - "__Attention python2 users!__ You may want to cast everything to unicode later during homework phase, just make sure you do it _everywhere_." + "We have implemented this thing for you so that you can focus on more interesting parts." ] }, { @@ -150,7 +147,7 @@ "source": [ "### Building vocabularies\n", "\n", - "We now need to build vocabularies that map strings to token ids and vice versa. We're gonna need these fellas when we feed training data into model or convert output matrices into english words." + "We now need to build vocabularies that map strings to token ids and vice versa. We're gonna need these fellas when we feed training data into the model or convert output matrices into English words." ] }, { @@ -220,12 +217,12 @@ "* Encoder reads words character by character and outputs code vector (usually a function of last RNN state)\n", "* Decoder takes that code vector and produces translations character by character\n", "\n", - "Than it gets fed into a model that follows this simple interface:\n", - "* __`model(inp, out, **flags) -> logp`__ - takes symbolic int32 matrices of hebrew words and their english translations. Computes the log-probabilities of all possible english characters given english prefices and hebrew word.\n", - "* __`model.translate(inp, **flags) -> out, logp`__ - takes symbolic int32 matrix of hebrew words, produces output tokens sampled from the model and output log-probabilities for all possible tokens at each tick.\n", - " * if given flag __`greedy=True`__, takes most likely next token at each iteration. Otherwise samples with next token probabilities predicted by model.\n", + "Then it gets fed into a model that follows this simple interface:\n", + "* __`model(inp, out, **flags) -> logp`__ - takes symbolic int32 matrices of Hebrew words and their English translations. Computes the log-probabilities of all possible English characters given English prefixes and Hebrew word.\n", + "* __`model.translate(inp, **flags) -> out, logp`__ - takes symbolic int32 matrix of Hebrew words, produces output tokens sampled from the model and output log-probabilities for all possible tokens at each tick.\n", + " * if given flag __`greedy=True`__, takes most likely next token at each iteration. Otherwise, samples with next token probabilities predicted by model.\n", "\n", - "That's all! It's as hard as it gets. With those two methods alone you can implement all kinds of prediction and training." + "That's all! It's as hard as it gets. With those two methods alone, you can implement all kinds of prediction and training." ] }, { @@ -289,7 +286,7 @@ "source": [ "def translate(lines, max_len=MAX_OUTPUT_LENGTH):\n", " \"\"\"\n", - " You are given a list of input lines. \n", + " You are given a list of input lines.\n", " Make your neural network translate them.\n", " :return: a list of output lines\n", " \"\"\"\n", @@ -329,7 +326,7 @@ "### Scoring function\n", "\n", "LogLikelihood is a poor estimator of model performance.\n", - "* If we predict zero probability once, it shouldn't ruin entire model.\n", + "* If we predict zero probability once, it shouldn't ruin the entire model.\n", "* It is enough to learn just one translation if there are several correct ones.\n", "* What matters is how many mistakes model's gonna make when it translates!\n", "\n", @@ -545,9 +542,9 @@ "\n", "* __Train loss__ - that's your model's crossentropy over minibatches. It should go down steadily. Most importantly, it shouldn't be NaN :)\n", "* __Val score distribution__ - distribution of translation edit distance (score) within batch. It should move to the left over time.\n", - "* __Val score / training time__ - it's your current mean edit distance. This plot is much whimsier than loss, but make sure it goes below 8 by 2500 steps. \n", + "* __Val score / training time__ - it's your current mean edit distance. This plot is much whimsier than loss, but make sure it goes below 8 by 2500 steps.\n", "\n", - "If it doesn't, first try to re-create both model and opt. You may have changed it's weight too much while debugging. If that doesn't help, it's debugging time." + "If it doesn't, first try to re-create both model and opt. You may have changed its weight too much while debugging. If that doesn't help, it's debugging time." ] }, { @@ -584,7 +581,7 @@ "\n", "In this section you'll implement algorithm called self-critical sequence training (here's an [article](https://arxiv.org/abs/1612.00563)).\n", "\n", - "The algorithm is a vanilla policy gradient with a special baseline. \n", + "The algorithm is a vanilla policy gradient with a special baseline.\n", "\n", "$$ \\nabla J = E_{x \\sim p(s)} E_{y \\sim \\pi(y|x)} \\nabla log \\pi(y|x) \\cdot (R(x,y) - b(x)) $$\n", "\n", @@ -637,7 +634,7 @@ "\n", " # compute log_pi(a_t|s_t), shape = [batch, seq_length]\n", " logp_sample = \n", - " \n", + "\n", " # ^-- hint: look at how crossentropy is implemented in supervised learning loss above\n", " # mind the sign - this one should not be multiplied by -1 :)\n", "\n", @@ -727,11 +724,11 @@ "\n", "\n", " * As usual, don't expect improvements right away, but in general the model should be able to show some positive changes by 5k steps.\n", - " * Entropy is a good indicator of many problems. \n", + " * Entropy is a good indicator of many problems.\n", " * If it reaches zero, you may need greater entropy regularizer.\n", " * If it has rapid changes time to time, you may need gradient clipping.\n", " * If it oscillates up and down in an erratic manner... it's perfectly okay for entropy to do so. But it should decrease at the end.\n", - " \n", + "\n", " * We don't show loss_history cuz it's uninformative for pseudo-losses in policy gradient. However, if something goes wrong you can check it to see if everything isn't a constant zero." ] }, @@ -775,7 +772,7 @@ "source": [ "## Step 6: Make it actually work (5++ pts)\n", "\n", - "In this section we want you to finally __restart with EASY_MODE=False__ and experiment to find a good model/curriculum for that task.\n", + "In this section, we want you to finally __restart with EASY_MODE=False__ and experiment to find a good model/curriculum for that task.\n", "\n", "We recommend you to start with the following architecture\n", "\n", @@ -791,7 +788,7 @@ "input y_prev\n", "```\n", "\n", - "__Note:__ you can fit all 4 state tensors of both LSTMs into a in a single state - just assume that it contains, for example, [h0, c0, h1, c1] - pack it in encode and update in decode.\n", + "__Note:__ you can fit all 4 state tensors of both LSTMs into in a single state - just assume that it contains, for example, [h0, c0, h1, c1] - pack it in encode and update in decode.\n", "\n", "\n", "Here are some cool ideas on what you can do then.\n", @@ -800,13 +797,13 @@ "* You will likely need to adjust pre-training time for such a network.\n", "* Supervised pre-training may benefit from clipping gradients somehow.\n", "* SCST may indulge a higher learning rate in some cases and changing entropy regularizer over time.\n", - "* It's often useful to save pre-trained model parameters to not re-train it every time you want new policy gradient parameters. \n", + "* It's often useful to save pre-trained model parameters to not re-train it every time you want new policy gradient parameters.\n", "* When leaving training for nighttime, try setting REPORT_FREQ to a larger value (e.g. 500) not to waste time on it.\n", "\n", "__Formal criteria:__\n", - "To get 5 points we want you to build an architecture that:\n", + "To get 5 points, we want you to build an architecture that:\n", "* _doesn't consist of single GRU_\n", - "* _works better_ than single GRU baseline. \n", + "* _works better_ than single GRU baseline.\n", "* We also want you to provide either learning curve or trained model, preferably both\n", "* ... and write a brief report or experiment log describing what you did and how it fared.\n", "\n", @@ -815,7 +812,7 @@ " * __Vanilla:__ layer_i of encoder last state goes to layer_i of decoder initial state\n", " * __Every tick:__ feed encoder last state _on every iteration_ of decoder.\n", " * __Attention:__ allow decoder to \"peek\" at one (or several) positions of encoded sequence on every tick.\n", - " \n", + "\n", "The most effective (and cool) of those is, of course, attention.\n", "You can read more about attention [in this nice blog post](https://distill.pub/2016/augmented-rnns/). The easiest way to begin is to use \"soft\" attention with \"additive\" or \"dot-product\" intermediate layers.\n", "\n", @@ -823,8 +820,8 @@ "* Model usually generalizes better if you no longer allow decoder to see final encoder state\n", "* Once your model made it through several epochs, it is a good idea to visualize attention maps to understand what your model has actually learned\n", "\n", - "* There's more stuff [here](https://github.com/yandexdataschool/Practical_RL/blob/master/week8_scst/bonus.ipynb)\n", - "* If you opted for hard attention, we recommend [gumbel-softmax](https://blog.evjang.com/2016/11/tutorial-categorical-variational.html) instead of sampling. Also please make sure soft attention works fine before you switch to hard.\n", + "* There's more stuff [here](bonus_pytorch.ipynb)\n", + "* If you opted for hard attention, we recommend [gumbel-softmax](https://blog.evjang.com/2016/11/tutorial-categorical-variational.html) instead of sampling. Also, please make sure soft attention works fine before you switch to hard.\n", "\n", "### UREX\n", "* This is a way to improve exploration in policy-based settings. The main idea is that you find and upweight under-appreciated actions.\n", @@ -835,8 +832,8 @@ "\n", "### Some additional ideas:\n", "* (advanced deep learning) It may be a good idea to first train on small phrases and then adapt to larger ones (a.k.a. training curriculum).\n", - "* (advanced nlp) You may want to switch from raw utf8 to something like unicode or even syllables to make task easier.\n", - "* (advanced nlp) Since hebrew words are written __with vowels omitted__, you may want to use a small Hebrew vowel markup dataset at `he-pron-wiktionary.txt`.\n", + "* (advanced nlp) You may want to switch from raw utf8 to something like unicode or even syllables to make the task easier.\n", + "* (advanced nlp) Since Hebrew words are written __with vowels omitted__, you may want to use a small Hebrew vowel markup dataset at `he-pron-wiktionary.txt`.\n", "\n" ] }, diff --git a/week08_pomdp/README.md b/week08_pomdp/README.md index 8154b5b49..6bb589a2f 100644 --- a/week08_pomdp/README.md +++ b/week08_pomdp/README.md @@ -5,6 +5,7 @@ _Links on all articles mentioned during the lecture could be found in "Reference ## Basics * Our [lecture](https://yadi.sk/i/AHzpTjiT3U8L8e) and [seminar](https://yadi.sk/i/Ka-I7nBp3U8LAG) (russian) +* A Lecture on Basics by Pavel Shvechikov (english) [Video](https://www.youtube.com/watch?v=aV4wz7FAXmo) * A lecture on basics by Andrew NG (english, LQ) - [video](https://www.youtube.com/watch?v=yCqPMD6coO8) * A lecture on basics by 5vision (russian) - [video](https://www.youtube.com/watch?v=_dkaynuKUFE) * _[alternative]_ Chalkboard-style 2-part lecture by B. Ravindran. - [part1](https://www.youtube.com/watch?v=9G_KevA8DFY), [part2](https://www.youtube.com/watch?v=dMOUp7YzUpQ) diff --git a/week08_pomdp/atari_util.py b/week08_pomdp/atari_util.py index ae19e2ab3..11065cde6 100644 --- a/week08_pomdp/atari_util.py +++ b/week08_pomdp/atari_util.py @@ -1,14 +1,14 @@ import cv2 import numpy as np -from gym.core import Wrapper -from gym.spaces.box import Box +from gymnasium import Wrapper +from gymnasium.spaces import Box class PreprocessAtari(Wrapper): def __init__(self, env, height=42, width=42, color=False, crop=lambda img: img, n_frames=4, dim_order='pytorch', reward_scale=1): """A gym wrapper that reshapes, crops and scales image into the desired shapes""" - super(PreprocessAtari, self).__init__(env) + super().__init__(env) self.img_size = (height, width) self.crop = crop self.color = color @@ -18,7 +18,6 @@ def __init__(self, env, height=42, width=42, color=False, n_channels = (3 * n_frames) if color else n_frames obs_shape = { - 'theano': (n_channels, height, width), 'pytorch': (n_channels, height, width), 'tensorflow': (height, width, n_channels), }[dim_order] @@ -26,18 +25,19 @@ def __init__(self, env, height=42, width=42, color=False, self.observation_space = Box(0.0, 1.0, obs_shape) self.framebuffer = np.zeros(obs_shape, 'float32') - def reset(self): + def reset(self, **kwargs): """Resets the game, returns initial frames""" self.framebuffer = np.zeros_like(self.framebuffer) - self.update_buffer(self.env.reset()) - return self.framebuffer + state, info = self.env.reset(**kwargs) + self.update_buffer(state) + return self.framebuffer, info def step(self, action): """Plays the game for 1 step, returns frame buffer""" - new_img, r, done, info = self.env.step(action) + new_img, r, terminated, truncated, info = self.env.step(action) self.update_buffer(new_img) - return self.framebuffer, r * self.reward_scale, done, info + return self.framebuffer, r * self.reward_scale, terminated, truncated, info ### image processing ### diff --git a/week08_pomdp/env_pool.py b/week08_pomdp/env_pool.py index 2eda898b7..709dca407 100644 --- a/week08_pomdp/env_pool.py +++ b/week08_pomdp/env_pool.py @@ -1,5 +1,5 @@ """ -A thin wrapper for OpenAI gym environments that maintains a set of parallel games and has a method to generate +A thin wrapper for Farama gymnasium environments that maintains a set of parallel games and has a method to generate interaction sessions given agent one-step applier function. """ @@ -15,7 +15,7 @@ def __init__(self, agent, make_env, n_parallel_games=1): and is capable of some auxilary actions like evaluating agent on one game session (See .evaluate()). :param agent: Agent which interacts with the environment. - :param make_env: Factory that produces environments OR a name of the gym environment. + :param make_env: Factory that produces environments OR a name of the gymnasium environment. :param n_games: Number of parallel games. One game by default. :param max_size: Max pool size by default (if appending sessions). By default, pool is not constrained in size. """ @@ -25,17 +25,17 @@ def __init__(self, agent, make_env, n_parallel_games=1): self.envs = [self.make_env() for _ in range(n_parallel_games)] # Initial observations. - self.prev_observations = [env.reset() for env in self.envs] + self.prev_observations = [env.reset()[0] for env in self.envs] # Agent memory variables (if you use recurrent networks). self.prev_memory_states = agent.get_initial_state(n_parallel_games) - # Whether particular session has just been terminated and needs + # Whether particular session has just been terminated or truncated and needs # restarting. self.just_ended = [False] * len(self.envs) def interact(self, n_steps=100, verbose=False): - """Generate interaction sessions with ataries (OpenAI gym Atari environments) + """Generate interaction sessions with ataries (Farama gymnasium Atari environments) Sessions will have length n_steps. Each time one of games is finished, it is immediately getting reset and this time is recorded in is_alive_log (See returned values). @@ -46,9 +46,9 @@ def interact(self, n_steps=100, verbose=False): def env_step(i, action): if not self.just_ended[i]: - new_observation, cur_reward, is_done, info = \ + new_observation, cur_reward, terminated, truncated, info = \ self.envs[i].step(action) - if is_done: + if terminated or truncated: # Game ends now, will finalize on next tick. self.just_ended[i] = True @@ -58,7 +58,7 @@ def env_step(i, action): else: # Reset environment, get new observation to be used on next # tick. - new_observation = self.envs[i].reset() + new_observation = self.envs[i].reset()[0] # Reset memory for new episode. initial_memory_state = self.agent.get_initial_state( diff --git a/week08_pomdp/homework_common_part2.ipynb b/week08_pomdp/homework_common_part2.ipynb deleted file mode 100644 index ec4766342..000000000 --- a/week08_pomdp/homework_common_part2.ipynb +++ /dev/null @@ -1,307 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### This is a common homework assignment for both frameworks\n", - "\n", - "This week's assignment appears to be unusually grandeur, so please read submission/grading guidelines before you upload it for review.\n", - "\n", - "__Submisson__: To ease mutual pain, please submit\n", - "- Some kind of readable report with links to your evaluations, gym uploads, investigation results, etc.\n", - "- Explicitly state that you took on a bonus task and where to find it [to make sure it is found and graded].\n", - "\n", - "__Grading__: The main purpose (and source of points) for this notebook is your investigation, not squeezing out average rewards from random environments. \n", - "\n", - "Getting near/above state of the art performance on one particular game will earn you some bonus points, but you can get much more by digging deeper into what makes the algorithms tick and how they compare to one another.\n", - "\n", - "Okay, now brace yourselves, here comes an assignment!\n", - "\n", - "#### 7.2 Deep kung-fu (3 pts)\n", - "\n", - "Implement and train recurrent actor-critic on `KungFuMaster-v0` env in the second notebook. Try to get a score of >=20k.\n", - "\n", - "__[bonus points]__ +1 point per each +5k average reward over 20k baseline (25k = +1, 30k = +2, ...)\n", - "\n", - "\n", - "#### 7.3 Comparing what we know (7+ pts)\n", - "\n", - "_Please read this assignment carefully._\n", - "\n", - "Choose a partially-observable environment for experimentation out of [atari](https://gym.openai.com/envs#atari), [doom](https://gym.openai.com/envs#doom) or [pygame](https://gym.openai.com/envs#pygame) catalogue (if you really want to try some other pomdp, feel free to proceed at your own risk).\n", - "\n", - "Not all Atari environements are bug free and these minor bugs can hurt learning performance. \n", - "We recommend to pick one of those:\n", - "* [Assault-v0](https://gym.openai.com/envs/Assault-v0) \n", - "* [DoomDefendCenter-v0](https://gym.openai.com/envs/DoomDefendCenter-v0) (use env code from [this](https://github.com/yandexdataschool/Practical_RL/blob/master/week4/Seminar4.2_conv_agent.ipynb) notebook)\n", - "* [RoadRunner-v0](https://gym.openai.com/envs/RoadRunner-v0)\n", - "\n", - "Unless you have aesthetical preference, we would appreciate if you chose env out of recommended ones by `random.choice`.\n", - "\n", - "__Your task__ is to implement DRQN and A3C (seminar code may be reused) and apply them __both__ to the environement of your choice. Then compare them on the chosen game (convergence / sample efficiency / final performance).\n", - "\n", - "\n", - "* It's probably a good idea to compare a3c vs q-learning with similar network complexity. \n", - "* Also remember that you can only use large experience replay for 1-step q-learning\n", - "\n", - "\n", - "__Tips__:\n", - "Your new environment may require some tuning before it gives up to your agent:\n", - "\n", - "\n", - "* Different preprocessing. Mostly cropping.\n", - " * In some cases, even larger screen size or colorization. \n", - " * View resulting image to figure that out.\n", - "\n", - "\n", - "* Reward scaling. \n", - " * Kung-fu used `rewards=replay.rewards/100.` because you got +100 per success.\n", - " * Just avoid training on raw +100 rewards or it's gonna blow up mean squared error.\n", - "\n", - "\n", - "* Deterministic/FrameSkip\n", - " * For doom/pygame/custom, use frameskip to speed up learning\n", - " * ```from gym.wrappers import SkipWrapper```\n", - " * ```env = SkipWrapper(how_many_frames_to_skip)(your_env)``` in your make_env\n", - " \n", - " * For Atari only, consider __training__ on deterministic version of environment\n", - " * Works by appending Deterministic to env name: `AssaultDeterministic-v0`, `KungFuMasterDeterministic-v0`\n", - " * Expect faster training due to less variance.\n", - " * You still need to __switch back to normal env for evaluation__ (there's no leaderbord for deterministic envs)\n", - "\n", - "* Knowledge transfer\n", - " * If you want to switch network mid-game, you are recommended to use some pre-trained layers\n", - " * At minimum, save convolutional weights and re-use them in every new architecture using fine-tuning\n", - " * At it's darkest, [soft-targets](http://www.kdnuggets.com/2015/05/dark-knowledge-neural-network.html), [policy distillation](https://arxiv.org/pdf/1511.06295.pdf), [net2net](https://arxiv.org/abs/1511.05641) or similar __[bonus points]__.\n", - "\n", - "\n", - "\n", - "#### For the curious\n", - "- __[4+ bonus points]__ Implement attentive model for DQRN/A3C (see lecture slides for implementation details). How does it compare to the vanilla architecture? \n", - "* __[2+ bonus points]__ If you have any q-learning modiffications from week5 (double q-l, prioritized replay, etc.), they are most welcome here!\n", - "* __[2+ bonus points]__ How different memory amounts and types (LSTM / GRU / RNN / combo / custom) affects DRQN / A2C performance? Try to find optimal configuration.\n", - "- __[2+ bonus points]__ No one said l2 loss is perfect. Implement Huber or MAE loss for DRQN and/or A2C critic and compare it's performance on the game of your choice (pass proper `loss_function` to `get_elementwise_objective()`) .\n", - "- __[1++ bonus points]__ Does it help to add recurrent units when in MDP scenario, e.g fully observable \"CartPole-v0\"? How about if you only give it access to position observations? Only speed observations? Try that out!\n", - "- __[4+ bonus points]__ See the very end of this notebook. Some of the games (right side) benefit a lot from additional LSTM memory. But others (left side) do not. That is interesting. Pick up one or several games from the left side and try to figure out why A2C performance decreases when adding LSTM to feadforward architecture?\n", - "\n", - "#### Bonus: Neural Maps (a LOT of points if successful)\n", - "\n", - "Pick up either [DoomMyWayHome-v0](https://gym.openai.com/envs/DoomMyWayHome-v0) or [RaycastMaze-v0](https://gym.openai.com/envs/RaycastMaze-v0) and apply Neural Map to it. Main details of Neural Map are given in lecture slides and you could also benefit from reading [Neural Map article](https://arxiv.org/abs/1702.08360). \n", - "\n", - "[hse/ysda] Feel free to ask Pavel Shvechikov / Fedor Ratnikov any questions, guidance and clarifications on the topic.\n", - "\n", - "This block is highly experimental and may be connected with some additional difficulties compared to main track. With some brief description of you work you could get additional points\n", - "\n", - "_Scoring points are not pre-determined for this task because we're uncertain of implementation complexity._\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "__You can use the following template for DRQN implementation or throw it away entirely__" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "N_ACTIONS = env.action_space.n\n", - "OBS_SHAPE = env.observation_space.shape\n", - "OBS_CHANNELS, OBS_HEIGHT, OBS_WIDTH = OBS_SHAPE\n", - "\n", - "N_SIMULTANEOUS_GAMES = 2 # this is also known as number of agents in exp_replay_pool\n", - "MAX_POOL_SIZE = 1000\n", - "REPLAY_SIZE = 100\n", - "SEQ_LENGTH = 15\n", - "\n", - "N_POOL_UPDATES = 1\n", - "EVAL_EVERY_N_ITER = 10\n", - "N_EVAL_GAMES = 1\n", - "\n", - "N_FRAMES_IN_BUFFER = 4 # number of consequent frames to feed in CNN" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "observation_layer = InputLayer((None,) + OBS_SHAPE)\n", - "prev_wnd = InputLayer((None, N_FRAMES_IN_BUFFER) + OBS_SHAPE)\n", - "new_wnd = WindowAugmentation(observation_layer, prev_wnd)\n", - "wnd_reshape = reshape(\n", - " new_wnd, [-1, N_FRAMES_IN_BUFFER * OBS_CHANNELS, OBS_HEIGHT, OBS_WIDTH])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "conv1 = Conv2DLayer(wnd_reshape, num_filters=32, filter_size=(8, 8), stride=4)\n", - "conv2 = Conv2DLayer(conv1, num_filters=64, filter_size=(4, 4), stride=2)\n", - "conv3 = Conv2DLayer(conv2, num_filters=64, filter_size=(3, 3), stride=1)\n", - "dense1 = DenseLayer(conv3, num_units=512)\n", - "qvalues_layer = DenseLayer(dense1, num_units=N_ACTIONS, nonlinearity=None)\n", - "action_layer = EpsilonGreedyResolver(qvalues_layer)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "targetnet = TargetNetwork(qvalues_layer)\n", - "qvalues_old_layer = targetnet.output_layers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "agent = Agent(observation_layers=observation_layer,\n", - " policy_estimators=(qvalues_layer, qvalues_old_layer),\n", - " action_layers=action_layer,\n", - " agent_states={new_wnd: prev_wnd})\n", - "pool = EnvPool(agent, make_env=make_env,\n", - " n_games=N_SIMULTANEOUS_GAMES, max_size=MAX_POOL_SIZE)\n", - "replay = pool.experience_replay.sample_session_batch(REPLAY_SIZE)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# .get_sessions() returns env_states, observations, agent_states, actions, policy_estimators\n", - "(qvalues_seq, old_qvalues_seq) = agent.get_sessions(\n", - " replay, session_length=SEQ_LENGTH, experience_replay=True)[-1]\n", - "elwise_mse_loss = qlearning.get_elementwise_objective(\n", - " qvalues_seq,\n", - " replay.actions[0],\n", - " replay.rewards,\n", - " replay.is_alive,\n", - " qvalues_target=old_qvalues_seq,\n", - " gamma_or_gammas=0.999,\n", - " n_steps=1\n", - ")\n", - "loss = elwise_mse_loss.sum() / replay.is_alive.sum()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "weights = lasagne.layers.get_all_params(action_layer, trainable=True)\n", - "updates = lasagne.updates.adam(loss, weights, learning_rate=1e-4)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "train_step = theano.function([], loss, updates=updates)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "***\n", - "***\n", - "***" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### A3C feadforward vs A3C LSTM on Atari games" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "a3c_ff = [518.4, 263.9, 5474.9, 22140.5, 4474.5, 911091.0, 970.1, 12950.0, 22707.9, 817.9, 35.1, 59.8, 681.9, 3755.8, 7021.0, 112646.0, 56533.0, 113308.4, -0.1, -82.5, 18.8, 0.1, 190.5, 10022.8, 303.5, 32464.1, -2.8, 541.0, 94.0,\n", - " 5560.0, 28819.0, 67.0, 653.7, 10476.1, 52894.1, -78.5, 5.6, 206.9, 15148.8, 12201.8, 34216.0, 32.8, 2355.4, -10911.1, 1956.0, 15730.5, 138218.0, -9.7, -6.3, 12679.0, 156.3, 74705.7, 23.0, 331628.1, 17244.0, 7157.5, 24622.0]\n", - "a3c_lstm = [945.3, 173.0, 14497.9, 17244.5, 5093.1, 875822.0, 932.8, 20760.0, 24622.2, 862.2, 41.8, 37.3, 766.8, 1997.0, 10150.0, 138518.0, 233021.5, 115201.9, 0.1, -82.5, 22.6, 0.1, 197.6, 17106.8, 320.0, 28889.5, -1.7, 613.0,\n", - " 125.0, 5911.4, 40835.0, 41.0, 850.7, 12093.7, 74786.7, -135.7, 10.7, 421.1, 21307.5, 6591.9, 73949.0, 2.6, 1326.1, -14863.8, 1936.4, 23846.0, 164766.0, -8.3, -6.4, 27202.0, 144.2, 105728.7, 25.0, 470310.5, 18082.0, 5615.5, 23519.0]\n", - "game_names = \"Alien Amidar Assault Asterix Asteroids Atlantis Bank Battle Beam Berzerk Bowling Boxing Breakout Centipede Chopper Crazy Defender Demon Double Enduro Fishing Freeway Frostbite Gopher Gravitar H.E.R.O. Ice James Kangaroo Krull Kung-Fu Montezuma's Ms. Name Phoenix Pit Pong Private Q*Bert River Road Robotank Seaquest Skiing Solaris Space Star Surround Tennis Time Tutankham Up Venture Video Wizard Yars Zaxxon\".split(\n", - " \" \")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "score_difference = np.array(a3c_lstm) - np.array(a3c_ff)\n", - "idxs = np.argsort(score_difference)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\nIYQQQgghuizVFNj6A+Oz24cA7wDrEIpup+XkSwghhBBCCCGEEEKILkE1BbaewMfZ7T2Bv7j7QuAR\nQqFNZJx99tk1qZW3XirelDO+XirelDO+XirelDO+XirelDO+XirelDO+XirelDO+XireajmnaE41\nBbaXgQPMbC1gL6Aw79qqwEd5GesOrL322jWplbdeKt6UM75eKt6UM75eKt6UM75eKt6UM75eKt6U\nM75eKt6UM75eKt7y1Jo3D9ZYI9/zJhZRzSIHhwC3AD2Af7r717P284Cd3H2f3F12ElrkQAghhBBC\nCCGEEF2duXPhueegsXHR9t//wm23QV1dbHddh0oWOVi6UnF3v93MJgB9gaeLHrofuKNSPSGEEEII\nIYQQQghRHXPnwrPPtiymzZ0LSy0FG28MAwbAkUfCZpvFdtt9qbjABuDub5vZCsDXzewhd58NPO6V\ndofrBMzsNeADwIH33X33uI6EEEIIIYQQQgghKufTT1sW0555ZlExbZNNQjHtW98KP7fcEnr1iu06\nDSqeg83MepvZ/cCLwN2EnmwA15vZZXmay4mFwCB336qzi2uTJk2qSa289VLxppzx9VLxppzx9VLx\nppzx9VLxppzx9VLxppzx9VLxppzx9VLw5g5//vMkrr0Wjj8+FMw+/3kYOBBOOgn+/W/46lfhl7+E\nhx+Gjz4Kxbff/x5OOw22375lcS3v8yaKcPeKNuAm4B5gTcJqoutl7XsBz1Wq19EbMBno1cZ9+wPe\n2NjoeVBXV5eLTt5aeeul4k054+ul4k054+ul4k054+ul4k054+ul4k054+ul4k054+t1d2/z57sf\ncYQ71HmPHu6bb+4+ZIj7lVe6//vf7rNmxfOWEo2NjU4YEdnfW6sptbZDiyfA28AW2e3iAtt6wCeV\n6nX0BrwKNAKPAke0sm+uBbYpU6bkopO3Vt56qXhTzvh6qXhTzvh6qXhTzvh6qXhTzvh6qXhTzvh6\nqXhTzvh63dnbggXuxxzj3qOH+69+NcWbmnIy5vmft+5OJQW2alYR/TgTfim7vYW7v2pmA4Fx7t67\n0l50iznOjsDZwADCMNQD3H1syT6nAEOBPoQFF77n7o+X7NPX3aeZWR/gPuAwd392McfUKqJCCCGE\nEEIIIYSIgnsY/jlyJPzxj3DEEbEdpU0lq4hWPAcbMB44uui+m9lSwDnAA1XoLY5ewFPAyYRqYTPM\n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\n1sBS7v5oSfu2wAJ3fyIvc0IIIYQQQgghhBCxmTULnnxyUSHtiSfgxRfDYyusAAMGwMEHw8CBsM8+\nsOKKcf2KzqeaRQ7+D1i9TPsa2WMio76+via18tZLxZtyxtdLxZtyxtdLxZtyxtdLxZtyxtdLxZty\nxtdLxZtyxtfrSG9z5sBjj8H//R8MGQKbbRaGeu64I5x3HkyeHBYwuOkmeP55+OADePBB+OUv4bDD\n4Fvf6ho5Rb70aGhoqOgJw4cPvxwY1tDQ8EFJ+xzgwoaGhp/lZ69zGT58eF/ghBNOOIG+ffu2W693\n797069ev/cZy1spbLxVvyhlfLxVvyhlfLxVvyhlfLxVvyhlfLxVvyhlfLxVvyhlfLy+tjz4K86ZN\nndqbO+7ox7BhcMYZMHJkGOZpBoMGwQknwEUXweWXw3HHhV5qW2wBq6wCS5V0XarFnB2l192ZNm0a\nI0eOBBjZ0NAwbUn7VrOK6HvAfu7+n5L2rwF/c/cuO8pYq4gKIYQQQgghhBDdhzlzYMqU0Ous3Pb+\n+2G/Hj3C3GkDB4Zt661Dz7XllovrX8SlQ1cRBe4FfmZm+7v7hwBm9kXgYuAfVegJIYQQQgghhBBC\nVMz8+fDGG82LZq+9tuj2W28t2nfppWHttWHddWGrreCgg8Lt9dYLxbSePaPFEN2AagpsQ4GHgClm\n9mTWtiXwDvCtvIwJIYQQQgghhBCia7NwIUybBq++Ch9/DPPmwdy5zX+Wa2vtsZkzQwHt9ddDkQ3C\ncM7VV19UNNt993C7sK2xRuipJkRHUPEiB+7+JrA5cA7wPNAInA5s5u6v52uvazNmzJia1MpbLxVv\nyhlfLxVvyhlfLxVvyhlfLxVvyhlfLxVvyhlfLxVvytmcefPg5Zdh3Di46io46yzYf3/46lehVy9Y\nc03YaSf4xjfGcMABcOihcOSRYQGB44+HM8+EH/0ILr4YRoyA666DW2+FsWPh/vvhkUfgv/8NRbq3\n34ZPPoE5c8bwzW/CFVfAPffA//4Hs2eH3mzjx4cFCIYPh2OOgZ13Dj3XllRc6+rXIJaeWEQ1q4ji\n7rPcfaS7n+LuQ939Jnefl7e5rs6oUaNqUitvvVS8KWd8vVS8KWd8vVS8KWd8vVS8KWd8vVS8KWd8\nvVS8pZhz1ix45hkYMwYuuwxOOgn23BP69YPPfQ422AD23jssEPC3v4Wi2667ws9+BnfdFRYSqKsb\n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\nO1CYl82y+yM6w0NbWHvttWtSK2+9VLwpZ3y9VLwpZ3y9VLwpZ3y9VLwpZ3y9VLwpZ3y9vLQ+/RTe\new969lyb556DOXOab7Nnt2wrtxXv9/zza/OXv4QhnJ980vx4ZtC7N6y6Kqy2Wvi56aaLbpf+vOGG\ntfne93KJCtTmNchbK2+9VLzVck7RnIpXETWzc4FhwG+Bx7LmbYFjgR+7+yW5GDPrBawPGDAROAt4\nAHjf3V83s0MJPdZOzHycCRwCbOzu06s8phY5EEIIIYQQQogccYcPPwxDKKdPX/Sz+HZp28cft11/\nueVg+eUXbZ/7XPP7yy8f9llppZaFssLtlVeGpavpfiKE6NZ0xCIHn+Hul5jZq8DpwFFZ8wvAEHcf\nXaneEhhIKKgVuuNdlrX/HjjW3Ueb2crARYS5354C9qq2uCaEEEIIIYQQou3MnQtvvglTp8Lrr4ef\nb73Vslg2YwbMm9fy+V/8IqyySthWXhk22yz8LLR96UvQq9eSC2fLLhsWFBBCiNhUVGAzsx6EoaD3\n5lxMa4G7/4tWFmFw96vovJVLhRBCCCGEECIJ3MNQykLhrLiIVvj59tthvwK9e4eVMgsFsk02aV5A\nK/7Zuzcss0y8fEIIkTcV1frdfQFwL7BSx9jpXpSualErWnnrpeJNOePrpeJNOePrpeJNOePrpeJN\nOePrpeJNOSvnscfgoosmccEFcMwxsNtusP76obdYnz6w9dZw8MFhlcy//hU++AC+8hU4/nj47W/h\n3nth0qQwp9mMGTB69CTuvx9uvRWuvBKGDYOTT4ZDD4Vddw291Pr0aXtxrVbPm15r8fVS8VbLOUUJ\nra2CULoBTwC7V/q8rrCR8yqidXV1uejkrZW3XirelDO+XirelDO+XirelDO+XirelDO+XirelLPt\nPPec+777FlbFrPM113QfNMh98GD3oUPdR4xwHzPGvbHRffp094ULO89bR+nVqlbeerWqlbdeKt5q\nOWcKVLKKaDVFqL2BJ4H9gL7AF4q3SvVqacu7wDZlypRcdPLWylsvFW/KGV8vFW/KGV8vFW/KGV8v\nFW/KGV8vFW/K2TrvvON+0knuPXq4r7uu++jR7i+/XBveOlqvVrXy1qtVrbz1UvFWyzlToJICWzWr\niC4s7gBX/FDoEOc9KutDVztoFVEhhBBCCCFEd2TOHPj1r+Hii8OiABdcAKeeGlbXFEIIUZ4OXUUU\n2LUqV0IIIYQQQgghOpWFC8N8aOedF1b4PPlkuPDCsMiAEEKI/Ki4wOZhdU8hhBBCCCGEEDXMww/D\nWWeFhQwOOAD+8Q/YcMPYroQQontS0SqixZhZTzPb2Mw2L97yNNfVufTSS2tSK2+9VLwpZ3y9VLwp\nZ3y9VLwpZ3y9VLwpZ3y9VLwpZ+CVV+CQQ2CHHWD+fHjwQbjjjsUX12o1Z956taqVt16tauWtl4q3\nWs4pmlNxDzYzWwX4HbDPYnbpsnOw5U1TU1NNauWtl4o35Yyvl4o35Yyvl4o35Yyvl4o35Yyvl4q3\n1HPOnAk//jFceSWsthrcdBMceWSYcy22t1rQq1WtvPVqVStvvVS81XJO0ZxqFjm4GVgHOAN4EDgQ\nWA34EfB9d/9bzh47DS1yIIQQQgghhOhqzJ0LV10FF10Ubp93Hpx5JvTsGduZEEJ0bTp6kYPdgP3d\n/YlsRdEp7v4PM/sIOA/osgU2IYQQQgghhOgquMOYMXDOOfDqq/Cd74QiW58+sZ0JIUR6VDMHWy/g\n3ez2TGCV7PYzgLp9CSGEEEIIIUQH88QTsMsucNBB0K8fPP00jByp4poQQsSimgLb/4CNsttPAyeY\n2RrAicC0vIx1B2bMmFGTWnnrpeJNOePrpeJNOePrpeJNOePrpeJNOePrpeIthZzPPQff/OYMtt4a\n3nsP/v53uOce+OpX43vLWytvvVrVyluvVrXy1kvFWy3nFM2ppsD2G6Bvdns4YbGDqcBpwA9z8tUt\nOPbYY2tSK2+9VLwpZ3y9VLwpZ3y9VLwpZ3y9VLwpZ3y9VLx115xz5sDNN8OOO4ZC2l13Hcu118JT\nT8Hee8f11pFaeevVqlbeerWqlbdeKt5qOacowd3btQE9CUNDV26vVuwty+GNjY2eB3np5K2Vt14q\n3pQzvl4q3pQzvl4q3pQzvl4q3pQzvl4q3rpbzhdfdB861L13b3dw320399Gj3R95pHvl7Cy9WtXK\nW69WtfLWS8VbLedMgcbGRgcc6O+t1JSqWUV0PXd/Nd8yX22gVUSFEEIIIYQQMZk3D8aOhWuugfvu\ngy99CY45Bk44ATbcMLY7IYRIi45eRfRlM3sD+BfwIPAvd3+5Ch0hhBBCCCGEEMCUKfDb38L118Pb\nb8P228Mf/gCHHALLLx/bnRBCiNaopsC2FrALsDNwDvBbM3uLUHB7wN2vy8+eEEIIIYQQQnRPFiwI\nixRccw3cfTessAIcfXTorbbZZrHdCSGEqISKFzlw9zfd/WZ3P97dNyKsKHofcChwbd4GuzLXX399\nTWrlrZeKN+WMr5eKN+WMr5eKN+WMr5eKN+WMr5eKt66Sc9o0+MlPYN11oa4u9FgbORLeeguuvLL1\n4lpXyVlrerWqlbderWrlrZeKt1rOKZpTcYHNzHqa2Z5mdrGZ/Rv4L7AFcCVwUN4GuzITJy5xeG40\nrbz1UvGmnPH1UvGmnPH1UvGmnPH1UvGmnPH1UvFWyzkbGydy331hyOfaa8PPfgZ77gmPPw5PPAHf\n/W7owdbZvvLWS8WbcsbXS8VbLecUzalmkYO5wEzgZsIcbOPdfWb+1jofLXIghBBCCCFEusyeDa+9\nBpMnhznR5syBhQvDtmDBotul91t7bMECePBBePll2HRTOOkkOOooWHHF2ImFEEIsiY5e5OBuYAfg\nMKAP0MfMHnT3F6vQEkIIIYQQQohOYcECeOONUEArbK++uuj2tGmL9u3RIywu0KMHLLVU2Cq9XXx/\n0CC48Ub42tfALNopEEII0UFUXGBz9wMAzGxzwkIHewI/NrP5wIPufmS+FoUQQgghhBCiddzhvfea\nF82Ki2hTp8K8eYv2X311WG896NcP9tgjzIm23nrh5+qrh+KYEEII0Raq6cFW4Jns+csCywN7AYOB\nmimwmdmKhAUYehC8jtAqp0IIIYQQQnQvpk2DhgYYNQo+/nhR+xe/uKhoduCB4Xbh/jrrhB5qQggh\nRB5Us8jBWWY2FngPeBQ4HHgROBhYJV977eYjYEd37w9sC/zQzFbqrIPX19fXpFbeeql4U874eql4\nU874eql4U874eql4U874et3V20cfwQUXwPrrw+23Q9++9dx+O0ycCDNnhm3ixPDYL34BJ58M++wD\nG23UtuJareTsSK289VLxppzx9VLxVss5RXN6NDQ0VPSE4cOHjwAmApcDp7r7FQ0NDeMaGhr+19DQ\nMKcDPFZNQ0MDDQ0N8wGGDx/+BeB44LcNDQ2zy+0/fPjwvsAJJ5xwAn379m338Xv37k2/fv3arZO3\nVt56qXhTzvh6qXhTzvh6qXhTzvh6qXhTzvh63c3b3Llw1VVw8MFh8YDTT4fRo2GLLXpTV9ePvn3z\n6Z0WO2dnaOWtl4o35Yyvl4q3Ws6ZAtOmTWPkyJEAIxsaGqYtad+KVhE1s6WBHwI3uPsb7XLZSWTD\n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\nmj3tDeArbb5tY+CxEvuIiETj2Wdh0aL8t4eKiIiIiIhIxyr5GWxzSBa0SmJmd5nZuWb2V8B1cMrp\nwBVmdp2ZNQEnAi3A+DbnPA583Tk32Dm3HrAfcHepnYrV0NCQyizfebF005zh82LploY558yBddeF\nPfYoP2t10jBnV2T5zktrlu+8tGb5zoulm+YMnxdLN80ZPi+WbpozfF4s3dI8p7RjZhW5Ae8DW3jK\nagUybe73Bj5peyx7/BrgtnbHDgReBF4Cju/kcYYD1tjYaD5UV1d7yfGd5Tsvlm6aM3xeLN3SMOde\ne5llMn6yVicNc3ZFlu+8tGb5zktrlu+8WLppzvB5sXTTnOHzYummOcPnxdItzXPGoLGx0Uj2Ixhu\nna1ddXZCqbcKL7ANzh7bud15tcCjZTzOcMD69OljAwcOtOHDh1t1dbVVV1fbLrvsYrfddlveP+i7\n7767w7+cJ510kl155ZXW3Nyc96RUV1fbkiVL8s4999xz7Te/+U3esQULFlh1dbW98MILnx5rbm62\nyy67zM4888y8c5ubm626utoeeuihvOM33HCD/eAHP1il2xFHHGG33XZbXrfO5mirozmam5sLnsPM\nOp2jbbfO5mirozmam5sLnsNszc/H/Pnzi5qjrY7maG5uLngOszU/HwsWLCh4js6ej+bm5pL/XnU0\nR9vns7M5Ons+mpubS/571dEc7buV83w0NzeX/XOem+PUU08tao722s/R3Nxc1N+r++9vNKi2iy9e\ndY7zzjuv4Dk6ez5y//zL/TnPzTFjxoy8Y+U8H7luvn7v3njjjQXP0dnPR66bj9+7BxxwgJef87aZ\nhc6Rs7o5DjjgAC8/5217FTpHzurmOOCAA8r+Oc/Nkevm6/fuAQccUPAcnT0fuW4+fu9effXVXn7O\nc3Pkuvn4vfvb3/42la+vzMx+/vOfp/L1lZnZhAkTvLy+euGFF/K6pen11ZIlS/K6lft7d8mSJal8\nfWVm1tTUlMrXV2ZmDQ0NXl5fnXnmmXnduvr1VWfPR9tu5f7ebW5uTuXrq1y3NL6+ynXw9e+1c+fO\nLXiOrnx9VYl/ry10jhxfc/h6ndjWLrvsYjvttJNVV1fb8OHDbeDAgdavX7+CF9gK3kW0WM6594Ht\nzezVTs47Crgie9eA/c3s4XbntNJmkwPn3GBgEVBlZo+1Oa8W2NPMqkrsrF1ERSR6t9wChx0G//43\nbLpp6DYiIiIiIiJhVGoX0Ur5KzCvzf1FBXzPUmAlMLDd8YHAm556iYhEac4c2GYbLa6JiIiIiIgU\nqpKbHBR0aZyZNZvZq21une46amafAI3A3rljzjmXvf9IqYVFRGJnliywHXBA6CYiIiIiIiLdRyUX\n2Dra+bPwb3ZuXefc9s65YdlDW2Tvb5K9fwlwgnPuWOfc1sAfgb4kGx2kwuTJk1OZ5Tsvlm6aM3xe\nLN1CzvnMM/DGG7D//uVndSaW59N3XlqzfOelNct3XizdNGf4vFi6ac7webF005zh82LpluY5JV/B\nbxF1zn0e2Be4z8zeb/e19YFRwD1m9iGAmfUrs9uOwH0kV8IZMC17/FpgvJnd5JwbAJxH8tbQp4Bv\nm9mSMh/XmyFDhqQyy3deLN00Z/i8WLqFnHPOHFh3Xdh99/KzOhPL8+k7L61ZvvPSmuU7L5ZumjN8\nXizdNGf4vFi6ac7webF0S/Ockq/gTQ6cc6eS7OS592q+/jdgrpnVeuzXpbTJgYjEbq+94ItfhPr6\n0E1ERERERETCKmaTg2LeIno0cOkavn4pcGgReSIikiLvvgsPP7z6t4eKiIiIiIhIx4pZYNsSeHoN\nX38me46IiHRDc+fCypVaYBMRERERESlWMQtsawMbreHrG1HEZ7rFoKmpKZVZvvNi6aY5w+fF0i3U\nnHPmwLbbwpo+lqEnzNnVWb7z0prlOy+tWb7zYummOcPnxdJNc4bPi6Wb5gyfF0u3NM8p7ZhZQTdg\nHvCzNXz958C8QvPSeAOGA9bY2Gg+VFdXe8nxneU7L5ZumjN8XizdQszZ2mo2eLDZmWeWn1WoWJ5P\n33lpzfKdl9Ys33mxdNOc4fNi6aY5w+fF0k1zhs+LpVua54xBY2NjbuPN4dbZmlJnJ9hni08TgA+A\nAzv4WnX2axMKzUvjzfcC24IFC7zk+M7ynRdLN80ZPi+WbiHmfPLJ5P8R/v738rMKFcvz6TsvrVm+\n89Ka5Tsvlm6aM3xeLN00Z/i8WLppzvB5sXRL85wxKGaBreBdRAGcc38GjgKagBezh7cGtgJuMrMj\nS76ULgW0i6iIxOrXv4YLL4T//Af69AndRkREREREJLxK7SKKmR0DfA94iWRR7WskC21HdvfFNRGR\nmM2ZA3vvrcU1ERERERGRUhS9KYGZ3QTcVIEuIiISwDvvwCOPwIwZoZuIiIiIiIh0T0VdwdYR59xA\n59wa9pyLV21tbSqzfOfF0k1zhs+LpVtXzzl3LqxcCfvvX35WMWJ5Pn3npTXLd15as3z65Q2hAAAg\nAElEQVTnxdJNc4bPi6Wb5gyfF0s3zRk+L5ZuaZ5T8hW8wOac6+ec+7NzboFz7lrnXB/n3O+BxcBr\nzrkHnHPrV65q99PS0pLKLN95sXTTnOHzYunW1XPOmQNf/zpsskn5WcWI5fn0nZfWLN95ac3ynRdL\nN80ZPi+WbpozfF4s3TRn+LxYuqV5TslX8CYHzrnpwD7ADOAQ4F1gKHAi0Av4A1BvZmdXpmrlaZMD\nEYmNGWy8MRxzDFx0Ueg2IiIiIiIi6VHMJgfFfAbbd4HjzOw+59wtwP8BGTN7GMA591NgGtBtF9hE\nRGLz9NOweHFhbw8VERERERGRjhXzGWxfAl4BMLM3gOUku4nmPAcU8AYjERFJizvvhPXWg912C91E\nRERERESk+ypmge0/wEZt7v8VeKfN/fWAj3yU6imWLl2ayizfebF005zh82Lp1pVzzpkD++wDffqU\nn1WsWJ5P33lpzfKdl9Ys33mxdNOc4fNi6aY5w+fF0k1zhs+LpVua55R8xSywPQPslLtjZkeZ2dtt\nvr4T8IKvYj3B+PHjU5nlOy+WbpozfF4s3bpqznfegUcfhQMOKD+rFLE8n77z0prlOy+tWb7zYumm\nOcPnxdJNc4bPi6Wb5gyfF0u3NM8p7ZhZQTdgQ+ALa/j6/sCoQvPSeAOGA9bY2Gg++MrxneU7L5Zu\nmjN8XizdumrOm24yA7PXXy8/qxSxPJ++89Ka5TsvrVm+82LppjnD58XSTXOGz4ulm+YMnxdLtzTP\nGYPGxkYDDBhunawpFbyLaCGcc98ws+e8BXYx7SIqIjEZNw6eeAKefTZ0ExERERERkfQpZhfRYt4i\n2iHnXD/n3ATn3OPA0+XmiYhI5bW2wl13afdQERERERERH0peYHPO7emcuxZYDJwJ3Avs4quYiIhU\nztNPw5tvFvf5ayIiIiIiItKxohbYnHODnHNnOedeBm4G3gM+BxxkZmeZ2T8qUbK7qqurS2WW77xY\numnO8HmxdOuKOe+8E/r1g912Kz+rVLE8n77z0prlOy+tWb7zYummOcPnxdJNc4bPi6Wb5gyfF0u3\nNM8p+QpeYHPO/T/gReCbwGnAl83s5EoV6wnmz1/j23ODZfnOi6Wb5gyfF0u3rphzzhzYZx/o3bv8\nrFLF8nz6zktrlu+8tGb5zoulm+YMnxdLN80ZPi+WbpozfF4s3dI8p+QreJMD59wK4DLgD2b2cpvj\nnwDbm9nzlanYdbTJgYjE4L//hQED4I9/hBNOCN1GREREREQknSq1ycHuQD+g0Tn3mHPux865AWX0\nFBGRAObOTTY50AYHIiIiIiIifhS8wGZm88zsBGAwcAXwPeCNbMa+zrl+lakoIiI+3XknbLcdfOUr\noZuIiIiIiIj0DEXvImpmzWZ2lZntDmwHTAPOAt52zt3uu6CIiPjT2gp33aWr10RERERERHwqeoGt\nLTN70cx+CnwFONJPpZ4jk8mkMst3XizdNGf4vFi6VXLOp56Ct96CAw4oP6tcsTyfvvPSmuU7L61Z\nvvNi6aY5w+fF0k1zhs+LpZvmDJ8XS7c0zyn5etXU1JQdUlNTYzU1NU01NTWzyq8UztSpUwcDEydO\nnMjgwYPLzuvfvz9Dhw4tv5jnLN95sXTTnOHzYulWyTmvugqeeAKmT4devcJ2i+X59J2X1izfeWnN\n8p0XSzfNGT4vlm6aM3xeLN00Z/i8WLqlec4YLF68mJkzZwLMrKmpWbymcwveRTQG2kVURHq63XaD\nQYPglltCNxEREREREUm3Su0iKiIi3diyZTBvnj5/TURERERExDctsImIRGLu3GSTAy2wiYiIiIiI\n+KUFtgqqr69PZZbvvFi6ac7webF0q9Scc+bAN78JG29cfpYPsTyfvvPSmuU7L61ZvvNi6aY5w+fF\n0k1zhs+LpZvmDJ8XS7c0zyn5Slpgc85t6Zyb4Jz7pXPu3LY33wXL5Zy71Tm3zDl3U1c/9qxZ/vZ8\n8JnlOy+WbpozfF4s3SoxZ2trssBW7tVraZ8zjVm+89Ka5TsvrVm+82LppjnD58XSTXOGz4ulm+YM\nnxdLtzTPKfmK3uTAOXcC8AdgKfAm0DbAzCxVuwM45/YE+gHHmdkRnZyrTQ5EpEdqbIQdd4T774e9\n9grdRkREREREJP2K2eRg7RLyfwmcbWa1pZTramb2oHNO/zopIlGbMwfWXx923TV0ExERERERkZ6n\nlLeIfhG42XcRERGpnDvvhH33hd69QzcRERERERHpeUpZYLsZGOO7SHvOuT2cc7c75xY551qdc5kO\nzpnknHvNObfcOTfPObdTpXuJiHQ3y5bBY49p91AREREREZFKKWWB7RXgV865a5xzZzjnTml789ht\nXeAp4CTyP+cNAOfcWGAaMAXYAXgauNs5N8Bjh7KMGzculVm+82LppjnD58XSzfechxwyjtZW2G+/\n8rPSPKe6hc3ynZfWLN95sXTTnOHzYummOcPnxdJNc4bPi6VbmueUfKV8BtsE4ANgr+ytLQMuK7cU\ngJndBdwF4JxzHZxyOnCFmV2XPedE4DvAeOCidue67K1LjRnj70I/n1m+82LppjnD58XSzfecra1j\n2H572Hjj8rPSPKe6hc3ynZfWLN95sXTTnOHzYummOcPnxdJNc4bPi6VbmueUfEXvIhqCc64VOMjM\nbs/e7w20AIfmjmWPXwNsYGYHtzk2F/gmyRVxy4DDzeyx1TyOdhEVkR6ltRUGDYLjj4df/zp0GxER\nERERke6j0ruIAuCc6wNsDvzLzFaUmlOiAUAv4K12x98Cvtb2gJnt21WlRETSZv58WLJEn78mIiIi\nIiJSSUV/Bptzrq9zro7kCrJ/AkOyx6c7584qIe8o59z72dt7zrndis3wraqqikGDBjFixAgymQyZ\nTIaqqirq6+vzzrvnnnvIZFbZe4FJkyZRV1eXd2z+/PlkMhmWLl2ad3zKlCnU1tbmHVu4cCGZTIam\npqa849OnT2fy5Ml5x1paWshkMjQ0NOQdnzVrVofvrR47dqzm0ByaI6I55syBDTaADz7o3nPkdPfn\nQ3NoDs2hOTSH5tAcmkNzaA7Nkc45qqqqGDlyJJlMhhEjRjBo0CBGjRq1ynmrZWZF3YDfAU8Au5N8\nFtsW2ePfBZ4sIW9dYIs2t891cE4rkGlzvzfwSdtj2ePXALcV26HN9w8HrLGx0Xx46KGHvOT4zvKd\nF0s3zRk+L5ZuPrOqqsxGjUpnt1ieT995ac3ynZfWLN95sXTTnOHzYummOcPnxdJNc4bPi6VbmueM\nQWNjo5HsNzDcOltT6uyEVb4BFgC7ZP/8fpsFtq8C7xWbV+BjtnawmDYP+F2b+w54HZhcxuN4XWCr\nrq72kuM7y3deLN00Z/i8WLqVm7Vihdns2Wbf/W7yW37YsPR0q1SW77xYumnO8HmxdNOc4fNi6aY5\nw+fF0k1zhs+LpVua54xBMQtsRW9y4JxrAb5hZq86594Hts/+eXvgQTPboKjA1T/OuiSLdg6YD/wE\nuA9YZmavO+eOILli7UTgcZJdRQ8DtjazJSU+ptdNDlpaWujbt2/ZOb6zfOfF0k1zhs+LpVupWf/3\nf3DVVXDllfD667D99jBxInz/+y2st17PmbMr8mLppjnD58XSTXOGz4ulm+YMnxdLN80ZPi+Wbmme\nMwbFbHJQygLbg8DNZjY9u8D2TTN7zTk3HdjSzPYrtXi7x9mLZEGtfcFrzWx89pyTgJ8CA4GngJPN\n7IkyHlO7iIpIt7JiBdx1F8ycCbNnw+c/D0ceCRMmwI47gnOhG4qIiIiIiHRPld5F9BfAHOfcttnv\nPzX7512BvUrI65CZPUAnmzCY2Qxghq/HFBHpLhYuTK5Wq6tLrlwbPhxmzEgW19ZfP3Q7ERERERGR\nuBS9wGZmDc65YcBZwLPAGJK3cFaZ2bOe+4mISNaKFclVan/6U7I7aN++cNRRydVqyX9UERERERER\nkRDWeIXY6pjZv8zsBDMbaWbbmtkxWlxbVfstYtOS5Tsvlm6aM3xeLN3aZ/3733DOObDppnDQQfDW\nW/DHP8Ibb8AVV3S+uNZd5kxTXizdNGf4vFi6ac7webF005zh82LppjnD58XSLc1zSr5S3iKKc24o\nMA7YAjjNzN52zu0PLDSzf/os2J0NGTIklVm+82LppjnD58XSbciQIXzyCdxxR/LZanffDeutB0cf\nDSeckLwdNGS3NGb5zoulm+YMnxdLN80ZPi+WbpozfF4s3TRn+LxYuqV5TslXyiYHewFzgIeBPYFt\nsruIngXsaGaH+a/ZNbTJgYiE8u67yeeqvf46PPxw8vlqb74JI0cmbwEdOzZZZBMREREREZGuUelN\nDn4D/NLMLsnuIppzL/DjEvJERHq05cuThbPcLbeQ1vb2fpvfpuuvD8cck1ytNmxYuN4iIiIiIiJS\nmFIW2LYDjurg+NvAgPLqiIh0LytWJJ+FtnBhxwtnCxfCf/6T/z1f+hJsskly23vvz/48ZEjyv4MH\nw9olvYFfREREREREQihlk4N3gMEdHN8BWFRenZ6lqakplVm+82LppjnD54Xo9sEH8Pzzya6dV1wB\nv/hFcnXZHnv8/+ydeZgcVdm+75cQtkT2JWEnAVR2EkBGZFFZP8yAfiooyhJRUMJuUFFJAipEILK4\nEQmbH0RcIKIiIIhI+AWUCSCIQRBCSAghI3vCmry/P04109Ppmenqqcmp5Dz3ddU13dXVzzxPL1XV\nb50lFMRWXjlMPrDnnjM44gg491y46y54++3QvfPUU+Hqq+HPf4bHHw+t2ebNg/vvhxtvhEsugdGj\n4fDD4YMfDAW2J55I4z3QZ2350ipar6xaReul4k054+ul4k054+ul4k054+ul4q3MOUUN7p5rAS4A\n7gYGAa8AWwJ7AP8BxuTVK9MCDAO8ra3Ni2DEiBGF6BStVbReKt6UM75eX3h77jn3++5z/9Wv3C+4\nwP3EE90POcR9p53c117bHTqWfv3cN93Ufc893Y84wv3MM90vu8z9j39032efEf7KK8X5KpKyvgep\n5Cxar6xaReuVVatovVS8KWd8vVS8KWd8vVS8KWd8vVS8lTlnCrS1tTngwDDvoabUzCQHKwE/Ao4G\n+gHvZH+vA45290W9rvpFouhJDmbNmlXYDB1FahWtl4o35Yyvl1dr0SKYOxdmzgzL00/X/p3FW291\n6A0YEFqjbbZZaJ1W+3fDDbvuuqn3IK5W0XqpeFPO+HqpeFPO+HqpeFPO+HqpeFPO+HqpeCtzzhTI\nM8lB7gLbu0802xTYDhgIPODujzclVCI0i6gQyxbvvANz5nQumlXfnjUrbFNhnXVg883DUimkVRfR\n1loLzGIkEUIIIYQQQghRNvp0FlEzG+LuT7r7LGBWkx6FEKIh3noLZsyARx6Bxx7rXEibPTu0Uquw\n/vodBbThw5cspg0cGCOBEEIIIYQQQojlnWbmqXvCzGYDdwF/Ae5y9ycKdSWESI7Fi0PR7JFH4OGH\nw1IpqlVaoQ0a1FE0a2kJRbPK/U03hdVWi2ZfCCGEEEIIIUTCNDOL6CbAN4DXgTOAf5vZbDO71syO\nLdTdMs748eNLqVW0XirelLM4veefD7NqXnwxHHss7L47rL46DB0KhxwCF1wAzz4Le+0VZtm8+254\n4QU45ZTxTJsGkyeH2TqPPx4OPBDe977mimtlfd30WYuvl4o35Yyvl4o35Yyvl4o35Yyvl4o35Yyv\nl4q3MucUncndgs3d5wDXZgtmthXwTeAI4HDg8iINLsssXLiwlFpF66XiTTnzs2ABPP74QiZN6miR\n9vDDocAGsPLKsM02sP328L//G/5utx1stFH9sdD0HsTXK6tW0XqpeFPO+HqpeFPO+HqpeFPO+Hqp\neFPO+HqpeCtzTtGZZmYRXQ34ELBPtuwMzCB0F/2Lu/+2UIdLEU1yIETvefNNuPlmuO46+N3vwn0z\n2HLLjgLa9tuHZejQrmflFEIIIYQQQgghYtKnkxwALwEvElqwnQfc7e4vNqEjhFhOWLQI7rorFNV+\n/Wt4+WXYeWc45xz48IdDKzWNjyaEEEIIIYQQYnmlmQLbzYQWbIcDg4BBZvYXd/93oc6EEKXGHR54\nAK69Fn7xizBm2pAhcOKJ8NnPwvvfH9uhEEIIIYQQQgixdMg9yYG7H+ru6wIHAtOA/YG7zWyOmV1b\ntMFlmfb29lJqFa2XijflDDzxBJx9diigDR8O//d/Yfy0adPCY+ec07m4VtacReuVVatovbJqFa2X\nijfljK+XijfljK+XijfljK+XijfljK+Xircy5xSdaWYW0QoPA/cQimx/B9YHDivC1PLCyJEjS6lV\ntF4q3lLO+dxzYcbPD3wAttoKzj8/3L7lFpgzJ8z0ufvu9ScmKGvOovXKqlW0Xlm1itZLxZtyxtdL\nxZtyxtdLxZtyxtdLxZtyxtdLxVuZc4oa3D3XApwG3AS8ALwN3A9MAFqBtfLqlWkBhgHe1tbmRVCU\nTtFaReul4i21nC+/7H7lle777ee+wgru/fu7t7a6X3+9+4IFcb2VUa+sWkXrlVWraL1UvClnfL1U\nvClnfL1UvClnfL1UvClnfL1UvJU5Zwq0tbU54MAw76Gm1Mwson8H7iLMGnq3u79cSKWvBGgWUZE6\nb70VZgC99tqOGUD33huOOCJ0A1177dgOhRBCCCGEEEKIpUNfzyL6v8Bsd19cvdLMDNjE3Wc1oSmE\niMjDD8MVV4Tx1NrbYaedwlhqhx8Om2wS250QQgghhBBCCFFumimwPQUMBp6vWb929li/3poqCjPb\nGPg5YXy4t4HvuPuv47oSohy89BJMnhwKa/ffD+utB0cdBUcfDdttF9udEEIIIYQQQgix7NDMJAd1\nhjEHYCDwRi+89AXvACe7+7bAAcBFZrbq0vrnkyZNKqVW0XqpeFseci5eDHfcEbp8Dh4MJ54Y/t54\nY5is4IIL4L77lv2cMfTKqlW0Xlm1itZLxZtyxtdLxZtyxtdLxZtyxtdLxZtyxtdLxVuZc4rONFxg\nM7MJZjaBMLjb2ZX72XIxcD3wYF8ZbQZ3f87d/5Hdnge0E1raLRWmT++2e240raL1UvG2LOecORPG\njoUhQ2DffaGtDcaNg2eegZtugkMPhf79i/dVtF4q3pQzvl4q3pQzvl4q3pQzvl4q3pQzvl4q3pQz\nvl4q3sqcU3Sm4UkOzOzO7ObewDTgraqH3wJmAhe4++NFGiwKMxsOXOnuO3SzjSY5EMsNr78eWqZd\ncUVotTZwIBx2GIwcCS0tYF21RRVCCCGEEEIIIUTfTHLg7h8GMLMrCd0uX+mVyx4wsz2B0cBwwphv\nh7r7TTXbnAB8FRgEPASc6O5/r6O1NnA18IW+9CxEbNxD67QrroDrroOXX4Y994Qrr4RPfjIU2YQQ\nQgghhBBCCFEsuSc5cPdjAMxsS2Ao8Fd3f93MzBttDtcYAwhdTicBN9Q+aGaHARcCXwL+BpwK3Gpm\nW7t7e9V2KwE3At9z9/sK9CdEaZg/H669NhTWHn4YNtwQTjghTFiw1Vax3QkhhBBCCCGEEMs3uQts\nWWuwXwEfJozHthXwJDDJzF5099OLMObutwC3ZP+zXme2U4HL3P2abJvjgYOBkcD3q7a7GrjD3a8r\nwpcQZeO88+Css8LtQw6B8eNhv/1gxWbmCBZCCCGEEEIIIURumplF9CLgbWBTYGHV+uuBA4sw1RNm\n1p/QdfSOyrqs9dztQEvVdnsAnwIONbMHzGy6mW27NDwCtLa2llKraL1UvJUx5zPPwJgxsOGGrTz7\nLPzqV3DQQb0rrpUxZ19oFa1XVq2i9cqqVbReKt6UM75eKt6UM75eKt6UM75eKt6UM75eKt7KnFN0\nppkC2/7A19x9ds36x4HNem+pIdYF+gHzatbPI4zHBoC73+PuK7r7MHffOfv7z57EW1paGDRoEMOH\nD6e1tZXW1lZaWlqYMmVKp+1uu+22uh/OE044gUmTJjFq1Kh3102fPp3W1lba29s7bTtmzBjGjx/f\nad2sWbNobW1lxowZ764bNWoUl156KaNHj+607cKFC2ltbWXq1Kmd1k+ePJljjjlmCW+HHXYYU6ZM\n6eStpxzV1MsxatSohnMAPeao9tZTjmrq5Rg1alTDOaD796NWu7fvx6hRoxrOAfXfj9NPn457K2ef\n/XnWXbexHD29H6NGjWr6c1UvR/X72VWORt+PUaNGNf25qpej1ltv3o9Ro0b1+nteybHyyivnylFL\nbY5Ro0b1+nteybHeeus1nKOn96Py+vf2e17JseWWWzaco6f3o+KtqP1u7cQ5vXk/Kt6K2O/Onz+/\nkO95hYq3Iva78+fPL+R7Xu2r0RwVusoxf/78Xn/PKzkq3ora786fP7/hHD29HxVvRex3t91220K+\n55UcFW9F7Hc32WSTUp5fAay++uqlPL+qUMT51YwZMzp5K8P5VXWOam+93e8ee+yxpTy/Avj0pz9d\nyvMrgAMOOKCQ86vRo0d38lam86vx48d38tbb/e6oUaNKeX5V8VbG86uKt6J+1+6zzz4N51ia51d9\n8bu20RwVispR1HliNS0tLey22260trYyfPhwBg0atMR72R0NzyL67hPMXgWGufvj2e0d3f1JM9sF\nuNXd18mp91ngsuyuAwe5+z012yymapIDMxsMzAFaqsdVM7PxwF7u3kITaBZRsSzxzDOw5ZahBduZ\nZ8Z2I4QQQgghhBBCLF/kmUW0mRZsdwNHVt13M1sBOAO4swm93wI7ZstOwP0NPKcdWARsULN+A+C5\nJjwIscxx3nlhVtCai4RCCCGEEEIIIYRYyjQzUtMZwB1Zi7WVCBMKbAusDeyRV8zdFxAmScjznLfN\nrA34KFBp1WbZ/UvyehBiWWP2bLj88tB6bfXVY7sRQgghhBBCCCHSJncLNnd/BNgamEpofTYAuAHY\n2d3/U5QxMxtgZjua2U7ZqiHZ/U2y+xOAL5rZkWb2PuCnwGrAVUV56C21fZDLolW0XireypTzvPNg\nwICO1mvLa86+1Cpar6xaReuVVatovVS8KWd8vVS8KWd8vVS8KWd8vVS8KWd8vVS8lTmn6EwzXURx\n95fd/bvu/ml3/x93/5a7zy3Y2y7AA0AbYWy2C4HpwLjMwy+BrwJnZ9vtABzg7kuO7huJyZMnl1Kr\naL1UvJUl5+zZ8LOfwemnd7ReWx5z9rVW0Xpl1Spar6xaReul4k054+ul4k054+ul4k054+ul4k05\n4+ul4q3MOUVnck9yAGBmawFfAN6frXoUuNLdXyjQ21JHkxyIZYETT4Rrr4WZM9U9VAghhBBCCCGE\n6Cv6dJIDM9sLmAmcBKyVLScBT2WPCSH6iDlzYOLEzq3XhBBCCCGEEEIIEZdmJjn4EXA98GV3XwRg\nZv2AH2ePbV+cPSFENZWx1048MbYTIYQQQgghhBBCVGhmDLYtgQsrxTWA7PaE7DEhRB9Qab122mlq\nvSaEEEIIIYQQQpSJZgps0+kYe62a9wMP9c7O8sUxxxxTSq2i9VLxFjvn+PFdt15bnnIuLa2i9cqq\nVbReWbWK1kvFm3LG10vFm3LG10vFm3LG10vFm3LG10vFW5lzis401EXUzHaounsJcLGZbQncm63b\nHTgB+Hqx9pZt9t9//1JqFa2XireYOSut1771LVhjjd5pFelraeul4k054+ul4k054+ul4k054+ul\n4k054+ul4k054+ul4q3MOUVnGppF1MwWAw5YD5u6u/crwlgMNIuoKCsnnQQ//3mYObRegU0IIYQQ\nQgghhBDFkmcW0UYnOdii166EEE3x7LOh9do3v6nimhBCCCGEEEIIUUYaKrC5+9N9bUQIUZ/x42HV\nVUMrNiGEEEIIIYQQQpSPZiY5EA0yderUUmoVrZeKtxg5n30WLrsMTj21+9Zry3rOGFpF65VVq2i9\nsmoVrZeKN+WMr5eKN+WMr5eKN+WMr5eKN+WMr5eKtzLnFDW4u5ZsAYYB3tbW5kUwYsSIQnSK1ipa\nLxVvMXKedJL7mmu6v/hi77UaJZX3s2i9smoVrVdWraL1UvGmnPH1UvGmnPH1UvGmnPH1UvGmnPH1\nUvFW5pwp0NbW5oQ5CYZ5DzWlhiY5SIWiJzlYuHAhq622Wu+NFaxVtF4q3pZ2zrlzYcgQ+MY34Kyz\nlp63VN7PovXKqlW0Xlm1itZLxZtyxtdLxZtyxtdLxZtyxtdLxZtyxtdLxVuZc6ZAnkkOVGCrQrOI\nijJxyilw9dXw1FOw5pqx3QghhBBCCCGEEGmRp8DW1BhsZrammR1rZuea2drZumFmtlEzekKIzsyd\nG8ZeO+UUFdeEEEIIIYQQQoiy09AsotWY2Q7A7cDLwObAz4AXgE8AmwJHFuhPiCQZPx5WXhlOPjm2\nEyGEEEIIIYQQQvREMy3YJgBXuftWwBtV628G9irE1XLC6NGjS6lVtF4q3pZWzkrrtVNPbbz12rKY\nM7ZW0Xpl1Spar6xaReul4k054+ul4k054+ul4k054+ul4k054+ul4q3MOUVnmimw7QpcVmf9HGBQ\n7+wsX2y66aal1CpaLxVvSyvn97+fv/XaspgztlbRemXVKlqvrFpF66XiTTnj66XiTTnj66XiTTnj\n66XiTTnj66Xircw5RWdyT3JgZs8DB7j7A2b2KrCjuz9pZvsBV7j7Jn1hdGmgSQ5EbCozh37tazB2\nbGw3QgghhBBCCCFEuvT1JAc3AWeZWf/svpvZpsB44DdN6AkhMiqt1045JbYTIYQQQgghhBBCNEoz\nBbbTgYHA88CqwF3AE8CrwDeLsyZEWjz3HPz0p5o5VAghhBBCCCGEWNbIXWBz95fdfT/gY8BJwA+B\n/3H3vd19QdEGl2VmzJhRSq2i9VLx1tc5v/99WGml5mYOXZZylkWraL2yahWtV1atovVS8aac8fVS\n8aac8fVS8aac8fVS8aac8fVS8VbmnKIGd9eSLcAwwNva2rwIRowYUYhO0VpF6z3elw4AACAASURB\nVKXirS9zzp3rvsoq7med1Xut3pLK+1m0Xlm1itYrq1bReql4U874eql4U874eql4U874eql4U874\neql4K3POFGhra3PAgWHeU02ppw2WeAJcAoyqs34UcFFevTItRRfYnn766UJ0itYqWi8Vb32Z87TT\n3Fdf3f2FF3qv1VtSeT+L1iurVtF6ZdUqWi8Vb8oZXy8Vb8oZXy8Vb8oZXy8Vb8oZXy8Vb2XOmQJ5\nCmzNzCI6BzjY3R+sWT8MuMndN+5Fg7pCMbM1gNuBfsCKwCXufnk322sWUbHUee65MHPo6NEwblxs\nN0IIIYQQQgghhIB8s4iu2IT+OoQJDWp5BVi3Cb2+5BVgT3d/w8xWBf5pZr9x9xdjGxOiwvnnQ//+\nmjlUCCGEEEIIIYRYVmlmFtEngIPqrD8IeLJ3doola9H3RnZ31eyvxfIjRC3z5sFPfhImNlhrrdhu\nhBBCCCGEEEII0QzNFNgmAN83s3Fmtne2nA2cB/ygWHu9x8zWMLMHgVnA+e7+wtL63+PHjy+lVtF6\nqXjri5xFtV4re84yahWtV1atovXKqlW0XirelDO+XirelDO+XirelDO+XirelDO+XireypxTdCZ3\ngc3drwBOB74A3JktnwO+7O4/K8qYme1pZjeZ2RwzW2xmrXW2OcHMnjKz183sXjPbtY7fl919J2AL\n4AgzW68ojz2xcOHCUmoVrZeKt6JzPv/8Qn7849B6be21e6dV5pzyFleraL2yahWtl4o35Yyvl4o3\n5Yyvl4o35Yyvl4o35Yyvl4q3MucUnck9yUGnJ4di1evu/lpxlt7VPhD4INAG3AB83N1vqnr8MOBq\n4EvA34BTgU8BW7t7exeaPwLucPcbunhckxyIpcZXvwoTJ8LMmb0vsAkhhBBCCCGEEKJY8kxy0EwX\n0Xdx9/l9UVzLtG9x97Pc/bfUHzftVOAyd7/G3WcAxwMLgZGVDcxsfTMbmN1eA9gLeKwv/AqRh3nz\nKKz1mhBCCCGEEEIIIeKSu8BmZhuY2c/N7Fkze8fMFlUvfWGyjof+wHDgjso6D03xbgdaqjbdDLjb\nzB4A7gIudvd/Lg2PQnTHBRfAiivCqafGdiKEEEIIIYQQQoje0kwLtquAYcA5wCeBT9QsS4N1gX7A\n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\nVuacojPNdBHdE/igu79lnSsvM4GNijC1vLD//vsXprXHHvszdWrnFmmPPAIvvxweX2ONUFzbc0/4\nylfCbJ7bbRfW97W3IrWK1iurVtF6ZdUqWi8Vb8oZXy8Vb8oZXy8Vb8oZXy8Vb8oZXy8Vb8oZXy8V\nb2XOKTrTzCyiLwJ7uPujZvYqsKO7P2lmHwJ+4+4b9IXRpUGsWURffz1033zmmbBU367cr4yNtuKK\n8L73hWLaDjuEv9tvD5tsom6cQgghhBBCCCGEEEXRp7OIArcBpwBfyu67mQ0ExgE3N6G3XPPmm2FC\nge6KZ+3tnZ+z7rqhYLbxxqFF2iabwGabwbbbhuLaSivFySKEEEIIIYQQQgghlqSZAtvpwK1m9iiw\nCnAdsBXQDnymQG/LNGPGwGWXwbx5ndevtVZH8ewDH4BPfrLjfuXvqqvG8SyEEEIIIYQQQggh8pN7\nkgN3nw3sCHwX+AHwAPB1YGd3f75Ye8smt98OZ58Nu+46lSuugNtug3/9C159FV54AR56CP7wB/jp\nT+Gb34Qjj4SPfAS22qrr4trUqVML9VikXirelDO+XirelDO+XirelDO+XirelDO+XirelDO+Xire\nlDO+XireypxT1ODuPS7AdGCt7PZZwGqNPK8sC7AqYRKG7/ew3TDA29ravFlefdV9883d99nH/WMf\nG9G0Ti0jRhSnVbReKt6UM75eKt6UM75eKt6UM75eKt6UM75eKt6UM75eKt6UM75eKt7KnDMF2tra\nHHBgmPdQe2pokgMzex3Yyt1nm9kiYLAvQ63VzOw7wFDgGXc/o5vtej3JwYknwhVXhJk+Bw9eyGqr\nrdac6RoWLixOq2i9VLwpZ3y9VLwpZ3y9VLwpZ3y9VLwpZ3y9VLwpZ3y9VLwpZ3y9VLyVOWcK5Jnk\noNEC2zTgNWAqMAa4ILu/BO5+dl7DfYmZbQmcC/wO2K4vC2x//SvsvTdcdBGcfHLTloUQQgghhBBC\nCCFEZPpiFtGjCbOEfozQNO4g4J062zlQqgIboRj4VWCPvvwnCxfCyJGwxx6hFZsQQgghhBBCCCGE\nSIOGJjlw98fc/XB33xUw4KPuvnOdpbl+lXUwsz3N7CYzm2Nmi82stc42J5jZU2b2upnda2a71jze\nCjzm7k9UVhXlr5ZvfxvmzAndQ1fIPXWEEEIIIYQQQgghhFhWaagUZGbTzWyt7O44uugeWjADgAeB\nrxBaxtV6Ogy4kNBldWfgIeBWM1u3arPdgcPN7ElCS7ZjzexbRRudNg1+8IMwc+jWW3esHz16dGH/\no0itovVS8aac8fVS8aac8fVS8aac8fVS8aac8fVS8aac8fVS8aac8fVS8VbmnKIzjba1ej+h4AVh\nFtGBfWOnA3e/xd3PcvffUr/l2anAZe5+jbvPAI4HFgIjqzTOdPfN3H0IoZvoz9z9O0X6fOON0DV0\n113htNM6P7bpppsW9n+K1CpaLxVvyhlfLxVvyhlfLxVvyhlfLxVvyhlfLxVvyhlfLxVvyhlfLxVv\nZc4pOrNMTHJgZouBQ939pux+f0Ix7X8r67L1VwFruPvH62gcBWxb9CQH3/gGTJgA06fDttvmSSWE\nEEIIIYQQQgghykqeSQ4abcF2NPBfOk9y8PE6y6HNWc7NukA/YF7N+nnAoHpPcPeruyuuVdPS0sKg\nQYMYPnw4ra2ttLa20tLSwpQpUzpt98Mf3sZ557Vy1lmdi2snnHACkyZN6rTt9OnTaW1tpb29vdP6\nMWPGMH78+E7rZs2aRWtrKzNmzOi0/tJLL12iOefChQtpbW1l6tSpndZPnjyZY445Zolshx122BI5\nbrvtNlpblxjiTjmUQzmUQzmUQzmUQzmUQzmUQzmUQzmUI4kcLS0t7LbbbrS2tjJ8+HAGDRrEPvvs\ns8R2XdFQC7ZOTwityQa5+/O5nti13meBy7K7Dhzk7vfU+Z/VLdgGA3OAFne/r2q78cBe7t7SpJeG\nW7C99RYMHw79+8N994W/QgghhBBCCCGEEGL5oC9asL2Lu69QVHEt47fAjtmyE3B/A89pBxYBG9Ss\n3wB4rkBvXfLd78KMGXDllV0X12orqr2hSK2i9VLxppzx9VLxppzx9VLxppzx9VLxppzx9VLxppzx\n9VLxppzx9VLxVuacogZ373EBWoH+Vbe7XBrRy7sAi2u1gXuBi6vuG/AMMLoX/2cY4G1tbd4dDz7o\nvuKK7med1e1mPmLEiO43yEGRWkXrpeJNOePrpeJNOePrpeJNOePrpeJNOePrpeJNOePrpeJNOePr\npeKtzDlToK2tzQm9LYd5TzWlnjbwjgLX+lW3u1oWNaLX4P8cQEertsXAKdn9TbLHP02Y6OBI4H2E\nbqb/Bdbrxf/sscD21lvuO+/svt127m++2f0b8fTTT3e/QQ6K1CpaLxVvyhlfLxVvyhlfLxVvyhlf\nLxVvyhlfLxVvyhlfLxVvyhlfLxVvZc6ZAnkKbLnHYFtamNnewJ2EINVc7e4js22+ApxB6Br6IHCi\nuzfSxbSr/9njGGzf+x6cdRbcey/sskuz/0kIIYQQQgghhBBClJk8Y7CtuHQs5cfd76KHMeLc/cfA\nj5eOI/jnP2HcOBg9WsU1IYQQQgghhBBCCBHIVWAzsxWAo4FPAJsTWpc9Bfwa+LmXtTlcAbzzDowc\nCUOGwJgxsd0IIYQQQgghhBBCiLLQ8CyiZmbATcDlwEbAw8A/gc2Aq4Ab+8BfabjoIvj73+GKK2CV\nVRp7zvjx4wv7/0VqFa2XijfljK+XijfljK+XijfljK+XijfljK+XijfljK+XijfljK+Xircy5xSd\nydOC7WhgL+Cj7n5n9QNm9hFgipkd6e7XFOivFPz73/Dtb8Mpp0BLS+PPW7hwYWEeitQqWi8Vb8oZ\nXy8Vb8oZXy8Vb8oZXy8Vb8oZXy8Vb8oZXy8Vb8oZXy8Vb2XOKTrT8CQHZnYb8Gd3P6+Lx88E9nb3\nAwr0t1SpN8nB4sWw114wbx489BCstlpcj0IIIYQQQgghhBCi78kzyUHDXUSBHYBbunn8j8COOfSW\nCX74Q7jnHpg0ScU1IYQQQgghhBBCCLEkeQpsawPzunl8HrBW7+yUi//8B77xDTjhhNCKTQghhBBC\nCCGEEEKIWvIU2PoB73Tz+CJyzkpaZhYvhi9+EdZfH86r2ym2Z9rb2wvzU6RW0XqpeFPO+HqpeFPO\n+HqpeFPO+HqpeFPO+HqpeFPO+HqpeFPO+HqpeCtzTtGZPAU2A64ysxvqLcAVfeQxChMnwp13wuWX\nw8CBzWmMHDmyMD9FahWtl4o35Yyvl4o35Yyvl4o35Yyvl4o35Yyvl4o35Yyvl4o35Yyvl4q3MucU\nnek3duzYhjYcN27c5sAC4M0ulgXAQ2PHjv1tH/hcKowbN24wcFxr63Ecd9xgjjoKTj65eb33vve9\nDB48uBBvRWoVrZeKN+WMr5eKN+WMr5eKN+WMr5eKN+WMr5eKN+WMr5eKN+WMr5eKtzLnTIG5c+cy\nceJEgIljx46d2922Dc8imgKVWUR3372N2bOH8cgjsMYasV0JIYQQQgghhBBCiKVNnllEl5sx04rk\n3nvh5ptVXBNCCCGEEEIIIYQQPZNnDLZk+NjH4KCDYrsQQgghhBBCCCGEEMsCKrDV4fTTi9GZNGlS\nMUIFaxWtl4o35Yyvl4o35Yyvl4o35Yyvl4o35Yyvl4o35Yyvl4o35Yyvl4q3MucUnVGBrQ6rr16M\nzvTp3XbPjaZVtF4q3pQzvl4q3pQzvl4q3pQzvl4q3pQzvl4q3pQzvl4q3pQzvl4q3sqcU3RGkxxU\nUZnkoK2tjWHDhsW2I4QQQgghhBBCCCEikWeSA7VgE0IIIYQQQgghhBCiF6jAJoQQQgghhBBCCCFE\nL1CBTQghhBBCCCGEEEKIXqACWx/S2tpaSq2i9VLxppzx9VLxppzx9VLxppzx9VLxppzx9VLxppzx\n9VLxppzx9VLxVuacojP9xo4dG9tDaRg3btxg4LjjjjuOwYMH91pvnXXWYejQob03VrBW0XqpeFPO\n+HqpeFPO+HqpeFPO+HqpeFPO+HqpeFPO+HqpeFPO+HqpeCtzzhSYO3cuEydOBJg4duzYud1tq1lE\nq9AsokIIIYQQQgghhBACNIuoEEIIIYQQQgghhBBLjRVjG+hrzGwm8BLgwAvu/tG4joQQQgghhBBC\nCCHE8kQKLdgWAy3uvvPSLq5NmTKllFpF66XiTTnj66XiTTnj66XiTTnj66XiTTnj66XiTTnj66Xi\nTTnj66Xircw5RQ3uvlwvwFPAgAa3HQZ4W1ubF8Huu+9eiE7RWkXrpeJNOePrpeJNOePrpeJNOePr\npeJNOePrpeJNOePrpeJNOePrpeKtzDlToK2tzQk9Iod5DzWlFFqwOfBXM7vPzD67NP/xeuutV0qt\novVS8aac8fVS8aac8fVS8aac8fVS8aac8fVS8aac8fVS8aac8fVS8VbmnKIzpS2wmdmeZnaTmc0x\ns8Vm1lpnmxPM7Ckze93M7jWzXetI7eHuw4FDgDPNbLs+Ny+EEEIIIYQQQgghkqG0BTZgAPAg8BVC\nK7ROmNlhwIXAGGBn4CHgVjNbt3o7d5+b/X0OuJnQDVQIIYQQQgghhBBCiEIobYHN3W9x97Pc/beA\n1dnkVOAyd7/G3WcAxwMLgZGVDcxsNTMbmN0eCHwE+GffuxdCCCGEEEIIIYQQqbBibAPNYGb9geHA\n9yrr3N3N7HagpWrTDYAbzcyBfsBEd2/rRnoVgH/961+F+Pzb3/7G9OnTS6dVtF4q3pQzvl4q3pQz\nvl4q3pQzvl4q3pQzvl4q3pQzvl4q3pQzvl4q3sqcMwWq6kOr9LStuS/R+7J0mNli4FB3vym7PxiY\n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\nD6lwIZ0LMZmFAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure(figsize=(15, 6))\n", - "plt.plot(np.sort(score_difference))\n", - "plt.yscale(\"symlog\")\n", - "plt.xticks(np.arange(len(game_names)), np.array(\n", - " game_names)[idxs], rotation='vertical')\n", - "plt.grid()\n", - "plt.title(\"Comparison A3C on Atari games: with and without LSTM memory\")\n", - "plt.ylabel(\"Difference between A3C_LSTM and A3C_FeadForward scores\")" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week08_pomdp/practice_pytorch.ipynb b/week08_pomdp/practice_pytorch.ipynb index 52be1fac4..2d3d43b46 100644 --- a/week08_pomdp/practice_pytorch.ipynb +++ b/week08_pomdp/practice_pytorch.ipynb @@ -1,678 +1,681 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "if 'google.colab' in sys.modules:\n", - " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/0ccb0673965dd650d9b284e1ec90c2bfd82c8a94/week08_pomdp/atari_util.py\n", - " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/0ccb0673965dd650d9b284e1ec90c2bfd82c8a94/week08_pomdp/env_pool.py\n", - "\n", - "# If you are running on a server, launch xvfb to record game videos\n", - "# Please make sure you have xvfb installed\n", - "import os\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "from IPython.core import display\n", - "import matplotlib.pyplot as plt\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Kung-Fu, recurrent style\n", - "\n", - "In this notebook we'll once again train RL agent for for Atari [KungFuMaster](https://gym.openai.com/envs/KungFuMaster-v0/), this time using recurrent neural networks.\n", - "\n", - "![img](https://upload.wikimedia.org/wikipedia/en/6/66/Kung_fu_master_mame.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ + "cells": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mWARN: gym.spaces.Box autodetected dtype as . Please provide explicit dtype.\u001b[0m\n", - "Observation shape: (1, 42, 42)\n", - "Num actions: 14\n", - "Action names: ['NOOP', 'UP', 'RIGHT', 'LEFT', 'DOWN', 'DOWNRIGHT', 'DOWNLEFT', 'RIGHTFIRE', 'LEFTFIRE', 'DOWNFIRE', 'UPRIGHTFIRE', 'UPLEFTFIRE', 'DOWNRIGHTFIRE', 'DOWNLEFTFIRE']\n" - ] - } - ], - "source": [ - "import gym\n", - "from atari_util import PreprocessAtari\n", - "\n", - "\n", - "def make_env():\n", - " env = gym.make(\"KungFuMasterDeterministic-v0\")\n", - " env = PreprocessAtari(env, height=42, width=42,\n", - " crop=lambda img: img[60:-30, 15:],\n", - " color=False, n_frames=1)\n", - " return env\n", - "\n", - "\n", - "env = make_env()\n", - "\n", - "obs_shape = env.observation_space.shape\n", - "n_actions = env.action_space.n\n", - "\n", - "print(\"Observation shape:\", obs_shape)\n", - "print(\"Num actions:\", n_actions)\n", - "print(\"Action names:\", env.env.env.get_action_meanings())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "if 'google.colab' in sys.modules:\n", + " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week08_pomdp/atari_util.py\n", + " !wget https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week08_pomdp/env_pool.py\n", + "\n", + " !pip install -q gymnasium[atari,accept-rom-license]\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !touch .setup_complete\n", + "# If you are running on a server, launch xvfb to record game videos\n", + "# Please make sure you have xvfb installed\n", + "import os\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from IPython.core import display\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Kung-Fu, recurrent style\n", + "\n", + "In this notebook we'll once again train RL agent for for Atari [KungFuMaster](https://gymnasium.farama.org/environments/atari/kung_fu_master/), this time using recurrent neural networks.\n", + "\n", + "![img](https://upload.wikimedia.org/wikipedia/en/6/66/Kung_fu_master_mame.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mWARN: gym.spaces.Box autodetected dtype as . Please provide explicit dtype.\u001b[0m\n", + "Observation shape: (1, 42, 42)\n", + "Num actions: 14\n", + "Action names: ['NOOP', 'UP', 'RIGHT', 'LEFT', 'DOWN', 'DOWNRIGHT', 'DOWNLEFT', 'RIGHTFIRE', 'LEFTFIRE', 'DOWNFIRE', 'UPRIGHTFIRE', 'UPLEFTFIRE', 'DOWNRIGHTFIRE', 'DOWNLEFTFIRE']\n" + ] + } + ], + "source": [ + "import gymnasium as gym\n", + "from atari_util import PreprocessAtari\n", + "\n", + "\n", + "def make_env():\n", + " env = gym.make(\"KungFuMasterDeterministic-v0\", render_mode=\"rgb_array\")\n", + " env = PreprocessAtari(env, height=42, width=42,\n", + " crop=lambda img: img[60:-30, 15:],\n", + " color=False, n_frames=1)\n", + " return env\n", + "\n", + "\n", + "env = make_env()\n", + "\n", + "obs_shape = env.observation_space.shape\n", + "n_actions = env.action_space.n\n", + "\n", + "print(\"Observation shape:\", obs_shape)\n", + "print(\"Num actions:\", n_actions)\n", + "print(\"Action names:\", env.unwrapped.get_action_meanings())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/jheuristic/anaconda3/lib/python3.6/site-packages/scipy/misc/pilutil.py:482: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.\n", + " if issubdtype(ts, int):\n", + "/home/jheuristic/anaconda3/lib/python3.6/site-packages/scipy/misc/pilutil.py:485: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n", + " elif issubdtype(type(size), float):\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "s, _ = env.reset()\n", + "for _ in range(100):\n", + " s, _, _, _, _ = env.step(env.action_space.sample())\n", + "\n", + "plt.title('Game image')\n", + "plt.imshow(env.render())\n", + "plt.show()\n", + "\n", + "plt.title('Agent observation')\n", + "plt.imshow(s.reshape([42, 42]))\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### POMDP setting\n", + "\n", + "The Atari game we're working with is actually a POMDP: your agent needs to know timing at which enemies spawn and move, but cannot do so unless it has some memory. \n", + "\n", + "Let's design another agent that has a recurrent neural net memory to solve this. Here's a sketch.\n", + "\n", + "![img](img1.jpg)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class SimpleRecurrentAgent(nn.Module):\n", + " def __init__(self, obs_shape, n_actions, reuse=False):\n", + " \"\"\"A simple actor-critic agent\"\"\"\n", + " super(self.__class__, self).__init__()\n", + "\n", + " self.conv0 = nn.Conv2d(1, 32, kernel_size=(3, 3), stride=(2, 2))\n", + " self.conv1 = nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2))\n", + " self.conv2 = nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2))\n", + " self.flatten = nn.Flatten()\n", + "\n", + " self.hid = nn.Linear(512, 128)\n", + " self.rnn = nn.LSTMCell(128, 128)\n", + "\n", + " self.logits = nn.Linear(128, n_actions)\n", + " self.state_value = nn.Linear(128, 1)\n", + "\n", + " def forward(self, prev_state, obs_t):\n", + " \"\"\"\n", + " Takes agent's previous hidden state and a new observation,\n", + " returns a new hidden state and whatever the agent needs to learn\n", + " \"\"\"\n", + "\n", + " # Apply the whole neural net for one step here.\n", + " # See docs on self.rnn(...).\n", + " # The recurrent cell should take the last feedforward dense layer as input.\n", + " \n", + "\n", + " new_state = \n", + " logits = \n", + " state_value = \n", + "\n", + " return new_state, (logits, state_value)\n", + "\n", + " def get_initial_state(self, batch_size):\n", + " \"\"\"Return a list of agent memory states at game start. Each state is a np array of shape [batch_size, ...]\"\"\"\n", + " return torch.zeros((batch_size, 128)), torch.zeros((batch_size, 128))\n", + "\n", + " def sample_actions(self, agent_outputs):\n", + " \"\"\"pick actions given numeric agent outputs (np arrays)\"\"\"\n", + " logits, state_values = agent_outputs\n", + " probs = F.softmax(logits, dim=-1)\n", + " return torch.multinomial(probs, 1)[:, 0].data.numpy()\n", + "\n", + " def step(self, prev_state, obs_t):\n", + " \"\"\" like forward, but obs_t is a numpy array \"\"\"\n", + " obs_t = torch.tensor(np.asarray(obs_t), dtype=torch.float32)\n", + " (h, c), (l, s) = self.forward(prev_state, obs_t)\n", + " return (h.detach(), c.detach()), (l.detach(), s.detach())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "n_parallel_games = 5\n", + "gamma = 0.99\n", + "\n", + "agent = SimpleRecurrentAgent(obs_shape, n_actions)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "state = [env.reset()[0]]\n", + "_, (logits, value) = agent.step(agent.get_initial_state(1), state)\n", + "print(\"action logits:\\n\", logits)\n", + "print(\"state values:\\n\", value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Let's play!\n", + "Let's build a function that measures agent's average reward." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate(agent, env, n_games=1):\n", + " \"\"\"Plays an entire game start to end, returns session rewards.\"\"\"\n", + "\n", + " game_rewards = []\n", + " for _ in range(n_games):\n", + " # initial observation and memory\n", + " observation, _ = env.reset()\n", + " prev_memories = agent.get_initial_state(1)\n", + "\n", + " total_reward = 0\n", + " while True:\n", + " new_memories, readouts = agent.step(\n", + " prev_memories, observation[None, ...])\n", + " action = agent.sample_actions(readouts)\n", + "\n", + " observation, reward, terminated, truncated, info = env.step(action[0])\n", + "\n", + " total_reward += reward\n", + " prev_memories = new_memories\n", + " if terminated or truncated:\n", + " break\n", + "\n", + " game_rewards.append(total_reward)\n", + " return game_rewards" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from gymnasium.wrappers import RecordVideo\n", + "\n", + "with make_env() as record_env, RecordVideo(record_env, video_folder=\"videos\") as env_monitor:\n", + " rewards = evaluate(agent, env_monitor, n_games=3)\n", + "\n", + "print(rewards)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Show video. This may not work in some setups. If it doesn't\n", + "# work for you, you can download the videos and view them locally.\n", + "\n", + "from pathlib import Path\n", + "from base64 import b64encode\n", + "from IPython.display import HTML\n", + "\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", + "\n", + "HTML(\"\"\"\n", + "\n", + "\"\"\".format(data_url))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Training on parallel games\n", + "\n", + "We introduce a class called EnvPool - it's a tool that handles multiple environments for you. Here's how it works:\n", + "![img](img2.jpg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from env_pool import EnvPool\n", + "pool = EnvPool(agent, make_env, n_parallel_games)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We gonna train our agent on a thing called __rollouts:__\n", + "![img](img3.jpg)\n", + "\n", + "A rollout is just a sequence of T observations, actions and rewards that agent took consequently.\n", + "* First __s0__ is not necessarily initial state for the environment\n", + "* Final state is not necessarily terminal\n", + "* We sample several parallel rollouts for efficiency" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# for each of n_parallel_games, take 10 steps\n", + "rollout_obs, rollout_actions, rollout_rewards, rollout_mask = pool.interact(10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Actions shape:\", rollout_actions.shape)\n", + "print(\"Rewards shape:\", rollout_rewards.shape)\n", + "print(\"Mask shape:\", rollout_mask.shape)\n", + "print(\"Observations shape: \", rollout_obs.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Actor-critic objective\n", + "\n", + "Here we define a loss function that uses rollout above to train advantage actor-critic agent.\n", + "\n", + "\n", + "Our loss consists of three components:\n", + "\n", + "* __The policy \"loss\"__\n", + " $$ \\hat J = {1 \\over T} \\cdot \\sum_t { \\log \\pi(a_t | s_t) } \\cdot A_{const}(s,a) $$\n", + " * This function has no meaning in and of itself, but it was built such that\n", + " * $ \\nabla \\hat J = {1 \\over N} \\cdot \\sum_t { \\nabla \\log \\pi(a_t | s_t) } \\cdot A(s,a) \\approx \\nabla E_{s, a \\sim \\pi} R(s,a) $\n", + " * Therefore if we __maximize__ J_hat with gradient descent we will maximize expected reward\n", + " \n", + " \n", + "* __The value \"loss\"__\n", + " $$ L_{td} = {1 \\over T} \\cdot \\sum_t { [r + \\gamma \\cdot V_{const}(s_{t+1}) - V(s_t)] ^ 2 }$$\n", + " * Ye Olde TD_loss from q-learning and alike\n", + " * If we minimize this loss, V(s) will converge to $V_\\pi(s) = E_{a \\sim \\pi(a | s)} R(s,a) $\n", + "\n", + "\n", + "* __Entropy Regularizer__\n", + " $$ H = - {1 \\over T} \\sum_t \\sum_a {\\pi(a|s_t) \\cdot \\log \\pi (a|s_t)}$$\n", + " * If we __maximize__ entropy we discourage agent from predicting zero probability to actions\n", + " prematurely (a.k.a. exploration)\n", + " \n", + " \n", + "So we optimize a linear combination of $L_{td}$ $- \\hat J$, $-H$\n", + " \n", + "```\n", + "\n", + "```\n", + "\n", + "```\n", + "\n", + "```\n", + "\n", + "```\n", + "\n", + "```\n", + "\n", + "\n", + "__One more thing:__ since we train on T-step rollouts, we can use N-step formula for advantage for free:\n", + " * At the last step, $A(s_t,a_t) = r(s_t, a_t) + \\gamma \\cdot V(s_{t+1}) - V(s) $\n", + " * One step earlier, $A(s_t,a_t) = r(s_t, a_t) + \\gamma \\cdot r(s_{t+1}, a_{t+1}) + \\gamma ^ 2 \\cdot V(s_{t+2}) - V(s) $\n", + " * Et cetera, et cetera. This way agent starts training much faster since it's estimate of A(s,a) depends less on his (imperfect) value function and more on actual rewards. There's also a [nice generalization](https://arxiv.org/abs/1506.02438) of this.\n", + "\n", + "\n", + "__Note:__ it's also a good idea to scale rollout_len up to learn longer sequences. You may wish set it to >=20 or to start at 10 and then scale up as time passes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "opt = torch.optim.Adam(agent.parameters(), lr=1e-5)\n", + "\n", + "\n", + "def train_on_rollout(states, actions, rewards, is_not_done, prev_memory_states, gamma=0.99):\n", + " \"\"\"\n", + " Takes a sequence of states, actions and rewards produced by generate_session.\n", + " Updates agent's weights by following the policy gradient above.\n", + " Please use Adam optimizer with default parameters.\n", + " \"\"\"\n", + "\n", + " # shape: [batch_size, time, c, h, w]\n", + " states = torch.tensor(np.asarray(states), dtype=torch.float32)\n", + " actions = torch.tensor(np.array(actions), dtype=torch.int64) # shape: [batch_size, time]\n", + " rewards = torch.tensor(np.array(rewards), dtype=torch.float32) # shape: [batch_size, time]\n", + " is_not_done = torch.tensor(np.array(is_not_done), dtype=torch.float32) # shape: [batch_size, time]\n", + " rollout_length = rewards.shape[1] - 1\n", + "\n", + " # predict logits, probas and log-probas using an agent.\n", + " memory = [m.detach() for m in prev_memory_states]\n", + "\n", + " logits = [] # append logit sequence here\n", + " state_values = [] # append state values here\n", + " for t in range(rewards.shape[1]):\n", + " obs_t = states[:, t]\n", + "\n", + " # use agent to comute logits_t and state values_t.\n", + " # append them to logits and state_values array\n", + "\n", + " memory, (logits_t, values_t) = \n", + "\n", + " logits.append(logits_t)\n", + " state_values.append(values_t)\n", + "\n", + " logits = torch.stack(logits, dim=1)\n", + " state_values = torch.stack(state_values, dim=1)\n", + " probas = F.softmax(logits, dim=2)\n", + " logprobas = F.log_softmax(logits, dim=2)\n", + "\n", + " # select log-probabilities for chosen actions, log pi(a_i|s_i)\n", + " actions_one_hot = F.one_hot(actions, n_actions).view(\n", + " actions.shape[0], actions.shape[1], n_actions)\n", + " logprobas_for_actions = torch.sum(logprobas * actions_one_hot, dim=-1)\n", + "\n", + " # Now let's compute two loss components:\n", + " # 1) Policy gradient objective.\n", + " # Notes: Please don't forget to call .detach() on advantage term. Also please use mean, not sum.\n", + " # it's okay to use loops if you want\n", + " J_hat = 0 # policy objective as in the formula for J_hat\n", + "\n", + " # 2) Temporal difference MSE for state values\n", + " # Notes: Please don't forget to call .detach() on V(s') term. Also please use mean, not sum.\n", + " # it's okay to use loops if you want\n", + " value_loss = 0\n", + "\n", + " cumulative_returns = state_values[:, -1].detach()\n", + "\n", + " for t in reversed(range(rollout_length)):\n", + " r_t = rewards[:, t] # current rewards\n", + " # current state values\n", + " V_t = state_values[:, t]\n", + " V_next = state_values[:, t + 1].detach() # next state values\n", + " # log-probability of a_t in s_t\n", + " logpi_a_s_t = logprobas_for_actions[:, t]\n", + "\n", + " # update G_t = r_t + gamma * G_{t+1} as we did in week6 reinforce\n", + " cumulative_returns = r_t + gamma * cumulative_returns\n", + "\n", + " # Compute temporal difference error (MSE for V(s))\n", + " value_loss += \n", + "\n", + " # compute advantage A(s_t, a_t) using cumulative returns and V(s_t) as baseline\n", + " advantage = \n", + " advantage = advantage.detach()\n", + "\n", + " # compute policy pseudo-loss aka -J_hat.\n", + " J_hat += \n", + "\n", + " # regularize with entropy\n", + " entropy_reg = \n", + "\n", + " # add-up three loss components and average over time\n", + " loss = -J_hat / rollout_length +\\\n", + " value_loss / rollout_length +\\\n", + " -0.01 * entropy_reg\n", + "\n", + " # Gradient descent step\n", + " \n", + "\n", + " return loss.data.numpy()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# let's test it\n", + "memory = list(pool.prev_memory_states)\n", + "rollout_obs, rollout_actions, rollout_rewards, rollout_mask = pool.interact(10)\n", + "\n", + "train_on_rollout(rollout_obs, rollout_actions,\n", + " rollout_rewards, rollout_mask, memory)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Train \n", + "\n", + "just run train step and see if agent learns any better" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import clear_output\n", + "from tqdm import trange\n", + "from pandas import DataFrame\n", + "moving_average = lambda x, **kw: DataFrame(\n", + " {'x': np.asarray(x)}).x.ewm(**kw).mean().values\n", + "\n", + "rewards_history = []" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for i in trange(15000):\n", + "\n", + " memory = list(pool.prev_memory_states)\n", + " rollout_obs, rollout_actions, rollout_rewards, rollout_mask = pool.interact(\n", + " 10)\n", + " train_on_rollout(rollout_obs, rollout_actions,\n", + " rollout_rewards, rollout_mask, memory)\n", + "\n", + " if i % 100 == 0:\n", + " rewards_history.append(np.mean(evaluate(agent, env, n_games=1)))\n", + " clear_output(True)\n", + " plt.plot(rewards_history, label='rewards')\n", + " plt.plot(moving_average(np.array(rewards_history),\n", + " span=10), label='rewards ewma@10')\n", + " plt.legend()\n", + " plt.show()\n", + " if rewards_history[-1] >= 10000:\n", + " print(\"Your agent has just passed the minimum homework threshold\")\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Relax and grab some refreshments while your agent is locked in an infinite loop of violence and death.\n", + "\n", + "__How to interpret plots:__\n", + "\n", + "The session reward is the easy thing: it should in general go up over time, but it's okay if it fluctuates ~~like crazy~~. It's also OK if it reward doesn't increase substantially before some 10k initial steps. However, if reward reaches zero and doesn't seem to get up over 2-3 evaluations, there's something wrong happening.\n", + "\n", + "\n", + "Since we use a policy-based method, we also keep track of __policy entropy__ - the same one you used as a regularizer. The only important thing about it is that your entropy shouldn't drop too low (`< 0.1`) before your agent gets the yellow belt. Or at least it can drop there, but _it shouldn't stay there for long_.\n", + "\n", + "If it does, the culprit is likely:\n", + "* Some bug in entropy computation. Remember that it is $ - \\sum p(a_i) \\cdot log p(a_i) $\n", + "* Your agent architecture converges too fast. Increase entropy coefficient in actor loss. \n", + "* Gradient explosion - just [clip gradients](https://stackoverflow.com/a/56069467) and maybe use a smaller network\n", + "* Us. Or PyTorch developers. Or aliens. Or lizardfolk. Contact us on forums before it's too late!\n", + "\n", + "If you're debugging, just run `logits, values = agent.step(batch_states)` and manually look into logits and values. This will reveal the problem 9 times out of 10: you'll likely see some NaNs or insanely large numbers or zeros. Try to catch the moment when this happens for the first time and investigate from there." + ] + }, { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/jheuristic/anaconda3/lib/python3.6/site-packages/scipy/misc/pilutil.py:482: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.\n", - " if issubdtype(ts, int):\n", - "/home/jheuristic/anaconda3/lib/python3.6/site-packages/scipy/misc/pilutil.py:485: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n", - " elif issubdtype(type(size), float):\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### \"Final\" evaluation" + ] }, { - "data": { - "image/png": "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\nRQAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from gymnasium.wrappers import RecordVideo\n", + "\n", + "with make_env() as record_env, RecordVideo(record_env, video_folder=\"videos\") as env_monitor:\n", + " final_rewards = evaluate(agent, env_monitor, n_games=20)\n", + "\n", + "print(\"Final mean reward\", np.mean(final_rewards))" ] - }, - "metadata": {}, - "output_type": "display_data" }, { - "data": { - "image/png": "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\nYII=\n", - "text/plain": [ - "" + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Show video. This may not work in some setups. If it doesn't\n", + "# work for you, you can download the videos and view them locally.\n", + "\n", + "from pathlib import Path\n", + "from base64 import b64encode\n", + "from IPython.display import HTML\n", + "\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", + "\n", + "HTML(\"\"\"\n", + "\n", + "\"\"\".format(data_url))" ] - }, - "metadata": {}, - "output_type": "display_data" } - ], - "source": [ - "s = env.reset()\n", - "for _ in range(100):\n", - " s, _, _, _ = env.step(env.action_space.sample())\n", - "\n", - "plt.title('Game image')\n", - "plt.imshow(env.render('rgb_array'))\n", - "plt.show()\n", - "\n", - "plt.title('Agent observation')\n", - "plt.imshow(s.reshape([42, 42]))\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### POMDP setting\n", - "\n", - "The Atari game we're working with is actually a POMDP: your agent needs to know timing at which enemies spawn and move, but cannot do so unless it has some memory. \n", - "\n", - "Let's design another agent that has a recurrent neural net memory to solve this. Here's a sketch.\n", - "\n", - "![img](img1.jpg)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import torch\n", - "import torch.nn as nn\n", - "import torch.nn.functional as F\n", - "\n", - "# a special module that converts [batch, channel, w, h] to [batch, units]\n", - "\n", - "\n", - "class Flatten(nn.Module):\n", - " def forward(self, input):\n", - " return input.view(input.size(0), -1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class SimpleRecurrentAgent(nn.Module):\n", - " def __init__(self, obs_shape, n_actions, reuse=False):\n", - " \"\"\"A simple actor-critic agent\"\"\"\n", - " super(self.__class__, self).__init__()\n", - "\n", - " self.conv0 = nn.Conv2d(1, 32, kernel_size=(3, 3), stride=(2, 2))\n", - " self.conv1 = nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2))\n", - " self.conv2 = nn.Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2))\n", - " self.flatten = Flatten()\n", - "\n", - " self.hid = nn.Linear(512, 128)\n", - " self.rnn = nn.LSTMCell(128, 128)\n", - "\n", - " self.logits = nn.Linear(128, n_actions)\n", - " self.state_value = nn.Linear(128, 1)\n", - "\n", - " def forward(self, prev_state, obs_t):\n", - " \"\"\"\n", - " Takes agent's previous hidden state and a new observation,\n", - " returns a new hidden state and whatever the agent needs to learn\n", - " \"\"\"\n", - "\n", - " # Apply the whole neural net for one step here.\n", - " # See docs on self.rnn(...).\n", - " # The recurrent cell should take the last feedforward dense layer as input.\n", - " \n", - "\n", - " new_state = \n", - " logits = \n", - " state_value = \n", - "\n", - " return new_state, (logits, state_value)\n", - "\n", - " def get_initial_state(self, batch_size):\n", - " \"\"\"Return a list of agent memory states at game start. Each state is a np array of shape [batch_size, ...]\"\"\"\n", - " return torch.zeros((batch_size, 128)), torch.zeros((batch_size, 128))\n", - "\n", - " def sample_actions(self, agent_outputs):\n", - " \"\"\"pick actions given numeric agent outputs (np arrays)\"\"\"\n", - " logits, state_values = agent_outputs\n", - " probs = F.softmax(logits)\n", - " return torch.multinomial(probs, 1)[:, 0].data.numpy()\n", - "\n", - " def step(self, prev_state, obs_t):\n", - " \"\"\" like forward, but obs_t is a numpy array \"\"\"\n", - " obs_t = torch.tensor(np.asarray(obs_t), dtype=torch.float32)\n", - " (h, c), (l, s) = self.forward(prev_state, obs_t)\n", - " return (h.detach(), c.detach()), (l.detach(), s.detach())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n_parallel_games = 5\n", - "gamma = 0.99\n", - "\n", - "agent = SimpleRecurrentAgent(obs_shape, n_actions)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "state = [env.reset()]\n", - "_, (logits, value) = agent.step(agent.get_initial_state(1), state)\n", - "print(\"action logits:\\n\", logits)\n", - "print(\"state values:\\n\", value)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Let's play!\n", - "Let's build a function that measures agent's average reward." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def evaluate(agent, env, n_games=1):\n", - " \"\"\"Plays an entire game start to end, returns session rewards.\"\"\"\n", - "\n", - " game_rewards = []\n", - " for _ in range(n_games):\n", - " # initial observation and memory\n", - " observation = env.reset()\n", - " prev_memories = agent.get_initial_state(1)\n", - "\n", - " total_reward = 0\n", - " while True:\n", - " new_memories, readouts = agent.step(\n", - " prev_memories, observation[None, ...])\n", - " action = agent.sample_actions(readouts)\n", - "\n", - " observation, reward, done, info = env.step(action[0])\n", - "\n", - " total_reward += reward\n", - " prev_memories = new_memories\n", - " if done:\n", - " break\n", - "\n", - " game_rewards.append(total_reward)\n", - " return game_rewards" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym.wrappers\n", - "\n", - "with gym.wrappers.Monitor(make_env(), directory=\"videos\", force=True) as env_monitor:\n", - " rewards = evaluate(agent, env_monitor, n_games=3)\n", - "\n", - "print(rewards)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Show video. This may not work in some setups. If it doesn't\n", - "# work for you, you can download the videos and view them locally.\n", - "\n", - "from pathlib import Path\n", - "from IPython.display import HTML\n", - "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", - "\n", - "HTML(\"\"\"\n", - "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Training on parallel games\n", - "\n", - "We introduce a class called EnvPool - it's a tool that handles multiple environments for you. Here's how it works:\n", - "![img](img2.jpg)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from env_pool import EnvPool\n", - "pool = EnvPool(agent, make_env, n_parallel_games)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We gonna train our agent on a thing called __rollouts:__\n", - "![img](img3.jpg)\n", - "\n", - "A rollout is just a sequence of T observations, actions and rewards that agent took consequently.\n", - "* First __s0__ is not necessarily initial state for the environment\n", - "* Final state is not necessarily terminal\n", - "* We sample several parallel rollouts for efficiency" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# for each of n_parallel_games, take 10 steps\n", - "rollout_obs, rollout_actions, rollout_rewards, rollout_mask = pool.interact(10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Actions shape:\", rollout_actions.shape)\n", - "print(\"Rewards shape:\", rollout_rewards.shape)\n", - "print(\"Mask shape:\", rollout_mask.shape)\n", - "print(\"Observations shape: \", rollout_obs.shape)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Actor-critic objective\n", - "\n", - "Here we define a loss function that uses rollout above to train advantage actor-critic agent.\n", - "\n", - "\n", - "Our loss consists of three components:\n", - "\n", - "* __The policy \"loss\"__\n", - " $$ \\hat J = {1 \\over T} \\cdot \\sum_t { \\log \\pi(a_t | s_t) } \\cdot A_{const}(s,a) $$\n", - " * This function has no meaning in and of itself, but it was built such that\n", - " * $ \\nabla \\hat J = {1 \\over N} \\cdot \\sum_t { \\nabla \\log \\pi(a_t | s_t) } \\cdot A(s,a) \\approx \\nabla E_{s, a \\sim \\pi} R(s,a) $\n", - " * Therefore if we __maximize__ J_hat with gradient descent we will maximize expected reward\n", - " \n", - " \n", - "* __The value \"loss\"__\n", - " $$ L_{td} = {1 \\over T} \\cdot \\sum_t { [r + \\gamma \\cdot V_{const}(s_{t+1}) - V(s_t)] ^ 2 }$$\n", - " * Ye Olde TD_loss from q-learning and alike\n", - " * If we minimize this loss, V(s) will converge to $V_\\pi(s) = E_{a \\sim \\pi(a | s)} R(s,a) $\n", - "\n", - "\n", - "* __Entropy Regularizer__\n", - " $$ H = - {1 \\over T} \\sum_t \\sum_a {\\pi(a|s_t) \\cdot \\log \\pi (a|s_t)}$$\n", - " * If we __maximize__ entropy we discourage agent from predicting zero probability to actions\n", - " prematurely (a.k.a. exploration)\n", - " \n", - " \n", - "So we optimize a linear combination of $L_{td}$ $- \\hat J$, $-H$\n", - " \n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "```\n", - "\n", - "\n", - "__One more thing:__ since we train on T-step rollouts, we can use N-step formula for advantage for free:\n", - " * At the last step, $A(s_t,a_t) = r(s_t, a_t) + \\gamma \\cdot V(s_{t+1}) - V(s) $\n", - " * One step earlier, $A(s_t,a_t) = r(s_t, a_t) + \\gamma \\cdot r(s_{t+1}, a_{t+1}) + \\gamma ^ 2 \\cdot V(s_{t+2}) - V(s) $\n", - " * Et cetera, et cetera. This way agent starts training much faster since it's estimate of A(s,a) depends less on his (imperfect) value function and more on actual rewards. There's also a [nice generalization](https://arxiv.org/abs/1506.02438) of this.\n", - "\n", - "\n", - "__Note:__ it's also a good idea to scale rollout_len up to learn longer sequences. You may wish set it to >=20 or to start at 10 and then scale up as time passes." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def to_one_hot(y, n_dims=None):\n", - " \"\"\" Take an integer tensor and convert it to 1-hot matrix. \"\"\"\n", - " y_tensor = y.to(dtype=torch.int64).view(-1, 1)\n", - " n_dims = n_dims if n_dims is not None else int(torch.max(y_tensor)) + 1\n", - " y_one_hot = torch.zeros(y_tensor.size()[0], n_dims).scatter_(1, y_tensor, 1)\n", - " return y_one_hot" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "opt = torch.optim.Adam(agent.parameters(), lr=1e-5)\n", - "\n", - "\n", - "def train_on_rollout(states, actions, rewards, is_not_done, prev_memory_states, gamma=0.99):\n", - " \"\"\"\n", - " Takes a sequence of states, actions and rewards produced by generate_session.\n", - " Updates agent's weights by following the policy gradient above.\n", - " Please use Adam optimizer with default parameters.\n", - " \"\"\"\n", - "\n", - " # shape: [batch_size, time, c, h, w]\n", - " states = torch.tensor(np.asarray(states), dtype=torch.float32)\n", - " actions = torch.tensor(np.array(actions), dtype=torch.int64) # shape: [batch_size, time]\n", - " rewards = torch.tensor(np.array(rewards), dtype=torch.float32) # shape: [batch_size, time]\n", - " is_not_done = torch.tensor(np.array(is_not_done), dtype=torch.float32) # shape: [batch_size, time]\n", - " rollout_length = rewards.shape[1] - 1\n", - "\n", - " # predict logits, probas and log-probas using an agent.\n", - " memory = [m.detach() for m in prev_memory_states]\n", - "\n", - " logits = [] # append logit sequence here\n", - " state_values = [] # append state values here\n", - " for t in range(rewards.shape[1]):\n", - " obs_t = states[:, t]\n", - "\n", - " # use agent to comute logits_t and state values_t.\n", - " # append them to logits and state_values array\n", - "\n", - " memory, (logits_t, values_t) = \n", - "\n", - " logits.append(logits_t)\n", - " state_values.append(values_t)\n", - "\n", - " logits = torch.stack(logits, dim=1)\n", - " state_values = torch.stack(state_values, dim=1)\n", - " probas = F.softmax(logits, dim=2)\n", - " logprobas = F.log_softmax(logits, dim=2)\n", - "\n", - " # select log-probabilities for chosen actions, log pi(a_i|s_i)\n", - " actions_one_hot = to_one_hot(actions, n_actions).view(\n", - " actions.shape[0], actions.shape[1], n_actions)\n", - " logprobas_for_actions = torch.sum(logprobas * actions_one_hot, dim=-1)\n", - "\n", - " # Now let's compute two loss components:\n", - " # 1) Policy gradient objective.\n", - " # Notes: Please don't forget to call .detach() on advantage term. Also please use mean, not sum.\n", - " # it's okay to use loops if you want\n", - " J_hat = 0 # policy objective as in the formula for J_hat\n", - "\n", - " # 2) Temporal difference MSE for state values\n", - " # Notes: Please don't forget to call on V(s') term. Also please use mean, not sum.\n", - " # it's okay to use loops if you want\n", - " value_loss = 0\n", - "\n", - " cumulative_returns = state_values[:, -1].detach()\n", - "\n", - " for t in reversed(range(rollout_length)):\n", - " r_t = rewards[:, t] # current rewards\n", - " # current state values\n", - " V_t = state_values[:, t]\n", - " V_next = state_values[:, t + 1].detach() # next state values\n", - " # log-probability of a_t in s_t\n", - " logpi_a_s_t = logprobas_for_actions[:, t]\n", - "\n", - " # update G_t = r_t + gamma * G_{t+1} as we did in week6 reinforce\n", - " cumulative_returns = G_t = r_t + gamma * cumulative_returns\n", - "\n", - " # Compute temporal difference error (MSE for V(s))\n", - " value_loss += \n", - "\n", - " # compute advantage A(s_t, a_t) using cumulative returns and V(s_t) as baseline\n", - " advantage = \n", - " advantage = advantage.detach()\n", - "\n", - " # compute policy pseudo-loss aka -J_hat.\n", - " J_hat += \n", - "\n", - " # regularize with entropy\n", - " entropy_reg = \n", - "\n", - " # add-up three loss components and average over time\n", - " loss = -J_hat / rollout_length +\\\n", - " value_loss / rollout_length +\\\n", - " -0.01 * entropy_reg\n", - "\n", - " # Gradient descent step\n", - " \n", - "\n", - " return loss.data.numpy()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# let's test it\n", - "memory = list(pool.prev_memory_states)\n", - "rollout_obs, rollout_actions, rollout_rewards, rollout_mask = pool.interact(10)\n", - "\n", - "train_on_rollout(rollout_obs, rollout_actions,\n", - " rollout_rewards, rollout_mask, memory)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Train \n", - "\n", - "just run train step and see if agent learns any better" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import clear_output\n", - "from tqdm import trange\n", - "from pandas import DataFrame\n", - "moving_average = lambda x, **kw: DataFrame(\n", - " {'x': np.asarray(x)}).x.ewm(**kw).mean().values\n", - "\n", - "rewards_history = []" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for i in trange(15000):\n", - "\n", - " memory = list(pool.prev_memory_states)\n", - " rollout_obs, rollout_actions, rollout_rewards, rollout_mask = pool.interact(\n", - " 10)\n", - " train_on_rollout(rollout_obs, rollout_actions,\n", - " rollout_rewards, rollout_mask, memory)\n", - "\n", - " if i % 100 == 0:\n", - " rewards_history.append(np.mean(evaluate(agent, env, n_games=1)))\n", - " clear_output(True)\n", - " plt.plot(rewards_history, label='rewards')\n", - " plt.plot(moving_average(np.array(rewards_history),\n", - " span=10), label='rewards ewma@10')\n", - " plt.legend()\n", - " plt.show()\n", - " if rewards_history[-1] >= 10000:\n", - " print(\"Your agent has just passed the minimum homework threshold\")\n", - " break" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Relax and grab some refreshments while your agent is locked in an infinite loop of violence and death.\n", - "\n", - "__How to interpret plots:__\n", - "\n", - "The session reward is the easy thing: it should in general go up over time, but it's okay if it fluctuates ~~like crazy~~. It's also OK if it reward doesn't increase substantially before some 10k initial steps. However, if reward reaches zero and doesn't seem to get up over 2-3 evaluations, there's something wrong happening.\n", - "\n", - "\n", - "Since we use a policy-based method, we also keep track of __policy entropy__ - the same one you used as a regularizer. The only important thing about it is that your entropy shouldn't drop too low (`< 0.1`) before your agent gets the yellow belt. Or at least it can drop there, but _it shouldn't stay there for long_.\n", - "\n", - "If it does, the culprit is likely:\n", - "* Some bug in entropy computation. Remember that it is $ - \\sum p(a_i) \\cdot log p(a_i) $\n", - "* Your agent architecture converges too fast. Increase entropy coefficient in actor loss. \n", - "* Gradient explosion - just [clip gradients](https://stackoverflow.com/a/56069467) and maybe use a smaller network\n", - "* Us. Or PyTorch developers. Or aliens. Or lizardfolk. Contact us on forums before it's too late!\n", - "\n", - "If you're debugging, just run `logits, values = agent.step(batch_states)` and manually look into logits and values. This will reveal the problem 9 times out of 10: you'll likely see some NaNs or insanely large numbers or zeros. Try to catch the moment when this happens for the first time and investigate from there." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### \"Final\" evaluation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym.wrappers\n", - "\n", - "with gym.wrappers.Monitor(make_env(), directory=\"videos\", force=True) as env_monitor:\n", - " final_rewards = evaluate(agent, env_monitor, n_games=20)\n", - "\n", - "print(\"Final mean reward\", np.mean(final_rewards))" - ] + ], + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + } }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Show video. This may not work in some setups. If it doesn't\n", - "# work for you, you can download the videos and view them locally.\n", - "\n", - "from pathlib import Path\n", - "from IPython.display import HTML\n", - "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", - "\n", - "HTML(\"\"\"\n", - "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 + "nbformat": 4, + "nbformat_minor": 1 } diff --git a/week08_pomdp/practice_tensorflow.ipynb b/week08_pomdp/practice_tensorflow.ipynb index f776acfa6..f4465f21a 100644 --- a/week08_pomdp/practice_tensorflow.ipynb +++ b/week08_pomdp/practice_tensorflow.ipynb @@ -22,9 +22,9 @@ " %tensorflow_version 1.x\n", " \n", " if not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", "\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week08_pomdp/atari_util.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week08_pomdp/atari_util.py\n", "\n", " !touch .setup_complete\n", "\n", @@ -284,15 +284,25 @@ "# work for you, you can download the videos and view them locally.\n", "\n", "from pathlib import Path\n", + "from base64 import b64encode\n", "from IPython.display import HTML\n", "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", "\n", "HTML(\"\"\"\n", "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" + "\"\"\".format(data_url))" ] }, { @@ -547,15 +557,25 @@ "# work for you, you can download the videos and view them locally.\n", "\n", "from pathlib import Path\n", + "from base64 import b64encode\n", "from IPython.display import HTML\n", "\n", - "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", "\n", "HTML(\"\"\"\n", "\n", - "\"\"\".format(video_names[-1])) # You can also try other indices" + "\"\"\".format(data_url))" ] }, { diff --git a/week08_pomdp/practice_theano.ipynb b/week08_pomdp/practice_theano.ipynb deleted file mode 100644 index 63d19af0a..000000000 --- a/week08_pomdp/practice_theano.ipynb +++ /dev/null @@ -1,509 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import print_function, division" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# If you are running on a server, launch xvfb to record game videos\n", - "# Please make sure you have xvfb installed\n", - "import os\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you are new to this course and want more instructions on how to set up environement and all the libs (docker / windows / gpu / blas / etc.), you could read [vital instructions here](https://github.com/yandexdataschool/Practical_RL/issues/1#issue-202648393). \n", - "\n", - "Please make sure that your have bleeding edge versions of Theano, Lasagne and Agentnet." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# General purpose libs import" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "%matplotlib inline\n", - "from timeit import default_timer as timer\n", - "\n", - "from IPython.core import display" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# if you have GPU uncomment the line below\n", - "%env THEANO_FLAGS = device = gpu0, floatX = float32" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Universal collection of a gentleman:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "\n", - "from agentnet.agent import Agent\n", - "from agentnet.experiments.openai_gym.wrappers import PreprocessImage\n", - "from agentnet.memory import WindowAugmentation, LSTMCell, GRUCell\n", - "from agentnet.target_network import TargetNetwork\n", - "from agentnet.resolver import EpsilonGreedyResolver, ProbabilisticResolver\n", - "from agentnet.experiments.openai_gym.pool import EnvPool\n", - "from agentnet.learning import qlearning\n", - "\n", - "import theano\n", - "import theano.tensor as T\n", - "\n", - "import lasagne\n", - "from lasagne.layers import DenseLayer, Conv2DLayer, InputLayer, NonlinearityLayer\n", - "from lasagne.layers import batch_norm, get_all_params, get_output, reshape, concat, dropout\n", - "from lasagne.nonlinearities import rectify, leaky_rectify, elu, tanh, softmax" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Helper function definitions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Downsample image, and crop it, showing only the most useful part of image. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def make_env():\n", - " env = gym.make(\"KungFuMaster-v0\")\n", - " env = PreprocessImage(env, height=64, width=64,\n", - " grayscale=True, crop=lambda img: img[60:-30, 7:])\n", - " return env" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Function for tracking performance while training " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def eval_and_plot(rewards, epoch_counter, pool, target_score, th_times, loop_times):\n", - " rewards[epoch_counter] = np.mean(pool.evaluate(\n", - " n_games=N_EVAL_GAMES, record_video=False, verbose=False))\n", - " info_string = \"Time (DL/All) {:.1f}/{:.1f} epoch={}, mean_score={:.2f}\"\n", - " info_string = info_string.format(np.mean(th_times), np.mean(loop_times),\n", - " epoch_counter, np.mean(rewards[epoch_counter]))\n", - " plt.figure(figsize=(8, 5))\n", - " plt.plot([rewards[i] for i in sorted(rewards.keys())])\n", - " plt.grid()\n", - " plt.ylabel(\"Mean reward over evaluation games\")\n", - " plt.title(info_string)\n", - " plt.show()\n", - " display.clear_output(wait=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Experiment setup\n", - "Here we basically just load the game and check that it works" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "env = gym.make('KungFuMaster-v0')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(env.env.get_action_meanings())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.imshow(env.reset())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "env = make_env()\n", - "plt.imshow(np.squeeze(env.reset()), interpolation='none', cmap='gray')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Global constants definition" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "All hyperparameters (except number of layers and neurons) are declared here as upper case letters along with global varaibles." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "N_ACTIONS = env.action_space.n\n", - "OBS_SHAPE = env.observation_space.shape\n", - "OBS_CHANNELS, OBS_HEIGHT, OBS_WIDTH = OBS_SHAPE\n", - "\n", - "# These 4 constanst were shown to lead to nearly state of the art on kung-fu master game\n", - "N_SIMULTANEOUS_GAMES = 10 # this is also known as number of agents in exp_replay_pool\n", - "SEQ_LENGTH = 25\n", - "\n", - "EVAL_EVERY_N_ITER = 100\n", - "N_EVAL_GAMES = 2\n", - "\n", - "N_FRAMES_IN_BUFFER = 4 # number of consequent frames to feed in CNN" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# A2C with memory" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "observation_layer = InputLayer((None,) + OBS_SHAPE)\n", - "prev_wnd = InputLayer(\n", - " [None, N_FRAMES_IN_BUFFER, OBS_CHANNELS, OBS_HEIGHT, OBS_WIDTH])\n", - "new_wnd = WindowAugmentation(observation_layer, prev_wnd)\n", - "wnd_reshape = reshape(\n", - " new_wnd, [-1, N_FRAMES_IN_BUFFER * OBS_CHANNELS, OBS_HEIGHT, OBS_WIDTH])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# TYPE YOUR CODE HERE\n", - "# provide the main body of the network : first three convolutional layers and dense one on top\n", - "# you may want to change nonlinearity - feel free to do this\n", - "# note that we have changed filter size here because of reduced image width and height compared to those in papers\n", - "conv1 = Conv2DLayer(wnd_reshape, ...)\n", - "...\n", - "dense = Dense(...)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# define 256 neuron LSTM cell:\n", - "# - define two input layers each of n_lstm_cells (maybe 256 is a good baseline) neurons\n", - "# - feed into `LSTMcell` this two layers and\n", - "# input layer (last `Dense` in case of A2C+LSTM) as additional third parameter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "neck_layer = concat([ , ]) # network neck " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# define actors head as\n", - "# - logits_layer – dense(neck) with nonlinearity=None\n", - "# - policy layer – softmax over logits_layer\n", - "........\n", - "action_layer = ProbabilisticResolver(policy_layer)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# critic head\n", - "V_layer = DenseLayer(neck_layer, 1, nonlinearity=None)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# `observation_layers` is input layer to NN, as usual\n", - "# `policy_estimators` should include 1) logits_layer and 2) V_layer\n", - "# `agent_states` is a dictionary of {new_value: old_value}. You should bother to update\n", - "# a) prev window (input buffer, prev_wnd) b) previous LSTM cell state c) output of LSTM cell\n", - "# `action_layers` is action_layer, as usual : )\n", - "agent = Agent(....)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# may need to adjust (increasing N_SIMULTANEOUS_GAMES is usually a good idea)\n", - "pool = EnvPool(agent, make_env, n_games=N_SIMULTANEOUS_GAMES)\n", - "replay = pool.experience_replay" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_, _, _, action_seq, (logits_seq, V_seq) = agent.get_sessions(\n", - " replay,\n", - " session_length=SEQ_LENGTH,\n", - " experience_replay=True\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# compute pi(a|s) and log(pi(a|s)) manually [use logsoftmax]\n", - "# we can't guarantee that theano optimizes logsoftmax automatically since it's still in dev\n", - "# for more info see (https://github.com/Theano/Theano/issues/2944 of 2015 year)\n", - "\n", - "# logits_seq.shape is (batch_size, SEQ_LENGTH, N_ACTIONS)\n", - "logits_flat = logits_seq.reshape([-1, N_ACTIONS])\n", - "policy_seq = T.nnet.softmax(logits_flat).reshape(logits_seq.shape)\n", - "logpolicy_seq = T.nnet.logsoftmax(logits_flat).reshape(logits_seq.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get policy gradient\n", - "from agentnet.learning import a2c\n", - "elwise_actor_loss, elwise_critic_loss = a2c.get_elementwise_objective(\n", - " policy=logpolicy_seq,\n", - " treat_policy_as_logpolicy=True,\n", - " state_values=V_seq[:, :, 0],\n", - " actions=replay.actions[0],\n", - " rewards=replay.rewards/10,\n", - " is_alive=replay.is_alive,\n", - " gamma_or_gammas=0.99,\n", - " n_steps=None,\n", - " return_separate=True\n", - ")\n", - "\n", - "# add losses with magic numbers\n", - "# (you can change them more or less harmlessly, this usually just makes learning faster/slower)\n", - "# actor and critic multipliers were selected guided by prior knowledge\n", - "# entropy / regularization multipliers were tuned with logscale gridsearch\n", - "# NB: regularization affects exploration\n", - "reg_logits = T.mean(logits_seq ** 2)\n", - "reg_entropy = T.mean(T.sum(policy_seq * logpolicy_seq, axis=-1))\n", - "loss = 0.1 * elwise_actor_loss.mean() + 0.25 * elwise_critic_loss.mean() + \\\n", - " 1e-3 * reg_entropy + 1e-3 * reg_logits" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Compute weight updates, clip by norm for stability\n", - "weights = lasagne.layers.get_all_params(\n", - " [V_layer, policy_layer], trainable=True)\n", - "grads = T.grad(loss, weights)\n", - "grads = lasagne.updates.total_norm_constraint(grads, 10)\n", - "updates = lasagne.updates.adam(grads, weights)\n", - "train_step = theano.function([], loss, updates=updates)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Train " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "epoch_counter = 1 # starting epoch\n", - "rewards = {} # full game rewards\n", - "target_score = 10000\n", - "loss, eval_rewards = 0, []" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "untrained_reward = np.mean(pool.evaluate(\n", - " n_games=5, record_video=False, verbose=False))\n", - "untrained_reward" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# IF you feel disgust about stderr messages due to pool.evaluate() execution\n", - "# which pollutes output of jupyter cell, you could do one of the following:\n", - "# 1. use warnings.filterwarnings(\"ignore\")\n", - "# 2. use cell magic %%capture\n", - "# 3. simply redirect stderr to /dev/null with command\n", - "# import os, sys\n", - "# stder_old = sys.stderr\n", - "# sys.stderr = open(os.devnull, 'w')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "th_times, loop_times = [], []\n", - "for i in range(2000):\n", - " loop_starts = timer()\n", - " pool.update(SEQ_LENGTH)\n", - "\n", - " train_starts = timer()\n", - "\n", - " \n", - " raise NotImplementedError\n", - "\n", - " th_times.append(timer() - train_starts)\n", - " epoch_counter += 1\n", - " loop_times.append(timer() - loop_starts)\n", - "\n", - " # You may want to set EVAL_EVERY_N_ITER=1 for the time being\n", - " if epoch_counter % EVAL_EVERY_N_ITER == 0:\n", - " eval_and_plot(rewards, epoch_counter, pool,\n", - " target_score, th_times, loop_times)\n", - " if rewards[epoch_counter] >= target_score:\n", - " print(\"VICTORY!\")\n", - " break\n", - " th_times, loop_times = [], []" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "eval_and_plot(rewards, epoch_counter, pool, target_score, th_times, loop_times)" - ] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/week08_pomdp/theano_optional_recurrence_tutorial.ipynb b/week08_pomdp/theano_optional_recurrence_tutorial.ipynb deleted file mode 100644 index deeeda072..000000000 --- a/week08_pomdp/theano_optional_recurrence_tutorial.ipynb +++ /dev/null @@ -1,434 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Recurrent memory intro\n", - "\n", - "In the seminar you'll deploy recurrent neural network inside SARSA agent.\n", - "\n", - "The environment it plays is a simple POMDP of rock-paper-scissors game with exploitable opponent.\n", - "\n", - "#### Instructions\n", - "\n", - "First, read through the code and __run it as you read__. The code will create a feedforward neural network and train it with SARSA.\n", - "\n", - "Since the game is partially observable, default algorithm will won't reach optimal score. In fact, it's unstable and may even end up worse than random.\n", - "\n", - "After you ran the code, __find the two ```#YOUR CODE HERE``` chunks__ (mb ctrl+f) and implement a recurrent memory.\n", - "\n", - "Re-run the experiment and compare the performance of feedworward vs recurrent agent. \n", - "RNN should be _much_ better, session __reward > 50__.\n", - "\n", - "After you're done with that, proceed to the next part, for it is going to be much more interesting." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "%matplotlib inline\n", - "\n", - "# number of parallel agents and batch sequence length (frames)\n", - "N_AGENTS = 10\n", - "SEQ_LENGTH = 25" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The environment we're going to use now is not a default gym env.\n", - "\n", - "It was instead written from scratch in `rockpaperscissors.py`.\n", - "\n", - "Morale: you can make your own gym environments easily with anything you want (including OS and the web, e.g. selenium)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "from rockpaperscissors import RockPaperScissors\n", - "\n", - "\n", - "def make_env():\n", - " env = RockPaperScissors()\n", - " return gym.wrappers.TimeLimit(env, max_episode_steps=100)\n", - "\n", - "\n", - "# spawn game instance\n", - "env = make_env()\n", - "observation_shape = env.observation_space.shape\n", - "n_actions = env.action_space.n\n", - "\n", - "env.reset()\n", - "obs = env.step(env.action_space.sample())[0]\n", - "\n", - "print obs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Basic agent setup\n", - "Here we define a simple agent that maps game images into policy with a minimalistic neural net\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# setup theano/lasagne. Prefer CPU\n", - "%env THEANO_FLAGS = device = cpu, floatX = float32\n", - "\n", - "import theano\n", - "import lasagne\n", - "import theano.tensor as T\n", - "from lasagne.layers import *" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# observation\n", - "obs = InputLayer((None,)+observation_shape,)\n", - "\n", - "nn = DenseLayer(obs, 32, nonlinearity=T.nnet.elu)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.memory import RNNCell, GRUCell, LSTMCell\n", - ":\n", - "# Implement a recurrent agent memory by un-comemnting code below and defining h_new\n", - "\n", - "#h_prev = InputLayer((None,50),name=\"previous memory state with 50 units\")\n", - "\n", - "# h_new = RNNCell(,,nonlinearity=T.nnet.elu)\n", - "\n", - "# (IMPORTANT!) use new cell to compute q-values instead of dense layer\n", - "#nn = h_new" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.resolver import EpsilonGreedyResolver\n", - "l_qvalues = DenseLayer(nn, n_actions)\n", - "l_actions = EpsilonGreedyResolver(l_qvalues)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Agent, as usual" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.agent import Agent\n", - "\n", - "# uncomment agent_states and define what layers should be used\n", - "\n", - "agent = Agent(observation_layers=obs,\n", - " policy_estimators=(l_qvalues),\n", - " # agent_states={:},\n", - " action_layers=l_actions)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Pool, as usual" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from agentnet.experiments.openai_gym.pool import EnvPool\n", - "\n", - "pool = EnvPool(agent, make_env, n_games=16) # may need to adjust\n", - "\n", - "pool.update(SEQ_LENGTH)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Learning\n", - "\n", - "For N+1'st time, we use vanilla SARSA" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "replay = pool.experience_replay\n", - "\n", - "qvalues_seq = agent.get_sessions(\n", - " replay,\n", - " session_length=SEQ_LENGTH,\n", - " experience_replay=True,\n", - " unroll_scan=False, # this new guy makes compilation 100x faster for a bit slower runtime\n", - ")[-1]\n", - "\n", - "auto_updates = agent.get_automatic_updates() # required if unroll_scan=False" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get SARSA mse loss\n", - "from agentnet.learning import sarsa\n", - "elemwise_mse = sarsa.get_elementwise_objective(qvalues_seq,\n", - " actions=replay.actions[0],\n", - " rewards=replay.rewards,\n", - " is_alive=replay.is_alive)\n", - "loss = elemwise_mse.mean()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Compute weights and updates\n", - "weights = lasagne.layers.get_all_params([l_actions], trainable=True)\n", - "\n", - "updates = lasagne.updates.adam(loss, weights)\n", - "\n", - "# compile train function\n", - "train_step = theano.function([], loss, updates=auto_updates+updates)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Demo run" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "untrained_reward = np.mean(pool.evaluate(save_path=\"./records\", n_games=10,\n", - " record_video=False, use_monitor=False))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Training loop" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# starting epoch\n", - "epoch_counter = 1\n", - "\n", - "# full game rewards\n", - "rewards = {0: untrained_reward}\n", - "loss, reward = 0, untrained_reward" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from tqdm import trange\n", - "from IPython.display import clear_output\n", - "\n", - "for i in trange(10000):\n", - "\n", - " # play\n", - " pool.update(SEQ_LENGTH)\n", - " # train\n", - " loss = train_step()\n", - "\n", - " # update epsilon\n", - " new_epsilon = max(0.01, 1-2e-4*epoch_counter)\n", - " l_actions.epsilon.set_value(np.float32(new_epsilon))\n", - "\n", - " # record current learning progress and show learning curves\n", - " if epoch_counter % 100 == 0:\n", - " clear_output(True)\n", - " print(\"iter=%i,loss=%.3f,epsilon=%.3f\" %\n", - " (epoch_counter, loss, new_epsilon))\n", - " reward = 0.9*reward + 0.1*np.mean(np.mean(pool.evaluate(save_path=\"./records\", n_games=10,\n", - " record_video=False, use_monitor=False)))\n", - " rewards[epoch_counter] = reward\n", - "\n", - " plt.plot(*zip(*sorted(rewards.items(), key=lambda (t, r): t)))\n", - " plt.grid()\n", - " plt.show()\n", - "\n", - " epoch_counter += 1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Evaluating results\n", - " * Here we plot learning curves and sample testimonials" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "plt.plot(*zip(*sorted(rewards.items(), key=lambda k: k[0])))\n", - "plt.grid()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Bonus (1++ points)\n", - "\n", - "Compare two types of nonlinearities for the RNN:\n", - "- `T.nnet.elu`\n", - "- `T.nnet.sigmoid`\n", - "\n", - "Re-train agent at least 10 times. It's probably a good idea to automate the process.\n", - "\n", - "Notice something weird? Any clue why this happens and how to fix it?\n", - "\n", - "_Running the experiment and reporting results gets your 1 point. Reward will get much higher as you go down the rabbit hole! Don't forget to send this notebook to Anytask and mention that you went for this bonus._" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# results, ideas, solutions..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n", - "```\n", - "\n", - "\n", - "```\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/week09_policy_II/README.md b/week09_policy_II/README.md index b10fd7592..727562223 100644 --- a/week09_policy_II/README.md +++ b/week09_policy_II/README.md @@ -2,17 +2,17 @@ * [__slides #2 (dpg)__](https://yadi.sk/i/uV6IA-C23UTn7c) ## Materials -This section covers some steroids for policy gradient methods, along with a cool general trick called +This section covers some steroids for policy gradient methods, along with a cool general trick called * Lecture on NPG and TRPO by J. Schulman - [video](https://www.youtube.com/watch?v=_t5fpZuuf-4) * Alternative lecture on TRPO and open problems by... J. Schulman - [video](https://www.youtube.com/watch?v=gb5Q2XL5c8A) -* Our videos: [lecture](https://yadi.sk/i/c7GR1kAAJc00Og), [seminar(pytorch)](https://yadi.sk/i/OGZJJjkQH_7h5g) [seminar(theano)](https://yadi.sk/i/b0ol2gUV3HiKKJ) (russian) +* Our videos: [lecture](https://yadi.sk/i/c7GR1kAAJc00Og), [seminar(PyTorch)](https://yadi.sk/i/OGZJJjkQH_7h5g) (russian) * Original articles - [TRPO](https://arxiv.org/abs/1502.05477), [NPG](https://papers.nips.cc/paper/2073-a-natural-policy-gradient.pdf) ## Practice -* Seminar: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week09_policy_II/seminar_TRPO_pytorch.ipynb) +* TRPO: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week09_policy_II/seminar_TRPO_pytorch.ipynb) -* Homework: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week09_policy_II/ppo.ipynb) +* PPO: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week09_policy_II/ppo.ipynb) ## More: Reinforcement learning in large/continuous action spaces While you already know algorithms that will work with continuously many actions, it can't hurt to learn something more specialized. @@ -21,5 +21,4 @@ While you already know algorithms that will work with continuously many actions, * Deterministic policy gradient - [article](https://arxiv.org/pdf/1512.07679.pdf), [post+code](https://yanpanlau.github.io/2016/10/11/Torcs-Keras.html) * Stochastic value gradient - [article](https://arxiv.org/abs/1510.09142) * Embedding large discrete action spaces for RL - [article](https://arxiv.org/pdf/1512.07679.pdf) - * Lecture by A. Seleznev, 5vision (russian) - [video](www.youtube.com/watch?v=j1L2FnanXPo&t=119m45s) - + * Lecture by A. Seleznev, 5vision (russian) - [video](https://www.youtube.com/watch?v=j1L2FnanXPo&t=119m45s) diff --git a/week09_policy_II/mujoco_wrappers.py b/week09_policy_II/mujoco_wrappers.py index 72bc1bd9c..9ca1b9dae 100644 --- a/week09_policy_II/mujoco_wrappers.py +++ b/week09_policy_II/mujoco_wrappers.py @@ -1,6 +1,6 @@ """ MuJoCo env wrappers. """ # Adapted from https://github.com/openai/baselines -import gym +import gymnasium as gym import numpy as np @@ -83,17 +83,17 @@ def observation(self, obs): return obs def step(self, action): - obs, rews, resets, info = self.env.step(action) + obs, rews, terminated, truncated, info = self.env.step(action) self.ret = self.ret * self.gamma + rews obs = self.observation(obs) if self.ret_rmv: self.ret_rmv.update(self.ret) rews = np.clip(rews / np.sqrt(self.ret_rmv.var + self.eps), -self.cliprew, self.cliprew) - self.ret[resets] = 0. - return obs, rews, resets, info + self.ret[terminated] = 0. + return obs, rews, terminated, truncated, info def reset(self, **kwargs): self.ret = np.zeros(getattr(self.env.unwrapped, "nenvs", 1)) - obs = self.env.reset(**kwargs) - return self.observation(obs) + obs, info = self.env.reset(**kwargs) + return self.observation(obs), info diff --git a/week09_policy_II/ppo.ipynb b/week09_policy_II/ppo.ipynb index 2cd6d67d0..9640490c8 100644 --- a/week09_policy_II/ppo.ipynb +++ b/week09_policy_II/ppo.ipynb @@ -3,15 +3,22 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "j9dfWABRNCVm", + "outputId": "ee8f0e74-ab77-4b9e-ff10-05d4e7a0930b" + }, "outputs": [], "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", - " \n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week09_policy_II/runners.py\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/week09_policy_II/mujoco_wrappers.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/mujoco_wrappers.py\n", + "\n", + " !pip -q install gymnasium[mujoco]\n", " \n", " !touch .setup_complete\n", "\n", @@ -24,7 +31,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "WI0kqjVINCVt" + }, "source": [ "# Implementing Proximal Policy Optimization \n", "\n", @@ -36,47 +45,52 @@ "You will be solving a continuous control environment on which it may be easier and faster \n", "to train an agent, however note that PPO here may not be the best algorithm as, for example,\n", "Deep Deterministic Policy Gradient and Soft Actor Critic may be more suited \n", - "for continuous control environments. To run the environment you will need to install \n", - "[pybullet-gym](https://github.com/benelot/pybullet-gym) which unlike MuJoCo \n", - "does not require you to have a license.\n", - "\n", - "To install the library:" + "for continuous control environments." ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "MZeKC7aO4RIC" + }, "outputs": [], "source": [ - "!git clone https://github.com/benelot/pybullet-gym lib/pybullet-gym\n", - "!pip install -e lib/pybullet-gym" + "from tqdm import tqdm\n", + "from sklearn.metrics import r2_score" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "Iod_fZUFNCVw" + }, "source": [ "The overall structure of the code is similar to the one in the A2C optional homework, but don't worry if you haven't done it, it should be relatively easy to figure it out. \n", "First, we will create an instance of the environment. \n", "We will normalize the observations and rewards, but before that you will need a wrapper that will \n", - "write summaries, mainly, the total reward during an episode. You can either use one for `TensorFlow` \n", + "write summaries, mainly, the total reward during an episode. You can either use one for `TensorBoard` \n", "implemented in `atari_wrappers.py` file from the optional A2C homework, or implement your own. " ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Y2N76WIRNCVx", + "outputId": "b23c69ce-eedb-4043-9f8c-1d89eec416a8" + }, "outputs": [], "source": [ - "import gym \n", - "import pybulletgym\n", + "import gymnasium as gym\n", "\n", - "env = gym.make(\"HalfCheetahMuJoCoEnv-v0\")\n", + "env = gym.make(\"HalfCheetah-v4\", render_mode=\"rgb_array\")\n", "print(\"observation space: \", env.observation_space,\n", - " \"\\nobservations:\", env.reset())\n", - "print(\"action space: \", env.action_space, \n", + " \"\\nobservations:\", env.reset()[0])\n", + "print(\"action space: \", env.action_space,\n", " \"\\naction_sample: \", env.action_space.sample())" ] }, @@ -86,20 +100,60 @@ "metadata": {}, "outputs": [], "source": [ + "import matplotlib.pyplot as plt\n", + "plt.imshow(env.render())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_au8nSY479qw" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", "class Summaries(gym.Wrapper):\n", - " \"\"\" Wrapper to write summaries. \"\"\"\n", - " def step(self, action):\n", - " # TODO: implement writing summaries\n", - " return self.env.step(action)\n", - " \n", - " def reset(self, **kwargs):\n", - " # TODO: implement writing summaries\n", - " return self.env.reset(**kwargs)" + " \"\"\" Wrapper to write summaries. \"\"\"\n", + " def __init__(self, env):\n", + " super().__init__(env)\n", + " self.episode_counter = 0\n", + " self.current_step_var = 0\n", + "\n", + " self.episode_rewards = []\n", + " self.episode_lens = []\n", + "\n", + " self.current_reward = 0\n", + " self.current_len = 0\n", + "\n", + " def step(self, action):\n", + " obs, rew, terminated, truncated, info = self.env.step(action)\n", + "\n", + " self.current_reward += rew\n", + " self.current_len += 1\n", + " self.current_step_var += 1\n", + "\n", + " if terminated or truncated:\n", + " self.episode_rewards.append((self.current_step_var, self.current_reward))\n", + " self.episode_lens.append((self.current_step_var, self.current_len))\n", + "\n", + " return obs, rew, terminated, truncated, info\n", + "\n", + " def reset(self, **kwargs):\n", + " self.episode_counter += 1\n", + "\n", + " self.current_reward = 0\n", + " self.current_len = 0\n", + "\n", + " return self.env.reset(**kwargs)" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "JVom_S9yNCVz" + }, "source": [ "The normalization wrapper will subtract running mean from observations and rewards and divide \n", "the resulting quantities by the running variances." @@ -108,29 +162,34 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "lxevKC-FNCVz", + "outputId": "11bcf7dd-b04c-47c8-c8e0-ca8724aee842" + }, "outputs": [], "source": [ "from mujoco_wrappers import Normalize\n", "\n", - "env = Normalize(Summaries(gym.make(\"HalfCheetahMuJoCoEnv-v0\")));\n", - "env.unwrapped.seed(0);" + "env = Normalize(Summaries(gym.make(\"HalfCheetah-v4\", render_mode=\"rgb_array\")));\n", + "env.reset(seed=0)" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "_9lf2Z8bNCV0" + }, "source": [ "Next, you will need to define a model for training. We suggest that you use two separate networks: one for policy\n", "and another for value function. Each network should be a 3-layer MLP with 64 hidden units, $\\mathrm{tanh}$ \n", - "activation function, kernel matrices initialized with orthogonal initializer with parameter $\\sqrt{2}$\n", - "and biases initialized with zeros. \n", + "activation function.\n", "\n", "Our policy distribution is going to be multivariate normal with diagonal covariance. \n", "The network from above will predict the mean, and the covariance should be represented by a single \n", - "(learned) vector of size 6 (corresponding to the dimensionality of the action space from above). \n", - "You should initialize this vector to zero and take the exponent of it to always\n", - "have a non-negative quantity. \n", + "(learned) vector of size 6 (corresponding to the dimensionality of the action space from above). Or you can also predict the variance using your model. You should take the exponent of that values to always have a non-negative quantity. \n", "\n", "Overall the model should return three things: predicted mean of the distribution, variance vector, \n", "value function. " @@ -139,18 +198,47 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "OwwLcUApNCV0" + }, "outputs": [], "source": [ "# import tensorflow as tf\n", - "# import torch\n", + "import torch\n", + "\n", + "from torch import nn\n", + "from torch.nn import functional as F\n", + "import torch\n", + "\n", + "class PolicyModel(nn. Module):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.h = 64\n", "\n", - "" + " self.policy_model = < Create your model >\n", + "\n", + " self.value_model = < Create your model >\n", + "\n", + " def get_policy(self, x):\n", + " < insert your code here >\n", + " return means, var\n", + "\n", + " def get_value(self, x):\n", + " out = self.value_model(x.float())\n", + " return out\n", + "\n", + " def forward(self, x):\n", + " policy = self.get_policy(x)\n", + " value = self.get_value(x)\n", + "\n", + " return policy, value" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "YI6d9Xq_NCV1" + }, "source": [ "This model will be wrapped by a `Policy`. The policy can work in two modes, but in either case \n", "it is going to return dictionary with string-type keys. The first mode is when the policy is \n", @@ -178,21 +266,47 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "C54tGZahXbSa" + }, "outputs": [], "source": [ + "from torch.distributions.normal import Normal\n", + "from torch.distributions.multivariate_normal import MultivariateNormal\n", + "\n", "class Policy:\n", - " def __init__(self, model):\n", - " self.model = model\n", + " def __init__(self, model):\n", + " self.model = model\n", " \n", - " def act(self, inputs, training=False):\n", - " \n", - " # Should return a dict." + " def act(self, inputs, training=False):\n", + " inputs = torch.tensor(inputs)\n", + " if inputs.ndim < 2:\n", + " inputs = inputs.unsqueeze(0)\n", + " inputs = inputs.cuda()\n", + " \n", + " batch_size = inputs.shape[0]\n", + "\n", + " < insert your code here >\n", + " normal_distr = MultivariateNormal(means, covar_matrix)\n", + "\n", + " actions = normal_distr.sample()\n", + " log_probs = normal_distr.log_prob(actions)\n", + "\n", + " values = self.model.get_value(inputs)\n", + "\n", + " if not training:\n", + " return {'actions': actions.cpu().numpy().tolist()[0], \n", + " 'log_probs': log_probs[0].detach().cpu().numpy(),\n", + " 'values': values[0].detach().cpu().numpy()}\n", + " else:\n", + " return {'distribution': normal_distr, 'values': values}" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "-kML-jSsNCV2" + }, "source": [ "We will use `EnvRunner` to perform interactions with an environment with a policy for a fixed number of timesteps. Calling `.get_next()` on a runner will return a trajectory — dictionary \n", "containing keys\n", @@ -212,18 +326,19 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "5LeiuohcNCV3" + }, "outputs": [], "source": [ "class AsArray:\n", - " \"\"\" \n", - " Converts lists of interactions to ndarray.\n", - " \"\"\"\n", - " def __call__(self, trajectory):\n", - " # Modify trajectory inplace. \n", - " for k, v in filter(lambda kv: kv[0] != \"state\",\n", - " trajectory.items()):\n", - " trajectory[k] = np.asarray(v)" + " \"\"\" \n", + " Converts lists of interactions to ndarray.\n", + " \"\"\"\n", + " def __call__(self, trajectory):\n", + " # Modify trajectory inplace. \n", + " for k, v in filter(lambda kv: kv[0] != \"state\", trajectory.items()):\n", + " trajectory[k] = np.asarray(v)" ] }, { @@ -231,15 +346,94 @@ "execution_count": null, "metadata": {}, "outputs": [], + "source": [ + "\"\"\" RL env runner \"\"\"\n", + "from collections import defaultdict\n", + "\n", + "import numpy as np\n", + "\n", + "\n", + "class EnvRunner:\n", + " \"\"\" Reinforcement learning runner in an environment with given policy \"\"\"\n", + "\n", + " def __init__(self, env, policy, nsteps, transforms=None, step_var=None):\n", + " self.env = env\n", + " self.policy = policy\n", + " self.nsteps = nsteps\n", + " self.transforms = transforms or []\n", + " self.step_var = step_var if step_var is not None else 0\n", + " self.state = {\"latest_observation\": self.env.reset()[0]}\n", + "\n", + " @property\n", + " def nenvs(self):\n", + " \"\"\" Returns number of batched envs or `None` if env is not batched \"\"\"\n", + " return getattr(self.env.unwrapped, \"nenvs\", None)\n", + "\n", + " def reset(self, **kwargs):\n", + " \"\"\" Resets env and runner states. \"\"\"\n", + " self.state[\"latest_observation\"], info = self.env.reset(**kwargs)\n", + " self.policy.reset()\n", + "\n", + " def get_next(self):\n", + " \"\"\" Runs the agent in the environment. \"\"\"\n", + " trajectory = defaultdict(list, {\"actions\": []})\n", + " observations = []\n", + " rewards = []\n", + " resets = []\n", + " self.state[\"env_steps\"] = self.nsteps\n", + "\n", + " for i in range(self.nsteps):\n", + " observations.append(self.state[\"latest_observation\"])\n", + " act = self.policy.act(self.state[\"latest_observation\"])\n", + " if \"actions\" not in act:\n", + " raise ValueError(\"result of policy.act must contain 'actions' \"\n", + " f\"but has keys {list(act.keys())}\")\n", + " for key, val in act.items():\n", + " trajectory[key].append(val)\n", + "\n", + " obs, rew, terminated, truncated, _ = self.env.step(trajectory[\"actions\"][-1])\n", + " done = np.logical_or(terminated, truncated)\n", + " self.state[\"latest_observation\"] = obs\n", + " rewards.append(rew)\n", + " resets.append(done)\n", + " self.step_var += self.nenvs or 1\n", + "\n", + " # Only reset if the env is not batched. Batched envs should\n", + " # auto-reset.\n", + " if not self.nenvs and np.all(done):\n", + " self.state[\"env_steps\"] = i + 1\n", + " self.state[\"latest_observation\"] = self.env.reset()[0]\n", + "\n", + " trajectory.update(\n", + " observations=observations,\n", + " rewards=rewards,\n", + " resets=resets)\n", + " trajectory[\"state\"] = self.state\n", + "\n", + " for transform in self.transforms:\n", + " transform(trajectory)\n", + " return trajectory" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wNzPNxKLNCV4", + "outputId": "e15b29e7-1864-45db-e67a-3f1994b77a81" + }, + "outputs": [], "source": [ "import numpy as np\n", - "from runners import EnvRunner\n", "\n", "class DummyPolicy:\n", - " def act(self, inputs, training=False):\n", - " assert not training\n", - " return {\"actions\": np.random.randn(6), \"values\": np.nan}\n", - " \n", + " def act(self, inputs, training=False):\n", + " assert not training\n", + " return {\"actions\": np.random.randn(6), \"values\": np.nan}\n", + "\n", "runner = EnvRunner(env, DummyPolicy(), 3,\n", " transforms=[AsArray()])\n", "trajectory = runner.get_next()\n", @@ -249,7 +443,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "NyhcvAMZNCV5" + }, "source": [ "You will need to implement the following two transformations. \n", "\n", @@ -281,23 +477,66 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "AC5rUuiKNCV6" + }, "outputs": [], "source": [ + "import os\n", "class GAE:\n", - " \"\"\" Generalized Advantage Estimator. \"\"\"\n", - " def __init__(self, policy, gamma=0.99, lambda_=0.95):\n", - " self.policy = policy\n", - " self.gamma = gamma\n", - " self.lambda_ = lambda_\n", + " \"\"\" Generalized Advantage Estimator. \"\"\"\n", + " def __init__(self, policy, gamma=0.99, lambda_=0.95):\n", + " self.policy = policy\n", + " self.gamma = gamma\n", + " self.lambda_ = lambda_\n", + "\n", + " def __call__(self, trajectory):\n", + " gamma = self.gamma\n", + " lambda_ = self.lambda_\n", + " \n", + " < insert your code here >" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def test_gae():\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/actions.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/log_probs.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/values.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/observations.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/rewards.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/resets.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/state.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/advantages.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/value_targets.npy\n", + " !curl -O https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/test_ppo/policy\n", + "\n", + " trajectory = {}\n", + " for key in ['actions', 'log_probs', 'values', 'observations', 'rewards', 'resets']:\n", + " trajectory[key] = np.load(f'{key}.npy', allow_pickle=True)\n", + " trajectory['state'] = {\"latest_observation\": np.load('state.npy')}\n", " \n", - " def __call__(self, trajectory):\n", - " " + " policy = torch.load(f'policy')\n", + " gae_to_test = GAE(policy, gamma=0.99, lambda_=0.95)\n", + " \n", + " gae_to_test(trajectory)\n", + " \n", + " for key in ['advantages', 'value_targets']:\n", + " assert np.allclose(np.load(f'{key}.npy'), trajectory[key], atol=2e-2)\n", + " \n", + " print(\"It's all good!\")\n", + "test_gae()" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "yce0A8x7NCV7" + }, "source": [ "The main advantage of PPO over simpler policy based methods like A2C is that it is possible\n", "to train on the same trajectory for multiple gradient steps. The following class wraps \n", @@ -308,56 +547,96 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "J7tIjwbkNCV8" + }, "outputs": [], "source": [ "class TrajectorySampler:\n", - " \"\"\" Samples minibatches from trajectory for a number of epochs. \"\"\"\n", - " def __init__(self, runner, num_epochs, num_minibatches, transforms=None):\n", - " self.runner = runner\n", - " self.num_epochs = num_epochs\n", - " self.num_minibatches = num_minibatches\n", - " self.transforms = transforms or []\n", - " self.minibatch_count = 0\n", - " self.epoch_count = 0\n", - " self.trajectory = None\n", - " \n", - " def shuffle_trajectory(self):\n", - " \"\"\" Shuffles all elements in trajectory.\n", - " \n", - " Should be called at the beginning of each epoch.\n", - " \"\"\"\n", - " \n", - " \n", - " def get_next(self):\n", - " \"\"\" Returns next minibatch. \"\"\"\n", - " " + " \"\"\" Samples minibatches from trajectory for a number of epochs. \"\"\"\n", + " def __init__(self, runner, num_epochs, num_minibatches, transforms=None):\n", + " self.runner = runner\n", + " self.num_epochs = num_epochs\n", + " self.num_minibatches = num_minibatches\n", + " self.transforms = transforms or []\n", + " self.minibatch_count = 0\n", + " self.epoch_count = 0\n", + " self.trajectory = None\n", + "\n", + " def shuffle_trajectory(self):\n", + " \"\"\" Shuffles all elements in trajectory.\n", + "\n", + " Should be called at the beginning of each epoch.\n", + " \"\"\"\n", + " trajectory_len = self.trajectory[\"observations\"].shape[0]\n", + "\n", + " permutation = np.random.permutation(trajectory_len)\n", + " for key, value in self.trajectory.items():\n", + " if key != 'state':\n", + " self.trajectory[key] = value[permutation]\n", + "\n", + " def get_next(self):\n", + " \"\"\" Returns next minibatch. \"\"\"\n", + " if not self.trajectory:\n", + " self.trajectory = self.runner.get_next()\n", + "\n", + " if self.minibatch_count == self.num_minibatches:\n", + " self.shuffle_trajectory()\n", + " self.minibatch_count = 0\n", + " self.epoch_count += 1\n", + "\n", + " if self.epoch_count == self.num_epochs:\n", + " self.trajectory = self.runner.get_next()\n", + "\n", + " self.shuffle_trajectory()\n", + " self.minibatch_count = 0\n", + " self.epoch_count = 0\n", + "\n", + " trajectory_len = self.trajectory[\"observations\"].shape[0]\n", + "\n", + " batch_size = trajectory_len//self.num_minibatches\n", + "\n", + " minibatch = {}\n", + " for key, value in self.trajectory.items():\n", + " if key != 'state':\n", + " minibatch[key] = value[self.minibatch_count*batch_size: (self.minibatch_count + 1)*batch_size]\n", + "\n", + " self.minibatch_count += 1\n", + "\n", + " for transform in self.transforms:\n", + " transform(minibatch)\n", + "\n", + " return minibatch" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "U1UgHPb0NCV8" + }, "source": [ - "A common trick to use with GAE is to normalize advantages, the following transformation does that. " + "A common trick to use with GAE is to normalize advantages, please implement the normalization." ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "GZrUlmFYNCV9" + }, "outputs": [], "source": [ "class NormalizeAdvantages:\n", - " \"\"\" Normalizes advantages to have zero mean and variance 1. \"\"\"\n", - " def __call__(self, trajectory):\n", - " adv = trajectory[\"advantages\"]\n", - " adv = (adv - adv.mean()) / (adv.std() + 1e-8)\n", - " trajectory[\"advantages\"] = adv" + " \"\"\" Normalizes advantages to have zero mean and variance 1. \"\"\"\n", + " def __call__(self, trajectory):\n", + " < insert your code here >" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "DXnare-INCV-" + }, "source": [ "Finally, we can create our PPO runner. " ] @@ -365,28 +644,32 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "tx0Yr0GtNCV_" + }, "outputs": [], "source": [ "def make_ppo_runner(env, policy, num_runner_steps=2048,\n", " gamma=0.99, lambda_=0.95, \n", " num_epochs=10, num_minibatches=32):\n", - " \"\"\" Creates runner for PPO algorithm. \"\"\"\n", - " runner_transforms = [AsArray(),\n", + " \"\"\" Creates runner for PPO algorithm. \"\"\"\n", + " runner_transforms = [AsArray(),\n", " GAE(policy, gamma=gamma, lambda_=lambda_)]\n", - " runner = EnvRunner(env, policy, num_runner_steps, \n", + " runner = EnvRunner(env, policy, num_runner_steps, \n", " transforms=runner_transforms)\n", - " \n", - " sampler_transforms = [NormalizeAdvantages()]\n", - " sampler = TrajectorySampler(runner, num_epochs=num_epochs, \n", + "\n", + " sampler_transforms = [NormalizeAdvantages()]\n", + " sampler = TrajectorySampler(runner, num_epochs=num_epochs, \n", " num_minibatches=num_minibatches,\n", " transforms=sampler_transforms)\n", - " return sampler" + " return sampler" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "MX1aZueWNCWA" + }, "source": [ "In the next cell you will need to implement Proximal Policy Optimization algorithm itself. The algorithm\n", "modifies the typical policy gradient loss in the following way:\n", @@ -429,43 +712,55 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "id": "JYGV4EmxNCWB" + }, "outputs": [], "source": [ "class PPO:\n", - " def __init__(self, policy, optimizer,\n", + " def __init__(self, policy, optimizer,\n", " cliprange=0.2,\n", " value_loss_coef=0.25,\n", " max_grad_norm=0.5):\n", - " self.policy = policy\n", - " self.optimizer = optimizer\n", - " self.cliprange = cliprange\n", - " self.value_loss_coef = value_loss_coef\n", - " # Note that we don't need entropy regularization for this env.\n", - " self.max_grad_norm = max_grad_norm\n", - " \n", - " def policy_loss(self, trajectory, act):\n", - " \"\"\" Computes and returns policy loss on a given trajectory. \"\"\"\n", - " \n", - " \n", - " def value_loss(self, trajectory, act):\n", - " \"\"\" Computes and returns value loss on a given trajectory. \"\"\"\n", - " \n", - " \n", - " def loss(self, trajectory):\n", - " act = self.policy.act(trajectory[\"observations\"], training=True)\n", - " policy_loss = self.policy_loss(trajectory, act)\n", - " value_loss = self.value_loss(trajectory, act)\n", - " return policy_loss + self.value_loss_coef * value_loss\n", - " \n", - " def step(self, trajectory):\n", - " \"\"\" Computes the loss function and performs a single gradient step. \"\"\"\n", - " " + " self.policy = policy\n", + " self.optimizer = optimizer\n", + " self.cliprange = cliprange\n", + " self.value_loss_coef = value_loss_coef\n", + " # Note that we don't need entropy regularization for this env.\n", + " self.max_grad_norm = max_grad_norm\n", + "\n", + " def policy_loss(self, trajectory, act):\n", + " \"\"\" Computes and returns policy loss on a given trajectory. \"\"\"\n", + " < insert your code here >\n", + "\n", + " def value_loss(self, trajectory, act):\n", + " \"\"\" Computes and returns value loss on a given trajectory. \"\"\"\n", + " < insert your code here >\n", + "\n", + " def loss(self, trajectory):\n", + " act = self.policy.act(trajectory[\"observations\"], training=True)\n", + " policy_loss = self.policy_loss(trajectory, act)\n", + " value_loss = self.value_loss(trajectory, act)\n", + "\n", + " return policy_loss + self.value_loss_coef * value_loss\n", + "\n", + " def step(self, trajectory):\n", + " \"\"\" Computes the loss function and performs a single gradient step. \"\"\"\n", + " self.optimizer.zero_grad()\n", + " loss = self.loss(trajectory)\n", + "\n", + " loss.backward()\n", + "\n", + " grad_norm = nn.utils.clip_grad_norm_(self.policy.model.parameters(), self.max_grad_norm)\n", + "\n", + " self.optimizer.step()" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "AVNS0IFhNCWB" + }, "source": [ "Now everything is ready to do training. In one million of interactions it should be possible to \n", "achieve the total raw reward of about 1500. You should plot this quantity with respect to \n", @@ -486,6 +781,108 @@ "from 3e-4 to 0 and epsilon 1e-5." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WmroaOHX33nZ" + }, + "outputs": [], + "source": [ + "model = PolicyModel()\n", + "model = model.cuda()\n", + "\n", + "policy = Policy(model)\n", + "\n", + "runner = make_ppo_runner(env, policy)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Psvv8oru3POG" + }, + "outputs": [], + "source": [ + "from IPython.display import clear_output\n", + "from matplotlib import pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 312 + }, + "id": "2W5StJsb1mz2", + "outputId": "7a902763-0cc7-4dfe-9746-3511fbe555f5" + }, + "outputs": [], + "source": [ + "optimizer = torch.optim.Adam(policy.model.parameters(), lr = 3e-4, eps=1e-5)\n", + "epochs = 250000\n", + "\n", + "lr_mult = lambda epoch: (1 - (epoch/epochs))\n", + "sched = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_mult)\n", + "\n", + "ppo = PPO(policy, optimizer)\n", + "\n", + "for epoch in tqdm(range(epochs)):\n", + " trajectory = runner.get_next()\n", + "\n", + " if (epoch + 1) % 100 == 0:\n", + " clear_output(True)\n", + " rewards = np.array(env.env.episode_rewards)\n", + "\n", + " if rewards.size > 0:\n", + " plt.plot(rewards[:, 0], rewards[:, 1], label = \"episode rewards\")\n", + " plt.title(\"Reward\")\n", + " plt.xlabel(\"Total steps\")\n", + " plt.ylabel(\"Reward\")\n", + " plt.grid()\n", + " plt.show()\n", + "\n", + " ppo.step(trajectory)\n", + " sched.step()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 295 + }, + "id": "OxD3w7uWbsYt", + "outputId": "551690d0-f96d-406a-efc7-73ff50508c70" + }, + "outputs": [], + "source": [ + "rewards = np.array(env.env.episode_rewards)\n", + "\n", + "if rewards.size > 0:\n", + " plt.plot(rewards[:, 0], rewards[:, 1], label = \"episode rewards\")\n", + " plt.title(\"Reward\")\n", + " plt.xlabel(\"Total steps\")\n", + " plt.ylabel(\"Reward\")\n", + " plt.ylim(-1000, 2500)\n", + " plt.grid()\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sixQI_jMASJR" + }, + "outputs": [], + "source": [] + }, { "cell_type": "code", "execution_count": null, @@ -495,6 +892,13 @@ } ], "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [], + "name": "Копия блокнота \"Копия блокнота \"Копия блокнота \"Копия блокнота \"ppo.ipynb\"\"\"\"", + "provenance": [], + "toc_visible": true + }, "kernelspec": { "display_name": "Python 3", "language": "python", @@ -510,9 +914,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.9" + "version": "3.8.5" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 1 } diff --git a/week09_policy_II/seminar_TRPO_pytorch.ipynb b/week09_policy_II/seminar_TRPO_pytorch.ipynb index f00b906a3..f2d8dcc8f 100644 --- a/week09_policy_II/seminar_TRPO_pytorch.ipynb +++ b/week09_policy_II/seminar_TRPO_pytorch.ipynb @@ -6,17 +6,16 @@ "metadata": {}, "outputs": [], "source": [ - "import sys\n", - "if 'google.colab' in sys.modules:\n", - " import os\n", + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", "\n", - " os.system('apt-get install -y xvfb')\n", - " os.system('wget https://raw.githubusercontent.com/yandexdataschool/Practical_DL/fall18/xvfb -O ../xvfb')\n", - " os.system('apt-get install -y python-opengl ffmpeg')\n", - " os.system('pip install pyglet==1.2.4')\n", + " !pip install -q gymnasium\n", "\n", - "# launch XVFB if you run on a server\n", - "import os\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display to draw game images on.\n", + "# It will have no effect if your machine has a monitor.\n", "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", " !bash ../xvfb start\n", " os.environ['DISPLAY'] = ':1'" @@ -39,35 +38,30 @@ "metadata": {}, "outputs": [], "source": [ + "from typing import Tuple\n", + "\n", "import numpy as np\n", "import torch\n", "import torch.nn as nn\n", "import torch.nn.functional as F\n", - "from torch.autograd import Variable" + "\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mWARN: gym.spaces.Box autodetected dtype as . Please provide explicit dtype.\u001b[0m\n", - "Observation Space Box(6,)\n", - "Action Space Discrete(3)\n" - ] - } - ], - "source": [ - "import gym\n", - "\n", - "env = gym.make(\"Acrobot-v1\")\n", + "outputs": [], + "source": [ + "import gymnasium as gym\n", + "\n", + "env = gym.make(\"Acrobot-v1\", render_mode=\"rgb_array\")\n", "env.reset()\n", "observation_shape = env.observation_space.shape\n", "n_actions = env.action_space.n\n", + "\n", "print(\"Observation Space\", env.observation_space)\n", "print(\"Action Space\", env.action_space)" ] @@ -76,32 +70,9 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQsAAAD8CAYAAABgtYFHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAADjJJREFUeJzt3X3I3Wd9x/H3Z+mDborpw70Qkkgqhkn/2GpzUyvKcC2O2onpH1VaZAYJBDYHFQcu3WBD2B+6P6wKQw2rLA617XygoXRzXVoZ+8PaO/bBPqz2rrQ0oZqobd0Q3arf/XGu6DGmua8793lM3i84nOt3/a7fOd9TTj69fr9znXOnqpCklfzGtAuQNB8MC0ldDAtJXQwLSV0MC0ldDAtJXcYSFkmuSvJ4kuUke8bxHJImK6NeZ5FkHfBt4K3AIeA+4PqqenSkTyRposYxs7gMWK6q71TV/wK3ADvG8DySJuisMTzmJuCZoe1DwBtOdsCFF15YW7duHUMpko45ePDg96tq4VSPH0dYdEmyG9gN8OpXv5qlpaVplSKdEZI8vZbjx3EachjYMrS9ufX9iqraW1WLVbW4sHDKYSdpQsYRFvcB25JclOQc4Dpg/xieR9IEjfw0pKpeTPJnwFeBdcBnquqRUT+PpMkayzWLqroTuHMcjy1pOlzBKamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpy4phkeQzSY4keXio7/wkdyV5ot2f1/qT5BNJlpM8lOTScRYvaXJ6Zhb/CFx1XN8e4EBVbQMOtG2AtwHb2m038MnRlClp2lYMi6r6D+CHx3XvAPa19j7gmqH+z9bA14H1STaOqlhJ03Oq1yw2VNWzrf1dYENrbwKeGRp3qPX9miS7kywlWTp69OgpliFpUtZ8gbOqCqhTOG5vVS1W1eLCwsJay5A0ZqcaFt87dnrR7o+0/sPAlqFxm1ufpDl3qmGxH9jZ2juB24f639M+FbkceGHodEXSHDtrpQFJvgC8BbgwySHgb4APA7cl2QU8DbyrDb8TuBpYBn4MvHcMNUuaghXDoqquf4ldV55gbAHvW2tRkmaPKzgldTEsJHUxLCR1MSwkdTEsJHUxLCR1MSwkdTEsJHUxLCR1yWDR5ZSLSKZfhHT6O1hVi6d68IrLvSdh+/btLC0tTbsM6bSWZE3HexoiqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIamLYSGpi2EhqYthIanLimGRZEuSe5I8muSRJDe0/vOT3JXkiXZ/XutPkk8kWU7yUJJLx/0iJI1fz8ziReDPq+pi4HLgfUkuBvYAB6pqG3CgbQO8DdjWbruBT468akkTt2JYVNWzVfXN1v5v4DFgE7AD2NeG7QOuae0dwGdr4OvA+iQbR165pIla1TWLJFuB1wP3Ahuq6tm267vAhtbeBDwzdNih1idpjnWHRZJXAF8C3l9VPxreV4O/rryqP26cZHeSpSRLR48eXc2hkqagKyySnM0gKD5XVV9u3d87dnrR7o+0/sPAlqHDN7e+X1FVe6tqsaoWFxYWTrV+SRPS82lIgJuBx6rqo0O79gM7W3sncPtQ/3vapyKXAy8Mna5ImlNndYx5E/DHwLeSPND6/hL4MHBbkl3A08C72r47gauBZeDHwHtHWrGkqVgxLKrqP4G8xO4rTzC+gPetsS5JM8YVnJK6GBaSuhgWkroYFpK6GBaSuhgWkroYFpK6GBaSuhgWkroYFpK6GBaSuvR8kUz6hYMHf/VrQtu3r+pnTDTHnFmo2/FB8VJ9Oj0ZFupyslAwMM4MhoVW1BMGBsbpz7CQ1MWwkNTFsJDUxbDQihZZGskYzTfDQl1OFgYGxZnBsFC3E4WCQXHmcAWnVsVwOHM5s5DUxbCQ1MWwkNTFsJDUxbCQ1MWwkNTFsJDUxbCQ1MWwkNTFsJDUxbCQ1MWwkNTFsJDUZcWwSPKyJN9I8mCSR5J8qPVflOTeJMtJbk1yTus/t20vt/1bx/sSJE1Cz8zip8AVVfV7wCXAVUkuBz4C3FRVrwWeA3a18buA51r/TW2cpDm3YljUwP+0zbPbrYArgC+2/n3ANa29o23T9l+ZxN+Jl+Zc1zWLJOuSPAAcAe4CngSer6oX25BDwKbW3gQ8A9D2vwBccILH3J1kKcnS0aNH1/YqNHW1ffu0S9CYdYVFVf2sqi4BNgOXAa9b6xNX1d6qWqyqxYWFhbU+nKQxW9WnIVX1PHAP8EZgfZJjP8u3GTjc2oeBLQBt/6uAH4ykWklT0/NpyEKS9a39cuCtwGMMQuPaNmwncHtr72/btP13V5V/aluacz0/2LsR2JdkHYNwua2q7kjyKHBLkr8F7gdubuNvBv4pyTLwQ+C6MdQtacJWDIuqegh4/Qn6v8Pg+sXx/T8B3jmS6iTNDFdwSupiWOikcvDgtEvQjDAsJHUxLCR1MSwkdTEsJHUxLCR1MSwkdTEsJHUxLCR1MSwkdTEsJHUxLCR1MSwkdTEsJHUxLCR1MSy0KkssssTitMvQFPT8rJ70awFxbHuRpWmUoylwZqEVnWwm4SzjzGFYSOpiWOikemYOzi7ODIaFpC6GhaQuhoVOqufTDj8ROTMYFpK6GBZa0clmDs4qzhwuytJJ1fbt5OBBQ0HOLDQa/uWy059hIamLYSGpi2EhqYthIamLYSGpi2EhqUt3WCRZl+T+JHe07YuS3JtkOcmtSc5p/ee27eW2f+t4Spc0SauZWdwAPDa0/RHgpqp6LfAcsKv17wKea/03tXGS5lxXWCTZDPwR8A9tO8AVwBfbkH3ANa29o23T9l/ZxkuaY70zi48BHwR+3rYvAJ6vqhfb9iFgU2tvAp4BaPtfaOMlzbEVwyLJ24EjVTXS9bxJdidZSrJ09OjRUT60Rqy2b592CZoBPTOLNwHvSPIUcAuD04+PA+uTHPsi2mbgcGsfBrYAtP2vAn5w/INW1d6qWqyqxYWFhTW9CM0Gvx9yelsxLKrqxqraXFVbgeuAu6vq3cA9wLVt2E7g9tbe37Zp+++uqhpp1ZImbi3rLP4C+ECSZQbXJG5u/TcDF7T+DwB71laipFmwqt+zqKqvAV9r7e8Al51gzE+Ad46gNkkzxBWckroYFpK6GBaSuhgWkroYFpK6GBaSuhgW6uKSbxkWGimXfJ++DAtJXQwLSV0MC0ldDAtJXQwLSV0MC0ldDAtJXQwLSV0MC0ldDAtJXQwLSV0MC0ldDAtJXQwLSV0MC0ldDAtJXQwLdfPXss5shoVGzl/LOj0ZFpK6GBaSuqzqDyNLXrc4czmzkNTFsJDUxbCQ1MWwkNTFsJDUxbCQ1KUrLJI8leRbSR5IstT6zk9yV5In2v15rT9JPpFkOclDSS4d5wuQNBmrmVn8QVVdUlWLbXsPcKCqtgEH2jbA24Bt7bYb+OSoipU0PWs5DdkB7GvtfcA1Q/2frYGvA+uTbFzD80iaAb0rOAv4tyQFfLqq9gIbqurZtv+7wIbW3gQ8M3Tsodb37FAfSXYzmHkA/DTJw6dQ/7RcCHx/2kV0mqdaYb7qnadaAX5nLQf3hsWbq+pwkt8G7kryX8M7q6pakHRrgbMXIMnS0OnNzJuneuepVpiveuepVhjUu5bju05Dqupwuz8CfAW4DPjesdOLdn+kDT8MbBk6fHPrkzTHVgyLJL+V5JXH2sAfAg8D+4GdbdhO4PbW3g+8p30qcjnwwtDpiqQ51XMasgH4SpJj4z9fVf+a5D7gtiS7gKeBd7XxdwJXA8vAj4H3djzH3tUWPmXzVO881QrzVe881QprrDdVq7rUIOkM5QpOSV2mHhZJrkryeFvxuWflI8Zez2eSHBn+KHeWV6sm2ZLkniSPJnkkyQ2zWnOSlyX5RpIHW60fav0XJbm31XRrknNa/7lte7nt3zqpWodqXpfk/iR3zEGt411pXVVTuwHrgCeB1wDnAA8CF0+5pt8HLgUeHur7O2BPa+8BPtLaVwP/AgS4HLh3CvVuBC5t7VcC3wYunsWa23O+orXPBu5tNdwGXNf6PwX8SWv/KfCp1r4OuHUK/30/AHweuKNtz3KtTwEXHtc3svfBRF/MCV7cG4GvDm3fCNw4zZpaHVuPC4vHgY2tvRF4vLU/DVx/onFTrP124K2zXjPwm8A3gTcwWNh01vHvCeCrwBtb+6w2LhOscTODrzJcAdzR/mHNZK3teU8UFiN7H0z7NOSlVnvOmtWuVp2KNvV9PYP/Y89kzW1a/wCDdTl3MZhZPl9VL56gnl/U2va/AFwwqVqBjwEfBH7eti9gdmuFX660PthWSMMI3wf+YO8qVa1+teokJHkF8CXg/VX1o/ZRNzBbNVfVz4BLkqxnsMDvdVMu6YSSvB04UlUHk7xl2vV0GvlK62HTnlnMy2rPmV6tmuRsBkHxuar6cuue6Zqr6nngHgZT+fVJjv2Pa7ieX9Ta9r8K+MGESnwT8I4kTwG3MDgV+fiM1gqMf6X1tMPiPmBbu8J8DoMLQ/unXNOJzOxq1QymEDcDj1XVR4d2zVzNSRbajIIkL2dwbeUxBqFx7UvUeuw1XAvcXe0Ee9yq6saq2lxVWxm8L++uqnfPYq0woZXWk7wA8xIXZa5mcAX/SeCvZqCeLzD4huz/MTiP28Xg3PMA8ATw78D5bWyAv2+1fwtYnEK9b2ZwrvoQ8EC7XT2LNQO/C9zfan0Y+OvW/xrgGwxW/f4zcG7rf1nbXm77XzOl98Rb+OWnITNZa6vrwXZ75Ni/pVG+D1zBKanLtE9DJM0Jw0JSF8NCUhfDQlIXw0JSF8NCUhfDQlIXw0JSl/8Huhr8fpmXAZ4AAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "plt.imshow(env.render('rgb_array'))" + "plt.imshow(env.render())" ] }, { @@ -110,9 +81,9 @@ "source": [ "### Step 1: Defining a network\n", "\n", - "With all it's complexity, at it's core TRPO is yet another policy gradient method. \n", + "With all it's complexity, at it's core TRPO is yet another policy gradient method.\n", "\n", - "This essentially means we're actually training a stochastic policy $ \\pi_\\theta(a|s) $. \n", + "This essentially means we're actually training a stochastic policy $\\pi_\\theta \\left( a \\middle| s \\right)$.\n", "\n", "And yes, it's gonna be a neural network. So let's start by defining one." ] @@ -124,43 +95,46 @@ "outputs": [], "source": [ "class TRPOAgent(nn.Module):\n", - " def __init__(self, state_shape, n_actions, hidden_size=32):\n", + " def __init__(self, state_shape: Tuple[int], n_actions: int):\n", " '''\n", " Here you should define your model\n", " You should have LOG-PROBABILITIES as output because you will need it to compute loss\n", - " We recommend that you start simple: \n", + " We recommend that you start simple:\n", " use 1-2 hidden layers with 100-500 units and relu for the first try\n", " '''\n", - " nn.Module.__init__(self)\n", + " super().__init__()\n", "\n", - " \n", - " self.model = None\n", + " assert isinstance(state_shape, tuple)\n", + " assert len(state_shape) == 1\n", + " input_dim = state_shape[0]\n", + " \n", + " # Prepare your model here.\n", + " \n", "\n", - " def forward(self, states):\n", + " def forward(self, states: torch.Tensor):\n", " \"\"\"\n", - " takes agent's observation (Variable), returns log-probabilities (Variable)\n", + " takes agent's observation, returns log-probabilities\n", " :param state_t: a batch of states, shape = [batch_size, state_shape]\n", " \"\"\"\n", "\n", - " # Use your network to compute log_probs for given state\n", - " log_probs = self.model(states)\n", + " # Use your network to compute log_probs for the given states.\n", + " \n", + " \n", " return log_probs\n", "\n", - " def get_log_probs(self, states):\n", + " def get_log_probs(self, states: torch.Tensor):\n", " '''\n", " Log-probs for training\n", " '''\n", - "\n", " return self.forward(states)\n", "\n", - " def get_probs(self, states):\n", + " def get_probs(self, states: torch.Tensor):\n", " '''\n", " Probs for interaction\n", " '''\n", - "\n", " return torch.exp(self.forward(states))\n", "\n", - " def act(self, obs, sample=True):\n", + " def act(self, obs: np.ndarray, sample: bool = True):\n", " '''\n", " Samples action from policy distribution (sample = True) or takes most likely action (sample = False)\n", " :param: obs - single observation vector\n", @@ -168,7 +142,8 @@ " :returns: action (single integer) and probabilities for all actions\n", " '''\n", "\n", - " probs = self.get_probs(Variable(torch.FloatTensor([obs]))).data.numpy()\n", + " with torch.no_grad():\n", + " probs = self.get_probs(torch.tensor(obs[np.newaxis], dtype=torch.float32)).numpy()\n", "\n", " if sample:\n", " action = int(np.random.choice(n_actions, p=probs[0]))\n", @@ -185,37 +160,21 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "sampled: [(2, array([0.35253003, 0.37892205, 0.26854792], dtype=float32)), (2, array([0.35269254, 0.37673423, 0.27057323], dtype=float32)), (0, array([0.35406563, 0.37682924, 0.26910514], dtype=float32)), (0, array([0.3560282 , 0.37561142, 0.2683604 ], dtype=float32)), (1, array([0.35539204, 0.37685862, 0.26774937], dtype=float32))]\n", - "greedy: [(1, array([0.3518883 , 0.37830737, 0.2698043 ], dtype=float32)), (1, array([0.3544095 , 0.37609497, 0.26949552], dtype=float32)), (1, array([0.35528135, 0.37493262, 0.269786 ], dtype=float32)), (1, array([0.3589018 , 0.37457928, 0.26651892], dtype=float32)), (1, array([0.35414994, 0.3769723 , 0.26887777], dtype=float32))]\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.5/dist-packages/torch/nn/modules/container.py:67: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.\n", - " input = module(input)\n" - ] - } - ], + "outputs": [], "source": [ "# Check if log-probabilities satisfies all the requirements\n", - "log_probs = agent.get_log_probs(Variable(torch.FloatTensor([env.reset()])))\n", - "assert isinstance(\n", - " log_probs, Variable) and log_probs.requires_grad, \"qvalues must be a torch variable with grad\"\n", - "assert len(\n", - " log_probs.shape) == 2 and log_probs.shape[0] == 1 and log_probs.shape[1] == n_actions\n", - "sums = torch.sum(torch.exp(log_probs), dim=1)\n", - "assert (0.999 < sums).all() and (1.001 > sums).all()\n", + "log_probs = agent.get_log_probs(torch.tensor(env.reset()[0][np.newaxis], dtype=torch.float32))\n", + "assert (\n", + " isinstance(log_probs, torch.Tensor) and\n", + " log_probs.requires_grad\n", + "), \"log_probs must be a torch.Tensor with grad\"\n", + "assert log_probs.shape == (1, n_actions)\n", + "sums = torch.exp(log_probs).sum(dim=1)\n", + "assert torch.allclose(sums, torch.ones_like(sums))\n", "\n", "# Demo use\n", - "print(\"sampled:\", [agent.act(env.reset()) for _ in range(5)])\n", - "print(\"greedy:\", [agent.act(env.reset(), sample=False) for _ in range(5)])" + "print(\"sampled:\", [agent.act(env.reset()[0]) for _ in range(5)])\n", + "print(\"greedy:\", [agent.act(env.reset()[0], sample=False) for _ in range(5)])" ] }, { @@ -234,10 +193,7 @@ "outputs": [], "source": [ "def get_flat_params_from(model):\n", - " params = []\n", - " for param in model.parameters():\n", - " params.append(param.data.view(-1))\n", - "\n", + " params = [torch.ravel(param.detach()) for param in model.parameters()]\n", " flat_params = torch.cat(params)\n", " return flat_params\n", "\n", @@ -245,9 +201,10 @@ "def set_flat_params_to(model, flat_params):\n", " prev_ind = 0\n", " for param in model.parameters():\n", - " flat_size = int(np.prod(list(param.size())))\n", + " flat_size = int(np.prod(list(param.shape)))\n", " param.data.copy_(\n", - " flat_params[prev_ind:prev_ind + flat_size].view(param.size()))\n", + " flat_params[prev_ind:prev_ind + flat_size].reshape(param.shape)\n", + " )\n", " prev_ind += flat_size" ] }, @@ -255,7 +212,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Compute cummulative reward just like you did in vanilla REINFORCE" + "Compute cumulative reward just like you did in vanilla REINFORCE" ] }, { @@ -267,9 +224,9 @@ "import scipy.signal\n", "\n", "\n", - "def get_cummulative_returns(r, gamma=1):\n", + "def get_cumulative_returns(r, gamma=1):\n", " \"\"\"\n", - " Computes cummulative discounted rewards given immediate rewards\n", + " Computes cumulative discounted rewards given immediate rewards\n", " G_i = r_i + gamma*r_{i+1} + gamma^2*r_{i+2} + ...\n", " Also known as R(s,a).\n", " \"\"\"\n", @@ -285,7 +242,7 @@ "outputs": [], "source": [ "# simple demo on rewards [0,0,1,0,0,1]\n", - "get_cummulative_returns([0, 0, 1, 0, 0, 1], gamma=0.9)" + "get_cumulative_returns([0, 0, 1, 0, 0, 1], gamma=0.9)" ] }, { @@ -314,22 +271,23 @@ " total_timesteps = 0\n", " while total_timesteps < n_timesteps:\n", " obervations, actions, rewards, action_probs = [], [], [], []\n", - " obervation = env.reset()\n", + " obervation, _ = env.reset()\n", " for _ in range(max_pathlength):\n", " action, policy = agent.act(obervation)\n", " obervations.append(obervation)\n", " actions.append(action)\n", " action_probs.append(policy)\n", - " obervation, reward, done, _ = env.step(action)\n", + " obervation, reward, terminated, truncated, _ = env.step(action)\n", " rewards.append(reward)\n", " total_timesteps += 1\n", - " if done or total_timesteps == n_timesteps:\n", - " path = {\"observations\": np.array(obervations),\n", - " \"policy\": np.array(action_probs),\n", - " \"actions\": np.array(actions),\n", - " \"rewards\": np.array(rewards),\n", - " \"cumulative_returns\": get_cummulative_returns(rewards),\n", - " }\n", + " if terminated or truncated or total_timesteps >= n_timesteps:\n", + " path = {\n", + " \"observations\": np.array(obervations),\n", + " \"policy\": np.array(action_probs),\n", + " \"actions\": np.array(actions),\n", + " \"rewards\": np.array(rewards),\n", + " \"cumulative_returns\": get_cumulative_returns(rewards),\n", + " }\n", " paths.append(path)\n", " break\n", " return paths" @@ -341,14 +299,18 @@ "metadata": {}, "outputs": [], "source": [ + "from pprint import pprint\n", + "\n", "paths = rollout(env, agent, max_pathlength=5, n_timesteps=100)\n", - "print(paths[-1])\n", + "pprint(paths[-1])\n", + "\n", "assert (paths[0]['policy'].shape == (5, n_actions))\n", "assert (paths[0]['cumulative_returns'].shape == (5,))\n", "assert (paths[0]['rewards'].shape == (5,))\n", - "assert (paths[0]['observations'].shape == (5,)+observation_shape)\n", + "assert (paths[0]['observations'].shape == (5,) + observation_shape)\n", "assert (paths[0]['actions'].shape == (5,))\n", - "print('It\\'s ok')" + "\n", + "print(\"It's ok\")" ] }, { @@ -364,14 +326,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The surrogate reward should be\n", - "$$J_{surr}= {1 \\over N} \\sum\\limits_{i=0}^N \\frac{\\pi_{\\theta}(s_i, a_i)}{\\pi_{\\theta_{old}}(s_i, a_i)}A_{\\theta_{old}(s_i, a_i)}$$\n", + "The surrogate reward should be:\n", + "$$J_{surr}= {1 \\over N} \\sum\\limits_{i=1}^N \\frac{\\pi_{\\theta}(s_i, a_i)}{\\pi_{\\theta_{old}}(s_i, a_i)}A_{\\theta_{old}(s_i, a_i)}$$\n", "\n", - "For simplicity, let's use cummulative returns instead of advantage for now:\n", - "$$J'_{surr}= {1 \\over N} \\sum\\limits_{i=0}^N \\frac{\\pi_{\\theta}(s_i, a_i)}{\\pi_{\\theta_{old}}(s_i, a_i)}G_{\\theta_{old}(s_i, a_i)}$$\n", + "For simplicity, in this assignment we are going to use cumulative rewards instead of advantage:\n", + "$$J'_{surr}= {1 \\over N} \\sum\\limits_{i=1}^N \\frac{\\pi_{\\theta}(s_i, a_i)}{\\pi_{\\theta_{old}}(s_i, a_i)}G_{\\theta_{old}(s_i, a_i)}$$\n", "\n", - "Or alternatively, minimize the surrogate loss:\n", - "$$ L_{surr} = - J'_{surr} $$ \n" + "Since we want to maximize the reward, we are going to minimize the corresponding surrogate loss:\n", + "$$ L_{surr} = - J'_{surr} $$\n" ] }, { @@ -380,42 +342,39 @@ "metadata": {}, "outputs": [], "source": [ - "def get_loss(agent, observations, actions, cummulative_returns, old_probs):\n", + "def get_loss(agent, observations, actions, cumulative_returns, old_probs):\n", " \"\"\"\n", " Computes TRPO objective\n", - " :param: observations - batch of observations\n", - " :param: actions - batch of actions\n", - " :param: cummulative_returns - batch of cummulative returns\n", - " :param: old_probs - batch of probabilities computed by old network\n", + " :param: observations - batch of observations [timesteps x state_shape]\n", + " :param: actions - batch of actions [timesteps]\n", + " :param: cumulative_returns - batch of cumulative returns [timesteps]\n", + " :param: old_probs - batch of probabilities computed by old network [timesteps x num_actions]\n", " :returns: scalar value of the objective function\n", " \"\"\"\n", " batch_size = observations.shape[0]\n", - " log_probs_all = agent.get_log_probs(observations)\n", - " probs_all = torch.exp(log_probs_all)\n", + " probs_all = agent.get_probs(observations)\n", "\n", - " probs_for_actions = probs_all[torch.arange(\n", - " 0, batch_size, out=torch.LongTensor()), actions]\n", - " old_probs_for_actions = old_probs[torch.arange(\n", - " 0, batch_size, out=torch.LongTensor()), actions]\n", + " probs_for_actions = probs_all[torch.arange(batch_size), actions]\n", + " old_probs_for_actions = old_probs[torch.arange(batch_size), actions]\n", "\n", " # Compute surrogate loss, aka importance-sampled policy gradient\n", - " Loss = \n", + " \n", "\n", - " assert Loss.shape == torch.Size([])\n", - " return Loss" + " assert loss.ndim == 0\n", + " return loss" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We can ascend these gradients as long as our $pi_\\theta(a|s)$ satisfies the constraint\n", - "$$E_{s,\\pi_{\\Theta_{t}}}\\Big[KL(\\pi(\\Theta_{t}, s) \\:||\\:\\pi(\\Theta_{t+1}, s))\\Big]< \\alpha$$\n", + "We can ascend these gradients as long as our $\\pi_\\theta(a|s)$ satisfies the constraint\n", + "$$\\mathbb{E}_{s,\\pi_{\\theta_{t}}} \\Big[ \\operatorname{KL} \\left( \\pi_{\\theta_{t}} (s) \\:\\|\\: \\pi_{\\theta_{t+1}} (s) \\right) \\Big] < \\alpha$$\n", "\n", "\n", "where\n", "\n", - "$$KL(p||q) = E _p log({p \\over q})$$" + "$$\\operatorname{KL} \\left( p \\| q \\right) = \\mathbb{E}_p \\log \\left( \\frac p q \\right)$$" ] }, { @@ -424,26 +383,27 @@ "metadata": {}, "outputs": [], "source": [ - "def get_kl(agent, observations, actions, cummulative_returns, old_probs):\n", + "def get_kl(agent, observations, actions, cumulative_returns, old_probs):\n", " \"\"\"\n", " Computes KL-divergence between network policy and old policy\n", - " :param: observations - batch of observations\n", - " :param: actions - batch of actions\n", - " :param: cummulative_returns - batch of cummulative returns (we don't need it actually)\n", - " :param: old_probs - batch of probabilities computed by old network\n", + " :param: observations - batch of observations [timesteps x state_shape]\n", + " :param: actions - batch of actions [timesteps]\n", + " :param: cumulative_returns - batch of cumulative returns [timesteps] (we don't need it actually)\n", + " :param: old_probs - batch of probabilities computed by old network [timesteps x num_actions]\n", " :returns: scalar value of the KL-divergence\n", " \"\"\"\n", " batch_size = observations.shape[0]\n", " log_probs_all = agent.get_log_probs(observations)\n", " probs_all = torch.exp(log_probs_all)\n", "\n", - " # Compute Kullback-Leibler divergence (see formula above)\n", - " # Note: you need to sum KL and entropy over all actions, not just the ones agent took\n", - " old_log_probs = torch.log(old_probs+1e-10)\n", + " # Compute Kullback-Leibler divergence (see formula above).\n", + " # Note: you need to sum KL and entropy over all actions, not just the ones agent took.\n", + " # You will also need to compute max KL over all timesteps.\n", + " old_log_probs = torch.log(old_probs + 1e-10)\n", "\n", - " kl = \n", + " \n", "\n", - " assert kl.shape == torch.Size([])\n", + " assert kl.ndim == 0\n", " assert (kl > -0.0001).all() and (kl < 10000).all()\n", " return kl" ] @@ -456,20 +416,19 @@ "source": [ "def get_entropy(agent, observations):\n", " \"\"\"\n", - " Computes entropy of the network policy \n", + " Computes entropy of the network policy\n", " :param: observations - batch of observations\n", " :returns: scalar value of the entropy\n", " \"\"\"\n", "\n", - " observations = Variable(torch.FloatTensor(observations))\n", + " observations = torch.tensor(observations, dtype=torch.float32)\n", "\n", - " batch_size = observations.shape[0]\n", " log_probs_all = agent.get_log_probs(observations)\n", " probs_all = torch.exp(log_probs_all)\n", "\n", - " entropy = torch.sum(-probs_all * log_probs_all) / batch_size\n", + " entropy = (-probs_all * log_probs_all).sum(dim=1).mean(dim=0)\n", "\n", - " assert entropy.shape == torch.Size([])\n", + " assert entropy.ndim == 0\n", " return entropy" ] }, @@ -479,7 +438,7 @@ "source": [ "**Linear search**\n", "\n", - "TRPO in its core involves ascending surrogate policy gradient constrained by KL divergence. \n", + "TRPO in its core involves ascending surrogate policy gradient constrained by KL divergence.\n", "\n", "In order to enforce this constraint, we're gonna use linesearch. You can find out more about it [here](https://en.wikipedia.org/wiki/Linear_search)" ] @@ -490,7 +449,7 @@ "metadata": {}, "outputs": [], "source": [ - "def linesearch(f, x, fullstep, max_kl):\n", + "def linesearch(f, x: torch.Tensor, fullstep: torch.Tensor, max_kl: float, max_backtracks: int = 10, backtrack_coef: float = 0.5):\n", " \"\"\"\n", " Linesearch finds the best parameters of neural networks in the direction of fullstep contrainted by KL divergence.\n", " :param: f - function that returns loss, kl and arbitrary third component.\n", @@ -499,13 +458,11 @@ " :param: max_kl - constraint of KL divergence.\n", " :returns:\n", " \"\"\"\n", - " max_backtracks = 10\n", " loss, _, = f(x)\n", - " for stepfrac in .5**np.arange(max_backtracks):\n", + " for stepfrac in backtrack_coef**np.arange(max_backtracks):\n", " xnew = x + stepfrac * fullstep\n", " new_loss, kl = f(xnew)\n", - " actual_improve = new_loss - loss\n", - " if kl.data.numpy() <= max_kl and actual_improve.data.numpy() < 0:\n", + " if kl <= max_kl and new_loss < loss:\n", " x = xnew\n", " loss = new_loss\n", " return x" @@ -517,9 +474,9 @@ "source": [ "**Conjugate gradients**\n", "\n", - "Since TRPO includes contrainted optimization, we will need to solve Ax=b using conjugate gradients.\n", + "Since TRPO includes contrainted optimization, we will need to solve $A x = b$ using conjugate gradients.\n", "\n", - "In general, CG is an algorithm that solves Ax=b where A is positive-defined. A is Hessian matrix so A is positive-defined. You can find out more about them [here](https://en.wikipedia.org/wiki/Conjugate_gradient_method)" + "In general, CG is an algorithm that solves $A x = b$ where $A$ is positive-defined. $A$ is the Hessian matrix so $A$ is positive-defined. You can find out more about CG [here](https://en.wikipedia.org/wiki/Conjugate_gradient_method)." ] }, { @@ -528,12 +485,9 @@ "metadata": {}, "outputs": [], "source": [ - "from numpy.linalg import inv\n", - "\n", - "\n", "def conjugate_gradient(f_Ax, b, cg_iters=10, residual_tol=1e-10):\n", " \"\"\"\n", - " This method solves system of equation Ax=b using iterative method called conjugate gradients\n", + " This method solves system of equation Ax=b using an iterative method called conjugate gradients\n", " :f_Ax: function that returns Ax\n", " :b: targets for Ax\n", " :cg_iters: how many iterations this method should do\n", @@ -541,7 +495,7 @@ " \"\"\"\n", " p = b.clone()\n", " r = b.clone()\n", - " x = torch.zeros(b.size())\n", + " x = torch.zeros_like(b)\n", " rdotr = torch.sum(r*r)\n", " for i in range(cg_iters):\n", " z = f_Ax(p)\n", @@ -565,19 +519,18 @@ "source": [ "# This code validates conjugate gradients\n", "A = np.random.rand(8, 8)\n", - "A = np.matmul(np.transpose(A), A)\n", + "A = A.T @ A\n", "\n", "\n", "def f_Ax(x):\n", - " return torch.matmul(torch.FloatTensor(A), x.view((-1, 1))).view(-1)\n", + " return torch.ravel(torch.tensor(A, dtype=torch.float32) @ x.reshape(-1, 1))\n", "\n", "\n", "b = np.random.rand(8)\n", + "w = (np.linalg.inv(A.T @ A) @ A.T @ b.reshape(-1, 1)).reshape(-1)\n", "\n", - "w = np.matmul(np.matmul(inv(np.matmul(np.transpose(A), A)),\n", - " np.transpose(A)), b.reshape((-1, 1))).reshape(-1)\n", "print(w)\n", - "print(conjugate_gradient(f_Ax, torch.FloatTensor(b)).numpy())" + "print(conjugate_gradient(f_Ax, torch.tensor(b, dtype=torch.float32)).numpy())" ] }, { @@ -594,47 +547,44 @@ "metadata": {}, "outputs": [], "source": [ - "def update_step(agent, observations, actions, cummulative_returns, old_probs, max_kl):\n", + "def update_step(agent, observations, actions, cumulative_returns, old_probs, max_kl):\n", " \"\"\"\n", " This function does the TRPO update step\n", " :param: observations - batch of observations\n", " :param: actions - batch of actions\n", - " :param: cummulative_returns - batch of cummulative returns\n", + " :param: cumulative_returns - batch of cumulative returns\n", " :param: old_probs - batch of probabilities computed by old network\n", " :param: max_kl - controls how big KL divergence may be between old and new policy every step.\n", " :returns: KL between new and old policies and the value of the loss function.\n", " \"\"\"\n", "\n", " # Here we prepare the information\n", - " observations = Variable(torch.FloatTensor(observations))\n", - " actions = torch.LongTensor(actions)\n", - " cummulative_returns = Variable(torch.FloatTensor(cummulative_returns))\n", - " old_probs = Variable(torch.FloatTensor(old_probs))\n", + " observations = torch.tensor(observations, dtype=torch.float32)\n", + " actions = torch.tensor(actions, dtype=torch.int64)\n", + " cumulative_returns = torch.tensor(cumulative_returns, dtype=torch.float32)\n", + " old_probs = torch.tensor(old_probs, dtype=torch.float32)\n", "\n", " # Here we compute gradient of the loss function\n", - " loss = get_loss(agent, observations, actions,\n", - " cummulative_returns, old_probs)\n", + " loss = get_loss(agent, observations, actions, cumulative_returns, old_probs)\n", " grads = torch.autograd.grad(loss, agent.parameters())\n", - " loss_grad = torch.cat([grad.view(-1) for grad in grads]).data\n", + " loss_grad = torch.cat([torch.ravel(grad.detach()) for grad in grads])\n", "\n", " def Fvp(v):\n", " # Here we compute Fx to do solve Fx = g using conjugate gradients\n", " # We actually do here a couple of tricks to compute it efficiently\n", "\n", - " kl = get_kl(agent, observations, actions,\n", - " cummulative_returns, old_probs)\n", + " kl = get_kl(agent, observations, actions, cumulative_returns, old_probs)\n", "\n", " grads = torch.autograd.grad(kl, agent.parameters(), create_graph=True)\n", - " flat_grad_kl = torch.cat([grad.view(-1) for grad in grads])\n", + " flat_grad_kl = torch.cat([grad.reshape(-1) for grad in grads])\n", "\n", - " kl_v = (flat_grad_kl * Variable(v)).sum()\n", + " kl_v = (flat_grad_kl * v).sum()\n", " grads = torch.autograd.grad(kl_v, agent.parameters())\n", - " flat_grad_grad_kl = torch.cat(\n", - " [grad.contiguous().view(-1) for grad in grads]).data\n", + " flat_grad_grad_kl = torch.cat([torch.ravel(grad) for grad in grads]).detach()\n", "\n", " return flat_grad_grad_kl + v * 0.1\n", "\n", - " # Here we solveolve Fx = g system using conjugate gradients\n", + " # Here we solve Fx = g system using conjugate gradients\n", " stepdir = conjugate_gradient(Fvp, -loss_grad, 10)\n", "\n", " # Here we compute the initial vector to do linear search\n", @@ -651,8 +601,10 @@ " def get_loss_kl(params):\n", " # Helper for linear search\n", " set_flat_params_to(agent, params)\n", - " return [get_loss(agent, observations, actions, cummulative_returns, old_probs),\n", - " get_kl(agent, observations, actions, cummulative_returns, old_probs)]\n", + " return [\n", + " get_loss(agent, observations, actions, cumulative_returns, old_probs),\n", + " get_kl(agent, observations, actions, cumulative_returns, old_probs),\n", + " ]\n", "\n", " # Here we find our new parameters\n", " new_params = linesearch(get_loss_kl, prev_params, fullstep, max_kl)\n", @@ -667,7 +619,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "##### Step 5: Main TRPO loop\n", + "### Step 5: Main TRPO loop\n", "\n", "Here we will train our network!" ] @@ -680,16 +632,14 @@ "source": [ "import time\n", "from itertools import count\n", - "from collections import OrderedDict\n", "\n", - "# this is hyperparameter of TRPO. It controls how big KL divergence may be between old and new policy every step.\n", + "# TRPO hyperparameter; controls how big KL divergence may be between the old and the new policy at every step.\n", "max_kl = 0.01\n", - "numeptotal = 0 # this is number of episodes that we played.\n", + "numeptotal = 0 # Number of episodes we have completed so far.\n", "\n", "start_time = time.time()\n", "\n", "for i in count(1):\n", - "\n", " print(\"\\n********** Iteration %i ************\" % i)\n", "\n", " # Generating paths.\n", @@ -703,13 +653,12 @@ " returns = np.concatenate([path[\"cumulative_returns\"] for path in paths])\n", " old_probs = np.concatenate([path[\"policy\"] for path in paths])\n", "\n", - " loss, kl = update_step(agent, observations, actions,\n", - " returns, old_probs, max_kl)\n", + " loss, kl = update_step(agent, observations, actions, returns, old_probs, max_kl)\n", "\n", " # Report current progress\n", " episode_rewards = np.array([path[\"rewards\"].sum() for path in paths])\n", "\n", - " stats = OrderedDict()\n", + " stats = {}\n", " numeptotal += len(episode_rewards)\n", " stats[\"Total number of episodes\"] = numeptotal\n", " stats[\"Average sum of rewards per episode\"] = episode_rewards.mean()\n", @@ -719,8 +668,7 @@ " stats[\"Entropy\"] = get_entropy(agent, observations).data.numpy()\n", " stats[\"Surrogate loss\"] = loss.data.numpy()\n", " for k, v in stats.items():\n", - " print(k + \": \" + \" \" * (40 - len(k)) + str(v))\n", - " i += 1" + " print(k + \": \" + \" \" * (40 - len(k)) + str(v))" ] }, { @@ -733,12 +681,12 @@ "\n", "![img](https://s17.postimg.cc/i90chxgvj/vine.png)\n", "\n", - "In most gym environments, you can actually backtrack by using states. You can find a wrapper that saves/loads states in [the mcts seminar](https://github.com/yandexdataschool/Practical_RL/blob/master/week10_planning/seminar_MCTS.ipynb).\n", + "In most gym environments, you can actually backtrack by using states. You can find a wrapper that saves/loads states in [the MCTS seminar](https://github.com/yandexdataschool/Practical_RL/blob/master/week10_planning/seminar_MCTS.ipynb).\n", "\n", - "You can read more about in the [TRPO article](https://arxiv.org/abs/1502.05477) in section 5.2.\n", + "You can read more about TRPO in the [original paper](https://arxiv.org/abs/1502.05477) in section 5.2.\n", "\n", "The goal here is to implement such rollout policy (we recommend using tree data structure like in the seminar above).\n", - "Then you can assign cummulative rewards similar to `get_cummulative_rewards`, but for a tree.\n", + "Then you can assign cumulative rewards similar to `get_cumulative_rewards`, but for a tree.\n", "\n", "__bonus task__ - parallelize samples using multiple cores" ] @@ -750,14 +698,14 @@ "# Homework option II (10+pts)\n", "\n", "Let's use TRPO to train evil robots! (pick any of two)\n", - "* [MuJoCo robots](https://gym.openai.com/envs#mujoco)\n", - "* [Box2d robot](https://gym.openai.com/envs/BipedalWalker-v2)\n", + "* [MuJoCo robots](https://gymnasium.farama.org/environments/mujoco/#mujoco)\n", + "* [Box2d robot](https://gymnasium.farama.org/environments/box2d/bipedal_walker/)\n", "\n", - "The catch here is that those environments have continuous action spaces. \n", + "The catch here is that those environments have continuous action spaces.\n", "\n", "Luckily, TRPO is a policy gradient method, so it's gonna work for any parametric $\\pi_\\theta(a|s)$. We recommend starting with gaussian policy:\n", "\n", - "$$\\pi_\\theta(a|s) = N(\\mu_\\theta(s),\\sigma^2_\\theta(s)) = {1 \\over \\sqrt { 2 \\pi {\\sigma^2}_\\theta(s) } } e^{ (a - \n", + "$$\\pi_\\theta(a|s) = N(\\mu_\\theta(s),\\sigma^2_\\theta(s)) = {1 \\over \\sqrt { 2 \\pi {\\sigma^2}_\\theta(s) } } e^{ (a -\n", "\\mu_\\theta(s))^2 \\over 2 {\\sigma^2}_\\theta(s) } $$\n", "\n", "In the $\\sqrt { 2 \\pi {\\sigma^2}_\\theta(s) }$ clause, $\\pi$ means ~3.1415926, not agent's policy.\n", @@ -766,17 +714,10 @@ "* $\\mu_\\theta(s)$, a dense layer with linear activation\n", "* ${\\sigma^2}_\\theta(s)$, a dense layer with activation tf.exp (to make it positive; like rho from bandits)\n", "\n", - "For multidimensional actions, you can use fully factorized gaussian (basically a vector of gaussians).\n", + "For multidimensional actions, you can use a fully factorized gaussian (basically a vector of gaussians).\n", "\n", - "__bonus task__: compare performance of continuous action space method to action space discretization" + "__Bonus task__: compare the performance of the continuous action space method to action space discretization." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -786,5 +727,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 1 } diff --git a/week09_policy_II/seminar_TRPO_theano.ipynb b/week09_policy_II/seminar_TRPO_theano.ipynb deleted file mode 100644 index 15e0b367d..000000000 --- a/week09_policy_II/seminar_TRPO_theano.ipynb +++ /dev/null @@ -1,733 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# launch XVFB if you run on a server\n", - "import os\n", - "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", - " !bash ../xvfb start\n", - " os.environ['DISPLAY'] = ':1'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Let's make a TRPO!\n", - "\n", - "In this notebook we will write the code of the one Trust Region Policy Optimization.\n", - "As usually, it contains a few different parts which we are going to reproduce.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import theano\n", - "import theano.tensor as T" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Observation Space Box(6,)\n", - "Action Space Discrete(3)\n" - ] - } - ], - "source": [ - "import gym\n", - "\n", - "env = gym.make(\"Acrobot-v1\")\n", - "env.reset()\n", - "\n", - "observation_shape = env.observation_space.shape\n", - "n_actions = env.action_space.n\n", - "print(\"Observation Space\", env.observation_space)\n", - "print(\"Action Space\", env.action_space)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQsAAAD8CAYAAABgtYFHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADktJREFUeJzt3W2opGd9x/Hvr5sHbRXXJMew7K5sxKXoizZmD3ElpdhE\nS0zFzYsEIlKXsLDQWlAs2E0LLUJfaF+YIBR1aaRrUZPUB7KEtDZsEkpfGHPWPLuNOUpqDhvclTzY\nItpG/30x19Fx9yTn2j0zZ2Z2vx8Y5rqv+7pn/hNmf7nue64zk6pCklbzG5MuQNJsMCwkdTEsJHUx\nLCR1MSwkdTEsJHUZS1gkuTrJk0kWk+wbx3NIWl8Z9TqLJBuA7wLvBpaAB4H3V9V3RvpEktbVOGYW\nlwOLVfX9qvpf4DZg1xieR9I6OmcMj7kZeGZoewl4+ysdcNFFF9W2bdvGUIqkZYcPH/5RVc2d7vHj\nCIus0HfSuU6SvcBegDe+8Y0sLCyMoRRJy5L811qOH8dpyBKwdWh7C3D0xEFVtb+q5qtqfm7utMNO\n0joZR1g8CGxPckmS84AbgINjeB5J62jkpyFV9VKSPwO+AWwAPl9VT4z6eSStr3Fcs6Cq7gbuHsdj\nS5oMV3BK6mJYSOpiWEjqYlhI6mJYSOpiWEjqYlhI6mJYSOpiWEjqYlhI6mJYSOpiWEjqYlhI6mJY\nSOpiWEjqYlhI6mJYSOpiWEjqYlhI6mJYSOpiWEjqYlhI6mJYSOpiWEjqYlhI6mJYSOpiWEjqYlhI\n6mJYSOpiWEjqYlhI6mJYSOpiWEjqYlhI6mJYSOqyalgk+XySY0keH+q7IMk9SZ5q969v/Uny6SSL\nSR5Nctk4i5e0fnpmFv8IXH1C3z7gUFVtBw61bYD3ANvbbS/wmdGUKWnSVg2Lqvp34LkTuncBB1r7\nAHDtUP8XauCbwMYkm0ZVrKTJOd1rFhdX1bMA7f4NrX8z8MzQuKXWd5Ike5MsJFk4fvz4aZYhab2M\n+gJnVuirlQZW1f6qmq+q+bm5uRGXIWnUTjcsfrh8etHuj7X+JWDr0LgtwNHTL0/StDjdsDgI7G7t\n3cCdQ/0fbJ+K7AReXD5dkTTbzlltQJIvA+8ELkqyBPwN8AngjiR7gB8A17fhdwPXAIvAT4Abx1Cz\npAlYNSyq6v0vs+uqFcYW8KG1FiVp+riCU1IXw0JSF8NCUhfDQlIXw0JSF8NCUhfDQlIXw0JSF8NC\nUpcMFl1OuIhk8kVIZ77DVTV/ugevutx7PezYsYOFhYVJlyGd0ZKVvkGin6chkroYFpK6GBaSuhgW\nkroYFpK6GBaSuhgWkroYFpK6GBaSuhgWkroYFpK6GBaSuhgWkroYFpK6GBaSuhgWkroYFpK6GBaS\nuhgWkroYFpK6GBaSuhgWkroYFpK6rBoWSbYmuS/JkSRPJPlw678gyT1Jnmr3r2/9SfLpJItJHk1y\n2bhfhKTx65lZvAT8eVW9BdgJfCjJW4F9wKGq2g4catsA7wG2t9te4DMjr1rSuls1LKrq2ar6dmv/\nN3AE2AzsAg60YQeAa1t7F/CFGvgmsDHJppFXLmldndI1iyTbgLcBDwAXV9WzMAgU4A1t2GbgmaHD\nllqfpBnWHRZJXgN8FfhIVf34lYau0HfSDx8n2ZtkIcnC8ePHe8uQNCFdYZHkXAZB8cWq+lrr/uHy\n6UW7P9b6l4CtQ4dvAY6e+JhVtb+q5qtqfm5u7nTrl7ROej4NCXArcKSqPjW06yCwu7V3A3cO9X+w\nfSqyE3hx+XRF0uw6p2PMFcAfA48lebj1/SXwCeCOJHuAHwDXt313A9cAi8BPgBtHWrGkiVg1LKrq\nP1j5OgTAVSuML+BDa6xL0pRxBaekLoaFpC6GhaQuhoWkLoaFpC6GhaQuhoWkLoaFpC6GhaQuhoWk\nLoaFpC49f0gm/dLhw7/+Z0I7dpz0VSU6QzmzULcTg+Ll+nRmMizU5ZVCwcA4OxgWWlVPGBgYZz7D\nQlIXw0JSF8NCUhfDQquaZ2EkYzTbDAt1eaUwMCjODoaFuq0UCgbF2cMVnDolhsPZy5mFpC6GhaQu\nhoWkLoaFpC6GhaQuhoWkLoaFpC6GhaQuhoWkLoaFpC6GhaQuhoWkLoaFpC6rhkWSVyX5VpJHkjyR\n5OOt/5IkDyR5KsntSc5r/ee37cW2f9t4X4Kk9dAzs/gZcGVV/S5wKXB1kp3AJ4Gbq2o78Dywp43f\nAzxfVW8Gbm7jJM24VcOiBv6nbZ7bbgVcCXyl9R8Arm3tXW2btv+qJH5PvDTjuq5ZJNmQ5GHgGHAP\n8D3ghap6qQ1ZAja39mbgGYC2/0XgwhUec2+ShSQLx48fX9urkDR2XWFRVT+vqkuBLcDlwFtWGtbu\nV5pFnPSDmFW1v6rmq2p+bm6ut15JE3JKn4ZU1QvA/cBOYGOS5a/l2wIcbe0lYCtA2/864LlRFCtp\n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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "%matplotlib inline\n", - "plt.imshow(env.render('rgb_array'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 1: Defining a network\n", - "\n", - "With all it's complexity, at it's core TRPO is yet another policy gradient method. \n", - "\n", - "This essentially means we're actually training a stochastic policy $ \\pi_\\theta(a|s) $. \n", - "\n", - "And yes, it's gonna be a neural network. So let's start by defining one." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# input tensors\n", - "observations = T.matrix(name=\"obs\")\n", - "actions = T.ivector(name=\"action\")\n", - "cummulative_returns = T.vector(name=\"G = r + gamma*r' + gamma^2*r'' + ...\")\n", - "old_probs = T.matrix(name=\"action probabilities from previous iteration\")\n", - "\n", - "all_inputs = [observations, actions, cummulative_returns, old_probs]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Create neural network.\n", - "from lasagne.layers import *\n", - "\n", - "nn = InputLayer((None,)+observation_shape, input_var=observations)\n", - "\n", - "\n", - "\n", - "policy = \n", - "\n", - "probs = get_output(policy)\n", - "\n", - "weights = get_all_params(policy, trainable=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 2: Actions and rollouts\n", - "\n", - "In this section, we'll define functions that take actions $ a \\sim \\pi_\\theta(a|s) $ and rollouts $ $." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# compile function\n", - "get_policy = theano.function([observations], probs, allow_input_downcast=True)\n", - "\n", - "\n", - "def act(obs, sample=True):\n", - " \"\"\"\n", - " Samples action from policy distribution (sample = True) or takes most likely action (sample = False)\n", - " :param: obs - single observation vector\n", - " :param sample: if True, samples from \\pi, otherwise takes most likely action\n", - " :returns: action (single integer) and probabilities for all actions\n", - " \"\"\"\n", - "\n", - " policy = get_policy([obs])[0]\n", - "\n", - " if sample:\n", - " action = int(np.random.choice(n_actions, p=policy))\n", - " else:\n", - " action = int(np.argmax(policy))\n", - "\n", - " return action, policy" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# demo\n", - "print(\"sampled:\", [act(env.reset()) for _ in range(100)])\n", - "print(\"greedy:\", [act(env.reset(), sample=False) for _ in range(100)])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Compute cummulative reward just like you did in vanilla REINFORCE" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import scipy.signal\n", - "\n", - "\n", - "def get_cummulative_returns(r, gamma=1):\n", - " \"\"\"\n", - " Computes cummulative discounted rewards given immediate rewards\n", - " G_i = r_i + gamma*r_{i+1} + gamma^2*r_{i+2} + ...\n", - " Also known as R(s,a).\n", - " \"\"\"\n", - " r = np.array(r)\n", - " assert r.ndim >= 1\n", - " return scipy.signal.lfilter([1], [1, -gamma], r[::-1], axis=0)[::-1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# simple demo on rewards [0,0,1,0,0,1]\n", - "get_cummulative_returns([0, 0, 1, 0, 0, 1], gamma=0.9)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Rollout**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def rollout(env, act, max_pathlength=2500, n_timesteps=50000):\n", - " \"\"\"\n", - " Generate rollouts for training.\n", - " :param: env - environment in which we will make actions to generate rollouts.\n", - " :param: act - the function that can return policy and action given observation.\n", - " :param: max_pathlength - maximum size of one path that we generate.\n", - " :param: n_timesteps - total sum of sizes of all pathes we generate.\n", - " \"\"\"\n", - " paths = []\n", - "\n", - " total_timesteps = 0\n", - " while total_timesteps < n_timesteps:\n", - " obervations, actions, rewards, action_probs = [], [], [], []\n", - " obervation = env.reset()\n", - " for _ in range(max_pathlength):\n", - " action, policy = act(obervation)\n", - " obervations.append(obervation)\n", - " actions.append(action)\n", - " action_probs.append(policy)\n", - " obervation, reward, done, _ = env.step(action)\n", - " rewards.append(reward)\n", - " total_timesteps += 1\n", - " if done or total_timesteps == n_timesteps:\n", - " path = {\"observations\": np.array(obervations),\n", - " \"policy\": np.array(action_probs),\n", - " \"actions\": np.array(actions),\n", - " \"rewards\": np.array(rewards),\n", - " \"cumulative_returns\": get_cummulative_returns(rewards),\n", - " }\n", - " paths.append(path)\n", - " break\n", - " return paths" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "paths = rollout(env, act, max_pathlength=5, n_timesteps=100)\n", - "print(paths[-1])\n", - "assert (paths[0]['policy'].shape == (5, n_actions))\n", - "assert (paths[0]['cumulative_returns'].shape == (5,))\n", - "assert (paths[0]['rewards'].shape == (5,))\n", - "assert (paths[0]['observations'].shape == (5,)+observation_shape)\n", - "assert (paths[0]['actions'].shape == (5,))\n", - "print('It\\'s ok')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 3: loss functions\n", - "\n", - "Now let's define the loss functions and constraints for actual TRPO training." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The surrogate reward should be\n", - "$$J_{surr}= {1 \\over N} \\sum\\limits_{i=0}^N \\frac{\\pi_{\\theta}(s_i, a_i)}{\\pi_{\\theta_{old}}(s_i, a_i)}A_{\\theta_{old}(s_i, a_i)}$$\n", - "\n", - "For simplicity, let's use cummulative returns instead of advantage for now:\n", - "$$J'_{surr}= {1 \\over N} \\sum\\limits_{i=0}^N \\frac{\\pi_{\\theta}(s_i, a_i)}{\\pi_{\\theta_{old}}(s_i, a_i)}G_{\\theta_{old}(s_i, a_i)}$$\n", - "\n", - "Or alternatively, minimize the surrogate loss:\n", - "$$ L_{surr} = - J'_{surr} $$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# select probabilities of chosen actions\n", - "batch_size = actions.shape[0]\n", - "\n", - "probs_for_actions = probs[T.arange(batch_size), actions]\n", - "old_probs_for_actions = old_probs[T.arange(batch_size), actions]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Compute surrogate loss: negative importance-sampled policy gradient\n", - "\n", - "L_surr = " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# compute and return surrogate policy gradient\n", - "\n", - "\n", - "def get_flat_gradient(loss, var_list):\n", - " \"\"\"gradient of loss wrt var_list flattened into a large vector\"\"\"\n", - " grads = T.grad(loss, var_list)\n", - " return T.concatenate([grad.ravel() for grad in grads])\n", - "\n", - "\n", - "get_surrogate_gradients = theano.function(all_inputs, get_flat_gradient(L_surr, weights),\n", - " allow_input_downcast=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can ascend these gradients as long as our $pi_\\theta(a|s)$ satisfies the constraint\n", - "$$E_{s,\\pi_{\\Theta_{t}}}\\Big[KL(\\pi(\\Theta_{t}, s) \\:||\\:\\pi(\\Theta_{t+1}, s))\\Big] < \\alpha$$\n", - "\n", - "\n", - "where\n", - "\n", - "$$KL(p||q) = E _p log({p \\over q})$$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Compute Kullback-Leibler divergence (see formula above)\n", - "# Note: you need to sum KL and entropy over all actions, not just the ones agent took\n", - "old_log_probs = T.log(old_probs + 1e-10)\n", - "\n", - "kl = \n", - "\n", - "# Compute policy entropy\n", - "entropy = \n", - "\n", - "compute_losses = theano.function(all_inputs, [L_surr, kl, entropy],\n", - " allow_input_downcast=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Linear search**\n", - "\n", - "TRPO in its core involves ascending surrogate policy gradient constrained by KL divergence. \n", - "\n", - "In order to enforce this constraint, we're gonna use linesearch. You can find out more about it [here](https://en.wikipedia.org/wiki/Linear_search)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def linesearch(f, x, fullstep, max_kl):\n", - " \"\"\"\n", - " Linesearch finds the best parameters of neural networks in the direction of fullstep contrainted by KL divergence.\n", - " :param: f - function that returns loss, kl and arbitrary third component.\n", - " :param: x - old parameters of neural network.\n", - " :param: fullstep - direction in which we make search.\n", - " :param: max_kl - constraint of KL divergence.\n", - " :returns:\n", - " \"\"\"\n", - " max_backtracks = 10\n", - " loss, _, _ = f(x)\n", - " for stepfrac in .5 ** np.arange(max_backtracks):\n", - " xnew = x + stepfrac * fullstep\n", - " new_loss, kl, _ = f(xnew)\n", - " actual_improve = new_loss - loss\n", - " if kl <= max_kl and actual_improve < 0:\n", - " x = xnew\n", - " loss = new_loss\n", - " return x" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 4: training\n", - "In this section we construct rest parts of our computational graph" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def slice_vector(vector, shapes):\n", - " \"\"\"\n", - " Slices symbolic vector into several symbolic tensors of given shapes.\n", - " Auxilary function used to un-flatten gradients, tangents etc.\n", - " :param vector: 1-dimensional symbolic vector\n", - " :param shapes: list or tuple of shapes (list, tuple or symbolic)\n", - " :returns: list of symbolic tensors of given shapes\n", - " \"\"\"\n", - " assert vector.ndim == 1, \"vector must be 1-dimensional\"\n", - " start = 0\n", - " tensors = []\n", - " for shape in shapes:\n", - " size = T.prod(shape)\n", - " tensor = vector[start:(start + size)].reshape(shape)\n", - " tensors.append(tensor)\n", - " start += size\n", - " return tensors" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "conjugate_grad_intermediate_vector = T.vector(\n", - " \"intermediate grad in conjugate_gradient\")\n", - "\n", - "# slice flat_tangent into chunks for each weight\n", - "weight_shapes = [var.get_value().shape for var in weights]\n", - "tangents = slice_vector(conjugate_grad_intermediate_vector, weight_shapes)\n", - "\n", - "# KL divergence where first arg is fixed\n", - "from theano.gradient import disconnected_grad as const\n", - "kl_firstfixed = (const(probs) * (const(T.log(probs)) -\n", - " T.log(probs))).sum(axis=-1).mean()\n", - "\n", - "# compute fisher information matrix (used for conjugate gradients and to estimate KL)\n", - "gradients = T.grad(kl_firstfixed, weights)\n", - "gradient_vector_product = [T.sum(g * t) for (g, t) in zip(gradients, tangents)]\n", - "\n", - "fisher_vector_product = get_flat_gradient(\n", - " sum(gradient_vector_product), weights)\n", - "\n", - "compute_fisher_vector_product = theano.function(\n", - " [observations, conjugate_grad_intermediate_vector], fisher_vector_product)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TRPO helpers\n", - "\n", - "Here we define a few helper functions used in the main TRPO loop" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Conjugate gradients**\n", - "\n", - "Since TRPO includes contrainted optimization, we will need to solve Ax=b using conjugate gradients.\n", - "\n", - "In general, CG is an algorithm that solves Ax=b where A is positive-defined. A is Hessian matrix so A is positive-defined. You can find out more about them [here](https://en.wikipedia.org/wiki/Conjugate_gradient_method)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from numpy.linalg import inv\n", - "\n", - "\n", - "def conjugate_gradient(f_Ax, b, cg_iters=10, residual_tol=1e-10):\n", - " \"\"\"\n", - " This method solves system of equation Ax=b using iterative method called conjugate gradients\n", - " :f_Ax: function that returns Ax\n", - " :b: targets for Ax\n", - " :cg_iters: how many iterations this method should do\n", - " :residual_tol: epsilon for stability\n", - " \"\"\"\n", - " p = b.copy()\n", - " r = b.copy()\n", - " x = np.zeros_like(b)\n", - " rdotr = r.dot(r)\n", - " for i in range(cg_iters):\n", - " z = f_Ax(p)\n", - " v = rdotr / (p.dot(z) + 1e-8)\n", - " x += v * p\n", - " r -= v * z\n", - " newrdotr = r.dot(r)\n", - " mu = newrdotr / (rdotr + 1e-8)\n", - " p = r + mu * p\n", - " rdotr = newrdotr\n", - " if rdotr < residual_tol:\n", - " break\n", - " return x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# This code validates conjugate gradients\n", - "A = np.random.rand(8, 8)\n", - "A = np.matmul(np.transpose(A), A)\n", - "\n", - "\n", - "def f_Ax(x):\n", - " return np.matmul(A, x.reshape(-1, 1)).reshape(-1)\n", - "\n", - "\n", - "b = np.random.rand(8)\n", - "\n", - "w = np.matmul(np.matmul(inv(np.matmul(np.transpose(A), A)),\n", - " np.transpose(A)), b.reshape((-1, 1))).reshape(-1)\n", - "print(w)\n", - "print(conjugate_gradient(f_Ax, b))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Compile a function that exports network weights as a vector\n", - "flat_weights = T.concatenate([var.ravel() for var in weights])\n", - "get_flat_weights = theano.function([], flat_weights)\n", - "\n", - "# ... and another function that imports vector back into network weights\n", - "flat_weights_placeholder = T.vector(\"flattened weights\")\n", - "assigns = slice_vector(flat_weights_placeholder, weight_shapes)\n", - "\n", - "load_flat_weights = theano.function(\n", - " [flat_weights_placeholder], updates=dict(zip(weights, assigns)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Step 5: Main TRPO loop\n", - "\n", - "Here we will train our network!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "from itertools import count\n", - "from collections import OrderedDict\n", - "\n", - "# this is hyperparameter of TRPO. It controls how big KL divergence may be between old and new policy every step.\n", - "max_kl = 0.01\n", - "cg_damping = 0.1 # This parameters regularize addition to\n", - "numeptotal = 0 # this is number of episodes that we played.\n", - "\n", - "start_time = time.time()\n", - "\n", - "for i in count(1):\n", - "\n", - " print(\"\\n********** Iteration %i ************\" % i)\n", - "\n", - " # Generating paths.\n", - " print(\"Rollout\")\n", - " paths = rollout(env, act)\n", - " print(\"Made rollout\")\n", - "\n", - " # Updating policy.\n", - " observations = np.concatenate([path[\"observations\"] for path in paths])\n", - " actions = np.concatenate([path[\"actions\"] for path in paths])\n", - " returns = np.concatenate([path[\"cumulative_returns\"] for path in paths])\n", - " old_probs = np.concatenate([path[\"policy\"] for path in paths])\n", - " inputs_batch = [observations, actions, returns, old_probs]\n", - "\n", - " old_weights = get_flat_weights()\n", - "\n", - " def fisher_vector_product(p):\n", - " \"\"\"gets intermediate grads (p) and computes fisher*vector \"\"\"\n", - " return compute_fisher_vector_product(observations, p) + cg_damping * p\n", - "\n", - " flat_grad = get_surrogate_gradients(*inputs_batch)\n", - "\n", - " stepdir = conjugate_gradient(fisher_vector_product, -flat_grad)\n", - " shs = .5 * stepdir.dot(fisher_vector_product(stepdir))\n", - " lm = np.sqrt(shs / max_kl)\n", - " fullstep = stepdir / lm\n", - "\n", - " # Compute new weights with linesearch in the direction we found with CG\n", - "\n", - " def losses_f(flat_weights):\n", - " load_flat_weights(flat_weights)\n", - " return compute_losses(*inputs_batch)\n", - "\n", - " new_weights = linesearch(losses_f, old_weights, fullstep, max_kl)\n", - "\n", - " load_flat_weights(new_weights)\n", - "\n", - " # Report current progress\n", - " L_surr, kl, entropy = compute_losses(*inputs_batch)\n", - " episode_rewards = np.array([path[\"rewards\"].sum() for path in paths])\n", - "\n", - " stats = OrderedDict()\n", - " numeptotal += len(episode_rewards)\n", - " stats[\"Total number of episodes\"] = numeptotal\n", - " stats[\"Average sum of rewards per episode\"] = episode_rewards.mean()\n", - " stats[\"Std of rewards per episode\"] = episode_rewards.std()\n", - " stats[\"Entropy\"] = entropy\n", - " stats[\"Time elapsed\"] = \"%.2f mins\" % ((time.time() - start_time)/60.)\n", - " stats[\"KL between old and new distribution\"] = kl\n", - " stats[\"Surrogate loss\"] = L_surr\n", - " for k, v in stats.items():\n", - " print(k + \": \" + \" \" * (40 - len(k)) + str(v))\n", - " i += 1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Homework option I: better sampling (10+pts)\n", - "\n", - "In this section, you're invited to implement a better rollout strategy called _vine_.\n", - "\n", - "![img](https://s17.postimg.cc/i90chxgvj/vine.png)\n", - "\n", - "In most gym environments, you can actually backtrack by using states. You can find a wrapper that saves/loads states in [the mcts seminar](https://github.com/yandexdataschool/Practical_RL/blob/master/week10_planning/seminar_MCTS.ipynb).\n", - "\n", - "You can read more about in the [TRPO article](https://arxiv.org/abs/1502.05477) in section 5.2.\n", - "\n", - "The goal here is to implement such rollout policy (we recommend using tree data structure like in the seminar above).\n", - "Then you can assign cummulative rewards similar to `get_cummulative_rewards`, but for a tree.\n", - "\n", - "__bonus task__ - parallelize samples using multiple cores" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Homework option II (10+pts)\n", - "\n", - "Let's use TRPO to train evil robots! (pick any of two)\n", - "* [MuJoCo robots](https://gym.openai.com/envs#mujoco)\n", - "* [Box2d robot](https://gym.openai.com/envs/BipedalWalker-v2)\n", - "\n", - "The catch here is that those environments have continuous action spaces. \n", - "\n", - "Luckily, TRPO is a policy gradient method, so it's gonna work for any parametric $\\pi_\\theta(a|s)$. We recommend starting with gaussian policy:\n", - "\n", - "$$\\pi_\\theta(a|s) = N(\\mu_\\theta(s),\\sigma^2_\\theta(s)) = {1 \\over \\sqrt { 2 \\pi {\\sigma^2}_\\theta(s) } } e^{ (a - \n", - "\\mu_\\theta(s))^2 \\over 2 {\\sigma^2}_\\theta(s) } $$\n", - "\n", - "In the $\\sqrt { 2 \\pi {\\sigma^2}_\\theta(s) }$ clause, $\\pi$ means ~3.1415926, not agent's policy.\n", - "\n", - "This essentially means that you will need two output layers:\n", - "* $\\mu_\\theta(s)$, a dense layer with linear activation\n", - "* ${\\sigma^2}_\\theta(s)$, a dense layer with activation T.exp (to make it positive; like rho from bandits)\n", - "\n", - "For multidimensional actions, you can use fully factorized gaussian (basically a vector of gaussians).\n", - "\n", - "__bonus task__: compare performance of continuous action space method to action space discretization" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/week09_policy_II/td3_and_sac/hw-continuous-control_pytorch.ipynb b/week09_policy_II/td3_and_sac/hw-continuous-control_pytorch.ipynb new file mode 100644 index 000000000..714df58e0 --- /dev/null +++ b/week09_policy_II/td3_and_sac/hw-continuous-control_pytorch.ipynb @@ -0,0 +1,1066 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/week09_policy_II/td3_and_sac/logger.py\n", + "\n", + " !pip -q install gymnasium[mujoco]\n", + " !pip -q install tensorboardX\n", + "\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display to draw game images on.\n", + "# It will have no effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Continuous Control\n", + "\n", + "\n", + "In this notebook you will solve continuous control environment using either [Twin Delayed DDPG (TD3)](https://arxiv.org/pdf/1802.09477.pdf) or [Soft Actor-Critic (SAC)](https://arxiv.org/pdf/1801.01290.pdf). Both are off-policy algorithms that are current go-to algorithms for continuous control tasks.\n", + "\n", + "**Select one** of these two algorithms (TD3 or SAC) to implement. Both algorithms are extensions of basic [Deep Deterministic Policy Gradient (DDPG)](https://arxiv.org/abs/1509.02971) algorithm, and DDPG is kind of \"DQN with another neural net approximating greedy policy\", and all that differs is a set of stabilization tricks:\n", + "* TD3 trains deterministic policy, while SAC uses *stochastic policy*. This means that for SAC you can solve exploration-exploitation trade-off by simple sampling from policy, while in TD3 you will have to add noise to your actions.\n", + "* TD3 proposes to stabilize targets by adding a *clipped noise* to actions, which slightly prevents overestimation. In SAC, we formally switch to formalism of Maximum Entropy RL and add *entropy bonus* into our value function.\n", + "\n", + "Also both algorithms utilize a *twin trick*: train two critics and use pessimistic targets by taking minimum from two proposals. Standard trick with target networks is also necessary. We will go through all these tricks step-by-step.\n", + "\n", + "SAC is probably less clumsy scheme than TD3, but requires a bit more code to implement. More detailed description of algorithms can be found in Spinning Up documentation:\n", + "* on [DDPG](https://spinningup.openai.com/en/latest/algorithms/ddpg.html)\n", + "* on [TD3](https://spinningup.openai.com/en/latest/algorithms/td3.html)\n", + "* on [SAC](https://spinningup.openai.com/en/latest/algorithms/sac.html)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Environment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import gymnasium as gym\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we will create an instance of the environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-09-16T18:41:00.003174Z", + "start_time": "2020-09-16T18:40:59.921640Z" + } + }, + "outputs": [], + "source": [ + "env = gym.make(\"Ant-v4\", render_mode=\"rgb_array\")\n", + "\n", + "# we want to look inside\n", + "env.reset()\n", + "\n", + "# examples of states and actions\n", + "print(\"observation space: \", env.observation_space,\n", + " \"\\nobservations:\", env.reset()[0])\n", + "print(\"action space: \", env.action_space,\n", + " \"\\naction_sample: \", env.action_space.sample())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "plt.imshow(env.render())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's run random policy and see how it looks." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class RandomActor():\n", + " def get_action(self, states):\n", + " assert len(states.shape) == 1, \"can't work with batches\"\n", + " return env.action_space.sample()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s, _ = env.reset()\n", + "rewards_per_step = []\n", + "actor = RandomActor()\n", + "\n", + "for i in range(10000):\n", + " a = actor.get_action(s)\n", + " s, r, terminated, truncated, _ = env.step(a)\n", + "\n", + " rewards_per_step.append(r)\n", + "\n", + " if terminated or truncated:\n", + " s, _ = env.reset()\n", + " print(\"done: \", i)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So, basically most episodes are 1000 steps long (then happens termination by time), though sometimes we are terminated earlier if simulation discovers some obvious reasons to think that we crashed our ant. Important thing about continuous control tasks like this is that we receive non-trivial signal at each step: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rewards_per_step[100:110]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This dense signal will guide our optimizations. It also partially explains why off-policy algorithms are more effective and sample-efficient than on-policy algorithms like PPO: 1-step targets are already quite informative." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will add only one wrapper to our environment to simply write summaries, mainly, the total reward during an episode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from logger import TensorboardSummaries as Summaries\n", + "\n", + "env = gym.make(\"Ant-v4\", render_mode=\"rgb_array\")\n", + "env = Summaries(env, \"MyFirstWalkingAnt\");\n", + "\n", + "state_dim = env.observation_space.shape[0] # dimension of state space (27 numbers)\n", + "action_dim = env.action_space.shape[0] # dimension of action space (8 numbers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Models" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start with *critic* model. On the one hand, it will function as an approximation of $Q^*(s, a)$, on the other hand it evaluates current actor $\\pi$ and can be viewed as $Q^{\\pi}(s, a)$. This critic will take both state $s$ and action $a$ as input and output a scalar value. Recommended architecture is 3-layered MLP.\n", + "\n", + "**Danger:** when models have a scalar output it is a good rule to squeeze it to avoid unexpected broadcasting, since [batch_size, 1] broadcasts with many tensor sizes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", + "\n", + "class Critic(nn.Module):\n", + " def __init__(self, state_dim, action_dim):\n", + " super().__init__() \n", + "\n", + " \n", + "\n", + " def get_qvalues(self, states, actions):\n", + " '''\n", + " input:\n", + " states - tensor, (batch_size x features)\n", + " actions - tensor, (batch_size x actions_dim)\n", + " output:\n", + " qvalues - tensor, critic estimation, (batch_size)\n", + " '''\n", + " qvalues = \n", + "\n", + " assert len(qvalues.shape) == 1 and qvalues.shape[0] == states.shape[0]\n", + " \n", + " return qvalues" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, let's define a policy, or an actor $\\pi$. Use architecture, similar to critic (3-layered MLP). The output depends on algorithm:\n", + "\n", + "For **TD3**, model *deterministic policy*. You should output `action_dim` numbers in range $[-1, 1]$. Unfortunately, deterministic policies lead to problems with stability and exploration, so we will need three \"modes\" of how this policy can be operating:\n", + "* First one - greedy - is a simple feedforward pass through network that will be used to train the actor.\n", + "* Second one - exploration mode - is when we need to add noise (e.g. Gaussian) to our actions to collect more diverse data. \n", + "* Third mode - \"clipped noised\" - will be used when we will require a target for critic, where we need to somehow \"noise\" our actor output, but not too much, so we add *clipped noise* to our output:\n", + "$$\\pi_{\\theta}(s) + \\varepsilon, \\quad \\varepsilon = \\operatorname{clip}(\\epsilon, -0.5, 0.5), \\epsilon \\sim \\mathcal{N}(0, \\sigma^2 I)$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-09-16T18:41:06.246418Z", + "start_time": "2020-09-16T18:41:05.841255Z" + } + }, + "outputs": [], + "source": [ + "# template for TD3; template for SAC is below\n", + "class TD3_Actor(nn.Module):\n", + " def __init__(self, state_dim, action_dim):\n", + " super().__init__() \n", + "\n", + " \n", + "\n", + " def get_action(self, states, std_noise=0.1):\n", + " '''\n", + " Used to collect data by interacting with environment,\n", + " so your have to add some noise to actions.\n", + " input:\n", + " states - numpy, (batch_size x features)\n", + " output:\n", + " actions - numpy, (batch_size x actions_dim)\n", + " '''\n", + " # no gradient computation is required here since we will use this only for interaction\n", + " with torch.no_grad():\n", + " actions = \n", + " \n", + " assert isinstance(actions, (list,np.ndarray)), \"convert actions to numpy to send into env\"\n", + " assert actions.max() <= 1. and actions.min() >= -1, \"actions must be in the range [-1, 1]\"\n", + " return actions\n", + " \n", + " def get_best_action(self, states):\n", + " '''\n", + " Will be used to optimize actor. Requires differentiable w.r.t. parameters actions.\n", + " input:\n", + " states - PyTorch tensor, (batch_size x features)\n", + " output:\n", + " actions - PyTorch tensor, (batch_size x actions_dim)\n", + " '''\n", + " actions = \n", + " \n", + " assert actions.requires_grad, \"you must be able to compute gradients through actions\"\n", + " return actions\n", + " \n", + " def get_target_action(self, states, std_noise=0.2, clip_eta=0.5):\n", + " '''\n", + " Will be used to create target for critic optimization.\n", + " Returns actions with added \"clipped noise\".\n", + " input:\n", + " states - PyTorch tensor, (batch_size x features)\n", + " output:\n", + " actions - PyTorch tensor, (batch_size x actions_dim)\n", + " '''\n", + " # no gradient computation is required here since we will use this only for interaction\n", + " with torch.no_grad():\n", + " actions = \n", + " \n", + " # actions can fly out of [-1, 1] range after added noise\n", + " return actions.clamp(-1, 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For **SAC**, model *gaussian policy*. This means policy distribution is going to be multivariate normal with diagonal covariance. The policy head will predict the mean and covariance, and it should be guaranteed that covariance is non-negative. **Important:** the way you model covariance strongly influences optimization procedure, so here are some options: let $f_{\\theta}$ be the output of covariance head, then:\n", + "* use exponential function $\\sigma(s) = \\exp(f_{\\theta}(s))$\n", + "* transform output to $[-1, 1]$ using `tanh`, then project output to some interval $[m, M]$, where $m = -20$, $M = 2$ and then use exponential function. This will guarantee the range of modeled covariance is adequate. So, the resulting formula is:\n", + "$$\\sigma(s) = \\exp^{m + 0.5(M - m)(\\tanh(f_{\\theta}(s)) + 1)}$$\n", + "* `softplus` operation $\\sigma(s) = \\log(1 + \\exp^{f_{\\theta}(s)})$ seems to work poorly here. o_O\n", + "\n", + "**Note**: `torch.distributions.Normal` already has everything you will need to work with such policy after you modeled mean and covariance, i.e. sampling via reparametrization trick (see `rsample` method) and compute log probability (see `log_prob` method).\n", + "\n", + "There is one more problem with gaussian distribution. We need to force our actions to be in $[-1, 1]$ bound. To achieve this, model unbounded gaussian $\\mathcal{N}(\\mu_{\\theta}(s), \\sigma_{\\theta}(s)^2I)$, where $\\mu$ can be arbitrary. Then every time you have samples $u$ from this gaussian policy, squash it using $\\operatorname{tanh}$ function to get a sample from $[-1, 1]$:\n", + "$$u \\sim \\mathcal{N}(\\mu, \\sigma^2I)$$\n", + "$$a = \\operatorname{tanh}(u)$$\n", + "\n", + "**Important:** after that you are required to use change of variable formula every time you compute likelihood (see appendix C in [paper on SAC](https://arxiv.org/pdf/1801.01290.pdf) for details):\n", + "$$\\log p(a \\mid \\mu, \\sigma) = \\log p(u \\mid \\mu, \\sigma) - \\sum_{i = 1}^D \\log (1 - \\operatorname{tanh}^2(u_i)),$$\n", + "where $D$ is `action_dim`. In practice, add something like 1e-6 inside logarithm to protect from computational instabilities." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-09-16T18:41:06.246418Z", + "start_time": "2020-09-16T18:41:05.841255Z" + } + }, + "outputs": [], + "source": [ + "# template for SAC\n", + "from torch.distributions import Normal\n", + "\n", + "class SAC_Actor(nn.Module):\n", + " def __init__(self, state_dim, action_dim):\n", + " super().__init__() \n", + "\n", + " \n", + " \n", + " def apply(self, states):\n", + " '''\n", + " For given batch of states samples actions and also returns its log prob.\n", + " input:\n", + " states - PyTorch tensor, (batch_size x features)\n", + " output:\n", + " actions - PyTorch tensor, (batch_size x action_dim)\n", + " log_prob - PyTorch tensor, (batch_size)\n", + " '''\n", + " \n", + " \n", + " return actions, log_prob \n", + "\n", + " def get_action(self, states):\n", + " '''\n", + " Used to interact with environment by sampling actions from policy\n", + " input:\n", + " states - numpy, (batch_size x features)\n", + " output:\n", + " actions - numpy, (batch_size x actions_dim)\n", + " '''\n", + " # no gradient computation is required here since we will use this only for interaction\n", + " with torch.no_grad():\n", + " \n", + " # hint: you can use `apply` method here\n", + " actions = \n", + " \n", + " assert isinstance(actions, (list,np.ndarray)), \"convert actions to numpy to send into env\"\n", + " assert actions.max() <= 1. and actions.min() >= -1, \"actions must be in the range [-1, 1]\"\n", + " return actions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ReplayBuffer\n", + "\n", + "The same as in DQN. You can copy code from your DQN assignment, just check that it works fine with continuous actions (probably it is). \n", + "\n", + "Let's recall the interface:\n", + "* `exp_replay.add(obs, act, rw, next_obs, done)` - saves (s,a,r,s',done) tuple into the buffer\n", + "* `exp_replay.sample(batch_size)` - returns observations, actions, rewards, next_observations and is_done for `batch_size` random samples.\n", + "* `len(exp_replay)` - returns number of elements stored in replay buffer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class ReplayBuffer():\n", + " def __init__(self, size):\n", + " \"\"\"\n", + " Create Replay buffer.\n", + " Parameters\n", + " ----------\n", + " size: int\n", + " Max number of transitions to store in the buffer. When the buffer\n", + " overflows the old memories are dropped.\n", + "\n", + " Note: for this assignment you can pick any data structure you want.\n", + " If you want to keep it simple, you can store a list of tuples of (s, a, r, s') in self._storage\n", + " However you may find out there are faster and/or more memory-efficient ways to do so.\n", + " \"\"\"\n", + " self._storage = []\n", + " self._maxsize = size\n", + "\n", + " # OPTIONAL: YOUR CODE\n", + "\n", + " def __len__(self):\n", + " return len(self._storage)\n", + "\n", + " def add(self, obs_t, action, reward, obs_tp1, done):\n", + " '''\n", + " Make sure, _storage will not exceed _maxsize. \n", + " Make sure, FIFO rule is being followed: the oldest examples has to be removed earlier\n", + " ''' \n", + " data = (obs_t, action, reward, obs_tp1, done)\n", + " storage = self._storage\n", + " maxsize = self._maxsize\n", + " \n", + " # add data to storage\n", + "\n", + " def sample(self, batch_size):\n", + " \"\"\"Sample a batch of experiences.\n", + " Parameters\n", + " ----------\n", + " batch_size: int\n", + " How many transitions to sample.\n", + " Returns\n", + " -------\n", + " obs_batch: np.array\n", + " batch of observations\n", + " act_batch: np.array\n", + " batch of actions executed given obs_batch\n", + " rew_batch: np.array\n", + " rewards received as results of executing act_batch\n", + " next_obs_batch: np.array\n", + " next set of observations seen after executing act_batch\n", + " done_mask: np.array\n", + " done_mask[i] = 1 if executing act_batch[i] resulted in\n", + " the end of an episode and 0 otherwise.\n", + " \"\"\"\n", + " storage = self._storage\n", + " \n", + " # randomly generate batch_size integers\n", + " # to be used as indexes of samples\n", + " \n", + " \n", + " # collect for each index\n", + " \n", + " return \n", + " # , , , , " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "exp_replay = ReplayBuffer(10)\n", + "\n", + "for _ in range(30):\n", + " exp_replay.add(env.reset()[0], env.action_space.sample(),\n", + " 1.0, env.reset()[0], done=False)\n", + "\n", + "obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", + " 5)\n", + "\n", + "assert len(exp_replay) == 10, \"experience replay size should be 10 because that's what maximum capacity is\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def play_and_record(initial_state, agent, env, exp_replay, n_steps=1):\n", + " \"\"\"\n", + " Play the game for exactly n steps, record every (s,a,r,s', done) to replay buffer. \n", + " Whenever game ends, add record with done=True and reset the game.\n", + " It is guaranteed that env has done=False when passed to this function.\n", + "\n", + " :returns: return sum of rewards over time and the state in which the env stays\n", + " \"\"\"\n", + " s = initial_state\n", + " sum_rewards = 0\n", + "\n", + " # Play the game for n_steps as per instructions above\n", + " for t in range(n_steps):\n", + " \n", + " # select action using policy with exploration\n", + " a = \n", + " \n", + " ns, r, terminated, truncated, _ = env.step(a)\n", + " \n", + " exp_replay.add(s, a, r, ns, terminated)\n", + " \n", + " s = env.reset()[0] if terminated or truncated else ns\n", + " \n", + " sum_rewards += r \n", + "\n", + " return sum_rewards, s" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#testing your code.\n", + "exp_replay = ReplayBuffer(2000)\n", + "actor = (state_dim, action_dim).to(DEVICE)\n", + "\n", + "state, _ = env.reset()\n", + "play_and_record(state, actor, env, exp_replay, n_steps=1000)\n", + "\n", + "# if you're using your own experience replay buffer, some of those tests may need correction.\n", + "# just make sure you know what your code does\n", + "assert len(exp_replay) == 1000, \"play_and_record should have added exactly 1000 steps, \"\\\n", + " \"but instead added %i\" % len(exp_replay)\n", + "is_dones = list(zip(*exp_replay._storage))[-1]\n", + "\n", + "for _ in range(100):\n", + " obs_batch, act_batch, reward_batch, next_obs_batch, is_done_batch = exp_replay.sample(\n", + " 10)\n", + " assert obs_batch.shape == next_obs_batch.shape == (10,) + (state_dim,)\n", + " assert act_batch.shape == (\n", + " 10, action_dim), \"actions batch should have shape (10, 8) but is instead %s\" % str(act_batch.shape)\n", + " assert reward_batch.shape == (\n", + " 10,), \"rewards batch should have shape (10,) but is instead %s\" % str(reward_batch.shape)\n", + " assert is_done_batch.shape == (\n", + " 10,), \"is_done batch should have shape (10,) but is instead %s\" % str(is_done_batch.shape)\n", + " assert [int(i) in (0, 1)\n", + " for i in is_dones], \"is_done should be strictly True or False\"\n", + "\n", + "print(\"Well done!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialization\n", + "\n", + "Let's start initializing our algorithm. Here is our hyperparameters:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "gamma=0.99 # discount factor\n", + "max_buffer_size = 10**5 # size of experience replay\n", + "start_timesteps = 5000 # size of experience replay when start training\n", + "timesteps_per_epoch=1 # steps in environment per step of network updates\n", + "batch_size=128 # batch size for all optimizations\n", + "max_grad_norm=10 # max grad norm for all optimizations\n", + "tau=0.005 # speed of updating target networks\n", + "policy_update_freq=<> # frequency of actor update; vanilla choice is 2 for TD3 or 1 for SAC\n", + "alpha=0.1 # temperature for SAC\n", + "\n", + "# iterations passed\n", + "n_iterations = 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is our experience replay:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# experience replay\n", + "exp_replay = ReplayBuffer(max_buffer_size)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is our models: *two* critics and one actor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# models to train\n", + "actor = (state_dim, action_dim).to(DEVICE)\n", + "critic1 = Critic(state_dim, action_dim).to(DEVICE)\n", + "critic2 = Critic(state_dim, action_dim).to(DEVICE)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To stabilize training, we will require **target networks** - slow updating copies of our models. In **TD3**, both critics and actor have their copies, in **SAC** it is assumed that only critics require target copies while actor is always used fresh." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# target networks: slow-updated copies of actor and two critics\n", + "target_critic1 = Critic(state_dim, action_dim).to(DEVICE)\n", + "target_critic2 = Critic(state_dim, action_dim).to(DEVICE)\n", + "target_actor = TD3_Actor(state_dim, action_dim).to(DEVICE) # comment this line if you chose SAC\n", + "\n", + "# initialize them as copies of original models\n", + "target_critic1.load_state_dict(critic1.state_dict())\n", + "target_critic2.load_state_dict(critic2.state_dict())\n", + "target_actor.load_state_dict(actor.state_dict()) # comment this line if you chose SAC " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In continuous control, target networks are usually updated using exponential smoothing:\n", + "$$\\theta^{-} \\leftarrow \\tau \\theta + (1 - \\tau) \\theta^{-},$$\n", + "where $\\theta^{-}$ are target network weights, $\\theta$ - fresh parameters, $\\tau$ - hyperparameter. This util function will do it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def update_target_networks(model, target_model):\n", + " for param, target_param in zip(model.parameters(), target_model.parameters()):\n", + " target_param.data.copy_(tau * param.data + (1 - tau) * target_param.data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we will have three optimization procedures to train our three models, so let's welcome our three Adams:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# optimizers: for every model we have\n", + "opt_actor = torch.optim.Adam(actor.parameters(), lr=3e-4)\n", + "opt_critic1 = torch.optim.Adam(critic1.parameters(), lr=3e-4)\n", + "opt_critic2 = torch.optim.Adam(critic2.parameters(), lr=3e-4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# just to avoid writing this code three times\n", + "def optimize(name, model, optimizer, loss):\n", + " '''\n", + " Makes one step of SGD optimization, clips norm with max_grad_norm and \n", + " logs everything into tensorboard\n", + " '''\n", + " loss = loss.mean()\n", + " optimizer.zero_grad()\n", + " loss.backward()\n", + " grad_norm = nn.utils.clip_grad_norm_(model.parameters(), max_grad_norm)\n", + " optimizer.step()\n", + "\n", + " # logging\n", + " env.writer.add_scalar(name, loss.item(), n_iterations)\n", + " env.writer.add_scalar(name + \"_grad_norm\", grad_norm.item(), n_iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Critic target computation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's discuss our losses for critic and actor.\n", + "\n", + "To train both critics we would like to minimize MSE using 1-step targets: for one sampled transition $(s, a, r, s')$ it should look something like this:\n", + "$$y(s, a) = r + \\gamma V(s').$$\n", + "\n", + "How do we evaluate next state and compute $V(s')$? Well, technically Monte-Carlo estimation looks simple:\n", + "$$V(s') \\approx Q(s', a')$$\n", + "where (important!) $a'$ is a sample from our current policy $\\pi(a' \\mid s')$.\n", + "\n", + "But out actor $\\pi$ will be actually trained to search for actions $a'$ where our critic gives big estimates, and this straightforward approach leads to serious overesimation issues. We require some hacks. First, we will use target networks for $Q$ (and **TD3** also uses target network for $\\pi$). Second, we will use *two* critics and take minimum across their estimations:\n", + "$$V(s') = \\min_{i = 1,2} Q^{-}_i(s', a'),$$\n", + "where $a'$ is sampled from target policy $\\pi^{-}(a' \\mid s')$ in **TD3** and from fresh policy $\\pi(a' \\mid s')$ in **SAC**.\n", + "\n", + "###### And the last but not the least:\n", + "* in **TD3** to compute $a'$ use *mode with clipped noise* that will prevent our policy from exploiting narrow peaks in our critic approximation;\n", + "* in **SAC** add (estimation of) entropy bonus in next state $s'$:\n", + "$$V(s') = \\min_{i = 1,2} Q^{-}_i(s', a') - \\alpha \\log \\pi (a' \\mid s')$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def compute_critic_target(rewards, next_states, is_done):\n", + " '''\n", + " Important: use target networks for this method! Do not use \"fresh\" models except fresh policy in SAC!\n", + " input:\n", + " rewards - PyTorch tensor, (batch_size)\n", + " next_states - PyTorch tensor, (batch_size x features)\n", + " is_done - PyTorch tensor, (batch_size)\n", + " output:\n", + " critic target - PyTorch tensor, (batch_size)\n", + " '''\n", + " with torch.no_grad():\n", + " critic_target = \n", + " \n", + " assert not critic_target.requires_grad, \"target must not require grad.\"\n", + " assert len(critic_target.shape) == 1, \"dangerous extra dimension in target?\"\n", + "\n", + " return critic_target" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To train actor we want simply to maximize\n", + "$$\\mathbb{E}_{a \\sim \\pi(a \\mid s)} Q(s, a) \\to \\max_{\\pi}$$\n", + "\n", + "* in **TD3**, because of deterministic policy, the expectation reduces:\n", + "$$Q(s, \\pi(s)) \\to \\max_{\\pi}$$\n", + "* in **SAC**, use reparametrization trick to compute gradients and also do not forget to add entropy regularizer to motivate policy to be as stochastic as possible:\n", + "$$\\mathbb{E}_{a \\sim \\pi(a \\mid s)} Q(s, a) - \\alpha \\log \\pi(a \\mid s) \\to \\max_{\\pi}$$\n", + "\n", + "**Note:** We will use (fresh) critic1 here as Q-functon to \"exploit\". You can also use both critics and again take minimum across their estimations (this is done in original implementation of **SAC** and not done in **TD3**), but this seems to be not of high importance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def compute_actor_loss(states):\n", + " '''\n", + " Returns actor loss on batch of states\n", + " input:\n", + " states - PyTorch tensor, (batch_size x features)\n", + " output:\n", + " actor loss - PyTorch tensor, (batch_size)\n", + " '''\n", + " # make sure you have gradients w.r.t. actor parameters\n", + " actions = \n", + " \n", + " assert actions.requires_grad, \"actions must be differentiable with respect to policy parameters\"\n", + " \n", + " # compute actor loss\n", + " actor_loss = \n", + " return actor_loss" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Pipeline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally combining all together and launching our algorithm. Your goal is to reach at least 1000 average reward during evaluation after training in this ant environment (*since this is a new hometask, this threshold might be updated, so at least just see if your ant learned to walk in the rendered simulation*).\n", + "\n", + "* rewards should rise more or less steadily in this environment. There can be some drops due to instabilities of algorithm, but it should eventually start rising after 100K-200K iterations. If no progress in reward is observed after these first 100K-200K iterations, there is a bug.\n", + "* gradient norm appears to be quite big for this task, it is ok if it reaches 100-200 (we handled it with clip_grad_norm). Consider everything exploded if it starts growing exponentially, then there is a bug." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "seed = \n", + "np.random.seed(seed)\n", + "env.unwrapped.seed(seed)\n", + "torch.manual_seed(seed);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from tqdm.notebook import trange\n", + "\n", + "interaction_state = env.reset()\n", + "random_actor = RandomActor()\n", + "\n", + "for n_iterations in trange(0, 1000000, timesteps_per_epoch):\n", + " # if experience replay is small yet, no training happens\n", + " # we also collect data using random policy to collect more diverse starting data\n", + " if len(exp_replay) < start_timesteps:\n", + " _, interaction_state = play_and_record(interaction_state, random_actor, env, exp_replay, timesteps_per_epoch)\n", + " continue\n", + " \n", + " # perform a step in environment and store it in experience replay\n", + " _, interaction_state = play_and_record(interaction_state, actor, env, exp_replay, timesteps_per_epoch)\n", + " \n", + " # sample a batch from experience replay\n", + " states, actions, rewards, next_states, is_done = exp_replay.sample(batch_size)\n", + " \n", + " # move everything to PyTorch tensors\n", + " states = torch.tensor(states, device=DEVICE, dtype=torch.float)\n", + " actions = torch.tensor(actions, device=DEVICE, dtype=torch.float)\n", + " rewards = torch.tensor(rewards, device=DEVICE, dtype=torch.float)\n", + " next_states = torch.tensor(next_states, device=DEVICE, dtype=torch.float)\n", + " is_done = torch.tensor(\n", + " is_done.astype('float32'),\n", + " device=DEVICE,\n", + " dtype=torch.float\n", + " )\n", + " \n", + " # losses\n", + " critic1_loss = \n", + " optimize(\"critic1\", critic1, opt_critic1, critic1_loss)\n", + "\n", + " critic2_loss = \n", + " optimize(\"critic2\", critic2, opt_critic2, critic2_loss)\n", + "\n", + " # actor update is less frequent in TD3\n", + " if n_iterations % policy_update_freq == 0:\n", + " actor_loss = \n", + " optimize(\"actor\", actor, opt_actor, actor_loss)\n", + "\n", + " # update target networks\n", + " update_target_networks(critic1, target_critic1)\n", + " update_target_networks(critic2, target_critic2)\n", + " update_target_networks(actor, target_actor) # comment this line if you chose SAC" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-09-16T18:41:47.560269Z", + "start_time": "2020-09-16T18:41:47.546277Z" + } + }, + "outputs": [], + "source": [ + "def evaluate(env, actor, n_games=1, t_max=1000):\n", + " '''\n", + " Plays n_games and returns rewards and rendered games\n", + " '''\n", + " rewards = []\n", + "\n", + " for _ in range(n_games):\n", + " s, _ = env.reset()\n", + "\n", + " R = 0\n", + " for _ in range(t_max):\n", + " # select action for final evaluation of your policy\n", + " action = \n", + "\n", + " assert (action.max() <= 1).all() and (action.min() >= -1).all()\n", + "\n", + " s, r, terminated, truncated, _ = env.step(action)\n", + "\n", + " R += r\n", + "\n", + " if terminated or truncated:\n", + " break\n", + "\n", + " rewards.append(R)\n", + " return np.array(rewards)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-09-16T18:38:45.130920Z", + "start_time": "2020-09-16T18:38:13.090472Z" + } + }, + "outputs": [], + "source": [ + "# evaluation will take some time!\n", + "sessions = evaluate(env, actor, n_games=20)\n", + "score = sessions.mean()\n", + "print(f\"Your score: {score}\")\n", + "\n", + "assert score >= 1000, \"Needs more training?\"\n", + "print(\"Well done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Record" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-09-16T18:43:19.559507Z", + "start_time": "2020-09-16T18:43:19.522533Z" + } + }, + "outputs": [], + "source": [ + "from gymnasium.wrappers import RecordVideo\n", + "\n", + "# let's hope this will work\n", + "# don't forget to pray\n", + "with gym.make(\"Ant-v4\", render_mode=\"rgb_array\") as env, RecordVideo(\n", + " env=env, video_folder=\"./videos\"\n", + ") as env_monitor:\n", + " # note that t_max is 300, so collected reward will be smaller than 1000\n", + " evaluate(env_monitor, actor, n_games=1, t_max=300)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Show video. This may not work in some setups. If it doesn't\n", + "# work for you, you can download the videos and view them locally.\n", + "\n", + "from pathlib import Path\n", + "from base64 import b64encode\n", + "from IPython.display import HTML\n", + "import sys\n", + "\n", + "video_paths = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "video_path = video_paths[-1] # You can also try other indices\n", + "\n", + "if 'google.colab' in sys.modules:\n", + " # https://stackoverflow.com/a/57378660/1214547\n", + " with video_path.open('rb') as fp:\n", + " mp4 = fp.read()\n", + " data_url = 'data:video/mp4;base64,' + b64encode(mp4).decode()\n", + "else:\n", + " data_url = str(video_path)\n", + "\n", + "HTML(\"\"\"\n", + "\n", + "\"\"\".format(data_url))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Report\n", + "\n", + "We'd like to collect some statistics about computational resources you spent on this task. Please, report:\n", + "* which GPU or CPU you used: \n", + "* number of iterations you used for training: \n", + "* wall-clock time spent (on computation =D): " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/week09_policy_II/td3_and_sac/logger.py b/week09_policy_II/td3_and_sac/logger.py new file mode 100644 index 000000000..c393ad2cc --- /dev/null +++ b/week09_policy_II/td3_and_sac/logger.py @@ -0,0 +1,91 @@ +from collections import deque + +import gymnasium as gym +import numpy as np +from tensorboardX import SummaryWriter + + +class TensorboardSummaries(gym.Wrapper): + """Writes env summaries.""" + + def __init__(self, env, prefix=None, running_mean_size=100, step_var=None): + super().__init__(env) + self.episode_counter = 0 + self.prefix = prefix or self.env.spec.id + self.writer = SummaryWriter(f"logs/{self.prefix}") + self.step_var = 0 + + self.nenvs = getattr(self.env.unwrapped, "nenvs", 1) + self.rewards = np.zeros(self.nenvs) + self.had_ended_episodes = np.zeros(self.nenvs, dtype=bool) + self.episode_lengths = np.zeros(self.nenvs) + self.reward_queues = [ + deque([], maxlen=running_mean_size) for _ in range(self.nenvs) + ] + + def should_write_summaries(self): + """Returns true if it's time to write summaries.""" + return np.all(self.had_ended_episodes) + + def add_summaries(self): + """Writes summaries.""" + self.writer.add_scalar( + f"Episodes/total_reward", + np.mean([q[-1] for q in self.reward_queues]), + self.step_var, + ) + self.writer.add_scalar( + f"Episodes/reward_mean_{self.reward_queues[0].maxlen}", + np.mean([np.mean(q) for q in self.reward_queues]), + self.step_var, + ) + self.writer.add_scalar( + f"Episodes/episode_length", np.mean(self.episode_lengths), self.step_var + ) + if self.had_ended_episodes.size > 1: + self.writer.add_scalar( + f"Episodes/min_reward", + min(q[-1] for q in self.reward_queues), + self.step_var, + ) + self.writer.add_scalar( + f"Episodes/max_reward", + max(q[-1] for q in self.reward_queues), + self.step_var, + ) + self.episode_lengths.fill(0) + self.had_ended_episodes.fill(False) + + def step(self, action): + obs, rew, terminated, truncated, info = self.env.step(action) + self.rewards += rew + self.episode_lengths[~self.had_ended_episodes] += 1 + + info_collection = [info] if isinstance(info, dict) else info + terminated_collection = ( + [terminated] if isinstance(terminated, bool) else terminated + ) + truncated_collection = [truncated] if isinstance(truncated, bool) else truncated + done_indices = [ + i + for i, info in enumerate(info_collection) + if info.get( + "real_done", terminated_collection[i] or truncated_collection[i] + ) + ] + for i in done_indices: + if not self.had_ended_episodes[i]: + self.had_ended_episodes[i] = True + self.reward_queues[i].append(self.rewards[i]) + self.rewards[i] = 0 + + self.step_var += self.nenvs + if self.should_write_summaries(): + self.add_summaries() + return obs, rew, terminated, truncated, info + + def reset(self, **kwargs): + self.rewards.fill(0) + self.episode_lengths.fill(0) + self.had_ended_episodes.fill(False) + return self.env.reset(**kwargs) diff --git a/week09_policy_II/test_ppo/actions.npy b/week09_policy_II/test_ppo/actions.npy new file mode 100644 index 000000000..3e7f71f0f Binary files /dev/null and b/week09_policy_II/test_ppo/actions.npy differ diff --git a/week09_policy_II/test_ppo/advantages.npy b/week09_policy_II/test_ppo/advantages.npy new file mode 100644 index 000000000..351e12821 Binary files /dev/null and b/week09_policy_II/test_ppo/advantages.npy differ diff --git a/week09_policy_II/test_ppo/log_probs.npy b/week09_policy_II/test_ppo/log_probs.npy new file mode 100644 index 000000000..63387ab55 Binary files /dev/null and b/week09_policy_II/test_ppo/log_probs.npy differ diff --git a/week09_policy_II/test_ppo/observations.npy b/week09_policy_II/test_ppo/observations.npy new file mode 100644 index 000000000..bca704d8b Binary files /dev/null and b/week09_policy_II/test_ppo/observations.npy differ diff --git a/week09_policy_II/test_ppo/policy b/week09_policy_II/test_ppo/policy new file mode 100644 index 000000000..5cb4c8169 Binary files /dev/null and b/week09_policy_II/test_ppo/policy differ diff --git a/week09_policy_II/test_ppo/resets.npy b/week09_policy_II/test_ppo/resets.npy new file mode 100644 index 000000000..53c506758 Binary files /dev/null and b/week09_policy_II/test_ppo/resets.npy differ diff --git a/week09_policy_II/test_ppo/rewards.npy b/week09_policy_II/test_ppo/rewards.npy new file mode 100644 index 000000000..972587a7d Binary files /dev/null and b/week09_policy_II/test_ppo/rewards.npy differ diff --git a/week09_policy_II/test_ppo/state.npy b/week09_policy_II/test_ppo/state.npy new file mode 100644 index 000000000..a17063d8e Binary files /dev/null and b/week09_policy_II/test_ppo/state.npy differ diff --git a/week09_policy_II/test_ppo/value_targets.npy b/week09_policy_II/test_ppo/value_targets.npy new file mode 100644 index 000000000..0d105755a Binary files /dev/null and b/week09_policy_II/test_ppo/value_targets.npy differ diff --git a/week09_policy_II/test_ppo/values.npy b/week09_policy_II/test_ppo/values.npy new file mode 100644 index 000000000..de84548f3 Binary files /dev/null and b/week09_policy_II/test_ppo/values.npy differ diff --git a/week10_planning/README.md b/week10_planning/README.md index 042d8c513..5591f2c0f 100644 --- a/week10_planning/README.md +++ b/week10_planning/README.md @@ -1,7 +1,7 @@ ## Assignments -Just as usual, start with `seminar_MCTS.ipynb` -[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/spring20/week10_planning/seminar_MCTS.ipynb) +Just as usual, start with `seminar_MCTS.ipynb` +[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/yandexdataschool/Practical_RL/blob/master/week10_planning/seminar_MCTS.ipynb) ## Materials: planning @@ -13,9 +13,9 @@ Just as usual, start with `seminar_MCTS.ipynb` * Monte-carlo tree search * Monte-carlo tree search step-by-step by J.Levine (very intuitive) - [video](https://www.youtube.com/watch?v=UXW2yZndl7U) * Udacity video on monte-carlo tree search (first part of a chain) - [video](https://www.youtube.com/watch?v=onBYsen2_eA) - * A Survey of Monte Carlo Tree Search Methods (2011-2012) [pdf](http://mcts.ai/pubs/mcts-survey-master.pdf) + * A Survey of Monte Carlo Tree Search Methods (2011-2012) [pdf](http://ccg.doc.gold.ac.uk/ccg_old/papers/browne_tciaig12_1.pdf) * Reminder: UCB-1 - [slides](https://www.cs.bham.ac.uk/internal/courses/robotics/lectures/ucb1.pdf) - * Guide to MCTS - [url](https://jeffbradberry.com/posts/2015/09/intro-to-monte-carlo-tree-search/) + * Guide to MCTS - [url](https://jeffbradberry.com/posts/2015/09/intro-to-monte-carlo-tree-search/) or [cached](https://webcache.googleusercontent.com/search?q=cache:jeffbradberry.com/posts/2015/09/intro-to-monte-carlo-tree-search/) ## Supplementary materials diff --git a/week10_planning/seminar_MCTS.ipynb b/week10_planning/seminar_MCTS.ipynb index 864b7d86e..0b11c0607 100644 --- a/week10_planning/seminar_MCTS.ipynb +++ b/week10_planning/seminar_MCTS.ipynb @@ -70,7 +70,8 @@ "source": [ "import sys, os\n", "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", - " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/spring20/setup_colab.sh -O- | bash\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + " !pip install -q gymnasium\n", "\n", " !touch .setup_complete\n", "\n", @@ -98,7 +99,7 @@ "source": [ "---\n", "\n", - "But before we do that, we first need to make a wrapper for Gym environments to allow saving and loading game states to facilitate backtracking." + "But before we do that, we first need to make a wrapper for Gymnasium environments to allow saving and loading game states to facilitate backtracking." ] }, { @@ -107,8 +108,7 @@ "metadata": {}, "outputs": [], "source": [ - "import gym\n", - "from gym.core import Wrapper\n", + "import gymnasium as gym\n", "from pickle import dumps, loads\n", "from collections import namedtuple\n", "\n", @@ -117,7 +117,7 @@ " \"action_result\", (\"snapshot\", \"observation\", \"reward\", \"is_done\", \"info\"))\n", "\n", "\n", - "class WithSnapshots(Wrapper):\n", + "class WithSnapshots(gym.Wrapper):\n", " \"\"\"\n", " Creates a wrapper that supports saving and loading environemnt states.\n", " Required for planning algorithms.\n", @@ -128,8 +128,8 @@ " - ...\n", "\n", " You can also use reset() and step() directly for convenience.\n", - " - s = self.reset() # same as self.env.reset()\n", - " - s, r, done, _ = self.step(action) # same as self.env.step(action)\n", + " - s, _ = self.reset() # same as self.env.reset()\n", + " - s, r, terminated, truncated, _ = self.step(action) # same as self.env.step(action)\n", " \n", " Note that while you may use self.render(), it will spawn a window that cannot be pickled.\n", " Thus, you will need to call self.close() before pickling will work again.\n", @@ -153,9 +153,10 @@ " self.render() # close popup windows since we can't pickle them\n", " self.close()\n", " \n", - " if self.unwrapped.viewer is not None:\n", - " self.unwrapped.viewer.close()\n", - " self.unwrapped.viewer = None\n", + " self.unwrapped.screen = None\n", + " self.unwrapped.clock = None\n", + " self.unwrapped.surf = None\n", + "\n", " return dumps(self.env)\n", "\n", " def load_snapshot(self, snapshot, render=False):\n", @@ -181,7 +182,8 @@ "\n", " :returns: next snapshot, next_observation, reward, is_done, info\n", "\n", - " Basically it returns next snapshot and everything that env.step would have returned.\n", + " Basically it returns next snapshot and almost everything that env.step would have returned.\n", + " Note that is_done = terminated or truncated\n", " \"\"\"\n", "\n", " \n", @@ -210,7 +212,9 @@ "outputs": [], "source": [ "# make env\n", - "env = WithSnapshots(gym.make(\"CartPole-v0\"))\n", + "env = WithSnapshots(gym.make(\"CartPole-v1\",\n", + " render_mode=\"rgb_array\",\n", + " max_episode_steps=200))\n", "env.reset()\n", "\n", "n_actions = env.action_space.n" @@ -223,7 +227,7 @@ "outputs": [], "source": [ "print(\"initial_state:\")\n", - "plt.imshow(env.render('rgb_array'))\n", + "plt.imshow(env.render())\n", "env.close()\n", "\n", "# create first snapshot\n", @@ -238,13 +242,16 @@ "source": [ "# play without making snapshots (faster)\n", "while True:\n", - " is_done = env.step(env.action_space.sample())[2]\n", - " if is_done:\n", + " _, _, terminated, truncated, _ = env.step(env.action_space.sample())\n", + " if terminated:\n", " print(\"Whoops! We died!\")\n", " break\n", + " if truncated:\n", + " print(\"Time is over!\")\n", + " break\n", "\n", "print(\"final state:\")\n", - "plt.imshow(env.render('rgb_array'))\n", + "plt.imshow(env.render())\n", "env.close()" ] }, @@ -258,7 +265,7 @@ "env.load_snapshot(snap0)\n", "\n", "print(\"\\n\\nAfter loading snapshot\")\n", - "plt.imshow(env.render('rgb_array'))\n", + "plt.imshow(env.render())\n", "env.close()" ] }, @@ -524,8 +531,8 @@ "metadata": {}, "outputs": [], "source": [ - "env = WithSnapshots(gym.make(\"CartPole-v0\"))\n", - "root_observation = env.reset()\n", + "env = WithSnapshots(gym.make(\"CartPole-v1\", render_mode=\"rgb_array\", max_episode_steps=200))\n", + "root_observation, _ = env.reset()\n", "root_snapshot = env.get_snapshot()\n", "root = Root(root_snapshot, root_observation)" ] @@ -559,7 +566,6 @@ "source": [ "from IPython.display import clear_output\n", "from itertools import count\n", - "from gym.wrappers import Monitor\n", "\n", "total_reward = 0 # sum of rewards\n", "test_env = loads(root_snapshot) # env used to show progress\n", @@ -570,16 +576,16 @@ " best_child = \n", "\n", " # take action\n", - " s, r, done, _ = test_env.step(best_child.action)\n", + " s, r, terminated, truncated, _ = test_env.step(best_child.action)\n", "\n", " # show image\n", " clear_output(True)\n", " plt.title(\"step %i\" % i)\n", - " plt.imshow(test_env.render('rgb_array'))\n", + " plt.imshow(test_env.render())\n", " plt.show()\n", "\n", " total_reward += r\n", - " if done:\n", + " if terminated or truncated:\n", " print(\"Finished with reward = \", total_reward)\n", " break\n", "\n", @@ -624,6 +630,11 @@ "\n", "\"Build this\" assignment\n", "\n", + "Don't forget to run:\n", + "``` \n", + "pip install gymnasium[atari,accept-rom-license]\n", + "``` \n", + "\n", "Apply MCTS to play Atari games. In particular, let's start with ```gym.make(\"MsPacman-ramDeterministic-v0\")```.\n", "\n", "This requires two things:\n", @@ -712,35 +723,9 @@ } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.6" - }, - "toc": { - "base_numbering": 1, - "nav_menu": {}, - "number_sections": true, - "sideBar": true, - "skip_h1_title": false, - "title_cell": "Table of Contents", - "title_sidebar": "Contents", - "toc_cell": false, - "toc_position": {}, - "toc_section_display": true, - "toc_window_display": false + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/youtube_dl_lectures.sh b/youtube_dl_lectures.sh index 313ead9ec..4d67e8538 100644 --- a/youtube_dl_lectures.sh +++ b/youtube_dl_lectures.sh @@ -25,7 +25,6 @@ youtube-dl 'https://www.youtube.com/watch?v=IL3gVyJMmhg' --output 'week03_model_ # week04_recap youtube-dl 'https://www.youtube.com/watch?v=uXt8qF2Zzfo' --output 'week04_[recap]_deep_learning/lect/Lecture_basics.mp4' youtube-dl 'https://www.youtube.com/watch?v=FmpDIaiMIeA' --output 'week04_[recap]_deep_learning/lect/Lecture_convnets.mp4' -youtube-dl 'https://www.youtube.com/watch?v=OU8I1oJ9HhI' --output 'week04_[recap]_deep_learning/lect/Tutorial_theano.mp4' # week04 youtube-dl 'https://www.youtube.com/watch?v=UoPei5o4fps' --output 'week04_approx_rl/lect/Lecture_Silver.mp4'