强化学习系列(6) - Policy-Gradient-Softmax

Policy gradient 最大的一个优势是: 输出的这个 action 可以是一个连续的值, 之前我们说到的 value-based 方法输出的都是不连续的值, 然后再选择值最大的 action. 而 policy gradient 可以在一个连续分布上选取 action.
误差反向传递:这种反向传递的目的是让这次被选中的行为更有可能在下次发生. 但是我们要怎么确定这个行为是不是应当被增加被选的概率呢? 这时候我们的老朋友, reward 奖惩正可以在这时候派上用场,

"""
RL_brain for Policy-Gradient-Softmax
"""
import numpy as np
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

np.random.seed(1)
tf.set_random_seed(1)

class PolicyGradient:
    def __init__(
        self,
        n_actions,
        n_features,
        learning_rate=0.01,
        reward_decay=0.95,
        output_graph=False,
    ):
        self.n_actions = n_actions
        self.n_features = n_features
        self.lr = learning_rate
        self.gamma = reward_decay

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []

        self._build_net()

        self.sess = tf.Session()

        if output_graph:
            tf.summary.FileWriter("logs/", self.sess.graph)
        
        self.sess.run(tf.global_variables_initializer())
    
    def _build_net(self):
        with tf.name_scope('inputs'):
            self.tf_obs = tf.placeholder(tf.float32, [None, self.n_features], name="observations")
            self.tf_acts = tf.placeholder(tf.int32, [None, ], name="actions_num")
            self.tf_vt = tf.placeholder(tf.float32, [None, ], name="actions_value")

        # fc1
        layer = tf.layers.dense(
            inputs=self.tf_obs,
            units=10,
            activation=tf.nn.tanh,
            kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.3),
            bias_initializer=tf.constant_initializer(0.1),
            name='fc1'
        )
        # fc2
        all_act = tf.layers.dense(
            inputs=layer,
            units=self.n_actions,
            activation=None,
            kernel_initializer=tf.random_normal_initializer(mean=0,stddev=0.3),
            bias_initializer=tf.constant_initializer(0.1),
            name='fc2'
        )

        self.all_act_prob = tf.nn.softmax(all_act, name='act_prob')

        with tf.name_scope('loss'):
            # to maximize total reward (log_p * R) is to minimize - (log_p * R), and the tf only have minimize(loss)
            neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=all_act, labels=self.tf_acts)
            # or in this way:
            # neg_log_prob = tf.reduce_sum(-tf.log(self.all_act_prob)*tf.one_hot(self.tf_acts, self.n_actions), axis=1)
            loss = tf.reduce_mean(neg_log_prob * self.tf_vt) # reward guided loss
        with tf.name_scope('train'):
            self.train_op = tf.train.AdamOptimizer(self.lr).minimize(loss)
    
    def choose_action(self, observation):
        prob_weights = self.sess.run(self.all_act_prob, feed_dict={self.tf_obs:observation[np.newaxis, :]})
        action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel()) # select action w.r.t the actions prob
        return action
    
    def store_transition(self, s, a, r):
        self.ep_obs.append(s)
        self.ep_as.append(a)
        self.ep_rs.append(r)
    
    def learn(self):
        # discount and normalize episode reward
        discounted_ep_rs_norm = self._discount_and_norm_rewards()

        # train on episode
        self.sess.run(self.train_op, feed_dict={
            self.tf_obs: np.vstack(self.ep_obs), # shape=[None, n_obs]
            self.tf_acts: np.array(self.ep_as), # shape=[None, ]
            self.tf_vt: discounted_ep_rs_norm, # shape=[None, ]
        })

        self.ep_obs, self.ep_as, self.ep_rs = [], [], [] # empty episode data
        return discounted_ep_rs_norm
    
    def _discount_and_norm_rewards(self):
        """
        按回合为单位
        """
        # discount episode rewards
        discounted_ep_rs = np.zeros_like(self.ep_rs)
        running_add = 0
        for t in reversed(range(0, len(self.ep_rs))):
            running_add = running_add * self.gamma + self.ep_rs[t]
            discounted_ep_rs[t] = running_add
        
        # normalize episode rewards
        discounted_ep_rs -= np.mean(discounted_ep_rs)
        discounted_ep_rs /= np.std(discounted_ep_rs)
        return discounted_ep_rs
"""
test case 1.
"""
import gym
from RL_brain import PolicyGradient
import matplotlib.pyplot as plt

DISPLAY_REWARD_THRESHOLD = 400 # renders environment if total episode reward is greater than this threshold
RENDER = False # rendering wastes time
env = gym.make('CartPole-v0')
env.seed(1) # reproducible, general Policy gradient has high variance
env = env.unwrapped

print(env.action_space)
print(env.observation_space)
print(env.observation_space.high)
print(env.observation_space.low)

RL = PolicyGradient(
    n_actions=env.action_space.n,
    n_features=env.observation_space.shape[0],
    learning_rate=0.02,
    reward_decay=0.99,
    # output_graph=True,
)

for i_episode in range(3000):
    observation = env.reset()

    while True:
        if RENDER:env.render()

        action = RL.choose_action(observation)

        observation_, reward, done, info = env.step(action)

        RL.store_transition(observation, action, reward)

        if done:
            ep_rs_sum = sum(RL.ep_rs)

            if 'running_reward' not in globals():
                running_reward = ep_rs_sum
            
            else:
                running_reward = running_reward * 0.99 + ep_rs_sum * 0.01
            
            if running_reward > DISPLAY_REWARD_THRESHOLD: RENDER = True # rendering
            print("episode:", i_episode, " reward:", int(running_reward))

            vt = RL.learn()
            
            if i_episode == 0:
                plt.plot(vt) # plot the episode vt
                plt.xlabel('episode steps')
                plt.ylabel('normalized state-action value')
                plt.show()
            break

        observation = observation_

"""
test case 2.
"""
import gym
from RL_brain import PolicyGradient
import matplotlib.pyplot as plt

DISPLAY_REWARD_THRESHOLD = -2000 # renders environment if total episode reward is greater than this threshold
# episode: 154 reward: -10667
# episode: 387 reward: -2009
# episode: 489 reward: -1006
# episode: 628 reward: -502

RENDER = False # rendering wastes time

env = gym.make('MountainCar-v0')
env.seed(1) # reproducible, general Policy gradient has high variance
env = env.unwrapped

print(env.action_space)
print(env.observation_space)
print(env.observation_space.high)
print(env.observation_space.low)

RL = PolicyGradient(
    n_actions = env.action_space.n,
    n_features = env.observation_space.shape[0],
    learning_rate=0.02,
    reward_decay=0.995,
    # output_graph = True,
)

for i_episode in range(1000):
    observation = env.reset()

    while True:
        if RENDER: env.render()

        action = RL.choose_action(observation)

        observation_, reward, done, info = env.step(action) # reward = -1 in all cases

        RL.store_transition(observation, action, reward)

        if done:
            # calculate running reward
            ep_rs_sum = sum(RL.ep_rs)
            if 'running_reward' not in globals():
                running_reward = ep_rs_sum
            else:
                running_reward = running_reward * 0.99 + ep_rs_sum * 0.01
            if running_reward > DISPLAY_REWARD_THRESHOLD: RENDER = True # rendering

            print("episode:", i_episode, " reward:", int(running_reward))

            vt = RL.learn() # train

            if i_episode == 30:
                plt.plot(vt) # plot the episode vt
                plt.xlabel('episode steps')
                plt.ylabel('normalized state-action value')
                plt.show()

            break
        observation = observation_           

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
策略梯度法(Policy Gradient)是一种强化学习算法,它属于深度强化学习的范畴。在深度强化学习中,策略梯度法是一种基于策略的方法,它通过对策略进行参数化,并使用梯度的方法来更新策略,从而实现智能体的学习和决策。因此,策略梯度法是深度强化学习中非常重要的一种算法。 下面是一个使用策略梯度法解决CartPole问题的Python代码示例: ```python import gym import numpy as np import tensorflow as tf # 定义策略网络 class PolicyNetwork(tf.keras.Model): def __init__(self, num_actions): super(PolicyNetwork, self).__init__() self.dense1 = tf.keras.layers.Dense(32, activation='relu') self.dense2 = tf.keras.layers.Dense(num_actions, activation='softmax') def call(self, inputs): x = self.dense1(inputs) x = self.dense2(x) return x # 定义策略梯度算法 class PolicyGradient: def __init__(self, num_actions, learning_rate=0.01, gamma=0.99): self.num_actions = num_actions self.learning_rate = learning_rate self.gamma = gamma self.policy_network = PolicyNetwork(num_actions) self.optimizer = tf.keras.optimizers.Adam(learning_rate) def get_action(self, state): state = np.expand_dims(state, axis=0) action_probs = self.policy_network(state) action = np.random.choice(self.num_actions, p=np.squeeze(action_probs)) return action def update_policy(self, states, actions, rewards): with tf.GradientTape() as tape: action_probs = self.policy_network(states) actions_one_hot = tf.one_hot(actions, self.num_actions) action_probs = tf.reduce_sum(actions_one_hot * action_probs, axis=1) discounted_rewards = self._get_discounted_rewards(rewards) loss = -tf.reduce_mean(tf.math.log(action_probs) * discounted_rewards) grads = tape.gradient(loss, self.policy_network.trainable_variables) self.optimizer.apply_gradients(zip(grads, self.policy_network.trainable_variables)) def _get_discounted_rewards(self, rewards): discounted_rewards = np.zeros_like(rewards) running_total = 0 for i in reversed(range(len(rewards))): running_total = running_total * self.gamma + rewards[i] discounted_rewards[i] = running_total return discounted_rewards # 定义环境和训练参数 env = gym.make('CartPole-v0') num_actions = env.action_space.n policy_gradient = PolicyGradient(num_actions) num_episodes = 1000 max_steps_per_episode = 1000 # 训练策略网络 for episode in range(num_episodes): state = env.reset() episode_rewards = [] for step in range(max_steps_per_episode): action = policy_gradient.get_action(state) next_state, reward, done, _ = env.step(action) episode_rewards.append(reward) if done: break state = next_state policy_gradient.update_policy( states=np.array([state]), actions=np.array([action]), rewards=np.array(episode_rewards) ) if episode % 100 == 0: print("Episode {}/{}: Average reward = {}".format( episode, num_episodes, np.mean(episode_rewards) )) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值