diff --git a/Practical Reinforcement Learning/Week2_model_based/QUIZ Optimality in RL.pdf b/Practical Reinforcement Learning/Week2_model_based/QUIZ Optimality in RL.pdf new file mode 100644 index 0000000..05f96de Binary files /dev/null and b/Practical Reinforcement Learning/Week2_model_based/QUIZ Optimality in RL.pdf differ diff --git a/Practical Reinforcement Learning/Week2_model_based/QUIZ Policy Iteration.pdf b/Practical Reinforcement Learning/Week2_model_based/QUIZ Policy Iteration.pdf new file mode 100644 index 0000000..cd57921 Binary files /dev/null and b/Practical Reinforcement Learning/Week2_model_based/QUIZ Policy Iteration.pdf differ diff --git a/Practical Reinforcement Learning/Week2_model_based/QUIZ Reward design.pdf b/Practical Reinforcement Learning/Week2_model_based/QUIZ Reward design.pdf new file mode 100644 index 0000000..b33a7c8 Binary files /dev/null and b/Practical Reinforcement Learning/Week2_model_based/QUIZ Reward design.pdf differ diff --git a/Practical Reinforcement Learning/Week2_model_based/mdp.py b/Practical Reinforcement Learning/Week2_model_based/mdp.py new file mode 100644 index 0000000..3302e38 --- /dev/null +++ b/Practical Reinforcement Learning/Week2_model_based/mdp.py @@ -0,0 +1,239 @@ +# most of this code was politely stolen from https://github.com/berkeleydeeprlcourse/homework/ +# all creadit goes to https://github.com/abhishekunique (if i got the author right) +import sys +import random +import numpy as np +def weighted_choice(v, p): + total = sum(p) + r = random.uniform(0, total) + upto = 0 + for c, w in zip(v,p): + if upto + w >= r: + return c + upto += w + assert False, "Shouldn't get here" + +class MDP: + def __init__(self, transition_probs, rewards, initial_state=None): + """ + Defines an MDP. Compatible with gym Env. + :param transition_probs: transition_probs[s][a][s_next] = P(s_next | s, a) + A dict[state -> dict] of dicts[action -> dict] of dicts[next_state -> prob] + For each state and action, probabilities of next states should sum to 1 + If a state has no actions available, it is considered terminal + :param rewards: rewards[s][a][s_next] = r(s,a,s') + A dict[state -> dict] of dicts[action -> dict] of dicts[next_state -> reward] + The reward for anything not mentioned here is zero. + :param get_initial_state: a state where agent starts or a callable() -> state + By default, picks initial state at random. + + States and actions can be anything you can use as dict keys, but we recommend that you use strings or integers + + Here's an example from MDP depicted on http://bit.ly/2jrNHNr + transition_probs = { + 's0':{ + 'a0': {'s0': 0.5, 's2': 0.5}, + 'a1': {'s2': 1} + }, + 's1':{ + 'a0': {'s0': 0.7, 's1': 0.1, 's2': 0.2}, + 'a1': {'s1': 0.95, 's2': 0.05} + }, + 's2':{ + 'a0': {'s0': 0.4, 's1': 0.6}, + 'a1': {'s0': 0.3, 's1': 0.3, 's2':0.4} + } + } + rewards = { + 's1': {'a0': {'s0': +5}}, + 's2': {'a1': {'s0': -1}} + } + """ + self._check_param_consistency(transition_probs, rewards) + self._transition_probs = transition_probs + self._rewards = rewards + self._initial_state = initial_state + self.n_states = len(transition_probs) + self.reset() + + def get_all_states(self): + """ return a tuple of all possiblestates """ + return tuple(self._transition_probs.keys()) + + def get_possible_actions(self, state): + """ return a tuple of possible actions in a given state """ + return tuple(self._transition_probs.get(state, {}).keys()) + + def is_terminal(self, state): + """ return True if state is terminal or False if it isn't """ + return len(self.get_possible_actions(state)) == 0 + + def get_next_states(self, state, action): + """ return a dictionary of {next_state1 : P(next_state1 | state, action), next_state2: ...} """ + assert action in self.get_possible_actions(state), "cannot do action %s from state %s" % (action, state) + return self._transition_probs[state][action] + + def get_transition_prob(self, state, action, next_state): + """ return P(next_state | state, action) """ + return self.get_next_states(state, action).get(next_state, 0.0) + + def get_reward(self, state, action, next_state): + """ return the reward you get for taking action in state and landing on next_state""" + assert action in self.get_possible_actions(state), "cannot do action %s from state %s" % (action, state) + return self._rewards.get(state, {}).get(action, {}).get(next_state, 0.0) + + def reset(self): + """ reset the game, return the initial state""" + if self._initial_state is None: + self._current_state = random.choice(tuple(self._transition_probs.keys())) + elif self._initial_state in self._transition_probs: + self._current_state = self._initial_state + elif callable(self._initial_state): + self._current_state = self._initial_state() + else: + raise ValueError("initial state %s should be either a state or a function() -> state" % self._initial_state) + return self._current_state + + def step(self, action): + """ take action, return next_state, reward, is_done, empty_info """ + possible_states, probs = zip(*self.get_next_states(self._current_state, action).items()) + next_state = weighted_choice(possible_states, p=probs) + reward = self.get_reward(self._current_state, action, next_state) + is_done = self.is_terminal(next_state) + self._current_state = next_state + return next_state, reward, is_done, {} + + def render(self): + print("Currently at %s" % self._current_state) + + def _check_param_consistency(self, transition_probs, rewards): + for state in transition_probs: + assert isinstance(transition_probs[state], dict), "transition_probs for %s should be a dictionary " \ + "but is instead %s" % ( + state, type(transition_probs[state])) + 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])) + 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()) + assert abs(sum_probs - 1) <= 1e-10, "next state probabilities for state %s action %s " \ + "add up to %f (should be 1)" % (state, action, sum_probs) + 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])) + 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])) + 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 + assert None not in rewards, "please do not use None as an action identifier. " + msg + +class FrozenLakeEnv(MDP): + """ + Winter is here. You and your friends were tossing around a frisbee at the park + when you made a wild throw that left the frisbee out in the middle of the lake. + The water is mostly frozen, but there are a few holes where the ice has melted. + If you step into one of those holes, you'll fall into the freezing water. + At this time, there's an international frisbee shortage, so it's absolutely imperative that + you navigate across the lake and retrieve the disc. + However, the ice is slippery, so you won't always move in the direction you intend. + The surface is described using a grid like the following + + SFFF + FHFH + FFFH + HFFG + + S : starting point, safe + F : frozen surface, safe + H : hole, fall to your doom + G : goal, where the frisbee is located + + The episode ends when you reach the goal or fall in a hole. + You receive a reward of 1 if you reach the goal, and zero otherwise. + + """ + + MAPS = { + "4x4": [ + "SFFF", + "FHFH", + "FFFH", + "HFFG" + ], + "8x8": [ + "SFFFFFFF", + "FFFFFFFF", + "FFFHFFFF", + "FFFFFHFF", + "FFFHFFFF", + "FHHFFFHF", + "FHFFHFHF", + "FFFHFFFG" + ], + } + + + def __init__(self, desc=None, map_name="4x4", slip_chance=0.2): + if desc is None and map_name is None: + raise ValueError('Must provide either desc or map_name') + elif desc is None: + desc = self.MAPS[map_name] + assert ''.join(desc).count('S') == 1, "this implementation supports having exactly one initial state" + assert all(c in "SFHG" for c in ''.join(desc)), "all cells must be either of S, F, H or G" + + self.desc = desc = np.asarray(list(map(list,desc)),dtype='str') + self.lastaction = None + + nrow, ncol = desc.shape + states = [(i, j) for i in range(nrow) for j in range(ncol)] + actions = ["left","down","right","up"] + + initial_state = states[np.array(desc == b'S').ravel().argmax()] + + def move(row, col, movement): + if movement== 'left': + col = max(col-1,0) + elif movement== 'down': + row = min(row+1,nrow-1) + elif movement== 'right': + col = min(col+1,ncol-1) + elif movement== 'up': + row = max(row-1,0) + else: + raise("invalid action") + return (row, col) + + transition_probs = {s : {} for s in states} + rewards = {s : {} for s in states} + for (row,col) in states: + if desc[row, col] in "GH": continue + for action_i in range(len(actions)): + action = actions[action_i] + transition_probs[(row, col)][action] = {} + rewards[(row, col)][action] = {} + for movement_i in [(action_i - 1) % len(actions), action_i, (action_i + 1) % len(actions)]: + movement = actions[movement_i] + newrow, newcol = move(row, col, movement) + prob = (1. - slip_chance) if movement == action else (slip_chance / 2.) + if prob == 0: continue + if (newrow, newcol) not in transition_probs[row,col][action]: + transition_probs[row,col][action][newrow, newcol] = prob + else: + transition_probs[row, col][action][newrow, newcol] += prob + if desc[newrow, newcol] == 'G': + rewards[row,col][action][newrow, newcol] = 1.0 + + MDP.__init__(self, transition_probs, rewards, initial_state) + + def render(self): + desc_copy = np.copy(self.desc) + desc_copy[self._current_state] = '*' + print('\n'.join(map(''.join,desc_copy)), end='\n\n') + + diff --git a/Practical Reinforcement Learning/Week2_model_based/practice_vi.ipynb b/Practical Reinforcement Learning/Week2_model_based/practice_vi.ipynb new file mode 100644 index 0000000..566c7b1 --- /dev/null +++ b/Practical Reinforcement Learning/Week2_model_based/practice_vi.ipynb @@ -0,0 +1,1225 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Markov decision process\n", + "\n", + "This week's methods are all built to solve __M__arkov __D__ecision __P__rocesses. In the broadest sense, an MDP is defined by how it changes states and how rewards are computed.\n", + "\n", + "State transition is defined by $P(s' |s,a)$ - how likely areare you to end at state $s'$ if you take action $a$ from state $s$. Now there's more than one way to define rewards, but we'll use $r(s,a,s')$ function for convenience." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For starters, let's define a simple MDP from this picture:\n", + "\n", + "_img by MistWiz (Own work) [Public domain], via Wikimedia Commons_" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "transition_probs = {\n", + " 's0':{\n", + " 'a0': {'s0': 0.5, 's2': 0.5},\n", + " 'a1': {'s2': 1}\n", + " },\n", + " 's1':{\n", + " 'a0': {'s0': 0.7, 's1': 0.1, 's2': 0.2},\n", + " 'a1': {'s1': 0.95, 's2': 0.05}\n", + " },\n", + " 's2':{\n", + " 'a0': {'s0': 0.4, 's1': 0.6},\n", + " 'a1': {'s0': 0.3, 's1': 0.3, 's2':0.4}\n", + " }\n", + "}\n", + "rewards = {\n", + " 's1': {'a0': {'s0': +5}},\n", + " 's2': {'a1': {'s0': -1}}\n", + "}\n", + "\n", + "from mdp import MDP\n", + "mdp = MDP(transition_probs, rewards, initial_state='s0')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now use MDP just as any other gym environment:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "initial state = s0\n", + "next_state = s2, reward = 0.0, done = False\n" + ] + } + ], + "source": [ + "print('initial state =', mdp.reset())\n", + "next_state, reward, done, info = mdp.step('a1')\n", + "print('next_state = %s, reward = %s, done = %s' % (next_state, reward, done))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "but it also has other methods that you'll need for Value Iteration" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mdp.get_all_states = ('s0', 's1', 's2')\n", + "mdp.get_possible_actions('s1') = ('a0', 'a1')\n", + "mdp.get_next_states('s1', 'a0') = {'s0': 0.7, 's1': 0.1, 's2': 0.2}\n", + "mdp.get_reward('s1', 'a0', 's0') = 5\n", + "mdp.get_transition_prob('s1', 'a0', 's0') = 0.7\n" + ] + } + ], + "source": [ + "print(\"mdp.get_all_states =\", mdp.get_all_states())\n", + "print(\"mdp.get_possible_actions('s1') = \", mdp.get_possible_actions('s1'))\n", + "print(\"mdp.get_next_states('s1', 'a0') = \", mdp.get_next_states('s1', 'a0'))\n", + "print(\"mdp.get_reward('s1', 'a0', 's0') = \", mdp.get_reward('s1', 'a0', 's0'))\n", + "print(\"mdp.get_transition_prob('s1', 'a0', 's0') = \", mdp.get_transition_prob('s1', 'a0', 's0'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Value Iteration\n", + "\n", + "Now let's build something to solve this MDP. The simplest algorithm so far is __V__alue __I__teration\n", + "\n", + "Here's the pseudo-code for VI:\n", + "\n", + "---\n", + "\n", + "`1.` Initialize $V^{(0)}(s)=0$, for all $s$\n", + "\n", + "`2.` For $i=0, 1, 2, \\dots$\n", + " \n", + "`3.` $ \\quad V_{(i+1)}(s) = \\max_a \\sum_{s'} P(s' | s,a) \\cdot [ r(s,a,s') + \\gamma V_{i}(s')]$, for all $s$\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's write a function to compute the state-action value function $Q^{\\pi}$, defined as follows\n", + "\n", + "$$Q_i(s, a) = \\sum_{s'} P(s' | s,a) \\cdot [ r(s,a,s') + \\gamma V_{i}(s')]$$\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def get_action_value(mdp, state_values, state, action, gamma):\n", + " \"\"\" Computes Q(s,a) as in formula above \"\"\"\n", + " Q = sum(p*(mdp.get_reward(state, action, next_state) + gamma*state_values[next_state]) \n", + " for next_state, p in mdp.get_next_states(state, action).items())\n", + " return Q" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "test_Vs = {s : i for i, s in enumerate(mdp.get_all_states())}\n", + "assert np.allclose(get_action_value(mdp, test_Vs, 's2', 'a1', 0.9), 0.69)\n", + "assert np.allclose(get_action_value(mdp, test_Vs, 's1', 'a0', 0.9), 3.95)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using $Q(s,a)$ we can now define the \"next\" V(s) for value iteration.\n", + " $$V_{(i+1)}(s) = \\max_a \\sum_{s'} P(s' | s,a) \\cdot [ r(s,a,s') + \\gamma V_{i}(s')] = \\max_a Q_i(s,a)$$" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def get_new_state_value(mdp, state_values, state, gamma):\n", + " \"\"\" Computes next V(s) as per formula above. Please do not change state_values in process. \"\"\"\n", + " if mdp.is_terminal(state): return 0\n", + " \n", + " return max(get_action_value(mdp, state_values, state, action, gamma) for action in mdp.get_possible_actions(state))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "test_Vs_vopy = dict(test_Vs)\n", + "assert np.allclose(get_new_state_value(mdp, test_Vs, 's0', 0.9), 1.8)\n", + "assert np.allclose(get_new_state_value(mdp, test_Vs, 's2', 0.9), 0.69)\n", + "assert test_Vs == test_Vs_vopy, \"please do not change state_values in get_new_state_value\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's combine everything we wrote into a working value iteration algo." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter 0 | diff: 3.50000 | V(s0) = 0.000 V(s1) = 0.000 V(s2) = 0.000\n", + "\n", + "iter 1 | diff: 1.89000 | V(s0) = 0.000 V(s1) = 3.500 V(s2) = 0.000\n", + "\n", + "iter 2 | diff: 1.70100 | V(s0) = 0.000 V(s1) = 3.815 V(s2) = 1.890\n", + "\n", + "iter 3 | diff: 1.13542 | V(s0) = 1.701 V(s1) = 4.184 V(s2) = 2.060\n", + "\n", + "iter 4 | diff: 0.73024 | V(s0) = 1.854 V(s1) = 5.319 V(s2) = 2.871\n", + "\n", + "iter 5 | diff: 0.61135 | V(s0) = 2.584 V(s1) = 5.664 V(s2) = 3.540\n", + "\n", + "iter 6 | diff: 0.54664 | V(s0) = 3.186 V(s1) = 6.275 V(s2) = 3.989\n", + "\n", + "iter 7 | diff: 0.49198 | V(s0) = 3.590 V(s1) = 6.790 V(s2) = 4.535\n", + "\n", + "iter 8 | diff: 0.42210 | V(s0) = 4.082 V(s1) = 7.189 V(s2) = 4.959\n", + "\n", + "iter 9 | diff: 0.36513 | V(s0) = 4.463 V(s1) = 7.611 V(s2) = 5.352\n", + "\n", + "iter 10 | diff: 0.32862 | V(s0) = 4.816 V(s1) = 7.960 V(s2) = 5.717\n", + "\n", + "iter 11 | diff: 0.29262 | V(s0) = 5.145 V(s1) = 8.280 V(s2) = 6.032\n", + "\n", + "iter 12 | diff: 0.26189 | V(s0) = 5.429 V(s1) = 8.572 V(s2) = 6.323\n", + "\n", + "iter 13 | diff: 0.23503 | V(s0) = 5.691 V(s1) = 8.830 V(s2) = 6.584\n", + "\n", + "iter 14 | diff: 0.21124 | V(s0) = 5.925 V(s1) = 9.065 V(s2) = 6.817\n", + "\n", + "iter 15 | diff: 0.19012 | V(s0) = 6.135 V(s1) = 9.276 V(s2) = 7.028\n", + "\n", + "iter 16 | diff: 0.17091 | V(s0) = 6.325 V(s1) = 9.465 V(s2) = 7.218\n", + "\n", + "iter 17 | diff: 0.15366 | V(s0) = 6.496 V(s1) = 9.636 V(s2) = 7.388\n", + "\n", + "iter 18 | diff: 0.13830 | V(s0) = 6.649 V(s1) = 9.790 V(s2) = 7.542\n", + "\n", + "iter 19 | diff: 0.12445 | V(s0) = 6.788 V(s1) = 9.928 V(s2) = 7.680\n", + "\n", + "iter 20 | diff: 0.11200 | V(s0) = 6.912 V(s1) = 10.052 V(s2) = 7.805\n", + "\n", + "iter 21 | diff: 0.10079 | V(s0) = 7.024 V(s1) = 10.164 V(s2) = 7.917\n", + "\n", + "iter 22 | diff: 0.09071 | V(s0) = 7.125 V(s1) = 10.265 V(s2) = 8.017\n", + "\n", + "iter 23 | diff: 0.08164 | V(s0) = 7.216 V(s1) = 10.356 V(s2) = 8.108\n", + "\n", + "iter 24 | diff: 0.07347 | V(s0) = 7.297 V(s1) = 10.437 V(s2) = 8.190\n", + "\n", + "iter 25 | diff: 0.06612 | V(s0) = 7.371 V(s1) = 10.511 V(s2) = 8.263\n", + "\n", + "iter 26 | diff: 0.05951 | V(s0) = 7.437 V(s1) = 10.577 V(s2) = 8.329\n", + "\n", + "iter 27 | diff: 0.05356 | V(s0) = 7.496 V(s1) = 10.636 V(s2) = 8.389\n", + "\n", + "iter 28 | diff: 0.04820 | V(s0) = 7.550 V(s1) = 10.690 V(s2) = 8.442\n", + "\n", + "iter 29 | diff: 0.04338 | V(s0) = 7.598 V(s1) = 10.738 V(s2) = 8.491\n", + "\n", + "iter 30 | diff: 0.03904 | V(s0) = 7.641 V(s1) = 10.782 V(s2) = 8.534\n", + "\n", + "iter 31 | diff: 0.03514 | V(s0) = 7.681 V(s1) = 10.821 V(s2) = 8.573\n", + "\n", + "iter 32 | diff: 0.03163 | V(s0) = 7.716 V(s1) = 10.856 V(s2) = 8.608\n", + "\n", + "iter 33 | diff: 0.02846 | V(s0) = 7.747 V(s1) = 10.887 V(s2) = 8.640\n", + "\n", + "iter 34 | diff: 0.02562 | V(s0) = 7.776 V(s1) = 10.916 V(s2) = 8.668\n", + "\n", + "iter 35 | diff: 0.02306 | V(s0) = 7.801 V(s1) = 10.941 V(s2) = 8.694\n", + "\n", + "iter 36 | diff: 0.02075 | V(s0) = 7.824 V(s1) = 10.964 V(s2) = 8.717\n", + "\n", + "iter 37 | diff: 0.01867 | V(s0) = 7.845 V(s1) = 10.985 V(s2) = 8.738\n", + "\n", + "iter 38 | diff: 0.01681 | V(s0) = 7.864 V(s1) = 11.004 V(s2) = 8.756\n", + "\n", + "iter 39 | diff: 0.01513 | V(s0) = 7.881 V(s1) = 11.021 V(s2) = 8.773\n", + "\n", + "iter 40 | diff: 0.01361 | V(s0) = 7.896 V(s1) = 11.036 V(s2) = 8.788\n", + "\n", + "iter 41 | diff: 0.01225 | V(s0) = 7.909 V(s1) = 11.049 V(s2) = 8.802\n", + "\n", + "iter 42 | diff: 0.01103 | V(s0) = 7.922 V(s1) = 11.062 V(s2) = 8.814\n", + "\n", + "iter 43 | diff: 0.00992 | V(s0) = 7.933 V(s1) = 11.073 V(s2) = 8.825\n", + "\n", + "iter 44 | diff: 0.00893 | V(s0) = 7.943 V(s1) = 11.083 V(s2) = 8.835\n", + "\n", + "iter 45 | diff: 0.00804 | V(s0) = 7.952 V(s1) = 11.092 V(s2) = 8.844\n", + "\n", + "iter 46 | diff: 0.00724 | V(s0) = 7.960 V(s1) = 11.100 V(s2) = 8.852\n", + "\n", + "iter 47 | diff: 0.00651 | V(s0) = 7.967 V(s1) = 11.107 V(s2) = 8.859\n", + "\n", + "iter 48 | diff: 0.00586 | V(s0) = 7.973 V(s1) = 11.113 V(s2) = 8.866\n", + "\n", + "iter 49 | diff: 0.00527 | V(s0) = 7.979 V(s1) = 11.119 V(s2) = 8.872\n", + "\n", + "iter 50 | diff: 0.00475 | V(s0) = 7.984 V(s1) = 11.125 V(s2) = 8.877\n", + "\n", + "iter 51 | diff: 0.00427 | V(s0) = 7.989 V(s1) = 11.129 V(s2) = 8.882\n", + "\n", + "iter 52 | diff: 0.00384 | V(s0) = 7.993 V(s1) = 11.134 V(s2) = 8.886\n", + "\n", + "iter 53 | diff: 0.00346 | V(s0) = 7.997 V(s1) = 11.137 V(s2) = 8.890\n", + "\n", + "iter 54 | diff: 0.00311 | V(s0) = 8.001 V(s1) = 11.141 V(s2) = 8.893\n", + "\n", + "iter 55 | diff: 0.00280 | V(s0) = 8.004 V(s1) = 11.144 V(s2) = 8.896\n", + "\n", + "iter 56 | diff: 0.00252 | V(s0) = 8.007 V(s1) = 11.147 V(s2) = 8.899\n", + "\n", + "iter 57 | diff: 0.00227 | V(s0) = 8.009 V(s1) = 11.149 V(s2) = 8.902\n", + "\n", + "iter 58 | diff: 0.00204 | V(s0) = 8.011 V(s1) = 11.152 V(s2) = 8.904\n", + "\n", + "iter 59 | diff: 0.00184 | V(s0) = 8.014 V(s1) = 11.154 V(s2) = 8.906\n", + "\n", + "iter 60 | diff: 0.00166 | V(s0) = 8.015 V(s1) = 11.155 V(s2) = 8.908\n", + "\n", + "iter 61 | diff: 0.00149 | V(s0) = 8.017 V(s1) = 11.157 V(s2) = 8.909\n", + "\n", + "iter 62 | diff: 0.00134 | V(s0) = 8.019 V(s1) = 11.159 V(s2) = 8.911\n", + "\n", + "iter 63 | diff: 0.00121 | V(s0) = 8.020 V(s1) = 11.160 V(s2) = 8.912\n", + "\n", + "iter 64 | diff: 0.00109 | V(s0) = 8.021 V(s1) = 11.161 V(s2) = 8.913\n", + "\n", + "iter 65 | diff: 0.00098 | V(s0) = 8.022 V(s1) = 11.162 V(s2) = 8.915\n", + "\n", + "Terminated\n" + ] + } + ], + "source": [ + "# parameters\n", + "gamma = 0.9 # discount for MDP\n", + "num_iter = 100 # maximum iterations, excluding initialization\n", + "min_difference = 0.001 # stop VI if new values are this close to old values (or closer)\n", + "\n", + "# initialize V(s)\n", + "state_values = {s : 0 for s in mdp.get_all_states()}\n", + "\n", + "\n", + "for i in range(num_iter):\n", + " \n", + " # Compute new state values using the functions you defined above. It must be a dict {state : new_V(state)}\n", + " new_state_values = {state: get_new_state_value(mdp, state_values, state, gamma) for state in mdp.get_all_states()}\n", + " assert isinstance(new_state_values, dict)\n", + " \n", + " # Compute difference\n", + " diff = max(abs(new_state_values[s] - state_values[s]) for s in mdp.get_all_states())\n", + " print(\"iter %4i | diff: %6.5f | \"%(i, diff), end=\"\")\n", + " print(' '.join(\"V(%s) = %.3f\"%(s, v) for s,v in state_values.items()), end='\\n\\n')\n", + " state_values = new_state_values\n", + " \n", + " if diff < min_difference:\n", + " print(\"Terminated\"); break" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Final state values: {'s0': 8.023123818663871, 's1': 11.163174814980803, 's2': 8.915559364985523}\n" + ] + } + ], + "source": [ + "print(\"Final state values:\", state_values)\n", + "\n", + "assert abs(state_values['s0'] - 8.032) < 0.01\n", + "assert abs(state_values['s1'] - 11.169) < 0.01\n", + "assert abs(state_values['s2'] - 8.921) < 0.01" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's use those $V^{*}(s)$ to find optimal actions in each state\n", + "\n", + " $$\\pi^*(s) = argmax_a \\sum_{s'} P(s' | s,a) \\cdot [ r(s,a,s') + \\gamma V_{i}(s')] = argmax_a Q_i(s,a)$$\n", + " \n", + "The only difference vs V(s) is that here we take not max but argmax: find action such with maximum Q(s,a)." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def get_optimal_action(mdp, state_values, state, gamma=0.9):\n", + " \"\"\" Finds optimal action using formula above. \"\"\"\n", + " if mdp.is_terminal(state): return None\n", + " \n", + " Q_values = {action: get_action_value(mdp, state_values, state, action, gamma) for action in mdp.get_possible_actions(state)}\n", + " \n", + " return max(Q_values, key=lambda action: Q_values[action])" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "assert get_optimal_action(mdp, state_values, 's0', gamma) == 'a1'\n", + "assert get_optimal_action(mdp, state_values, 's1', gamma) == 'a0'\n", + "assert get_optimal_action(mdp, state_values, 's2', gamma) == 'a0'" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "average reward: 0.9215\n" + ] + } + ], + "source": [ + "# Measure agent's average reward\n", + "\n", + "s = mdp.reset()\n", + "rewards = []\n", + "for _ in range(10000):\n", + " s, r, done, _ = mdp.step(get_optimal_action(mdp, state_values, s, gamma))\n", + " rewards.append(r)\n", + " \n", + "print(\"average reward: \", np.mean(rewards))\n", + "\n", + "assert(0.85 < np.mean(rewards) < 1.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Frozen lake" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "*FFF\n", + "FHFH\n", + "FFFH\n", + "HFFG\n", + "\n" + ] + } + ], + "source": [ + "from mdp import FrozenLakeEnv\n", + "mdp = FrozenLakeEnv(slip_chance=0)\n", + "\n", + "mdp.render()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((0, 0),\n", + " (0, 1),\n", + " (0, 2),\n", + " (0, 3),\n", + " (1, 0),\n", + " (1, 1),\n", + " (1, 2),\n", + " (1, 3),\n", + " (2, 0),\n", + " (2, 1),\n", + " (2, 2),\n", + " (2, 3),\n", + " (3, 0),\n", + " (3, 1),\n", + " (3, 2),\n", + " (3, 3))" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mdp.get_all_states()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('left', 'down', 'right', 'up')" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mdp.get_possible_actions((0, 0))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "def value_iteration(mdp, state_values=None, gamma = 0.9, num_iter = 1000, min_difference = 1e-5):\n", + " \"\"\" performs num_iter value iteration steps starting from state_values. Same as before but in a function \"\"\"\n", + " state_values = state_values or {s : 0 for s in mdp.get_all_states()}\n", + " for i in range(num_iter):\n", + "\n", + " # Compute new state values using the functions you defined above. It must be a dict {state : new_V(state)}\n", + " new_state_values = {state: get_new_state_value(mdp, state_values, state, gamma) for state in mdp.get_all_states()}\n", + " assert isinstance(new_state_values, dict)\n", + "\n", + " # Compute difference\n", + " diff = max(abs(new_state_values[s] - state_values[s]) for s in mdp.get_all_states())\n", + " print(\"iter %4i | diff: %6.5f | V(start): %.3f \"%(i, diff, new_state_values[mdp._initial_state]))\n", + " \n", + " state_values = new_state_values\n", + " if diff < min_difference:\n", + " print(\"Terminated\"); break\n", + " \n", + " return state_values" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter 0 | diff: 1.00000 | V(start): 0.000 \n", + "iter 1 | diff: 0.90000 | V(start): 0.000 \n", + "iter 2 | diff: 0.81000 | V(start): 0.000 \n", + "iter 3 | diff: 0.72900 | V(start): 0.000 \n", + "iter 4 | diff: 0.65610 | V(start): 0.000 \n", + "iter 5 | diff: 0.59049 | V(start): 0.590 \n", + "iter 6 | diff: 0.00000 | V(start): 0.590 \n", + "Terminated\n" + ] + } + ], + "source": [ + "state_values = value_iteration(mdp)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "*FFF\n", + "FHFH\n", + "FFFH\n", + "HFFG\n", + "\n", + "down\n", + "\n", + "SFFF\n", + "*HFH\n", + "FFFH\n", + "HFFG\n", + "\n", + "down\n", + "\n", + "SFFF\n", + "FHFH\n", + "*FFH\n", + "HFFG\n", + "\n", + "right\n", + "\n", + "SFFF\n", + "FHFH\n", + "F*FH\n", + "HFFG\n", + "\n", + "down\n", + "\n", + "SFFF\n", + "FHFH\n", + "FFFH\n", + "H*FG\n", + "\n", + "right\n", + "\n", + "SFFF\n", + "FHFH\n", + "FFFH\n", + "HF*G\n", + "\n", + "right\n", + "\n", + "SFFF\n", + "FHFH\n", + "FFFH\n", + "HFF*\n", + "\n" + ] + } + ], + "source": [ + "s = mdp.reset()\n", + "mdp.render()\n", + "for t in range(100):\n", + " a = get_optimal_action(mdp, state_values, s, gamma)\n", + " print(a, end='\\n\\n')\n", + " s, r, done, _ = mdp.step(a)\n", + " mdp.render()\n", + " if done: break\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Let's visualize!\n", + "\n", + "It's usually interesting to see what your algorithm actually learned under the hood. To do so, we'll plot state value functions and optimal actions at each VI step." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "def draw_policy(mdp, state_values):\n", + " plt.figure(figsize=(3,3))\n", + " h,w = mdp.desc.shape\n", + " states = sorted(mdp.get_all_states())\n", + " V = np.array([state_values[s] for s in states])\n", + " Pi = {s: get_optimal_action(mdp, state_values, s, gamma) for s in states}\n", + " plt.imshow(V.reshape(w,h), cmap='gray', interpolation='none', clim=(0,1))\n", + " ax = plt.gca()\n", + " ax.set_xticks(np.arange(h)-.5)\n", + " ax.set_yticks(np.arange(w)-.5)\n", + " ax.set_xticklabels([])\n", + " ax.set_yticklabels([])\n", + " Y, X = np.mgrid[0:4, 0:4]\n", + " a2uv = {'left': (-1, 0), 'down':(0, -1), 'right':(1,0), 'up':(-1, 0)}\n", + " for y in range(h):\n", + " for x in range(w):\n", + " plt.text(x, y, str(mdp.desc[y,x].item()),\n", + " color='g', size=12, verticalalignment='center',\n", + " horizontalalignment='center', fontweight='bold')\n", + " a = Pi[y, x]\n", + " if a is None: continue\n", + " u, v = a2uv[a]\n", + " plt.arrow(x, y,u*.3, -v*.3, color='m', head_width=0.1, head_length=0.1) \n", + " plt.grid(color='b', lw=2, ls='-')\n", + " plt.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 0\n", + "iter 0 | diff: 1.00000 | V(start): 0.000 \n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 1\n", + "iter 0 | diff: 0.90000 | V(start): 0.000 \n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 2\n", + "iter 0 | diff: 0.81000 | V(start): 0.000 \n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 3\n", + "iter 0 | diff: 0.72900 | V(start): 0.000 \n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 4\n", + "iter 0 | diff: 0.65610 | V(start): 0.000 \n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 5\n", + "iter 0 | diff: 0.59049 | V(start): 0.590 \n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 6\n", + "iter 0 | diff: 0.00000 | V(start): 0.590 \n", + "Terminated\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 7\n", + "iter 0 | diff: 0.00000 | V(start): 0.590 \n", + "Terminated\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAALgAAAC4CAYAAABQMybHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvDW2N/gAADcpJREFUeJzt3X1sXNWZx/HvuTPjGb+Mx46dKTgJOHVCXCgLwSSgBPJSIEpSRLMorRLYKEvT0rgKossu0M2+NMKrsm23K1R2FVGVsqtUxFLZbldCaZqlW9ouQqkCQWEhCRAn5JXYie343Z6Xu3/c2Mbx2OOxfe+5c/J8/vGc0R3N46ufj+/cufc8yrZthDCVpbsAIdwkARdGk4ALo0nAhdEk4MJoEnBhNAm4MJoEXBhNAi6MFsy2gVLqUeBRZ1RcB7UulyREdiUlR+ns7FTZtlO5fFWv1O32zp1fm1Jhbqmv3wrA7t2NmisZ28aNGwDYt++/NVcytlWr7gP8vR8Btm/fTlNTU9aAyyGKMJoEXBhNAi6MJgEXRpOAC6NJwIXRJODCaBJwYTQJuDCaBFwYTQIujCYBF0aTgAujScCF0bJeD+6GlmQLv+j6BR8NfESf3UeJVUJVsIoN0Q3MDM7UUdIIjx17jAvJC6Oef/b6Z6mOVHtfUAab3trE+f7zo57fectOaoprNFQ0kl/2oZaAv3DpBc4kz7CgYAHxQJz2VDsfJj7kUvoSM9Ef8EG3Fd9GvCA+NC4NlGqsJrM7yu+gKlI1NI4FYxqrGU33PvQ84N3pbs4kz1CoCnm87HGUcq5ZT9gJbPy1TuKK2AoWRRdNePvQkRDRn0XpWt/FwC0DkPVy/KlbHV/N0oql7r8REDwVpGR3CQO1A/Q80DOh1+S6D6eb5wGPqAhhFabX7uW7rd9lQcEC5oXm8bnw5wirsNfljOv1S6/zfu/7Q+PN8c3jbh88GSR0PETZc2WkKlN0/lmn60Hf27yXQx2Hhsb1c+un/T2Cp4KUvFxC+L0wJIAUEw54rvtwunke8IAKsKl0Ey+3vczp5GlOJ0/zG35DqVVKfVk91aFqr0sa09vdb0P38Pjpx5/O+hpb2Vj9FtYZixnfm0H71nb6lve5VuP+tv0jxtMdcKvFovKpSmxs1OW/1MihCNdsvGbc1wW+FYCy0fvQ+IAD1EXqeOCnD3A4fJjfbv0tb/S+QUe6gz1de/hm+Td1lJTRE/EnWHJxydD4YsPFcbeP/CFC0f8UkbbSoKB7bTf9i/pdrbGhsYE7t9yJfYs7h3fpijTtW9uJNkZRvQqr3yIxJ0HHox3jvy6VBuAp6ynqZtaRLku7Ul82ngc8Zac4njjO3NRcFh9bTGlJKSWqhFe6XqHfdjcMOQtCYl5iwptbrRaFvyuke203PV/swS7212eKSbGgb3kffXf1EfnfCNHGKIl5iaz7xT5mQxKS1yRJR/WEGzQEPGEn+GHbD/n5V37O/FPz6evo452+dwCoDef3khT9i/tprmuGgO5KXBAYDno+fXviecBDKsQ9Rfdw4sIJ9s/fT19vH+WBcpZHlrOqaJXX5Uw/E8P9aXn2+2n5kLk+up65/zGX8LkwR3Ye8bqErJ6veV53CVntqtsFQGhHiCRJzdWM5pd9mEf/bITInQRcGE0CLowmARdGk4ALo0nAhdE8D3iwLcjs52cTPudcWDX7+dlEjkW8LiPvWa9YBP7aOSkd+FEA658s0PeFoW95HvBAV4Diw8VD4+KjxYRaQ16XkffUewr1tnPxkzqlsPZLwDPxPOD9c/rpru3GVs51Gsloks66Tq/LyHupR1JweV6wIzapr6Y0XTrnb1qOwVv+tAU7aJMuSNP8YLN8EpiM68BeZDsTRRjs+wy4sMsFWqLVP6efnnk9pIpTMntPQeqRlPNTZu8xadstZ79+FpVSMntPxXWQ3JWECt2F+Je2gKcL5RPRtIhn3+RqJvOnMFrObQThgIvlCDFRCtu2p95GUCn1qFLqgFLqALRMT21CeCTnGXz37r9ysZzJG2yy6sliJJPm7OuDB9/RXMfYFi689fIjP+9Hx7TM4ELkMwm4MJoEXBhNAi6MJgEXRpOAC6NJwIXRJODCaBJwYTQJuDCaBFwYTQIujCYBF0bz/I4ev/RPHNO3gDKgERhc2bka+HOgD/hHLVWNsnbfWs71nhv1fOOKRhbEFmio6Ao+2Y/ablnT3T/RFMs+s4zZxbOHxuUF5Rqr8R9tAdfdP9EU665fx8prV+ouw7e0BVx3/8SsFuL8SwXw8T+XX378Sw5cGL6N8Mmbn9RYTQaa96O2gOvun5iVDw5jJ+L3538/Yuy7gGvej9oCvv2j7Sx7exltf9emq4TxZfpw5EMNjQ2s+Yc1BGp82h1K837UdpowdDxE+H1/te7OV+k2WWNmLHIeXBhNAi6M5vkx+GD/xIqf+HRBvecyPHcC2OFtGdnsWbUHgPYd7ZorGYNP9qPM4MJoEnBhNAm4MJoEXBhNAi6MJgEXRpOAC6N53wj2eJD41+KETjs98OJb4kTekEawuer+djfty5xz4N3f6KZjXQd2QjqtXcnzgKdjaVT/8LLOKqFIVaS8LiPvWXHLuTMGnAawIaTTWgbeB3xGmt7lvdhBGxubxPUJErUJr8vIe+FHwjB4AWEhFD5RiFL+X7Tea1qOwbse7HIaCBRA58PSJ3MyrHKL8JfDYIE1yyJ4p0zfmWgJeHpGmp57ehiYPyCz9xSEHwmjyhWFfymz91i0/dl3bpaZe6qscovYazHdZfianCYURpOAC6NJI1iRp6QRrBC5z+D79j3rYjmTt2rVfUB+NFk9e3b0kmt+UVV17eVH/j8rI41gxVVPAi6MJgEXRpOAC6NJwIXRJODCaBJwYTQJuDCaBFwYTQIujCYBF0aTgAujScCF0Ty/ZW3TW5s4339+1PM7b9lJTXGN1+Vk5Psmq8Dilxdzuuv0qOf3PbiPz1d+XkNFV7jaG8HeUX4HVZGqoXEs6L97C/Ohyeq9191LdWn10Lii0KeNBTTRFvDV8dUsrVg68RfYwIdADcPrgbgsH5qsbqzdyJrqNbrL8C1tAd/bvJdDHYeGxvVz68d/wQkIbQthV9iktqSwV9quB933TVaB3Ud28+bZN4fGzyx5RmM1GVytjWD3t+0fMd72k23jbq+aFbayURcVgR8F4EVIPZHCXuTeeny+b7IKvHbytRFj3wX8am0E+53K77Bi24rJvXgASIA6rFwNeENjA1+46QsU/W2Ra+8xVQ2NDTz0g4corCvUXUpmmhvB6lvvqwIS+3JY1eoYBLcFIQB2nXOYwnXulTco/Yn/m6za/bKq7FjyZ0G7KkhvSJNemfYk2MIM+RPwQkhv9v9sKvzF84Dvqtvl9VvmbEST1RzOZHrpjw/9EYCjO45qrmQM0ghWCPdJwIXRJODCaBJwYTQJuDCaBFwYTQKegd1vkzrrtDa0223S5/x3/j3VkSJxyvkmOHEuQbIlqbkif5KAZ9D3Uh+dDzg9hFLvpehY20HyiL8CdGbzGZrubgLgk7/4hKY7m7AH5Cv7K0nAMwitDI34CkyVKwI1Hl2EPkHRL0VRwcvLY6eh6K4iVIH/1/T2mgQ8g+CCIMGFQWfvFELksQgq5K/wxDbGUGGnJlWgmLl9puaK/EkCPobI4xGwQEUUBfcX6C5nFCtsUflkJVhQdHcR4QVh3SX5Uv5cbOWxYG2Qgi8XELwt6LvZe1BsY4yeP/RQ+XSl7lJ8SwI+jqKn/HujAziz+KwXZ+kuw9fkEEUYTQIujCaNYEWekkawQkxmBn/LxXKmwvk98qHJag673HNqaE7055mjT5NGsOKqJwEXRpOAC6NJwIXRJODCaBJwYTQJuDCaBFwYTQIujCYBF0aTgAujScCF0STgwmje3rLmk+ag2fi+ySpQ/Vw1H1/6eNTzB79xkFuvuVVDRRnMAu4C5gCFQA/QjHNLwWFvSpB7MseRD01W77/hfmrKhztEzyzyyfIRNwLrcY4RWoAPgDBO6G9GAu4HuTZZTZxL0PlqJ7ENMQJRbxYK2rJwC+tq1014+0tvXqL3WC/xDXGsoEtHqCHgfpxwvwv8JzC4+p0CPFwEQE/ANTcHnahcm6x2/bqLlmdauPD9C8yon0H518tdD/qLB1/k9ROvD42fW52pd8iwk8+epPVXrTQ93cRnv/dZd4I+BxhckOB3DIcbnPtSPLwxTE/ANTcHnagrm6w+vP7h7C8KgN1t0/ovrbT+ayuz/n0WxXcVu1QhvPrBqyPG69ZMbDYfODvAB1s/oOnbTdz+1u0UfGYaFzf69K/bfvnnvTjH44N2TN/bjUdPwDU3B52oF256gZsbbh7uQ5nlD3Pg6IDzbzkFBCAYDxKY4e4M/tKcl7jxn28cfuKm8bfvea/HeaBw1jSsdWFNw+5PPS4FWoGTwCHgT6b3rbKRY/BxBGcFqd5bPeHt2/6tjea/aSY0N0T87+MUrypGKXfvbSxbUsbiry6e8PbvfuldLr56kbKVZdR8v4bobdHpL+oUzhmTIuBu4L9wPmR2IAHPZ7GvxAjPD1O4pND1YE/WDTtvYGDHANGFLgR7UALYAzyI83nrWuA0EHPvLcciAZ9GVpFF0VJ/L/cWrgoTrvJgoc7/w5mxl+J86FyIc+jyEfC++28/SJaN8JAsGzG9ZNkIcdWTgAujScCF0STgwmgScGE0CbgwmgRcGE0CLowmARdGk4ALo0nAhdEk4MJoEnBhNAm4MJoEXBgtx+vBVSdw1L1ypqwSuKC7iCykxulxvW3bWReByfWOnqO2bd8+yYJcp5Q64Of6QGr0mhyiCKNJwIXRcg34j12pYvr4vT6QGj2V04dMIfKNHKIIo0nAhdEk4MJoEnBhNAm4MNr/A0vg0SO2dsmQAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 8\n", + "iter 0 | diff: 0.00000 | V(start): 0.590 \n", + "Terminated\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAALgAAAC4CAYAAABQMybHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvDW2N/gAADcpJREFUeJzt3X1sXNWZx/HvuTPjGb+Mx46dKTgJOHVCXCgLwSSgBPJSIEpSRLMorRLYKEvT0rgKossu0M2+NMKrsm23K1R2FVGVsqtUxFLZbldCaZqlW9ouQqkCQWEhCRAn5JXYie343Z6Xu3/c2Mbx2OOxfe+5c/J8/vGc0R3N46ufj+/cufc8yrZthDCVpbsAIdwkARdGk4ALo0nAhdEk4MJoEnBhNAm4MJoEXBhNAi6MFsy2gVLqUeBRZ1RcB7UulyREdiUlR+ns7FTZtlO5fFWv1O32zp1fm1Jhbqmv3wrA7t2NmisZ28aNGwDYt++/NVcytlWr7gP8vR8Btm/fTlNTU9aAyyGKMJoEXBhNAi6MJgEXRpOAC6NJwIXRJODCaBJwYTQJuDCaBFwYTQIujCYBF0aTgAujScCF0bJeD+6GlmQLv+j6BR8NfESf3UeJVUJVsIoN0Q3MDM7UUdIIjx17jAvJC6Oef/b6Z6mOVHtfUAab3trE+f7zo57fectOaoprNFQ0kl/2oZaAv3DpBc4kz7CgYAHxQJz2VDsfJj7kUvoSM9Ef8EG3Fd9GvCA+NC4NlGqsJrM7yu+gKlI1NI4FYxqrGU33PvQ84N3pbs4kz1CoCnm87HGUcq5ZT9gJbPy1TuKK2AoWRRdNePvQkRDRn0XpWt/FwC0DkPVy/KlbHV/N0oql7r8REDwVpGR3CQO1A/Q80DOh1+S6D6eb5wGPqAhhFabX7uW7rd9lQcEC5oXm8bnw5wirsNfljOv1S6/zfu/7Q+PN8c3jbh88GSR0PETZc2WkKlN0/lmn60Hf27yXQx2Hhsb1c+un/T2Cp4KUvFxC+L0wJIAUEw54rvtwunke8IAKsKl0Ey+3vczp5GlOJ0/zG35DqVVKfVk91aFqr0sa09vdb0P38Pjpx5/O+hpb2Vj9FtYZixnfm0H71nb6lve5VuP+tv0jxtMdcKvFovKpSmxs1OW/1MihCNdsvGbc1wW+FYCy0fvQ+IAD1EXqeOCnD3A4fJjfbv0tb/S+QUe6gz1de/hm+Td1lJTRE/EnWHJxydD4YsPFcbeP/CFC0f8UkbbSoKB7bTf9i/pdrbGhsYE7t9yJfYs7h3fpijTtW9uJNkZRvQqr3yIxJ0HHox3jvy6VBuAp6ynqZtaRLku7Ul82ngc8Zac4njjO3NRcFh9bTGlJKSWqhFe6XqHfdjcMOQtCYl5iwptbrRaFvyuke203PV/swS7212eKSbGgb3kffXf1EfnfCNHGKIl5iaz7xT5mQxKS1yRJR/WEGzQEPGEn+GHbD/n5V37O/FPz6evo452+dwCoDef3khT9i/tprmuGgO5KXBAYDno+fXviecBDKsQ9Rfdw4sIJ9s/fT19vH+WBcpZHlrOqaJXX5Uw/E8P9aXn2+2n5kLk+up65/zGX8LkwR3Ye8bqErJ6veV53CVntqtsFQGhHiCRJzdWM5pd9mEf/bITInQRcGE0CLowmARdGk4ALo0nAhdE8D3iwLcjs52cTPudcWDX7+dlEjkW8LiPvWa9YBP7aOSkd+FEA658s0PeFoW95HvBAV4Diw8VD4+KjxYRaQ16XkffUewr1tnPxkzqlsPZLwDPxPOD9c/rpru3GVs51Gsloks66Tq/LyHupR1JweV6wIzapr6Y0XTrnb1qOwVv+tAU7aJMuSNP8YLN8EpiM68BeZDsTRRjs+wy4sMsFWqLVP6efnnk9pIpTMntPQeqRlPNTZu8xadstZ79+FpVSMntPxXWQ3JWECt2F+Je2gKcL5RPRtIhn3+RqJvOnMFrObQThgIvlCDFRCtu2p95GUCn1qFLqgFLqALRMT21CeCTnGXz37r9ysZzJG2yy6sliJJPm7OuDB9/RXMfYFi689fIjP+9Hx7TM4ELkMwm4MJoEXBhNAi6MJgEXRpOAC6NJwIXRJODCaBJwYTQJuDCaBFwYTQIujCYBF0bz/I4ev/RPHNO3gDKgERhc2bka+HOgD/hHLVWNsnbfWs71nhv1fOOKRhbEFmio6Ao+2Y/ablnT3T/RFMs+s4zZxbOHxuUF5Rqr8R9tAdfdP9EU665fx8prV+ouw7e0BVx3/8SsFuL8SwXw8T+XX378Sw5cGL6N8Mmbn9RYTQaa96O2gOvun5iVDw5jJ+L3538/Yuy7gGvej9oCvv2j7Sx7exltf9emq4TxZfpw5EMNjQ2s+Yc1BGp82h1K837UdpowdDxE+H1/te7OV+k2WWNmLHIeXBhNAi6M5vkx+GD/xIqf+HRBvecyPHcC2OFtGdnsWbUHgPYd7ZorGYNP9qPM4MJoEnBhNAm4MJoEXBhNAi6MJgEXRpOAC6N53wj2eJD41+KETjs98OJb4kTekEawuer+djfty5xz4N3f6KZjXQd2QjqtXcnzgKdjaVT/8LLOKqFIVaS8LiPvWXHLuTMGnAawIaTTWgbeB3xGmt7lvdhBGxubxPUJErUJr8vIe+FHwjB4AWEhFD5RiFL+X7Tea1qOwbse7HIaCBRA58PSJ3MyrHKL8JfDYIE1yyJ4p0zfmWgJeHpGmp57ehiYPyCz9xSEHwmjyhWFfymz91i0/dl3bpaZe6qscovYazHdZfianCYURpOAC6NJI1iRp6QRrBC5z+D79j3rYjmTt2rVfUB+NFk9e3b0kmt+UVV17eVH/j8rI41gxVVPAi6MJgEXRpOAC6NJwIXRJODCaBJwYTQJuDCaBFwYTQIujCYBF0aTgAujScCF0Ty/ZW3TW5s4339+1PM7b9lJTXGN1+Vk5Psmq8Dilxdzuuv0qOf3PbiPz1d+XkNFV7jaG8HeUX4HVZGqoXEs6L97C/Ohyeq9191LdWn10Lii0KeNBTTRFvDV8dUsrVg68RfYwIdADcPrgbgsH5qsbqzdyJrqNbrL8C1tAd/bvJdDHYeGxvVz68d/wQkIbQthV9iktqSwV9quB933TVaB3Ud28+bZN4fGzyx5RmM1GVytjWD3t+0fMd72k23jbq+aFbayURcVgR8F4EVIPZHCXuTeeny+b7IKvHbytRFj3wX8am0E+53K77Bi24rJvXgASIA6rFwNeENjA1+46QsU/W2Ra+8xVQ2NDTz0g4corCvUXUpmmhvB6lvvqwIS+3JY1eoYBLcFIQB2nXOYwnXulTco/Yn/m6za/bKq7FjyZ0G7KkhvSJNemfYk2MIM+RPwQkhv9v9sKvzF84Dvqtvl9VvmbEST1RzOZHrpjw/9EYCjO45qrmQM0ghWCPdJwIXRJODCaBJwYTQJuDCaBFwYTQKegd1vkzrrtDa0223S5/x3/j3VkSJxyvkmOHEuQbIlqbkif5KAZ9D3Uh+dDzg9hFLvpehY20HyiL8CdGbzGZrubgLgk7/4hKY7m7AH5Cv7K0nAMwitDI34CkyVKwI1Hl2EPkHRL0VRwcvLY6eh6K4iVIH/1/T2mgQ8g+CCIMGFQWfvFELksQgq5K/wxDbGUGGnJlWgmLl9puaK/EkCPobI4xGwQEUUBfcX6C5nFCtsUflkJVhQdHcR4QVh3SX5Uv5cbOWxYG2Qgi8XELwt6LvZe1BsY4yeP/RQ+XSl7lJ8SwI+jqKn/HujAziz+KwXZ+kuw9fkEEUYTQIujCaNYEWekkawQkxmBn/LxXKmwvk98qHJag673HNqaE7055mjT5NGsOKqJwEXRpOAC6NJwIXRJODCaBJwYTQJuDCaBFwYTQIujCYBF0aTgAujScCF0STgwmje3rLmk+ag2fi+ySpQ/Vw1H1/6eNTzB79xkFuvuVVDRRnMAu4C5gCFQA/QjHNLwWFvSpB7MseRD01W77/hfmrKhztEzyzyyfIRNwLrcY4RWoAPgDBO6G9GAu4HuTZZTZxL0PlqJ7ENMQJRbxYK2rJwC+tq1014+0tvXqL3WC/xDXGsoEtHqCHgfpxwvwv8JzC4+p0CPFwEQE/ANTcHnahcm6x2/bqLlmdauPD9C8yon0H518tdD/qLB1/k9ROvD42fW52pd8iwk8+epPVXrTQ93cRnv/dZd4I+BxhckOB3DIcbnPtSPLwxTE/ANTcHnagrm6w+vP7h7C8KgN1t0/ovrbT+ayuz/n0WxXcVu1QhvPrBqyPG69ZMbDYfODvAB1s/oOnbTdz+1u0UfGYaFzf69K/bfvnnvTjH44N2TN/bjUdPwDU3B52oF256gZsbbh7uQ5nlD3Pg6IDzbzkFBCAYDxKY4e4M/tKcl7jxn28cfuKm8bfvea/HeaBw1jSsdWFNw+5PPS4FWoGTwCHgT6b3rbKRY/BxBGcFqd5bPeHt2/6tjea/aSY0N0T87+MUrypGKXfvbSxbUsbiry6e8PbvfuldLr56kbKVZdR8v4bobdHpL+oUzhmTIuBu4L9wPmR2IAHPZ7GvxAjPD1O4pND1YE/WDTtvYGDHANGFLgR7UALYAzyI83nrWuA0EHPvLcciAZ9GVpFF0VJ/L/cWrgoTrvJgoc7/w5mxl+J86FyIc+jyEfC++28/SJaN8JAsGzG9ZNkIcdWTgAujScCF0STgwmgScGE0CbgwmgRcGE0CLowmARdGk4ALo0nAhdEk4MJoEnBhNAm4MJoEXBgtx+vBVSdw1L1ypqwSuKC7iCykxulxvW3bWReByfWOnqO2bd8+yYJcp5Q64Of6QGr0mhyiCKNJwIXRcg34j12pYvr4vT6QGj2V04dMIfKNHKIIo0nAhdEk4MJoEnBhNAm4MNr/A0vg0SO2dsmQAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 9\n", + "iter 0 | diff: 0.00000 | V(start): 0.590 \n", + "Terminated\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "state_values = {s : 0 for s in mdp.get_all_states()}\n", + "\n", + "for i in range(10):\n", + " print(\"after iteration %i\"%i)\n", + " state_values = value_iteration(mdp, state_values, num_iter=1)\n", + " draw_policy(mdp, state_values)\n", + "# please ignore iter 0 at each step" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "after iteration 29\n", + "iter 0 | diff: 0.00000 | V(start): 0.198 \n", + "Terminated\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import clear_output\n", + "from time import sleep\n", + "mdp = FrozenLakeEnv(map_name='8x8',slip_chance=0.1)\n", + "state_values = {s : 0 for s in mdp.get_all_states()}\n", + "\n", + "for i in range(30):\n", + " clear_output(True)\n", + " print(\"after iteration %i\"%i)\n", + " state_values = value_iteration(mdp, state_values, num_iter=1)\n", + " draw_policy(mdp, state_values)\n", + " sleep(0.5)\n", + "# please ignore iter 0 at each step" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Massive tests" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter 0 | diff: 1.00000 | V(start): 0.000 \n", + "iter 1 | diff: 0.90000 | V(start): 0.000 \n", + "iter 2 | diff: 0.81000 | V(start): 0.000 \n", + "iter 3 | diff: 0.72900 | V(start): 0.000 \n", + "iter 4 | diff: 0.65610 | V(start): 0.000 \n", + "iter 5 | diff: 0.59049 | V(start): 0.590 \n", + "iter 6 | diff: 0.00000 | V(start): 0.590 \n", + "Terminated\n", + "average reward: 1.0\n", + "Well done!\n" + ] + } + ], + "source": [ + "mdp = FrozenLakeEnv(slip_chance=0)\n", + "state_values = value_iteration(mdp)\n", + "\n", + "total_rewards = []\n", + "for game_i in range(1000):\n", + " s = mdp.reset()\n", + " rewards = []\n", + " for t in range(100):\n", + " s, r, done, _ = mdp.step(get_optimal_action(mdp, state_values, s, gamma))\n", + " rewards.append(r)\n", + " if done: break\n", + " total_rewards.append(np.sum(rewards))\n", + " \n", + "print(\"average reward: \", np.mean(total_rewards))\n", + "assert(1.0 <= np.mean(total_rewards) <= 1.0)\n", + "print(\"Well done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter 0 | diff: 0.90000 | V(start): 0.000 \n", + "iter 1 | diff: 0.72900 | V(start): 0.000 \n", + "iter 2 | diff: 0.62330 | V(start): 0.000 \n", + "iter 3 | diff: 0.50487 | V(start): 0.000 \n", + "iter 4 | diff: 0.40894 | V(start): 0.000 \n", + "iter 5 | diff: 0.34868 | V(start): 0.349 \n", + "iter 6 | diff: 0.06529 | V(start): 0.410 \n", + "iter 7 | diff: 0.05832 | V(start): 0.468 \n", + "iter 8 | diff: 0.01139 | V(start): 0.480 \n", + "iter 9 | diff: 0.00764 | V(start): 0.487 \n", + "iter 10 | diff: 0.00164 | V(start): 0.489 \n", + "iter 11 | diff: 0.00094 | V(start): 0.490 \n", + "iter 12 | diff: 0.00022 | V(start): 0.490 \n", + "iter 13 | diff: 0.00011 | V(start): 0.490 \n", + "iter 14 | diff: 0.00003 | V(start): 0.490 \n", + "iter 15 | diff: 0.00001 | V(start): 0.490 \n", + "iter 16 | diff: 0.00000 | V(start): 0.490 \n", + "Terminated\n", + "average reward: 0.891\n", + "Well done!\n" + ] + } + ], + "source": [ + "# Measure agent's average reward\n", + "mdp = FrozenLakeEnv(slip_chance=0.1)\n", + "state_values = value_iteration(mdp)\n", + "\n", + "total_rewards = []\n", + "for game_i in range(1000):\n", + " s = mdp.reset()\n", + " rewards = []\n", + " for t in range(100):\n", + " s, r, done, _ = mdp.step(get_optimal_action(mdp, state_values, s, gamma))\n", + " rewards.append(r)\n", + " if done: break\n", + " total_rewards.append(np.sum(rewards))\n", + " \n", + "print(\"average reward: \", np.mean(total_rewards))\n", + "assert(0.8 <= np.mean(total_rewards) <= 0.95)\n", + "print(\"Well done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter 0 | diff: 0.75000 | V(start): 0.000 \n", + "iter 1 | diff: 0.50625 | V(start): 0.000 \n", + "iter 2 | diff: 0.39867 | V(start): 0.000 \n", + "iter 3 | diff: 0.26910 | V(start): 0.000 \n", + "iter 4 | diff: 0.18164 | V(start): 0.000 \n", + "iter 5 | diff: 0.14013 | V(start): 0.140 \n", + "iter 6 | diff: 0.07028 | V(start): 0.199 \n", + "iter 7 | diff: 0.06030 | V(start): 0.260 \n", + "iter 8 | diff: 0.02594 | V(start): 0.285 \n", + "iter 9 | diff: 0.01918 | V(start): 0.305 \n", + "iter 10 | diff: 0.00858 | V(start): 0.313 \n", + "iter 11 | diff: 0.00560 | V(start): 0.319 \n", + "iter 12 | diff: 0.00260 | V(start): 0.321 \n", + "iter 13 | diff: 0.00159 | V(start): 0.323 \n", + "iter 14 | diff: 0.00076 | V(start): 0.324 \n", + "iter 15 | diff: 0.00045 | V(start): 0.324 \n", + "iter 16 | diff: 0.00022 | V(start): 0.324 \n", + "iter 17 | diff: 0.00012 | V(start): 0.325 \n", + "iter 18 | diff: 0.00006 | V(start): 0.325 \n", + "iter 19 | diff: 0.00003 | V(start): 0.325 \n", + "iter 20 | diff: 0.00002 | V(start): 0.325 \n", + "iter 21 | diff: 0.00001 | V(start): 0.325 \n", + "Terminated\n", + "average reward: 0.655\n", + "Well done!\n" + ] + } + ], + "source": [ + "# Measure agent's average reward\n", + "mdp = FrozenLakeEnv(slip_chance=0.25)\n", + "state_values = value_iteration(mdp)\n", + "\n", + "total_rewards = []\n", + "for game_i in range(1000):\n", + " s = mdp.reset()\n", + " rewards = []\n", + " for t in range(100):\n", + " s, r, done, _ = mdp.step(get_optimal_action(mdp, state_values, s, gamma))\n", + " rewards.append(r)\n", + " if done: break\n", + " total_rewards.append(np.sum(rewards))\n", + " \n", + "print(\"average reward: \", np.mean(total_rewards))\n", + "assert(0.6 <= np.mean(total_rewards) <= 0.7)\n", + "print(\"Well done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter 0 | diff: 0.80000 | V(start): 0.000 \n", + "iter 1 | diff: 0.57600 | V(start): 0.000 \n", + "iter 2 | diff: 0.41472 | V(start): 0.000 \n", + "iter 3 | diff: 0.29860 | V(start): 0.000 \n", + "iter 4 | diff: 0.24186 | V(start): 0.000 \n", + "iter 5 | diff: 0.19349 | V(start): 0.000 \n", + "iter 6 | diff: 0.15325 | V(start): 0.000 \n", + "iter 7 | diff: 0.12288 | V(start): 0.000 \n", + "iter 8 | diff: 0.09930 | V(start): 0.000 \n", + "iter 9 | diff: 0.08037 | V(start): 0.000 \n", + "iter 10 | diff: 0.06426 | V(start): 0.000 \n", + "iter 11 | diff: 0.05129 | V(start): 0.000 \n", + "iter 12 | diff: 0.04330 | V(start): 0.000 \n", + "iter 13 | diff: 0.03802 | V(start): 0.033 \n", + "iter 14 | diff: 0.03332 | V(start): 0.058 \n", + "iter 15 | diff: 0.02910 | V(start): 0.087 \n", + "iter 16 | diff: 0.01855 | V(start): 0.106 \n", + "iter 17 | diff: 0.01403 | V(start): 0.120 \n", + "iter 18 | diff: 0.00810 | V(start): 0.128 \n", + "iter 19 | diff: 0.00555 | V(start): 0.133 \n", + "iter 20 | diff: 0.00321 | V(start): 0.137 \n", + "iter 21 | diff: 0.00247 | V(start): 0.138 \n", + "iter 22 | diff: 0.00147 | V(start): 0.139 \n", + "iter 23 | diff: 0.00104 | V(start): 0.140 \n", + "iter 24 | diff: 0.00058 | V(start): 0.140 \n", + "iter 25 | diff: 0.00036 | V(start): 0.141 \n", + "iter 26 | diff: 0.00024 | V(start): 0.141 \n", + "iter 27 | diff: 0.00018 | V(start): 0.141 \n", + "iter 28 | diff: 0.00012 | V(start): 0.141 \n", + "iter 29 | diff: 0.00007 | V(start): 0.141 \n", + "iter 30 | diff: 0.00004 | V(start): 0.141 \n", + "iter 31 | diff: 0.00003 | V(start): 0.141 \n", + "iter 32 | diff: 0.00001 | V(start): 0.141 \n", + "iter 33 | diff: 0.00001 | V(start): 0.141 \n", + "Terminated\n", + "average reward: 0.758\n", + "Well done!\n" + ] + } + ], + "source": [ + "# Measure agent's average reward\n", + "mdp = FrozenLakeEnv(slip_chance=0.2, map_name='8x8')\n", + "state_values = value_iteration(mdp)\n", + "\n", + "total_rewards = []\n", + "for game_i in range(1000):\n", + " s = mdp.reset()\n", + " rewards = []\n", + " for t in range(100):\n", + " s, r, done, _ = mdp.step(get_optimal_action(mdp, state_values, s, gamma))\n", + " rewards.append(r)\n", + " if done: break\n", + " total_rewards.append(np.sum(rewards))\n", + " \n", + "print(\"average reward: \", np.mean(total_rewards))\n", + "assert(0.6 <= np.mean(total_rewards) <= 0.8)\n", + "print(\"Well done!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Submit to coursera" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "from submit import submit_assigment\n", + "submit_assigment(\n", + " get_action_value, \n", + " get_new_state_value, \n", + " get_optimal_action, \n", + " value_iteration, \n", + " 'jiadaizhao@gmail.com', \n", + " '03wHO9B5hDF0OZZp')" + ] + } + ], + "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.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Practical Reinforcement Learning/Week2_model_based/submit.py b/Practical Reinforcement Learning/Week2_model_based/submit.py new file mode 100644 index 0000000..b0ad092 --- /dev/null +++ b/Practical Reinforcement Learning/Week2_model_based/submit.py @@ -0,0 +1,121 @@ +import sys +import numpy as np +sys.path.append("..") +import grading + +from mdp import MDP, FrozenLakeEnv + + +def submit_assigment( + get_action_value, + get_new_state_value, + get_optimal_action, + value_iteration, + email, + token): + grader = grading.Grader("EheZDOgLEeenIA4g5qPHFA") + sys.stdout = None + + transition_probs = { + 's0': { + 'a0': {'s1': 0.8, 's2': 0.2}, + 'a1': {'s1': 0.2, 's2': 0.8}, + }, + 's1': { + 'a0': {'s0': 0.2, 's2': 0.8}, + 'a1': {'s0': 0.8, 's2': 0.2}, + }, + 's2': { + 'a0': {'s3': 0.5, 's4': 0.5}, + 'a1': {'s3': 1.0}, + }, + 's3': { + 'a0': {'s1': 0.9, 's2': 0.1}, + 'a1': {'s1': 0.7, 's2': 0.3}, + }, + 's4': { + 'a0': {'s3': 1.0}, + 'a1': {'s3': 0.7, 's1': 0.3}, + } + } + rewards = { + 's0': {'a0': {'s1': 0, 's2': 1}, 'a1': {'s1': 0, 's2': 1}}, + 's1': {'a0': {'s0': -1, 's2': 1}, 'a1': {'s0': -1, 's2': 1}}, + 's2': {'a0': {'s3': 0, 's4': 1}, 'a1': {'s3': 0, 's4': 1}}, + 's3': {'a0': {'s1': -3, 's2': -3}, 'a1': {'s1': -3, 's2': -3}}, + 's4': {'a1': {'s1': +10}} + } + + mdp = MDP(transition_probs, rewards, initial_state='s0') + + test_Vs = {s: i for i, s in enumerate(mdp.get_all_states())} + qvalue1 = get_action_value(mdp, test_Vs, 's1', 'a0', 0.9) + qvalue2 = get_action_value(mdp, test_Vs, 's4', 'a1', 0.9) + + grader.set_answer("F16dC", qvalue1 + qvalue2) + + # --- + + svalue1 = get_new_state_value(mdp, test_Vs, 's2', 0.9) + svalue2 = get_new_state_value(mdp, test_Vs, 's4', 0.9) + + grader.set_answer("72cBp", svalue1 + svalue2) + + # --- + + state_values = {s: 0 for s in mdp.get_all_states()} + gamma = 0.9 + + # --- + + action1 = get_optimal_action(mdp, state_values, 's1', gamma) + action2 = get_optimal_action(mdp, state_values, 's2', gamma) + + grader.set_answer("xIuti", action1 + action2) + + # --- + + s = mdp.reset() + rewards = [] + for _ in range(10000): + s, r, done, _ = mdp.step(get_optimal_action(mdp, state_values, s, gamma)) + rewards.append(r) + + grader.set_answer("Y8g0j", np.mean(rewards) + np.std(rewards)) + + mdp = FrozenLakeEnv(slip_chance=0.25) + state_values = value_iteration(mdp) + gamma = 0.9 + + total_rewards = [] + for game_i in range(1000): + s = mdp.reset() + rewards = [] + for t in range(100): + s, r, done, _ = mdp.step(get_optimal_action(mdp, state_values, s, gamma)) + rewards.append(r) + if done: break + total_rewards.append(np.sum(rewards)) + + grader.set_answer("ABf1b", np.mean(total_rewards) + np.std(total_rewards)) + + # --- + + mdp = FrozenLakeEnv(slip_chance=0.25, map_name='8x8') + state_values = value_iteration(mdp) + gamma = 0.9 + + total_rewards = [] + for game_i in range(1000): + s = mdp.reset() + rewards = [] + for t in range(100): + s, r, done, _ = mdp.step(get_optimal_action(mdp, state_values, s, gamma)) + rewards.append(r) + if done: break + total_rewards.append(np.sum(rewards)) + + grader.set_answer("U3RzE", np.mean(total_rewards) + np.std(total_rewards)) + + sys.stdout = sys.__stdout__ + grader.submit(email, token)