No account yet ?
Reinforcement learning is one of the three basic paradigms of machine learning such as supervised learning and unsupervised learning.
Reinforcement learning is a method of statistical learning, inspired by life learning.
Reinforcement learning involves letting computers learn from their experiences through a reward or penalty system.
Reinforcement Learning (RL) refers to a class of machine learning problems, the purpose of which is to learn, from successive experiences, what to do in order to find the best solution.
Reinforcement learning differs fundamentally from supervised and unsupervised problems by this interactive and iterative side, reinforcement learning explores several solutions and observes the reaction of the environment to then adapt its behavior by modifying the variables to find the best one. strategy.
Reinforcement learning must find the balance between the exploration phase and the exploitation phase.
This method is particularly suitable for problems requiring a compromise between the pursuit of short-term rewards and that of long-term rewards.
Reinforcement learning is a type of machine learning paradigm in which a learning algorithm is not trained on predefined data but rather on a feedback system.
Reinforcement learning refers to the set of methods that allow an agent to learn to choose which action to take, and this in an autonomous way.
Regardless of its environment, the agent learns by receiving rewards or penalties based on its actions.
Through his experience, he seeks to find the optimal decision-making strategy that can allow him to maximize the rewards accumulated over time.
Reinforcement learning is the future of machine learning because it eliminates the cost of data collection and cleaning.
Reinforcement learning introduces concepts and metrics, the main ones being:
The agent which is the system or the robot which interacts and acts in a given environment.
The action "a" which is an action among the set of actions.
The state "s" which is a particular situation in which the system or the agent finds itself.
The policy "π" which is the strategy that defines the behavior of the system or the agent.
In the case of a deterministic policy, the action "a" is defined by a = π(a|s).
In the case of a stochastic policy, the probability of action "a" is defined by p(a|s)= π(a|s).
The Reward r(s,a) which is the positive or negative gain collected by performing action "a" in state "s".
The objective is to maximize the total benefits of a policy.
The episode which is defined as the sequence of actions carried out until the end state or a predefined duration of action.
The Value Function V(s) which is the value function of a state "s" is the total amount of rewards an agent expects to be able to collect from that state until the end of the episode.
The action-value function Q(s, a) which is the action-value function "a" at state "s" is the total amount of rewards expected by taking action "a" at state " s" until the end of the episode.
Deep Deterministic Policy Gradient (DDPG)
Tested in Anaconda and Python 3.7
import gym import tensorflow as tf tf.enable_eager_execution() from tensorflow.keras import layers import numpy as np import matplotlib.pyplot as plt problem = "Pendulum-v1" env = gym.make(problem) num_states = env.observation_space.shape[0] print("Size of State Space -> {}".format(num_states)) num_actions = env.action_space.shape[0] print("Size of Action Space -> {}".format(num_actions)) upper_bound = env.action_space.high[0] lower_bound = env.action_space.low[0] print("Max Value of Action -> {}".format(upper_bound)) print("Min Value of Action -> {}".format(lower_bound)) class OUActionNoise: def __init__(self, mean, std_deviation, theta=0.15, dt=1e-2, x_initial=None): self.theta = theta self.mean = mean self.std_dev = std_deviation self.dt = dt self.x_initial = x_initial self.reset() def __call__(self): # Formula taken from https://www.wikipedia.org/wiki/Ornstein-Uhlenbeck_process. x = ( self.x_prev + self.theta * (self.mean - self.x_prev) * self.dt + self.std_dev * np.sqrt(self.dt) * np.random.normal(size=self.mean.shape) ) # Store x into x_prev # Makes next noise dependent on current one self.x_prev = x return x def reset(self): if self.x_initial is not None: self.x_prev = self.x_initial else: self.x_prev = np.zeros_like(self.mean) class Buffer: def __init__(self, buffer_capacity=100000, batch_size=64): # Number of "experiences" to store at max self.buffer_capacity = buffer_capacity # Num of tuples to train on. self.batch_size = batch_size # Its tells us num of times record() was called. self.buffer_counter = 0 # Instead of list of tuples as the exp.replay concept go # We use different np.arrays for each tuple element self.state_buffer = np.zeros((self.buffer_capacity, num_states)) self.action_buffer = np.zeros((self.buffer_capacity, num_actions)) self.reward_buffer = np.zeros((self.buffer_capacity, 1)) self.next_state_buffer = np.zeros((self.buffer_capacity, num_states)) # Takes (s,a,r,s') obervation tuple as input def record(self, obs_tuple): # Set index to zero if buffer_capacity is exceeded, # replacing old records index = self.buffer_counter % self.buffer_capacity self.state_buffer[index] = obs_tuple[0] self.action_buffer[index] = obs_tuple[1] self.reward_buffer[index] = obs_tuple[2] self.next_state_buffer[index] = obs_tuple[3] self.buffer_counter += 1 # Eager execution is turned on by default in TensorFlow 2. Decorating with tf.function allows # TensorFlow to build a static graph out of the logic and computations in our function. # This provides a large speed up for blocks of code that contain many small TensorFlow operations such as this one. @tf.function def update( self, state_batch, action_batch, reward_batch, next_state_batch, ): # Training and updating Actor & Critic networks. # See Pseudo Code. with tf.GradientTape() as tape: target_actions = target_actor(next_state_batch, training=True) y = reward_batch + gamma * target_critic( [next_state_batch, target_actions], training=True ) critic_value = critic_model([state_batch, action_batch], training=True) critic_loss = tf.math.reduce_mean(tf.math.square(y - critic_value)) critic_grad = tape.gradient(critic_loss, critic_model.trainable_variables) critic_optimizer.apply_gradients( zip(critic_grad, critic_model.trainable_variables) ) with tf.GradientTape() as tape: actions = actor_model(state_batch, training=True) critic_value = critic_model([state_batch, actions], training=True) # Used `-value` as we want to maximize the value given # by the critic for our actions actor_loss = -tf.math.reduce_mean(critic_value) actor_grad = tape.gradient(actor_loss, actor_model.trainable_variables) actor_optimizer.apply_gradients( zip(actor_grad, actor_model.trainable_variables) ) # We compute the loss and update parameters def learn(self): # Get sampling range record_range = min(self.buffer_counter, self.buffer_capacity) # Randomly sample indices batch_indices = np.random.choice(record_range, self.batch_size) # Convert to tensors state_batch = tf.convert_to_tensor(self.state_buffer[batch_indices]) action_batch = tf.convert_to_tensor(self.action_buffer[batch_indices]) reward_batch = tf.convert_to_tensor(self.reward_buffer[batch_indices]) reward_batch = tf.cast(reward_batch, dtype=tf.float32) next_state_batch = tf.convert_to_tensor(self.next_state_buffer[batch_indices]) self.update(state_batch, action_batch, reward_batch, next_state_batch) # This update target parameters slowly # Based on rate `tau`, which is much less than one. @tf.function def update_target(target_weights, weights, tau): for (a, b) in zip(target_weights, weights): a.assign(b * tau + a * (1 - tau)) def get_actor(): # Initialize weights between -3e-3 and 3-e3 last_init = tf.random_uniform_initializer(minval=-0.003, maxval=0.003) inputs = layers.Input(shape=(num_states,)) out = layers.Dense(256, activation="relu")(inputs) out = layers.Dense(256, activation="relu")(out) outputs = layers.Dense(1, activation="tanh", kernel_initializer=last_init)(out) # Our upper bound is 2.0 for Pendulum. outputs = outputs * upper_bound model = tf.keras.Model(inputs, outputs) return model def get_critic(): # State as input state_input = layers.Input(shape=(num_states)) state_out = layers.Dense(16, activation="relu")(state_input) state_out = layers.Dense(32, activation="relu")(state_out) # Action as input action_input = layers.Input(shape=(num_actions)) action_out = layers.Dense(32, activation="relu")(action_input) # Both are passed through seperate layer before concatenating concat = layers.Concatenate()([state_out, action_out]) out = layers.Dense(256, activation="relu")(concat) out = layers.Dense(256, activation="relu")(out) outputs = layers.Dense(1)(out) # Outputs single value for give state-action model = tf.keras.Model([state_input, action_input], outputs) return model def policy(state, noise_object): sampled_actions = tf.squeeze(actor_model(state)) noise = noise_object() # Adding noise to action sampled_actions = sampled_actions.numpy() + noise # We make sure action is within bounds legal_action = np.clip(sampled_actions, lower_bound, upper_bound) return [np.squeeze(legal_action)] std_dev = 0.2 ou_noise = OUActionNoise(mean=np.zeros(1), std_deviation=float(std_dev) * np.ones(1)) actor_model = get_actor() critic_model = get_critic() target_actor = get_actor() target_critic = get_critic() # Making the weights equal initially target_actor.set_weights(actor_model.get_weights()) target_critic.set_weights(critic_model.get_weights()) # Learning rate for actor-critic models critic_lr = 0.002 actor_lr = 0.001 critic_optimizer = tf.keras.optimizers.Adam(critic_lr) actor_optimizer = tf.keras.optimizers.Adam(actor_lr) total_episodes = 100 # Discount factor for future rewards gamma = 0.99 # Used to update target networks tau = 0.005 buffer = Buffer(50000, 64) # To store reward history of each episode ep_reward_list = [] # To store average reward history of last few episodes avg_reward_list = [] # Takes about 4 min to train for ep in range(total_episodes): prev_state = env.reset() episodic_reward = 0 while True: # Uncomment this to see the Actor in action # But not in a python notebook. # env.render() tf_prev_state = tf.expand_dims(tf.convert_to_tensor(prev_state), 0) action = policy(tf_prev_state, ou_noise) # Recieve state and reward from environment. state, reward, done, info = env.step(action) buffer.record((prev_state, action, reward, state)) episodic_reward += reward buffer.learn() update_target(target_actor.variables, actor_model.variables, tau) update_target(target_critic.variables, critic_model.variables, tau) # End this episode when `done` is True if done: break prev_state = state ep_reward_list.append(episodic_reward) # Mean of last 40 episodes avg_reward = np.mean(ep_reward_list[-40:]) print("Episode * {} * Avg Reward is ==> {}".format(ep, avg_reward)) avg_reward_list.append(avg_reward) # Plotting graph # Episodes versus Avg. Rewards plt.plot(avg_reward_list) plt.xlabel("Episode") plt.ylabel("Avg. Epsiodic Reward") plt.show() # Save the weights actor_model.save_weights("pendulum_actor.h5") critic_model.save_weights("pendulum_critic.h5") target_actor.save_weights("pendulum_target_actor.h5") target_critic.save_weights("pendulum_target_critic.h5")
Source : https://github.com/keras-team/keras-io/blob/master/examples/rl/ddpg_pendulum.py
keras-io/examples/rl/ddpg_pendulum.py
Copyright (c) Apache.
Keras : https://keras.io/examples/rl/ddpg_pendulum/
Size of State Space -> 3
Size of Action Space -> 1
Max Value of Action -> 2.0
Min Value of Action -> -2.0
Episode * 0 * Avg Reward is ==> -1280.118746210651
Episode * 1 * Avg Reward is ==> -1088.4778759130525
Episode * 2 * Avg Reward is ==> -1305.2469006464792
Episode * 3 * Avg Reward is ==> -1356.3321904411694
Episode * 4 * Avg Reward is ==> -1395.822620253863
Episode * 5 * Avg Reward is ==> -1426.6666036266513
Episode * 6 * Avg Reward is ==> -1419.6193097448133
Episode * 7 * Avg Reward is ==> -1380.687185935134
Episode * 8 * Avg Reward is ==> -1395.3997526957526
Episode * 9 * Avg Reward is ==> -1356.9320488198143
Episode * 10 * Avg Reward is ==> -1290.0292523342066
Episode * 11 * Avg Reward is ==> -1237.5289320282877
Episode * 12 * Avg Reward is ==> -1182.1551811574193
Episode * 13 * Avg Reward is ==> -1116.495174997364
Episode * 14 * Avg Reward is ==> -1059.2423049699964
Episode * 15 * Avg Reward is ==> -1000.6984587889716
Episode * 16 * Avg Reward is ==> -956.8036753242964
Episode * 17 * Avg Reward is ==> -910.9244751423804
Episode * 18 * Avg Reward is ==> -875.6828043864581
Episode * 19 * Avg Reward is ==> -851.458459846486
Episode * 20 * Avg Reward is ==> -816.9061933866975
Episode * 21 * Avg Reward is ==> -785.4484448071737
Episode * 22 * Avg Reward is ==> -751.348515554187
Episode * 23 * Avg Reward is ==> -725.1515961456051
Episode * 24 * Avg Reward is ==> -710.1314867061868
Episode * 25 * Avg Reward is ==> -691.8692412845573
Episode * 26 * Avg Reward is ==> -674.7966224069044
Episode * 27 * Avg Reward is ==> -650.7972894056294
Episode * 28 * Avg Reward is ==> -636.5676949955877
Episode * 29 * Avg Reward is ==> -623.4908733277568
Episode * 30 * Avg Reward is ==> -614.4279811861614
Episode * 31 * Avg Reward is ==> -599.0743834605153
Episode * 32 * Avg Reward is ==> -587.8407588902058
Episode * 33 * Avg Reward is ==> -585.5985720801718
Episode * 34 * Avg Reward is ==> -575.8597830327913
Episode * 35 * Avg Reward is ==> -563.2593506970347
Episode * 36 * Avg Reward is ==> -551.2559689838636
Episode * 37 * Avg Reward is ==> -536.7658131695038
Episode * 38 * Avg Reward is ==> -526.1771637687772
Episode * 39 * Avg Reward is ==> -513.0605532071131
Episode * 40 * Avg Reward is ==> -484.20615925831044
Episode * 41 * Avg Reward is ==> -470.84452692834145
Episode * 42 * Avg Reward is ==> -430.31619115544254
Episode * 43 * Avg Reward is ==> -395.6866809702809
Episode * 44 * Avg Reward is ==> -359.92902744224995
Episode * 45 * Avg Reward is ==> -320.48372847429715
Episode * 46 * Avg Reward is ==> -292.0780015898755
Episode * 47 * Avg Reward is ==> -267.5576189955411
Episode * 48 * Avg Reward is ==> -232.7688788873573
Episode * 49 * Avg Reward is ==> -210.59101035868463
Episode * 50 * Avg Reward is ==> -195.12824686589983
Episode * 51 * Avg Reward is ==> -181.81702714802216
Episode * 52 * Avg Reward is ==> -171.84055935020393
Episode * 53 * Avg Reward is ==> -174.09413694487327
Episode * 54 * Avg Reward is ==> -170.67101256346768
Episode * 55 * Avg Reward is ==> -167.75366223754978
Episode * 56 * Avg Reward is ==> -161.52885204767728
Episode * 57 * Avg Reward is ==> -164.67113263116292
Episode * 58 * Avg Reward is ==> -161.65524979192014
Episode * 59 * Avg Reward is ==> -154.9036366929094
Episode * 60 * Avg Reward is ==> -167.42081867601556
Episode * 61 * Avg Reward is ==> -167.51764882551018
Episode * 62 * Avg Reward is ==> -167.64066520107104
Episode * 63 * Avg Reward is ==> -171.0777233116772
Episode * 64 * Avg Reward is ==> -171.8246650896827
Episode * 65 * Avg Reward is ==> -168.86530503792315
Episode * 66 * Avg Reward is ==> -166.33522812887776
Episode * 67 * Avg Reward is ==> -172.63694448696452
Episode * 68 * Avg Reward is ==> -173.08864902437816
Episode * 69 * Avg Reward is ==> -170.00181374112466
Episode * 70 * Avg Reward is ==> -184.68892200770335
Episode * 71 * Avg Reward is ==> -184.87489920046605
Episode * 72 * Avg Reward is ==> -195.11923877507925
Episode * 73 * Avg Reward is ==> -194.67051328572393
Episode * 74 * Avg Reward is ==> -201.42908617849116
Episode * 75 * Avg Reward is ==> -201.46840488651924
Episode * 76 * Avg Reward is ==> -198.54207714905442
Episode * 77 * Avg Reward is ==> -204.2112968695747
Episode * 78 * Avg Reward is ==> -204.29093820719876
Episode * 79 * Avg Reward is ==> -225.9409941399834
Episode * 80 * Avg Reward is ==> -235.63288544274366
Episode * 81 * Avg Reward is ==> -239.82413736372183
Episode * 82 * Avg Reward is ==> -239.9863676341155
Episode * 83 * Avg Reward is ==> -237.12686779114702
Episode * 84 * Avg Reward is ==> -237.36826003952757
Episode * 85 * Avg Reward is ==> -237.38699386783688
Episode * 86 * Avg Reward is ==> -237.18657846019875
Episode * 87 * Avg Reward is ==> -237.0064619425719
Episode * 88 * Avg Reward is ==> -234.05243355476279
Episode * 89 * Avg Reward is ==> -234.21247900866578
Episode * 90 * Avg Reward is ==> -234.2315004264125
Episode * 91 * Avg Reward is ==> -231.169577176793
Episode * 92 * Avg Reward is ==> -231.28189484475024
Episode * 93 * Avg Reward is ==> -225.45022959982293
Episode * 94 * Avg Reward is ==> -222.54889812078545
Episode * 95 * Avg Reward is ==> -228.3907833237986
Episode * 96 * Avg Reward is ==> -228.31361697244864
Episode * 97 * Avg Reward is ==> -224.77755312533344
Episode * 98 * Avg Reward is ==> -224.8069660004678
Episode * 99 * Avg Reward is ==> -224.81774920427415
Before Training
After 100 episodes
Actor Critic Method
Tested in Anaconda and Python 3.7
import gym import numpy as np import tensorflow as tf tf.enable_eager_execution() from tensorflow import keras from tensorflow.keras import layers # Configuration parameters for the whole setup seed = 42 gamma = 0.99 # Discount factor for past rewards max_steps_per_episode = 10000 env = gym.make("CartPole-v0") # Create the environment env.seed(seed) eps = np.finfo(np.float32).eps.item() # Smallest number such that 1.0 + eps != 1.0 num_inputs = 4 num_actions = 2 num_hidden = 128 inputs = layers.Input(shape=(num_inputs,)) common = layers.Dense(num_hidden, activation="relu")(inputs) action = layers.Dense(num_actions, activation="softmax")(common) critic = layers.Dense(1)(common) model = keras.Model(inputs=inputs, outputs=[action, critic]) optimizer = keras.optimizers.Adam(learning_rate=0.01) huber_loss = keras.losses.Huber() action_probs_history = [] critic_value_history = [] rewards_history = [] running_reward = 0 episode_count = 0 while True: # Run until solved state = env.reset() episode_reward = 0 with tf.GradientTape() as tape: for timestep in range(1, max_steps_per_episode): # env.render(); Adding this line would show the attempts # of the agent in a pop up window. state = tf.convert_to_tensor(state) state = tf.expand_dims(state, 0) # Predict action probabilities and estimated future rewards # from environment state action_probs, critic_value = model(state) critic_value_history.append(critic_value[0, 0]) # Sample action from action probability distribution action = np.random.choice(num_actions, p=np.squeeze(action_probs)) action_probs_history.append(tf.math.log(action_probs[0, action])) # Apply the sampled action in our environment state, reward, done, _ = env.step(action) rewards_history.append(reward) episode_reward += reward if done: break # Update running reward to check condition for solving running_reward = 0.05 * episode_reward + (1 - 0.05) * running_reward # Calculate expected value from rewards # - At each timestep what was the total reward received after that timestep # - Rewards in the past are discounted by multiplying them with gamma # - These are the labels for our critic returns = [] discounted_sum = 0 for r in rewards_history[::-1]: discounted_sum = r + gamma * discounted_sum returns.insert(0, discounted_sum) # Normalize returns = np.array(returns) returns = (returns - np.mean(returns)) / (np.std(returns) + eps) returns = returns.tolist() # Calculating loss values to update our network history = zip(action_probs_history, critic_value_history, returns) actor_losses = [] critic_losses = [] for log_prob, value, ret in history: # At this point in history, the critic estimated that we would get a # total reward = `value` in the future. We took an action with log probability # of `log_prob` and ended up recieving a total reward = `ret`. # The actor must be updated so that it predicts an action that leads to # high rewards (compared to critic's estimate) with high probability. diff = ret - value actor_losses.append(-log_prob * diff) # actor loss # The critic must be updated so that it predicts a better estimate of # the future rewards. critic_losses.append( huber_loss(tf.expand_dims(value, 0), tf.expand_dims(ret, 0)) ) # Backpropagation loss_value = sum(actor_losses) + sum(critic_losses) grads = tape.gradient(loss_value, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables)) # Clear the loss and reward history action_probs_history.clear() critic_value_history.clear() rewards_history.clear() # Log details episode_count += 1 if episode_count % 10 == 0: template = "running reward: {:.2f} at episode {}" print(template.format(running_reward, episode_count)) if running_reward > 195: # Condition to consider the task solved print("Solved at episode {}!".format(episode_count)) break
Source : https://github.com/keras-team/keras-io/blob/master/examples/rl/actor_critic_cartpole.py
keras-io/examples/rl/actor_critic_cartpole.py
Copyright (c) Apache.
Keras : https://keras.io/examples/rl/actor_critic_cartpole/
running reward: 7.90 at episode 10
running reward: 17.99 at episode 20
running reward: 30.56 at episode 30
running reward: 25.71 at episode 40
running reward: 25.38 at episode 50
running reward: 29.02 at episode 60
running reward: 42.42 at episode 70
running reward: 59.00 at episode 80
running reward: 50.55 at episode 90
running reward: 49.82 at episode 100
running reward: 44.83 at episode 110
running reward: 42.80 at episode 120
running reward: 40.82 at episode 130
running reward: 38.79 at episode 140
running reward: 64.04 at episode 150
running reward: 79.35 at episode 160
running reward: 72.18 at episode 170
running reward: 70.77 at episode 180
running reward: 94.98 at episode 190
running reward: 128.29 at episode 200
running reward: 133.53 at episode 210
running reward: 128.91 at episode 220
running reward: 127.50 at episode 230
running reward: 138.20 at episode 240
running reward: 159.82 at episode 250
running reward: 175.95 at episode 260
running reward: 177.04 at episode 270
running reward: 180.55 at episode 280
running reward: 137.69 at episode 290
running reward: 110.44 at episode 300
running reward: 121.26 at episode 310
running reward: 129.06 at episode 320
running reward: 138.07 at episode 330
running reward: 128.58 at episode 340
running reward: 123.16 at episode 350
running reward: 120.64 at episode 360
running reward: 122.41 at episode 370
running reward: 127.28 at episode 380
running reward: 143.69 at episode 390
running reward: 161.21 at episode 400
running reward: 176.78 at episode 410
running reward: 186.09 at episode 420
running reward: 191.08 at episode 430
running reward: 194.66 at episode 440
Solved at episode 442!
In early stages of training
In later stages of training
Proximal Policy Optimization
Tested in Anaconda and Python 3.7
import numpy as np import tensorflow as tf tf.enable_eager_execution() from tensorflow import keras from tensorflow.keras import layers import gym import scipy.signal import time def discounted_cumulative_sums(x, discount): # Discounted cumulative sums of vectors for computing rewards-to-go and advantage estimates return scipy.signal.lfilter([1], [1, float(-discount)], x[::-1], axis=0)[::-1] class Buffer: # Buffer for storing trajectories def __init__(self, observation_dimensions, size, gamma=0.99, lam=0.95): # Buffer initialization self.observation_buffer = np.zeros( (size, observation_dimensions), dtype=np.float32 ) self.action_buffer = np.zeros(size, dtype=np.int32) self.advantage_buffer = np.zeros(size, dtype=np.float32) self.reward_buffer = np.zeros(size, dtype=np.float32) self.return_buffer = np.zeros(size, dtype=np.float32) self.value_buffer = np.zeros(size, dtype=np.float32) self.logprobability_buffer = np.zeros(size, dtype=np.float32) self.gamma, self.lam = gamma, lam self.pointer, self.trajectory_start_index = 0, 0 def store(self, observation, action, reward, value, logprobability): # Append one step of agent-environment interaction self.observation_buffer[self.pointer] = observation self.action_buffer[self.pointer] = action self.reward_buffer[self.pointer] = reward self.value_buffer[self.pointer] = value self.logprobability_buffer[self.pointer] = logprobability self.pointer += 1 def finish_trajectory(self, last_value=0): # Finish the trajectory by computing advantage estimates and rewards-to-go path_slice = slice(self.trajectory_start_index, self.pointer) rewards = np.append(self.reward_buffer[path_slice], last_value) values = np.append(self.value_buffer[path_slice], last_value) deltas = rewards[:-1] + self.gamma * values[1:] - values[:-1] self.advantage_buffer[path_slice] = discounted_cumulative_sums( deltas, self.gamma * self.lam ) self.return_buffer[path_slice] = discounted_cumulative_sums( rewards, self.gamma )[:-1] self.trajectory_start_index = self.pointer def get(self): # Get all data of the buffer and normalize the advantages self.pointer, self.trajectory_start_index = 0, 0 advantage_mean, advantage_std = ( np.mean(self.advantage_buffer), np.std(self.advantage_buffer), ) self.advantage_buffer = (self.advantage_buffer - advantage_mean) / advantage_std return ( self.observation_buffer, self.action_buffer, self.advantage_buffer, self.return_buffer, self.logprobability_buffer, ) def mlp(x, sizes, activation=tf.tanh, output_activation=None): # Build a feedforward neural network for size in sizes[:-1]: x = layers.Dense(units=size, activation=activation)(x) return layers.Dense(units=sizes[-1], activation=output_activation)(x) def logprobabilities(logits, a): # Compute the log-probabilities of taking actions a by using the logits (i.e. the output of the actor) logprobabilities_all = tf.nn.log_softmax(logits) logprobability = tf.reduce_sum( tf.one_hot(a, num_actions) * logprobabilities_all, axis=1 ) return logprobability # Sample action from actor @tf.function def sample_action(observation): logits = actor(observation) action = tf.squeeze(tf.random.categorical(logits, 1), axis=1) return logits, action # Train the policy by maxizing the PPO-Clip objective @tf.function def train_policy( observation_buffer, action_buffer, logprobability_buffer, advantage_buffer ): with tf.GradientTape() as tape: # Record operations for automatic differentiation. ratio = tf.exp( logprobabilities(actor(observation_buffer), action_buffer) - logprobability_buffer ) min_advantage = tf.where( advantage_buffer > 0, (1 + clip_ratio) * advantage_buffer, (1 - clip_ratio) * advantage_buffer, ) policy_loss = -tf.reduce_mean( tf.minimum(ratio * advantage_buffer, min_advantage) ) policy_grads = tape.gradient(policy_loss, actor.trainable_variables) policy_optimizer.apply_gradients(zip(policy_grads, actor.trainable_variables)) kl = tf.reduce_mean( logprobability_buffer - logprobabilities(actor(observation_buffer), action_buffer) ) kl = tf.reduce_sum(kl) return kl # Train the value function by regression on mean-squared error @tf.function def train_value_function(observation_buffer, return_buffer): with tf.GradientTape() as tape: # Record operations for automatic differentiation. value_loss = tf.reduce_mean((return_buffer - critic(observation_buffer)) ** 2) value_grads = tape.gradient(value_loss, critic.trainable_variables) value_optimizer.apply_gradients(zip(value_grads, critic.trainable_variables)) # Hyperparameters of the PPO algorithm steps_per_epoch = 4000 epochs = 30 gamma = 0.99 clip_ratio = 0.2 policy_learning_rate = 3e-4 value_function_learning_rate = 1e-3 train_policy_iterations = 80 train_value_iterations = 80 lam = 0.97 target_kl = 0.01 hidden_sizes = (64, 64) # True if you want to render the environment render = False # Initialize the environment and get the dimensionality of the # observation space and the number of possible actions env = gym.make("CartPole-v0") observation_dimensions = env.observation_space.shape[0] num_actions = env.action_space.n # Initialize the buffer buffer = Buffer(observation_dimensions, steps_per_epoch) # Initialize the actor and the critic as keras models observation_input = keras.Input(shape=(observation_dimensions,), dtype=tf.float32) logits = mlp(observation_input, list(hidden_sizes) + [num_actions], tf.tanh, None) actor = keras.Model(inputs=observation_input, outputs=logits) value = tf.squeeze( mlp(observation_input, list(hidden_sizes) + [1], tf.tanh, None), axis=1 ) critic = keras.Model(inputs=observation_input, outputs=value) # Initialize the policy and the value function optimizers policy_optimizer = keras.optimizers.Adam(learning_rate=policy_learning_rate) value_optimizer = keras.optimizers.Adam(learning_rate=value_function_learning_rate) # Initialize the observation, episode return and episode length observation, episode_return, episode_length = env.reset(), 0, 0 # Iterate over the number of epochs for epoch in range(epochs): # Initialize the sum of the returns, lengths and number of episodes for each epoch sum_return = 0 sum_length = 0 num_episodes = 0 # Iterate over the steps of each epoch for t in range(steps_per_epoch): if render: env.render() # Get the logits, action, and take one step in the environment observation = observation.reshape(1, -1) logits, action = sample_action(observation) observation_new, reward, done, _ = env.step(action[0].numpy()) episode_return += reward episode_length += 1 # Get the value and log-probability of the action value_t = critic(observation) logprobability_t = logprobabilities(logits, action) # Store obs, act, rew, v_t, logp_pi_t buffer.store(observation, action, reward, value_t, logprobability_t) # Update the observation observation = observation_new # Finish trajectory if reached to a terminal state terminal = done if terminal or (t == steps_per_epoch - 1): last_value = 0 if done else critic(observation.reshape(1, -1)) buffer.finish_trajectory(last_value) sum_return += episode_return sum_length += episode_length num_episodes += 1 observation, episode_return, episode_length = env.reset(), 0, 0 # Get values from the buffer ( observation_buffer, action_buffer, advantage_buffer, return_buffer, logprobability_buffer, ) = buffer.get() # Update the policy and implement early stopping using KL divergence for _ in range(train_policy_iterations): kl = train_policy( observation_buffer, action_buffer, logprobability_buffer, advantage_buffer ) if kl > 1.5 * target_kl: # Early Stopping break # Update the value function for _ in range(train_value_iterations): train_value_function(observation_buffer, return_buffer) # Print mean return and length for each epoch print( f" Epoch: {epoch + 1}. Mean Return: {sum_return / num_episodes}. Mean Length: {sum_length / num_episodes}" )
Source : https://github.com/keras-team/keras-io/blob/master/examples/rl/ppo_cartpole.py
keras-io/examples/rl/ppo_cartpole.py
Copyright (c) Apache.
Keras : https://keras.io/examples/rl/ppo_cartpole/
Epoch: 1. Mean Return: 17.02127659574468. Mean Length: 17.02127659574468
Epoch: 2. Mean Return: 22.988505747126435. Mean Length: 22.988505747126435
Epoch: 3. Mean Return: 25.641025641025642. Mean Length: 25.641025641025642
Epoch: 4. Mean Return: 34.78260869565217. Mean Length: 34.78260869565217
Epoch: 5. Mean Return: 52.63157894736842. Mean Length: 52.63157894736842
Epoch: 6. Mean Return: 86.95652173913044. Mean Length: 86.95652173913044
Epoch: 7. Mean Return: 137.93103448275863. Mean Length: 137.93103448275863
Epoch: 8. Mean Return: 160.0. Mean Length: 160.0
Epoch: 9. Mean Return: 190.47619047619048. Mean Length: 190.47619047619048
Epoch: 10. Mean Return: 173.91304347826087. Mean Length: 173.91304347826087
Epoch: 11. Mean Return: 190.47619047619048. Mean Length: 190.47619047619048
Epoch: 12. Mean Return: 190.47619047619048. Mean Length: 190.47619047619048
Epoch: 13. Mean Return: 200.0. Mean Length: 200.0
Epoch: 14. Mean Return: 190.47619047619048. Mean Length: 190.47619047619048
Epoch: 15. Mean Return: 200.0. Mean Length: 200.0
Epoch: 16. Mean Return: 200.0. Mean Length: 200.0
Epoch: 17. Mean Return: 181.8181818181818. Mean Length: 181.8181818181818
Epoch: 18. Mean Return: 190.47619047619048. Mean Length: 190.47619047619048
Epoch: 19. Mean Return: 200.0. Mean Length: 200.0
Epoch: 20. Mean Return: 200.0. Mean Length: 200.0
Epoch: 21. Mean Return: 200.0. Mean Length: 200.0
Epoch: 22. Mean Return: 200.0. Mean Length: 200.0
Epoch: 23. Mean Return: 200.0. Mean Length: 200.0
Epoch: 24. Mean Return: 200.0. Mean Length: 200.0
Epoch: 25. Mean Return: 200.0. Mean Length: 200.0
Epoch: 26. Mean Return: 200.0. Mean Length: 200.0
Epoch: 27. Mean Return: 200.0. Mean Length: 200.0
Epoch: 28. Mean Return: 200.0. Mean Length: 200.0
Epoch: 29. Mean Return: 200.0. Mean Length: 200.0
Epoch: 30. Mean Return: 200.0. Mean Length: 200.0
Before training
After 8 epochs of training
After 20 epochs of training
Welcome, my name is Eric Soupet and I am the administrator of the site elodees.com. elodees.com is a state of the art of Artificial Intelligence and aims to be collaborative, you can now offer content such as articles, events, tutorials, ... so don't hesitate !
Platform images credit : Pixabay - Pixabay License | Pexels - Pexels License