Logo elodees  elodees

A caring AI for a better world













Only alphabetic characters accented or not as well as the space are accepted

Logo IA




Reinforcement learning





No account yet ?

Sign up to access all content




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

License: Apache 2.0LicenseApache 2.0  Copyright (c) Apache.


GitHub



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



Free image provided by pexel.com




Before Training

Free image provided by pexel.com

After 100 episodes

Free image provided by pexel.com




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

License: Apache 2.0LicenseApache 2.0  Copyright (c) Apache.


GitHub



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

Free image provided by pexel.com

In later stages of training

Free image provided by pexel.com




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

License: Apache 2.0LicenseApache 2.0  Copyright (c) Apache.


GitHub



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

Free image provided by pexel.com

After 8 epochs of training

Free image provided by pexel.com

After 20 epochs of training

Free image provided by pexel.com


Deep Reinforcement Learning

Reverse Reinforcement Learning

Q-learning

On-Policy VS Off-Policy Reinforcement Learning

Multi-Agent Reinforcement Learning

Game theory

Adaptive algorithm

Temporal difference learning

Bandits Manchots

Value-Based Reinforcement Learning Algorithm

Trust Region Policy Optimization

Policy gradient method

The Actor-Critic Reinforcement Learning algorithm

Deep Q network (DQN)

Value function

Augmented random search

Explicit Explore or Exploit

Motion Planning

Hierarchical Actor Critic (HAC)

Several frameworks to move to reinforcement learning



Deep learning

Machine learning












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