{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# More Tic-Tac-Toe and a Simple Robot Arm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For this assignment, you will use the reinforcement learning algorithm, Q learning, with a neural network to approximate the Q function. You will apply this to the game Tic-Tac-Toe and to the control of a simple robot arm.\n", "\n", "Most of the code is provided. You are asked to make specific modifications and find parameter values that result in good performance on these tasks. The two tasks will probably require different parameter values." ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "Download necessary code from [ttt_arm.zip](https://www.cs.colostate.edu/~anderson/cs545/notebooks/ttt_arm.zip)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T19:56:38.171397Z", "start_time": "2024-10-24T19:56:37.398272Z" }, "tags": [] }, "outputs": [], "source": [ "%load_ext autoreload\n", "%autoreload 2\n", " \n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from IPython.display import display, clear_output\n", "import pandas as pd\n", "import pickle" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "## Tic Tac Toe" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T19:56:38.194043Z", "start_time": "2024-10-24T19:56:38.172790Z" }, "tags": [] }, "outputs": [], "source": [ "import tictactoe" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T20:09:04.569252Z", "start_time": "2024-10-24T20:09:04.538820Z" }, "tags": [] }, "outputs": [], "source": [ "class Game:\n", "\n", " def __init__(self, environment, agents):\n", "\n", " self.env = environment\n", " self.agents = agents\n", "\n", " def train(self, parms, verbose=True):\n", "\n", " n_batches = parms['n_batches']\n", " n_games_per_batch = parms['n_games_per_batch']\n", " n_epochs = parms['n_epochs']\n", " method = parms['method']\n", " learning_rate = parms['learning_rate']\n", " epsilon = parms['initial_epsilon']\n", " final_epsilon = parms['final_epsilon']\n", "\n", " ttt = self.env\n", "\n", " epsilon_decay = np.exp((np.log(final_epsilon) - np.log(epsilon)) / (n_batches)) # to produce this final value\n", " \n", " epsilon_trace = []\n", " outcomes = []\n", "\n", " for batch in range(n_batches):\n", " agents['X'].clear_samples()\n", " agents['O'].clear_samples()\n", " \n", " for gamei in range(n_games_per_batch):\n", "\n", " ttt.initialize()\n", " done = False\n", "\n", " while not done:\n", "\n", " agent = agents[ttt.player]\n", " obs = ttt.observe()\n", " if len(self.env.valid_actions()) == 9:\n", " action = np.random.choice(self.env.valid_actions())\n", " # print('picked random action at start of game') \n", " else:\n", " action = agent.epsilon_greedy(epsilon)\n", " # print('picked best action')\n", "\n", " ttt.act(action)\n", " r = ttt.reinforcement()\n", " done = ttt.terminal_state()\n", "\n", " agent.add_sample(obs, action, r, done)\n", "\n", " outcomes.append(r)\n", "\n", " # end n_trials_per_batch\n", " self.agents['X'].train(n_epochs, method, learning_rate)\n", " self.agents['O'].train(n_epochs, method, learning_rate)\n", "\n", " epsilon_trace.append(epsilon)\n", " epsilon *= epsilon_decay\n", "\n", " if verbose and (len(outcomes) % ((n_batches * n_games_per_batch) // 20) == 0):\n", " print(f'{len(outcomes)}/{n_batches * n_games_per_batch} games, {np.mean(outcomes):.2f} outcome mean')\n", "\n", " if verbose:\n", " plt.subplot(3, 1, 1)\n", " n_per = 10\n", " n_bins = len(outcomes) // n_per\n", " outcomes_binned = np.array(outcomes).reshape(-1, n_per)\n", " avgs = outcomes_binned.mean(1)\n", " xs = np.linspace(n_per, n_per * n_bins, len(avgs))\n", " plt.plot(xs, avgs)\n", " plt.axhline(y=0, color='orange', ls='--')\n", " plt.ylabel('R')\n", " \n", " plt.subplot(3, 1, 2)\n", " plt.plot(xs, np.sum(outcomes_binned == -1, axis=1), 'r-', label='O Wins')\n", " plt.plot(xs, np.sum(outcomes_binned == 0, axis=1), 'b-', label='Draws')\n", " plt.plot(xs, np.sum(outcomes_binned == 1, axis=1), 'g-', label='X Wins')\n", " plt.legend(loc='center')\n", " plt.ylabel(f'Number of Games\\nin Bins of {n_per:d}')\n", " \n", " plt.subplot(3, 1, 3)\n", " plt.plot(epsilon_trace)\n", " plt.ylabel(r'$\\epsilon$')\n", "\n", " return outcomes, epsilon_trace\n", "\n", "\n", " def play_game(self, epsilon=0.0, verbose=True):\n", " ttt = self.env\n", " agents = self.agents\n", " ttt.initialize()\n", " while True:\n", " agent = agents[ttt.player]\n", " obs = ttt.observe()\n", " if len(ttt.valid_actions()) == 9:\n", " action = agent.epsilon_greedy(epsilon=1.0)\n", " else:\n", " action = agent.epsilon_greedy(epsilon)\n", "\n", " ttt.act(action)\n", " if verbose:\n", " print(ttt)\n", " if ttt.terminal_state():\n", " return ttt.reinforcement()\n", "\n", " def play_game_show_Q(self, epsilon=0.0):\n", " ttt = self.env\n", " agents = self.agents\n", " step = 0\n", "\n", " ttt.initialize()\n", " while True:\n", " agent = agents[ttt.player]\n", " obs = ttt.observe()\n", " actions = ttt.valid_actions()\n", " if len(ttt.valid_actions()) == 9:\n", " action = agent.epsilon_greedy(epsilon=1.0)\n", " else:\n", " action = agent.epsilon_greedy(epsilon)\n", " ttt.act(action)\n", " step += 1\n", "\n", " plt.subplot(5, 2, step)\n", " Qs = np.array([agent.use(np.hstack((obs, a))) for a in actions])\n", " board_image = np.array([np.nan] * 9)\n", " for Q, a in zip(Qs, actions):\n", " board_image[a] = Q[0, 0]\n", " board_image = board_image.reshape(3, 3)\n", " maxmag = np.nanmax(np.abs(board_image))\n", " plt.imshow(board_image, cmap='coolwarm', vmin=-maxmag, vmax=maxmag)\n", " plt.colorbar()\n", " obs = ttt.observe()\n", " i = -1\n", " for row in range(3):\n", " for col in range(3):\n", " i += 1\n", " if obs[i] == 1:\n", " plt.text(col, row, 'X', ha='center',\n", " fontweight='bold', fontsize='large', color='black')\n", " elif obs[i] == -1:\n", " plt.text(col, row, 'O', ha='center',\n", " fontweight='bold', fontsize='large', color='black')\n", " plt.axis('off')\n", " if ttt.terminal_state():\n", " break\n", "\n", " plt.tight_layout()" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T20:09:04.931597Z", "start_time": "2024-10-24T20:09:04.913948Z" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " X| | \n", " -----\n", " | | \n", " ------\n", " | | \n", "\n", " X| | \n", " -----\n", " O| | \n", " ------\n", " | | \n", "\n", " X|X| \n", " -----\n", " O| | \n", " ------\n", " | | \n", "\n", " X|X| \n", " -----\n", " O|O| \n", " ------\n", " | | \n", "\n", " X|X|X\n", " -----\n", " O|O| \n", " ------\n", " | | \n" ] }, { "data": { "text/plain": [ "1" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ttt = tictactoe.TicTacToe()\n", "nh = [10]\n", "agents = {'X': tictactoe.QnetAgent(ttt, nh, 'max'), \n", " 'O': tictactoe.QnetAgent(ttt, nh, 'min')}\n", "game = Game(ttt, agents)\n", "game.play_game(0)" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T20:58:21.183792Z", "start_time": "2024-10-24T20:38:08.889535Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " hiddens batches games epochs mean r\n", "43 [50] 500 5 10 0.4244\n", "41 [50, 50, 50] 500 5 5 0.4168\n", "2 [50, 50, 50] 100 5 2 0.3840\n", "65 [50, 50, 50] 500 20 5 0.3734\n", "61 [50] 500 20 2 0.3726\n", ".. ... ... ... ... ...\n", "56 [50, 50, 50] 500 10 10 0.1780\n", "30 [] 100 20 10 0.1750\n", "33 [] 100 20 20 0.1575\n", "15 [] 100 10 5 0.1520\n", "68 [50, 50, 50] 500 20 10 0.1440\n", "\n", "[72 rows x 5 columns]\n" ] } ], "source": [ "previous_best = -np.inf\n", "results = []\n", "for nb in [100, 500]:\n", " for ng in [5, 10, 20]:\n", " for ne in [2, 5, 10, 20]:\n", " for nh in [ [], [50], [50, 50, 50] ]:\n", " parms = {\n", " 'n_batches': nb,\n", " 'n_games_per_batch': ng,\n", " 'n_epochs': ne,\n", " 'method': 'scg',\n", " 'learning_rate': 0.01,\n", " 'initial_epsilon': 1.0,\n", " 'final_epsilon': 0.01,\n", " 'gamma': 1.0\n", " }\n", " agents = {'X': tictactoe.QnetAgent(ttt, nh, 'max'), \n", " 'O': tictactoe.QnetAgent(ttt, nh, 'min')}\n", " game = Game(ttt, agents)\n", "\n", " outcomes, _ = game.train(parms, verbose=False)\n", " mean_outcomes = np.mean(outcomes)\n", " results.append([nh, nb, ng, ne, mean_outcomes])\n", " clear_output()\n", " df = pd.DataFrame(results, \n", " columns=('hiddens', 'batches', 'games', \n", " 'epochs', 'mean r'))\n", " print(df.sort_values(by='mean r', ascending=False))\n", " \n", " if mean_outcomes > previous_best:\n", " previous_best = mean_outcomes\n", " with open('best_ttt_agents.pkl', 'wb') as f:\n", " pickle.dump(agents, f)" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:11:44.934049Z", "start_time": "2024-10-24T21:11:44.713375Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "mean of final outcomes 0.35\n" ] } ], "source": [ "with open('best_ttt_agents.pkl', 'rb') as f:\n", " agents = pickle.load(f)\n", "\n", "ttt = agents['X'].env\n", "game = Game(ttt, agents)\n", "\n", "rs = []\n", "for n_games in range(100):\n", " rs.append(game.play_game(epsilon=0.05, verbose=False))\n", " \n", "print(f'mean of final outcomes {np.mean(rs)}')" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:11:46.330430Z", "start_time": "2024-10-24T21:11:45.985386Z" }, "tags": [] }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "game.play_game_show_Q()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Robot" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:24:11.306077Z", "start_time": "2024-10-24T21:24:10.532760Z" }, "tags": [] }, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from IPython.display import display, clear_output\n", "import pandas as pd\n", "import pickle\n", "\n", "import robot" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:24:11.484837Z", "start_time": "2024-10-24T21:24:11.475874Z" }, "tags": [] }, "outputs": [], "source": [ " class Experiment:\n", "\n", " def __init__(self, environment, agent):\n", "\n", " self.env = environment\n", " self.agent = agent\n", "\n", " def train(self, parms, verbose=True):\n", "\n", " n_batches = parms['n_batches']\n", " n_steps_per_batch = parms['n_steps_per_batch']\n", " n_epochs = parms['n_epochs']\n", " method = parms['method']\n", " learning_rate = parms['learning_rate']\n", " epsilon = parms['initial_epsilon']\n", " final_epsilon = parms['final_epsilon']\n", " gamma = parms['gamma']\n", "\n", " env = self.env\n", "\n", " epsilon_decay = np.exp((np.log(final_epsilon) - np.log(epsilon))/ (n_batches)) # to produce this final value\n", "\n", " epsilon_trace = []\n", " outcomes = []\n", "\n", " for batch in range(n_batches):\n", " agent.clear_samples()\n", " env.initialize()\n", "\n", " sum_rs = 0\n", " \n", " for step in range(n_steps_per_batch):\n", "\n", " obs = self.env.observe()\n", " action = agent.epsilon_greedy(epsilon)\n", "\n", " env.act(action)\n", " r = env.reinforcement()\n", " sum_rs += r\n", "\n", " done = step == n_steps_per_batch - 1\n", " agent.add_sample(obs, action, r, done)\n", "\n", " outcomes.append(sum_rs / n_steps_per_batch)\n", "\n", " self.agent.train(n_epochs, method, learning_rate, gamma)\n", "\n", " epsilon_trace.append(epsilon)\n", " epsilon *= epsilon_decay\n", "\n", " if verbose and (len(outcomes) % (n_batches // 20) == 0):\n", " print(f'{len(outcomes)}/{n_batches} batches, {np.mean(outcomes):.4f} outcome mean')\n", "\n", " if verbose:\n", " plt.figure(1)\n", " plt.clf()\n", " plt.subplot(2, 1, 1)\n", " n_per = 10\n", " n_bins = len(outcomes) // n_per\n", " outcomes_binned = np.array(outcomes).reshape(-1, n_per)\n", " avgs = outcomes_binned.mean(1)\n", " xs = np.linspace(n_per, n_per * n_bins, len(avgs))\n", " plt.plot(xs, avgs)\n", " plt.axhline(y=0, color='orange', ls='--')\n", " plt.ylabel('R')\n", " \n", " plt.subplot(2, 1, 2)\n", " plt.plot(epsilon_trace)\n", " plt.ylabel(r'$\\epsilon$')\n", " #plt.pause(0.1)\n", "\n", " return outcomes # , epsilon_trace\n", "\n", " def test(self, n_trials, n_steps, epsilon=0.0, graphics=True):\n", " if graphics:\n", " fig = plt.figure(figsize=(10, 10))\n", " robot = self.env\n", " sum_rs = 0\n", " for trial in range(n_trials):\n", " robot.initialize()\n", " agent = self.agent\n", " points = np.zeros((n_steps, robot.n_links + 1, 2))\n", " actions = np.zeros((n_steps, robot.n_links))\n", " Q_values = np.zeros((n_steps))\n", " \n", " for i in range(n_steps):\n", " action = agent.epsilon_greedy(epsilon)\n", " Q = agent.use(np.hstack((robot.observe(), action)))\n", " self.env.act(action)\n", " sum_rs += self.env.reinforcement()\n", " points[i] = robot.points\n", " actions[i] = action\n", " Q_values[i] = Q[0, 0]\n", " \n", " if graphics:\n", " Q_min, Q_max = np.min(Q_values), np.max(Q_values)\n", " print(Q_min, Q_max)\n", " for i in range(n_steps):\n", " fig.clf()\n", " plt.scatter(robot.goal[0], robot.goal[1], s=40, c='blue')\n", " action = actions[i]\n", " robot.set_points(points[i])\n", " robot.draw() # alpha=(Q_values[i] - Q_min) / (Q_max - Q_min))\n", " clear_output(wait=True)\n", " display(fig)\n", " \n", " clear_output(wait=True)\n", " return sum_rs / (n_trials * n_steps)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:25:13.752688Z", "start_time": "2024-10-24T21:25:13.748958Z" }, "tags": [] }, "outputs": [], "source": [ "robbie = robot.Robot()\n", "robbie.set_goal([5., 5.])\n", "\n", "agent = robot.QnetAgent(robbie, [100, 100, 100])\n", "experiment = Experiment(robbie, agent)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:30:14.566512Z", "start_time": "2024-10-24T21:26:42.489755Z" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " hiddens batches steps epochs dist\n", "13 [50] 200 50 5 -1.814330\n", "17 [50, 50] 200 50 10 -4.569909\n", "1 [50] 100 50 5 -5.063843\n", "16 [50] 200 50 10 -5.805537\n", "5 [50, 50] 100 50 10 -5.866438\n", "4 [50] 100 50 10 -7.114635\n", "18 [] 200 100 5 -7.848883\n", "7 [50] 100 100 5 -7.996590\n", "6 [] 100 100 5 -8.317250\n", "0 [] 100 50 5 -8.321376\n", "3 [] 100 50 10 -8.546975\n", "10 [50] 100 100 10 -8.749536\n", "12 [] 200 50 5 -8.816075\n", "2 [50, 50] 100 50 5 -8.881165\n", "15 [] 200 50 10 -9.246151\n", "9 [] 100 100 10 -9.302054\n", "11 [50, 50] 100 100 10 -10.096282\n", "8 [50, 50] 100 100 5 -10.254745\n", "14 [50, 50] 200 50 5 -10.688630\n", "\n" ] }, { "ename": "KeyboardInterrupt", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[11], line 23\u001b[0m\n\u001b[1;32m 20\u001b[0m agent \u001b[38;5;241m=\u001b[39m robot\u001b[38;5;241m.\u001b[39mQnetAgent(robbie, nh)\n\u001b[1;32m 21\u001b[0m experiment \u001b[38;5;241m=\u001b[39m Experiment(robbie, agent)\n\u001b[0;32m---> 23\u001b[0m outcomes \u001b[38;5;241m=\u001b[39m experiment\u001b[38;5;241m.\u001b[39mtrain(parms, verbose\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[1;32m 24\u001b[0m results\u001b[38;5;241m.\u001b[39mappend([nh, nb, ns, ne, outcomes[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]])\n\u001b[1;32m 25\u001b[0m clear_output()\n", "Cell \u001b[0;32mIn[2], line 35\u001b[0m, in \u001b[0;36mExperiment.train\u001b[0;34m(self, parms, verbose)\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m step \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(n_steps_per_batch):\n\u001b[1;32m 34\u001b[0m obs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39menv\u001b[38;5;241m.\u001b[39mobserve()\n\u001b[0;32m---> 35\u001b[0m action \u001b[38;5;241m=\u001b[39m agent\u001b[38;5;241m.\u001b[39mepsilon_greedy(epsilon)\n\u001b[1;32m 37\u001b[0m env\u001b[38;5;241m.\u001b[39mact(action)\n\u001b[1;32m 38\u001b[0m r \u001b[38;5;241m=\u001b[39m env\u001b[38;5;241m.\u001b[39mreinforcement()\n", "File \u001b[0;32m~/public_html/cs545/notebooks/tmp/robot.py:119\u001b[0m, in \u001b[0;36mQnetAgent.epsilon_greedy\u001b[0;34m(self, epsilon)\u001b[0m\n\u001b[1;32m 117\u001b[0m np\u001b[38;5;241m.\u001b[39mrandom\u001b[38;5;241m.\u001b[39mshuffle(actions)\n\u001b[1;32m 118\u001b[0m obs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39menv\u001b[38;5;241m.\u001b[39mobserve()\n\u001b[0;32m--> 119\u001b[0m Qs \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39marray([\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39muse(np\u001b[38;5;241m.\u001b[39mhstack((obs, a))) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m actions])\n\u001b[1;32m 120\u001b[0m action \u001b[38;5;241m=\u001b[39m actions[np\u001b[38;5;241m.\u001b[39margmax(Qs)] \u001b[38;5;66;03m# Minimize sum of distances to goal\u001b[39;00m\n\u001b[1;32m 121\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m action\n", "File \u001b[0;32m~/public_html/cs545/notebooks/tmp/robot.py:126\u001b[0m, in \u001b[0;36mQnetAgent.use\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 124\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m X\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 125\u001b[0m X \u001b[38;5;241m=\u001b[39m X\u001b[38;5;241m.\u001b[39mreshape(\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m)\n\u001b[0;32m--> 126\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mQnet\u001b[38;5;241m.\u001b[39muse(X)\n", "File \u001b[0;32m~/public_html/cs545/notebooks/tmp/neuralnetworksA4.py:410\u001b[0m, in \u001b[0;36mNeuralNetwork.use\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 408\u001b[0m \u001b[38;5;66;03m# Standardize X\u001b[39;00m\n\u001b[1;32m 409\u001b[0m X \u001b[38;5;241m=\u001b[39m (X \u001b[38;5;241m-\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mX_means) \u001b[38;5;241m/\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mX_stds\n\u001b[0;32m--> 410\u001b[0m Zs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward(X)\n\u001b[1;32m 411\u001b[0m \u001b[38;5;66;03m# Unstandardize output Y before returning it\u001b[39;00m\n\u001b[1;32m 412\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m Zs[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m] \u001b[38;5;241m*\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mT_stds \u001b[38;5;241m+\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mT_means\n", "File \u001b[0;32m~/public_html/cs545/notebooks/tmp/neuralnetworksA4.py:301\u001b[0m, in \u001b[0;36mNeuralNetwork._forward\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 298\u001b[0m \u001b[38;5;66;03m# Append output of each layer to list in self.Zs, then return it.\u001b[39;00m\n\u001b[1;32m 300\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m W \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mWs[:\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]: \u001b[38;5;66;03m# forward through all but last layer\u001b[39;00m\n\u001b[0;32m--> 301\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mZs\u001b[38;5;241m.\u001b[39mappend(np\u001b[38;5;241m.\u001b[39mtanh(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_add_ones(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mZs[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]) \u001b[38;5;241m@\u001b[39m W))\n\u001b[1;32m 302\u001b[0m last_W \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mWs[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m 303\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mZs\u001b[38;5;241m.\u001b[39mappend(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_add_ones(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mZs[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]) \u001b[38;5;241m@\u001b[39m last_W)\n", "File \u001b[0;32m~/public_html/cs545/notebooks/tmp/neuralnetworksA4.py:282\u001b[0m, in \u001b[0;36mNeuralNetwork._add_ones\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 281\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_add_ones\u001b[39m(\u001b[38;5;28mself\u001b[39m, X):\n\u001b[0;32m--> 282\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m np\u001b[38;5;241m.\u001b[39minsert(X, \u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m1\u001b[39m)\n", "File \u001b[0;32m~/anaconda3/lib/python3.12/site-packages/numpy/lib/function_base.py:5369\u001b[0m, in \u001b[0;36minsert\u001b[0;34m(arr, obj, values, axis)\u001b[0m\n\u001b[1;32m 5365\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_insert_dispatcher\u001b[39m(arr, obj, values, axis\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m 5366\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m (arr, obj, values)\n\u001b[0;32m-> 5369\u001b[0m \u001b[38;5;129m@array_function_dispatch\u001b[39m(_insert_dispatcher)\n\u001b[1;32m 5370\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minsert\u001b[39m(arr, obj, values, axis\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m 5371\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 5372\u001b[0m \u001b[38;5;124;03m Insert values along the given axis before the given indices.\u001b[39;00m\n\u001b[1;32m 5373\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 5456\u001b[0m \n\u001b[1;32m 5457\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m 5458\u001b[0m wrap \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", "\u001b[0;31mKeyboardInterrupt\u001b[0m: " ] } ], "source": [ "import pandas as pd\n", "\n", "previous_best = -np.inf\n", "\n", "results = []\n", "for nb in [100, 200, 5000]:\n", " for ns in [50, 100]:\n", " for ne in [5, 10]:\n", " for nh in [ [], [50], [50, 50] ]:\n", " parms = {\n", " 'n_batches': nb,\n", " 'n_steps_per_batch': ns,\n", " 'n_epochs': ne,\n", " 'method': 'scg',\n", " 'learning_rate': 0.01,\n", " 'initial_epsilon': 1.0,\n", " 'final_epsilon': 0.001,\n", " 'gamma': 1.0\n", " }\n", " agent = robot.QnetAgent(robbie, nh)\n", " experiment = Experiment(robbie, agent)\n", " \n", " outcomes = experiment.train(parms, verbose=False)\n", " results.append([nh, nb, ns, ne, outcomes[-1]])\n", " clear_output()\n", " df = pd.DataFrame(results, \n", " columns=('hiddens', 'batches', 'steps', \n", " 'epochs', 'dist'))\n", " print(df.sort_values(by='dist', ascending=False))\n", " \n", " if outcomes[-1] > previous_best:\n", " previous_best = outcomes[-1]\n", " with open('best_robot_agent.pkl', 'wb') as f:\n", " pickle.dump(agent, f)\n", " \n", " print()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:30:22.401149Z", "start_time": "2024-10-24T21:30:21.002316Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "mean of reinforcements -2.424\n" ] } ], "source": [ "with open('best_robot_agent.pkl', 'rb') as f:\n", " agent = pickle.load(f)\n", "\n", "robbie = agent.env\n", "experiment = Experiment(robbie, agent)\n", "\n", "mean_r = experiment.test(n_trials=10, n_steps=100, epsilon=0.0, graphics=False)\n", "\n", "print(f'mean of reinforcements {mean_r:.3f}')" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:31:50.619335Z", "start_time": "2024-10-24T21:31:18.194615Z" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "25/500 batches, -7.9906 outcome mean\n", "50/500 batches, -7.8550 outcome mean\n", "75/500 batches, -7.6936 outcome mean\n", "100/500 batches, -7.4452 outcome mean\n", "125/500 batches, -7.2722 outcome mean\n", "150/500 batches, -7.0897 outcome mean\n", "175/500 batches, -6.8215 outcome mean\n", "200/500 batches, -6.7659 outcome mean\n", "225/500 batches, -6.6292 outcome mean\n", "250/500 batches, -6.4414 outcome mean\n", "275/500 batches, -6.2562 outcome mean\n", "300/500 batches, -6.1209 outcome mean\n", "325/500 batches, -5.9951 outcome mean\n", "350/500 batches, -5.9060 outcome mean\n", "375/500 batches, -5.8354 outcome mean\n", "400/500 batches, -5.7448 outcome mean\n", "425/500 batches, -5.6290 outcome mean\n", "450/500 batches, -5.5753 outcome mean\n", "475/500 batches, -5.5057 outcome mean\n", "500/500 batches, -5.4142 outcome mean\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "parms = {\n", " 'n_batches': 500,\n", " 'n_steps_per_batch': 50, \n", " 'n_epochs': 5,\n", " 'method': 'scg',\n", " 'learning_rate': 0.01,\n", " 'initial_epsilon': 1.0,\n", " 'final_epsilon': 0.0001,\n", " 'gamma': 1.0\n", "}\n", "\n", "agent = robot.QnetAgent(robbie, [50])\n", "experiment = Experiment(robbie, agent)\n", "\n", "outcomes = experiment.train(parms)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2024-10-24T21:32:50.861380Z", "start_time": "2024-10-24T21:32:02.147369Z" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "-3.4894459784287455" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAMWCAYAAABsvhCnAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAgu0lEQVR4nO3de9Dn433/8dfuvbvi3NbZ7LiLNZpJO8SuXdqKQ4ggkiZtxCEkSkiVIpQ2nXRM1SHSmLZmZVctGyu767CWYiTVIo7bEAnqNLayuAmlSOIYu3v3j88vB78geN/3/fkeHo8Z4xr88f6H2/O+rutzjRseHh4OAABAwfi2BwAAALqfsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcICAAAoExYAAECZsAAAAMqEBQAAUCYsAACAMmEBAACUCQsAAKBMWAAAAGXCAgAAKBMWAABAmbAAAADKhAUAAFAmLAAAgDJhAQAAlAkLAACgTFgAAABlwgIAACgTFgAAQJmwAAAAyoQFAABQJiwAAIAyYQEAAJQJCwAAoExYAAAAZcIC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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "experiment.test(10, 100, epsilon=0.0, graphics=True)" ] } ], "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", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.2" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }