From 16d8781a9cf8882a9855f5fa29415b7f61f37a43 Mon Sep 17 00:00:00 2001 From: Yijie Zhuang Date: Mon, 18 Nov 2019 14:32:40 -0800 Subject: [PATCH] Add batch RL example notebook --- reinforcement_learning/common/env_utils.py | 211 +++++ .../rl_cartpole_batch_coach/README.md | 14 + .../rl_cartpole_batch_coach/__init__.py | 0 .../rl_cartpole_batch_coach/batch_rl.png | Bin 0 -> 131628 bytes .../rl_cartpole_batch_coach/common | 1 + .../rl_cartpole_batch_coach.ipynb | 726 ++++++++++++++++++ .../rl_cartpole_batch_coach/src/__init__.py | 0 .../src/evaluate-coach.py | 91 +++ .../src/preset-cartpole-ddqnbcq-env.py | 78 ++ .../src/preset-cartpole-ddqnbcq.py | 79 ++ .../src/train-coach.py | 61 ++ 11 files changed, 1261 insertions(+) create mode 100644 reinforcement_learning/common/env_utils.py create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/README.md create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/__init__.py create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/batch_rl.png create mode 120000 reinforcement_learning/rl_cartpole_batch_coach/common create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/rl_cartpole_batch_coach.ipynb create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/src/__init__.py create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/src/evaluate-coach.py create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/src/preset-cartpole-ddqnbcq-env.py create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/src/preset-cartpole-ddqnbcq.py create mode 100644 reinforcement_learning/rl_cartpole_batch_coach/src/train-coach.py diff --git a/reinforcement_learning/common/env_utils.py b/reinforcement_learning/common/env_utils.py new file mode 100644 index 0000000000..516af62115 --- /dev/null +++ b/reinforcement_learning/common/env_utils.py @@ -0,0 +1,211 @@ +import gym +import numpy as np +import pandas as pd +import json +from pathlib import Path + +gym.logger.set_level(40) + +class VectoredGymEnvironment(): + """ + Envrioment class to run multiple similations and collect rollout data + """ + def __init__(self, registered_gym_env, num_of_envs=1): + self.envs_initialized = False + self.initialized_envs = {} + self.env_states = {} + self.env_reset_counter = {} + self.num_of_envs = num_of_envs + self.data_rows = [] + + self.initialize_envs(num_of_envs, registered_gym_env) + + def is_initialized(self): + return self.envs_initialized + + def initialize_envs( + self, + num_of_envs, + registered_gym_env): + """Initialize multiple Openai gym environments. + Each envrionment will start with a different random seed. + + Arguments: + num_of_envs {int} -- Number of environments/simulations to initiate + registered_gym_env {str} -- Environment name of the registered gym environment + """ + print("Initializing {} environments of {}".format(num_of_envs, registered_gym_env)) + for i in range(0, num_of_envs): + environment_id = "environment_" + str(i) + environment = gym.make(registered_gym_env) + environment = environment.unwrapped + environment.seed(i) + self.env_states[environment_id] = environment.reset() + self.env_reset_counter[environment_id] = 0 + self.initialized_envs[environment_id] = environment + self.envs_initialized = True + self.state_dims = len(self.env_states[environment_id]) + + def get_environment_states(self): + return self.env_states + + def dump_environment_states(self, dir_path, file_name): + """Dumping current states of all the envrionments into file + + Arguments: + dir_path {str} -- Directory path of the target file + file_name {str} -- File name of the target file + """ + data_folder = Path(dir_path) + file_path = data_folder / file_name + + with open(file_path, 'w') as outfile: + for state in self.env_states.values(): + json.dump(list(state), outfile) + outfile.write('\n') + + def get_environment_ids(self): + return list(self.initialized_envs.keys()) + + def step(self, environment_id, action): + local_env = self.initialized_envs[environment_id] + observation, reward, done, info = local_env.step(action) + + self.env_states[environment_id] = observation + return observation, reward, done, info + + def reset(self, environment_id): + self.env_states[environment_id] = \ + self.initialized_envs[environment_id].reset() + return self.env_states[environment_id] + + def reset_all_envs(self): + print("Resetting all the environments...") + for i in range(0, self.num_of_envs): + environment_id = "environment_" + str(i) + self.reset(environment_id) + + def close(self, environment_id): + self.initialized_envs[environment_id].close() + return + + def render(self, environment_id): + self.initialized_envs[environment_id].render() + return + + def collect_rollouts_for_single_env_with_given_episodes(self, environment_id, action_prob, num_episodes): + """Collect rollouts with given steps from one environment + + Arguments: + environment_id {str} -- Environment id for the environment + action_prob {list} -- Action probabilities of the simulated policy + num_episodes {int} -- Number of episodes to run rollouts + """ + # normalization if sum of probs is not exact equal to 1 + action_prob = np.array(action_prob) + if action_prob.sum() != 1: + action_prob /= action_prob.sum() + action_prob = list(action_prob) + + for _ in range(num_episodes): + done = False + cumulative_rewards = 0 + while not done: + data_item = [] + action = np.random.choice(len(action_prob), p=action_prob) + cur_state_features = self.env_states[environment_id] + _, reward, done, _ = self.step(environment_id, action) + cumulative_rewards += reward + episode_id = int(environment_id.split('_')[-1]) + \ + self.num_of_envs * self.env_reset_counter[environment_id] + if not done: + data_item.extend([action, action_prob, episode_id, reward, 0.0]) + else: + data_item.extend([action, action_prob, episode_id, reward, cumulative_rewards]) + for j in range(len(cur_state_features)): + data_item.append(cur_state_features[j]) + self.data_rows.append(data_item) + + self.reset(environment_id) + self.env_reset_counter[environment_id] += 1 + + def collect_rollouts_for_single_env_with_given_steps(self, environment_id, action_prob, num_steps): + """Collect rollouts with given steps from one environment + + Arguments: + environment_id {str} -- Environment id for the environment + action_prob {list} -- Action probabilities of the simulated policy + num_episodes {int} -- Number of steps to run rollouts + """ + # normalization if sum of probs is not exact equal to 1 + action_prob = np.array(action_prob) + if action_prob.sum() != 1: + action_prob /= action_prob.sum() + action_prob = list(action_prob) + + for _ in range(num_steps): + data_item = [] + action = np.random.choice(len(action_prob), p=action_prob) + cur_state_features = self.env_states[environment_id] + _, reward, done, _ = self.step(environment_id, action) + episode_id = int(environment_id.split('_')[-1]) + \ + self.num_of_envs * self.env_reset_counter[environment_id] + data_item.extend([action, action_prob, episode_id, reward]) + for j in range(len(cur_state_features)): + data_item.append(cur_state_features[j]) + self.data_rows.append(data_item) + if done: + self.reset(environment_id) + self.env_reset_counter[environment_id] += 1 + + def collect_rollouts_with_given_action_probs(self, num_steps=None, num_episodes=None, action_probs=None, file_name=None): + """Collect rollouts from all the initiated environments with given action probs + + Keyword Arguments: + num_steps {int} -- Number of steps to run rollouts (default: {None}) + num_episodes {int} -- Number of episodes to run rollouts (default: {None}) + action_probs {list} -- Action probs for the policy (default: {None}) + file_name {str} -- Batch transform output that contain predictions of probs (default: {None}) + + Returns: + [Dataframe] -- Dataframe that contains the rollout data from all envs + """ + if file_name is not None: + assert action_probs is None + json_lines = [json.loads(line.rstrip('\n')) for line in open(file_name) if line is not ''] + action_probs = [] + for line in json_lines: + if line.get('SageMakerOutput') is not None: + action_probs.append(line['SageMakerOutput'].get("predictions")[0]) + else: + action_probs.append(line.get("predictions")[0]) + + assert len(action_probs) == self.num_of_envs + for index, environment_id in enumerate(self.get_environment_ids()): + if num_steps is not None: + assert num_episodes is None + self.collect_rollouts_for_single_env_with_given_steps( + environment_id, action_probs[index], num_steps + ) + else: + assert num_episodes is not None + self.collect_rollouts_for_single_env_with_given_episodes( + environment_id, action_probs[index], num_episodes + ) + + col_names = self._create_col_names() + df = pd.DataFrame(self.data_rows, columns = col_names) + + return df + + def _create_col_names(self): + """Create column names of dataframe that can be consumed by Coach + + Returns: + [list] -- List of column names + """ + col_names = ['action', 'all_action_probabilities', 'episode_id', 'reward', 'cumulative_rewards'] + for i in range(self.state_dims): + col_names.append('state_feature_' + str(i)) + + return col_names \ No newline at end of file diff --git a/reinforcement_learning/rl_cartpole_batch_coach/README.md b/reinforcement_learning/rl_cartpole_batch_coach/README.md new file mode 100644 index 0000000000..4a318f2a32 --- /dev/null +++ b/reinforcement_learning/rl_cartpole_batch_coach/README.md @@ -0,0 +1,14 @@ +# Training Batch Reinforcement Learning Policies with Amazon SageMaker RL + +In many real-world problems, the reinforcement learning agent cannot interact with neither the real environment nor a simulated one. On one hand, creating a simulator that imitates the real environment dynamic could be quite complex and on the other, letting the learning agent attempt sub-optimal actions in the real world is quite risky. In such cases, the learning agent can only have access to batches of offline data that generated by some deployed policy. The learning agent need to utilize these data correctly to learn a better policy to solve the problem. + +This notebook shows an example of how to use batch reinforcement learning techniques to address such type of real-world problems: training a new policy from offline dataset when there is no way to interact with real environments or simulators. This example is a simple toy demonstrating how one might begin to address this real and challenging problem. We use gym `CartPole-v0` as a fake simulated system to generate offline dataset and the RL agents are trained using Amazon SageMaker RL. + +## Contents + +* `rl_cartpole_batch_coach.ipynb`: notebook used for training policy with Batch RL to solve the cartpole problem. +* `src/` + * `train-coach.py`: launcher for coach training. + * `evaluate-coach.py`: launcher for coach evaluation. + * `preset-cartpole-ddqnbcq.py`: coach preset for BCQ algorithm. + * `preset-cartpole-ddqnbcq-env.py`: coach preset for BCQ algorithm with environment setup. diff --git a/reinforcement_learning/rl_cartpole_batch_coach/__init__.py b/reinforcement_learning/rl_cartpole_batch_coach/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/reinforcement_learning/rl_cartpole_batch_coach/batch_rl.png b/reinforcement_learning/rl_cartpole_batch_coach/batch_rl.png new file mode 100644 index 0000000000000000000000000000000000000000..0d560f64e7e63c197022ac104a3dd81aa5844eec GIT binary patch literal 131628 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

vlNv%VS9YhFgk>B*-Nll9}cb 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�uE;4_4?yBlZ6fn# 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

{J{Sp#w$8CjhfZ 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 literal 0 HcmV?d00001 diff --git a/reinforcement_learning/rl_cartpole_batch_coach/common b/reinforcement_learning/rl_cartpole_batch_coach/common new file mode 120000 index 0000000000..60d3b0a6a8 --- /dev/null +++ b/reinforcement_learning/rl_cartpole_batch_coach/common @@ -0,0 +1 @@ +../common \ No newline at end of file diff --git a/reinforcement_learning/rl_cartpole_batch_coach/rl_cartpole_batch_coach.ipynb b/reinforcement_learning/rl_cartpole_batch_coach/rl_cartpole_batch_coach.ipynb new file mode 100644 index 0000000000..611b23aa27 --- /dev/null +++ b/reinforcement_learning/rl_cartpole_batch_coach/rl_cartpole_batch_coach.ipynb @@ -0,0 +1,726 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Training Batch Reinforcement Learning Policies with Amazon SageMaker RL\n", + "\n", + "For many real-world problems, the reinforcement learning (RL) agent needs to learn from historical data that was generated by some deployed policy. For example, we may have historical data of experts playing games, users interacting with a website or sensor data from a control system. This notebook shows an example of how to use batch RL to train a new policy from offline dataset[1]. We use gym `CartPole-v0` as a fake simulated system to generate offline dataset and the RL agents are trained using Amazon SageMaker RL.\n", + "\n", + "We may want to evaluate the policy learned from historical data before deployment. Since simulators may not be available in all use cases, we need to evaluate how good the learned policy by using held out historical data. This is called as off-policy evaluation or counterfactual evaluation. In this notebook, we evaluate the policy during the training using several off-policy evaluation metrics. \n", + "\n", + "We can deploy the policy using SageMaker Hosting endpoint. However, some use cases may not require a persistent serving endpoint with sub-second latency. Here we demonstrate how to deploy the policy with [SageMaker Batch Transform](https://docs.aws.amazon.com/sagemaker/latest/dg/batch-transform.html), where large volumes of input state features can be inferenced with high throughput.\n", + "\n", + "Figure below shows an overview of the entire notebook.\n", + "\n", + "![Batch RL in Notebook](./batch_rl.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pre-requisites\n", + "\n", + "### Roles and permissions\n", + "\n", + "To get started, we'll import the Python libraries we need, set up the environment with a few pre-requisites for permissions and configurations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sagemaker\n", + "import boto3\n", + "import sys\n", + "import os\n", + "import glob\n", + "import re\n", + "import subprocess\n", + "from IPython.display import HTML\n", + "import time\n", + "from time import gmtime, strftime\n", + "sys.path.append(\"common\")\n", + "from misc import get_execution_role, wait_for_s3_object\n", + "from sagemaker.rl import RLEstimator, RLToolkit, RLFramework\n", + "# install gym environments if needed\n", + "!pip install gym\n", + "from env_utils import VectoredGymEnvironment" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Steup S3 buckets\n", + "\n", + "Setup the linkage and authentication to the S3 bucket that you want to use for checkpoint and the metadata. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# S3 bucket\n", + "sage_session = sagemaker.session.Session()\n", + "s3_bucket = sage_session.default_bucket() \n", + "region_name = sage_session.boto_region_name\n", + "s3_output_path = 's3://{}/'.format(s3_bucket) # SDK appends the job name and output folder\n", + "print(\"S3 bucket path: {}\".format(s3_output_path))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Define Variables \n", + "\n", + "We define variables such as the job prefix for the training jobs *and the image path for the container (only when this is BYOC).*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# create unique job name \n", + "job_name_prefix = 'rl-batch-cartpole'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Configure settings\n", + "\n", + "You can run your RL training jobs on a SageMaker notebook instance or on your own machine. In both of these scenarios, you can run the following in either `local` or `SageMaker` modes. The `local` mode uses the SageMaker Python SDK to run your code in a local container before deploying to SageMaker. This can speed up iterative testing and debugging while using the same familiar Python SDK interface. You just need to set `local_mode = True`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "# run in local mode?\n", + "local_mode = False\n", + "\n", + "image = '462105765813.dkr.ecr.{}.amazonaws.com/sagemaker-rl-coach-container:coach-1.0.0-tf-cpu-py3'.format(region_name)\n", + "print(\"Use ECR image: {}\".format(image))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Create an IAM role\n", + "Either get the execution role when running from a SageMaker notebook `role = sagemaker.get_execution_role()` or, when running from local machine, use utils method `role = get_execution_role()` to create an execution role." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " role = sagemaker.get_execution_role()\n", + "except:\n", + " role = get_execution_role()\n", + " \n", + "print(\"Using IAM role arn: {}\".format(role))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install docker for `local` mode\n", + "\n", + "In order to work in `local` mode, you need to have docker installed. When running from you local machine, please make sure that you have docker or docker-compose (for local CPU machines) and nvidia-docker (for local GPU machines) installed. Alternatively, when running from a SageMaker notebook instance, you can simply run the following script to install dependenceis.\n", + "\n", + "Note, you can only run a single local notebook at one time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# only run from SageMaker notebook instance\n", + "if local_mode:\n", + " !/bin/bash ./common/setup.sh" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Collect offline data\n", + "\n", + "In order to do Batch RL training, we need to first prepare the dataset that is generated by a deployed policy. In real world scenarios, customers can collect these offline data by interacting the live environment using the already deployed agent. In this notebook, we used OpenAI gym `Cartpole-v0` as the environment to mimic a live environment and used a random policy with uniform action distribution to mimic a deployed agent. By interacting with multiple environments simultaneously, we can gather more trajectories from the environments.\n", + "\n", + "Here is a short introduction of the cart-pole balancing problem, where a pole is attached by an un-actuated joint to a cart, moving along a frictionless track.\n", + "\n", + "1. *Objective*: Prevent the pole from falling over\n", + "2. *Environment*: The environment used in this example is part of OpenAI Gym, corresponding to the version of the cart-pole problem described by Barto, Sutton, and Anderson [2]\n", + "3. *State*: Cart position, cart velocity, pole angle, pole velocity at tip\t\n", + "4. *Action*: Push cart to the left, push cart to the right\n", + "5. *Reward*: Reward is 1 for every step taken, including the termination step" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# initiate 100 environment to collect rollout data\n", + "NUM_ENVS = 100\n", + "NUM_EPISODES = 5\n", + "vectored_envs = VectoredGymEnvironment('CartPole-v0', NUM_ENVS)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we have 100 environments of `Cartpole-v0` ready. We'll collect 5 episodes from each environment so we’ll have 500 episodes of data for training. We start from a random policy that generates the same uniform action probabilities regardless of the state features." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# initiate a random policy by setting action probabilities as uniform distribution \n", + "action_probs = [[1/2, 1/2] for _ in range(NUM_ENVS)]\n", + "df = vectored_envs.collect_rollouts_with_given_action_probs(action_probs=action_probs, num_episodes=NUM_EPISODES)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# the rollout dataframes contain attributes: action, action_probs, episode_id, reward, cumulative_rewards, state_features\n", + "# only show cumulative rewards at the last step of the episode\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use the average cumulative reward of the random policy as a baseline for the Batch RL trained policy. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# average cumulative rewards for each episode\n", + "avg_rewards = df['cumulative_rewards'].sum() / (NUM_ENVS * NUM_EPISODES)\n", + "print(\"Average cumulative rewards over {} episodes rollouts was {}.\".format((NUM_ENVS * NUM_EPISODES), avg_rewards))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Save Dataframe as CSV for Batch RL Training\n", + "\n", + "Coach Batch RL support reading off policy data in CSV format. We will dump our collected rollout data in CSV format." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# dump dataframe as csv file\n", + "df.to_csv(\"src/cartpole_dataset.csv\", index=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configure the presets for RL algorithm \n", + "\n", + "The presets that configure the Batch RL training jobs are defined in the `preset-cartpole-ddqnbcq.py` file which is also uploaded on the `/src` directory. Using the preset file, you can define agent parameters to select the specific agent algorithm. You can also set the environment parameters, define the schedule and visualization parameters, and define the graph manager. The schedule presets will define the number of heat up steps, periodic evaluation steps, training steps between evaluations.\n", + "\n", + "These can be overridden at runtime by specifying the `RLCOACH_PRESET` hyperparameter. Additionally, it can be used to define custom hyperparameters. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "!pygmentize src/preset-cartpole-ddqnbcq.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook, we use DDQN[6] to update the policy in an off-policy manner, and combine it with BCQ[5] to address the error induced by inaccurately estimated values for unseen state-action pairs. The training is completely off-line." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Write the Training Code \n", + "\n", + "The training code is written in the file “train-coach.py” which is uploaded in the /src directory. \n", + "First import the environment files and the preset files, and then define the `main()` function. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "!pygmentize src/train-coach.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Train the RL model using the Python SDK Script mode\n", + "\n", + "If you are using local mode, the training will run on the notebook instance. When using SageMaker for training, you can select a GPU or CPU instance. The RLEstimator is used for training RL jobs. \n", + "\n", + "1. Specify the source directory where the environment, presets and training code is uploaded.\n", + "2. Specify the entry point as the training code \n", + "3. Define the training parameters such as the instance count, job name, S3 path for output and job name. \n", + "4. Specify the hyperparameters for the RL agent algorithm. The `RLCOACH_PRESET` can be used to specify the RL agent algorithm you want to use. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "if local_mode:\n", + " instance_type = 'local'\n", + "else:\n", + " instance_type = \"ml.m4.xlarge\"\n", + " \n", + "estimator = RLEstimator(entry_point=\"train-coach.py\",\n", + " source_dir='src',\n", + " dependencies=[\"common/sagemaker_rl\"],\n", + " image_name=image,\n", + " role=role,\n", + " train_instance_type=instance_type,\n", + " train_instance_count=1,\n", + " output_path=s3_output_path,\n", + " base_job_name=job_name_prefix,\n", + " hyperparameters = {\n", + " \"RLCOACH_PRESET\": \"preset-cartpole-ddqnbcq\",\n", + " \"save_model\": 1\n", + " }\n", + " )\n", + "estimator.fit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Store intermediate training output and model checkpoints \n", + "\n", + "The output from the training job above is stored on S3. The intermediate folder contains gifs and metadata of the training. We'll need these metadata for metrics visualization and model evaluations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "job_name=estimator._current_job_name\n", + "print(\"Job name: {}\".format(job_name))\n", + "\n", + "s3_url = \"s3://{}/{}\".format(s3_bucket,job_name)\n", + "\n", + "if local_mode:\n", + " output_tar_key = \"{}/output.tar.gz\".format(job_name)\n", + "else:\n", + " output_tar_key = \"{}/output/output.tar.gz\".format(job_name)\n", + "\n", + "intermediate_folder_key = \"{}/output/intermediate/\".format(job_name)\n", + "output_url = \"s3://{}/{}\".format(s3_bucket, output_tar_key)\n", + "intermediate_url = \"s3://{}/{}\".format(s3_bucket, intermediate_folder_key)\n", + "\n", + "print(\"S3 job path: {}\".format(s3_url))\n", + "print(\"Output.tar.gz location: {}\".format(output_url))\n", + "print(\"Intermediate folder path: {}\".format(intermediate_url))\n", + " \n", + "tmp_dir = \"/tmp/{}\".format(job_name)\n", + "os.system(\"mkdir {}\".format(tmp_dir))\n", + "print(\"Create local folder {}\".format(tmp_dir))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualization" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot metrics for training job\n", + "We can pull the Off Policy Evaluation(OPE) metric of the training and plot it to see the performance of the model over time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "\n", + "csv_file_name = \"worker_0.batch_rl_graph.main_level.main_level.agent_0.csv\"\n", + "key = os.path.join(intermediate_folder_key, csv_file_name)\n", + "wait_for_s3_object(s3_bucket, key, tmp_dir, training_job_name=job_name)\n", + "\n", + "csv_file = \"{}/{}\".format(tmp_dir, csv_file_name)\n", + "df = pd.read_csv(csv_file)\n", + "df = df.dropna(subset=['Sequential Doubly Robust'])\n", + "df.dropna(subset=['Weighted Importance Sampling'])\n", + " \n", + "plt.figure(figsize=(12,5))\n", + "plt.xlabel('Number of epochs')\n", + "\n", + "ax1 = df['Weighted Importance Sampling'].plot(color='blue', grid=True, label='WIS')\n", + "ax2 = df['Sequential Doubly Robust'].plot(color='red', grid=True, secondary_y=True, label='SDR')\n", + "\n", + "h1, l1 = ax1.get_legend_handles_labels()\n", + "h2, l2 = ax2.get_legend_handles_labels()\n", + "\n", + "plt.legend(h1+h2, l1+l2, loc=1)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There is a set of methods used to investigate the performance of the current trained policy without interacting with simulator / live environment. They can be used to estimate the goodness of the policy, based on the dataset collected from other policy. Here we showed two of these OPE metrics: WIS (Weighted Importance Sampling) [3] and SDR (Sequential Doubly Robust) [4]. As we can see in the plot, these metrics are improving as the learning agent is iterating over the given dataset." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation of RL models\n", + "\n", + "To evaluate the model trained with off policy data, we need to see the accumulative rewards of the agent by interacting with the environment. We use the last checkpointed model to run evaluation of the RL Agent. We use a different preset file here `preset-cartpole-ddqnbcq-env.py` to let the RL agent interact with the environment and collect rewards.\n", + "\n", + "### Load checkpointed model\n", + "\n", + "Checkpoint is passed on for evaluation / inference in the checkpoint channel. In local mode, we can simply use the local directory, whereas in the SageMaker mode, it needs to be moved to S3 first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "wait_for_s3_object(s3_bucket, output_tar_key, tmp_dir, training_job_name=job_name) \n", + "\n", + "if not os.path.isfile(\"{}/output.tar.gz\".format(tmp_dir)):\n", + " raise FileNotFoundError(\"File output.tar.gz not found\")\n", + "os.system(\"tar -xvzf {}/output.tar.gz -C {}\".format(tmp_dir, tmp_dir))\n", + "\n", + "if local_mode:\n", + " checkpoint_dir = \"{}/data/checkpoint\".format(tmp_dir)\n", + "else:\n", + " checkpoint_dir = \"{}/checkpoint\".format(tmp_dir)\n", + "\n", + "print(\"Checkpoint directory {}\".format(checkpoint_dir))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if local_mode:\n", + " checkpoint_path = 'file://{}'.format(checkpoint_dir)\n", + " print(\"Local checkpoint file path: {}\".format(checkpoint_path))\n", + "else:\n", + " checkpoint_path = \"s3://{}/{}/checkpoint/\".format(s3_bucket, job_name)\n", + " if not os.listdir(checkpoint_dir):\n", + " raise FileNotFoundError(\"Checkpoint files not found under the path\")\n", + " os.system(\"aws s3 cp --recursive {} {}\".format(checkpoint_dir, checkpoint_path))\n", + " print(\"S3 checkpoint file path: {}\".format(checkpoint_path))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "estimator_eval = RLEstimator(entry_point=\"evaluate-coach.py\",\n", + " source_dir='src',\n", + " dependencies=[\"common/sagemaker_rl\"],\n", + " image_name=image,\n", + " role=role,\n", + " train_instance_type=instance_type,\n", + " train_instance_count=1,\n", + " output_path=s3_output_path,\n", + " base_job_name=job_name_prefix,\n", + " hyperparameters = {\n", + " \"RLCOACH_PRESET\": \"preset-cartpole-ddqnbcq-env\",\n", + " \"evaluate_steps\": 1000\n", + " }\n", + " )\n", + "\n", + "\n", + "estimator_eval.fit({'checkpoint': checkpoint_path})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Batch Transform\n", + "\n", + "As we can see from the above evaluation job, the trained agent gets a total reward of around `200` as compared to a total reward around `25` in our offline dataset. Therefore, we can confirm that the agent has learned a better policy from the off-policy data.\n", + "\n", + "After we get the trained model, we can use it to do SageMaker Batch Transform, where customers can provide large volumes of input state features and get predictions with high throughput." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "from sagemaker.tensorflow.serving import Model\n", + "if local_mode:\n", + " sage_session = sagemaker.local.LocalSession()\n", + "\n", + "# Create SageMaker model entity by using model data generated by the estimator \n", + "model = Model(model_data=estimator.model_data,\n", + " sagemaker_session=sage_session,\n", + " role=role)\n", + "\n", + "prefix = \"batch_test\"\n", + "\n", + "# setup input data prefix and output data prefix for batch transform\n", + "batch_input = 's3://{}/{}/{}/input/'.format(s3_bucket, job_name, prefix) # The location of the test dataset\n", + "batch_output = 's3://{}/{}/{}/output/'.format(s3_bucket, job_name, prefix) # The location to store the results of the batch transform job\n", + "print(\"Inputpath for batch transform: {}\".format(batch_input))\n", + "print(\"Outputpath for batch transform: {}\".format(batch_output))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook, we use the states of the environments as input for the Batch Transform." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "file_name = 'env_states_{}.json'.format(int(time.time()))\n", + "# resetting the environments\n", + "vectored_envs.reset_all_envs()\n", + "# dump environment states into jsonlines file\n", + "vectored_envs.dump_environment_states(tmp_dir, file_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to use SageMaker Batch Transform, we'll need to first upload the input data from local to S3 bucket" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "from pathlib import Path\n", + "\n", + "local_input_file_path = Path(tmp_dir) / file_name\n", + "s3_input_file_path = batch_input + file_name # Path library will remove :// from s3 path\n", + "print(\"Copy file from local path '{}' to s3 path '{}'\".format(local_input_file_path, s3_input_file_path))\n", + "assert os.system(\"aws s3 cp {} {}\".format(local_input_file_path, s3_input_file_path)) == 0\n", + "print(\"S3 batch input file path: {}\".format(s3_input_file_path))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similar to how we launch a training job on SageMaker, we can initiate a batch transform job either in `Local` mode or `SageMaker` mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if local_mode:\n", + " instance_type = 'local'\n", + "else:\n", + " instance_type = \"ml.m4.xlarge\"\n", + "\n", + "transformer = model.transformer(instance_count=1, instance_type=instance_type, output_path=batch_output, assemble_with = 'Line', accept = 'application/jsonlines', strategy='SingleRecord')\n", + "\n", + "transformer.transform(data=batch_input, data_type='S3Prefix', content_type='application/jsonlines', split_type='Line', join_source='Input')\n", + "\n", + "transformer.wait()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After we finished the batch transform job, we can download the prediction output from S3 bucket to local machine." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import subprocess\n", + "\n", + "# get the latest generated output file\n", + "cmd = \"aws s3 ls {} --recursive | sort | tail -n 1\".format(batch_output)\n", + "result = subprocess.check_output(cmd, shell=True).decode(\"utf-8\").split(' ')[-1].strip()\n", + "local_output_file_path = Path(tmp_dir) / f\"{file_name}.out\"\n", + "s3_output_file_path = 's3://{}/{}'.format(s3_bucket,result)\n", + "print(\"Copy file from s3 path '{}' to local path '{}'\".format(s3_output_file_path, local_output_file_path))\n", + "os.system(\"aws s3 cp {} {}\".format(s3_output_file_path, local_output_file_path))\n", + "print(\"S3 batch output file local path: {}\".format(local_output_file_path))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import subprocess\n", + "\n", + "batcmd=\"cat {}\".format(local_output_file_path)\n", + "results = subprocess.check_output(batcmd, shell=True).decode(\"utf-8\").split('\\n')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "results[:10]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook, we use simulated environments to collect rollout data of a random policy. Assuming the updated policy is now deployed, we can use Batch Transform to collect rollout data from this policy. \n", + "\n", + "Here are the steps on how to collect rollout data with Batch Transform:\n", + "1. Use Batch Transform to get action predictions, provided observation features from the live environment at timestep *t*\n", + "2. Deployed agent takes suggested actions against the environment (simulator / real) at timestep *t*\n", + "3. Environment returns new observation features at timestep *t+1*\n", + "4. Return back to step 1. Use Batch Transform to get action predictions at timestep *t+1*\n", + "\n", + "This iterative procedure enables us to collect a set of data that can cover the whole episode, similar to what we've shown at the beginning of the notebook. Once the data is sufficient, we can use these data to kick off a BatchRL training again.\n", + "\n", + "Batch Transform works well when there are multiple episodes interacting with the environments concurrently. One of the typical use cases is email campaign, where each email user is an independent episode interacting with the deployed policy. Batch Transform can concurrently collect rollout data from millions of user context with efficiency. The collected rollout data can then be supplied to Batch RL Training to train a better policy to serve the email users." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reference\n", + "\n", + "1. Batch Reinforcement Learning with Coach: https://github.com/NervanaSystems/coach/blob/master/tutorials/4.%20Batch%20Reinforcement%20Learning.ipynb\n", + "2. AG Barto, RS Sutton and CW Anderson, \"Neuronlike Adaptive Elements That Can Solve Difficult Learning Control Problem\", IEEE Transactions on Systems, Man, and Cybernetics, 1983.\n", + "3. Thomas, Philip, Georgios Theocharous, and Mohammad Ghavamzadeh. \"High confidence policy improvement.\" International Conference on Machine Learning. 2015.\n", + "4. Jiang, Nan, and Lihong Li. \"Doubly robust off-policy value evaluation for reinforcement learning.\" arXiv preprint arXiv:1511.03722 (2015).\n", + "5. Fujimoto, Scott, David Meger, and Doina Precup. \"Off-policy deep reinforcement learning without exploration.\" arXiv preprint arXiv:1812.02900 (2018)\n", + "6. Van Hasselt, Hado, Arthur Guez, and David Silver. \"Deep reinforcement learning with double q-learning.\" Thirtieth AAAI conference on artificial intelligence. 2016." + ] + } + ], + "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/reinforcement_learning/rl_cartpole_batch_coach/src/__init__.py b/reinforcement_learning/rl_cartpole_batch_coach/src/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/reinforcement_learning/rl_cartpole_batch_coach/src/evaluate-coach.py b/reinforcement_learning/rl_cartpole_batch_coach/src/evaluate-coach.py new file mode 100644 index 0000000000..0d6875a8c8 --- /dev/null +++ b/reinforcement_learning/rl_cartpole_batch_coach/src/evaluate-coach.py @@ -0,0 +1,91 @@ +from sagemaker_rl.coach_launcher import SageMakerCoachPresetLauncher, CoachConfigurationList +import argparse +import os +import rl_coach +from rl_coach.base_parameters import Frameworks, TaskParameters +from rl_coach.core_types import EnvironmentSteps + + +def inplace_replace_in_file(filepath, old, new): + with open(filepath, 'r') as f: + contents = f.read() + with open(filepath, 'w') as f: + contents = contents.replace(old, new) + f.write(contents) + + +class MyLauncher(SageMakerCoachPresetLauncher): + + def default_preset_name(self): + """This points to a .py file that configures everything about the RL job. + It can be overridden at runtime by specifying the RLCOACH_PRESET hyperparameter. + """ + return 'preset-cartpole-dqn' + + def start_single_threaded(self, task_parameters, graph_manager, args): + """Override to use custom evaluate_steps, instead of infinite steps. Just evaluate. + """ + graph_manager.agent_params.visualization.dump_csv = False # issues with CSV export in evaluation only + graph_manager.create_graph(task_parameters) + graph_manager.evaluate(EnvironmentSteps(args.evaluate_steps)) + graph_manager.close() + + def get_config_args(self, parser): + """Overrides the default CLI parsing. + Sets the configuration parameters for what a SageMaker run should do. + Note, this does not support the "play" mode. + """ + ### Parse Arguments + # first, convert the parser to a Namespace object with all default values. + empty_arg_list = [] + args, _ = parser.parse_known_args(args=empty_arg_list) + parser = self.sagemaker_argparser() + sage_args, unknown = parser.parse_known_args() + + ### Set Arguments + args.preset = sage_args.RLCOACH_PRESET + backend = os.getenv('COACH_BACKEND', 'tensorflow') + args.framework = args.framework = Frameworks[backend] + args.checkpoint_save_dir = None + args.checkpoint_restore_dir = "/opt/ml/input/data/checkpoint" + # Correct TensorFlow checkpoint file (https://github.com/tensorflow/tensorflow/issues/9146) + if backend == "tensorflow": + checkpoint_filepath = os.path.join(args.checkpoint_restore_dir, 'checkpoint') + inplace_replace_in_file(checkpoint_filepath, "/opt/ml/output/data/checkpoint", ".") + # Override experiment_path used for outputs (note CSV not stored, see `start_single_threaded`). + args.experiment_path = '/opt/ml/output/intermediate' + rl_coach.logger.experiment_path = '/opt/ml/output/intermediate' # for gifs + args.evaluate = True # not actually used, but must be set (see `evaluate_steps`) + args.evaluate_steps = sage_args.evaluate_steps + args.no_summary = True # so process doesn't hang at end + # must be set + self.hyperparameters = CoachConfigurationList() + + return args + + def sagemaker_argparser(self): + """ + Expose only the CLI arguments that make sense in the SageMaker context. + """ + parser = argparse.ArgumentParser() + parser.add_argument('-p', '--RLCOACH_PRESET', + help="(string) Name of the file with the RLCoach preset", + default=self.default_preset_name(), + type=str) + parser.add_argument('--evaluate_steps', + help="(int) Number of evaluation steps to takr", + default=1000, + type=int) + return parser + + @classmethod + def evaluate_main(cls): + """Entrypoint for training. + Parses command-line arguments and starts training. + """ + evaluator = cls() + evaluator.launch() + + +if __name__ == '__main__': + MyLauncher.evaluate_main() \ No newline at end of file diff --git a/reinforcement_learning/rl_cartpole_batch_coach/src/preset-cartpole-ddqnbcq-env.py b/reinforcement_learning/rl_cartpole_batch_coach/src/preset-cartpole-ddqnbcq-env.py new file mode 100644 index 0000000000..c27b10b5c0 --- /dev/null +++ b/reinforcement_learning/rl_cartpole_batch_coach/src/preset-cartpole-ddqnbcq-env.py @@ -0,0 +1,78 @@ +from rl_coach.agents.clipped_ppo_agent import ClippedPPOAgentParameters +from rl_coach.agents.dqn_agent import DQNAgentParameters +from rl_coach.agents.ddqn_bcq_agent import DDQNBCQAgentParameters +from rl_coach.architectures.layers import Dense +from rl_coach.base_parameters import VisualizationParameters, PresetValidationParameters, DistributedCoachSynchronizationType +from rl_coach.core_types import TrainingSteps, EnvironmentEpisodes, EnvironmentSteps, RunPhase, CsvDataset +from rl_coach.environments.gym_environment import GymVectorEnvironment, mujoco_v2 +from rl_coach.exploration_policies.e_greedy import EGreedyParameters +from rl_coach.graph_managers.basic_rl_graph_manager import BasicRLGraphManager +from rl_coach.graph_managers.batch_rl_graph_manager import BatchRLGraphManager +from rl_coach.graph_managers.graph_manager import ScheduleParameters +from rl_coach.memories.memory import MemoryGranularity +from rl_coach.schedules import LinearSchedule +from rl_coach.memories.episodic import EpisodicExperienceReplayParameters +from rl_coach.agents.ddqn_bcq_agent import KNNParameters +from rl_coach.spaces import SpacesDefinition, DiscreteActionSpace, VectorObservationSpace, StateSpace, RewardSpace + +# #################### +# # Graph Scheduling # +# #################### + +schedule_params = ScheduleParameters() +# 50 epochs (we run train over all the dataset, every epoch) of training +schedule_params.improve_steps = TrainingSteps(50) +# we evaluate the model every epoch +schedule_params.steps_between_evaluation_periods = TrainingSteps(1) + + +######### +# Agent # +######### +# note that we have moved to BCQ, which will help the training to converge better and faster +agent_params = DDQNBCQAgentParameters() +agent_params.network_wrappers['main'].batch_size = 128 +agent_params.algorithm.num_steps_between_copying_online_weights_to_target = TrainingSteps(50) +agent_params.algorithm.discount = 0.99 + +# NN configuration +agent_params.network_wrappers['main'].learning_rate = 0.0001 +agent_params.network_wrappers['main'].replace_mse_with_huber_loss = False + +# ER - we'll be needing an episodic replay buffer for off-policy evaluation +agent_params.memory = EpisodicExperienceReplayParameters() + +# E-Greedy schedule - there is no exploration in Batch RL. Disabling E-Greedy. +agent_params.exploration.epsilon_schedule = LinearSchedule(initial_value=0, final_value=0, decay_steps=1) +agent_params.exploration.evaluation_epsilon = 0 + +# can use either a kNN or a NN based model for predicting which actions not to max over in the bellman equation +agent_params.algorithm.action_drop_method_parameters = KNNParameters() + + +################# +# Visualization # +################# + +vis_params = VisualizationParameters() +vis_params.dump_gifs = True + +################ +# Environment # +################ +env_params = GymVectorEnvironment(level='CartPole-v0') + +######## +# Test # +######## +preset_validation_params = PresetValidationParameters() +preset_validation_params.test = True +preset_validation_params.min_reward_threshold = 150 +preset_validation_params.max_episodes_to_achieve_reward = 250 + + +graph_manager = BatchRLGraphManager(agent_params=agent_params, + env_params=env_params, + schedule_params=schedule_params, + vis_params=vis_params, + preset_validation_params=preset_validation_params) diff --git a/reinforcement_learning/rl_cartpole_batch_coach/src/preset-cartpole-ddqnbcq.py b/reinforcement_learning/rl_cartpole_batch_coach/src/preset-cartpole-ddqnbcq.py new file mode 100644 index 0000000000..e6c1bfcb15 --- /dev/null +++ b/reinforcement_learning/rl_cartpole_batch_coach/src/preset-cartpole-ddqnbcq.py @@ -0,0 +1,79 @@ +from rl_coach.agents.ddqn_bcq_agent import DDQNBCQAgentParameters +from rl_coach.base_parameters import VisualizationParameters, PresetValidationParameters +from rl_coach.core_types import TrainingSteps, EnvironmentEpisodes, EnvironmentSteps, RunPhase, CsvDataset +from rl_coach.graph_managers.batch_rl_graph_manager import BatchRLGraphManager +from rl_coach.graph_managers.graph_manager import ScheduleParameters +from rl_coach.schedules import LinearSchedule +from rl_coach.memories.episodic import EpisodicExperienceReplayParameters +from rl_coach.agents.ddqn_bcq_agent import KNNParameters +from rl_coach.spaces import SpacesDefinition, DiscreteActionSpace, VectorObservationSpace, StateSpace, RewardSpace + +# #################### +# # Graph Scheduling # +# #################### + +schedule_params = ScheduleParameters() +# 50 epochs (we run train over all the dataset, every epoch) of training +schedule_params.improve_steps = TrainingSteps(50) +# we evaluate the model every epoch +schedule_params.steps_between_evaluation_periods = TrainingSteps(1) + +######### +# Agent # +######### +# note that we have moved to BCQ, which will help the training to converge better and faster +agent_params = DDQNBCQAgentParameters() +agent_params.network_wrappers['main'].batch_size = 128 +agent_params.algorithm.num_steps_between_copying_online_weights_to_target = TrainingSteps(50) +agent_params.algorithm.discount = 0.99 + +# NN configuration +agent_params.network_wrappers['main'].learning_rate = 0.0001 +agent_params.network_wrappers['main'].replace_mse_with_huber_loss = False + +# ER - we'll be needing an episodic replay buffer for off-policy evaluation +agent_params.memory = EpisodicExperienceReplayParameters() + +# E-Greedy schedule - there is no exploration in Batch RL. Disabling E-Greedy. +agent_params.exploration.epsilon_schedule = LinearSchedule(initial_value=0, final_value=0, decay_steps=1) +agent_params.exploration.evaluation_epsilon = 0 + +# can use either a kNN or a NN based model for predicting which actions not to max over in the bellman equation +agent_params.algorithm.action_drop_method_parameters = KNNParameters() + +########### +# Dataset # +########### +DATATSET_PATH = 'cartpole_dataset.csv' +agent_params.memory = EpisodicExperienceReplayParameters() +agent_params.memory.load_memory_from_file_path = CsvDataset(DATATSET_PATH, is_episodic = True) + +spaces = SpacesDefinition(state=StateSpace({'observation': VectorObservationSpace(shape=4)}), + goal=None, + action=DiscreteActionSpace(2), + reward=RewardSpace(1)) + +################# +# Visualization # +################# + +vis_params = VisualizationParameters() +vis_params.dump_gifs = True + +######## +# Test # +######## +preset_validation_params = PresetValidationParameters() +preset_validation_params.test = True +preset_validation_params.min_reward_threshold = 150 +preset_validation_params.max_episodes_to_achieve_reward = 250 + + +graph_manager = BatchRLGraphManager(agent_params=agent_params, + env_params=None, + spaces_definition=spaces, + schedule_params=schedule_params, + vis_params=vis_params, + reward_model_num_epochs=30, + train_to_eval_ratio=0.4, + preset_validation_params=preset_validation_params) diff --git a/reinforcement_learning/rl_cartpole_batch_coach/src/train-coach.py b/reinforcement_learning/rl_cartpole_batch_coach/src/train-coach.py new file mode 100644 index 0000000000..b6cdf532e2 --- /dev/null +++ b/reinforcement_learning/rl_cartpole_batch_coach/src/train-coach.py @@ -0,0 +1,61 @@ +from sagemaker_rl.coach_launcher import SageMakerCoachPresetLauncher +import shutil + +class MyLauncher(SageMakerCoachPresetLauncher): + + def default_preset_name(self): + """This points to a .py file that configures everything about the RL job. + It can be overridden at runtime by specifying the RLCOACH_PRESET hyperparameter. + """ + return 'preset-acrobot-dqn' + + def map_hyperparameter(self, name, value): + """Here we configure some shortcut names for hyperparameters that we expect to use frequently. + Essentially anything in the preset file can be overridden through a hyperparameter with a name + like "rl.agent_params.algorithm.etc". + """ + # maps from alias (key) to fully qualified coach parameter (value) + mapping = { + "discount": "rl.agent_params.algorithm.discount", + "evaluation_episodes": "rl.evaluation_steps:EnvironmentEpisodes", + "improve_steps": "rl.improve_steps:TrainingSteps" + } + if name in mapping: + self.apply_hyperparameter(mapping[name], value) + else: + super().map_hyperparameter(name, value) + + def _save_tf_model(self): + import tensorflow as tf + ckpt_dir = '/opt/ml/output/data/checkpoint' + model_dir = '/opt/ml/model' + + # Re-Initialize from the checkpoint so that you will have the latest models up. + tf.train.init_from_checkpoint(ckpt_dir, + {'main_level/agent/online/network_0/': 'main_level/agent/online/network_0'}) + tf.train.init_from_checkpoint(ckpt_dir, + {'main_level/agent/online/network_1/': 'main_level/agent/online/network_1'}) + + # Create a new session with a new tf graph. + sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True)) + sess.run(tf.global_variables_initializer()) # initialize the checkpoint. + + # print([n.name for n in tf.get_default_graph().as_graph_def().node]) + # This is the node that will accept the input. + input_nodes = tf.get_default_graph().get_tensor_by_name('main_level/agent/main/online/' + \ + 'network_0/observation/observation:0') + # This is the node that will produce the output. + output_nodes = tf.get_default_graph().get_operation_by_name('main_level/agent/main/online/' + \ + 'network_0/q_values_head_0/softmax') + # Save the model as a servable model. + tf.saved_model.simple_save(session=sess, + export_dir='model', + inputs={"observation": input_nodes}, + outputs={"policy": output_nodes.outputs[0]}) + # Move to the appropriate folder. + shutil.move('model/', model_dir + '/model/tf-model/00000001/') + # SageMaker will pick it up and upload to the right path. + print("Success") + +if __name__ == '__main__': + MyLauncher.train_main()