【强化学习】Policy Gradients代码注释版本

import gym  #
import tensorflow as tf
import numpy as np

# Hyper Parameters
GAMMA = 0.95  # discount factor    折扣因子
LEARNING_RATE = 0.01  # 学习率


class Policy_Gradient():
    # 咱们来搞一下大头!
    def __init__(self, env):  # 初始化
        # 先初始化一些参量
        self.time_step = 0  # 某个地方需要用的步数
        self.state_dim = env.observation_space.shape[0]  # 状态维度
        self.action_dim = env.action_space.n  # 动作维度 TODO 这个.n是什么意思
        self.ep_obs, self.ep_as, self.ep_rs = [], [], []  # 初始化了一个三状态,为了后面用store_transition存到智能体中
        self.create_softmax_network()

        # Init session      初始化tensorflow参数
        self.session = tf.InteractiveSession()
        self.session.run(tf.global_variables_initializer())  # 初始化 tensorflow 参数。

    def create_softmax_network(self):
        # network weights
        """
        当在time-step-i时刻,策略网络输出概率向量若与采样到的time-step-i时刻的动作越相似,
        那么交叉熵会越小。最小化这个交叉熵误差也就能够使策略网络的决策越接近我们采样的动作。
        最后用交叉熵乘上对应time-step的reward,就将reward的大小引入损失函数,entropy*reward越大,
        神经网络调整参数时计算得到的梯度就会越偏向该方向。
        :return:
        """

        W1 = self.weight_variable([self.state_dim, 20])  # w1 权重,4*20的网络
        b1 = self.bias_variable([20])  # b1权重,y = w1*x + b1
        W2 = self.weight_variable([20, self.action_dim])
        b2 = self.bias_variable([self.action_dim])

        # input layer
        self.state_input = tf.placeholder("float", [None, self.state_dim])  # 状态输入层占位,多少组不知道,每组有4个状态
        self.tf_acts = tf.placeholder(tf.int32, [None, ],
                                      name="actions_num")  # 动作数  TODO 这里我其实没太看出来是干啥的,很想输出一下这些参量长什么样,晚上学一下
        self.tf_vt = tf.placeholder(tf.float32, [None, ], name="actions_value")  # 这是我们的状态价值函数

        # hidden layers
        h_layer = tf.nn.relu(tf.matmul(self.state_input, W1) + b1)  # 进行 y = w1*x + b1 的运算 ,并激活成可输出的状态

        # softmax layer
        # matmul返回两个数组的矩阵乘积,结果还是一个矩阵
        self.softmax_input = tf.matmul(h_layer, W2) + b2  # 进行 y = w2*x + b2 的运算,输出是两个是数(不确定)TODO
        # softmax output
        self.all_act_prob = tf.nn.softmax(self.softmax_input, name='act_prob')  # softmax输出层,输出每个动作的概率

        # 计算logits 和 labels 之间的稀疏softmax 交叉熵
        # 函数先对 logits 进行 softmax 处理得到归一化的概率,将lables向量进行one-hot处理,然后求logits和labels的交叉熵:
        # TODO https://blog.csdn.net/qq_22194315/article/details/77991283   一会儿研究一下这个链接
        self.neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.softmax_input,
                                                                           labels=self.tf_acts)

        # tf.reduce_mean  :计算张量tensor沿着指定的数轴(tensor的某一维度)上的的平均值
        # 损失函数计算,定义为softmax交叉熵损失函数和状态价值函数的乘积
        self.loss = tf.reduce_mean(self.neg_log_prob * self.tf_vt)  # reward guided loss

        # 我的理解是,利用tensorflow中的Adam优化算法最小化loss函数
        # Adam优化算法:是一个寻找全局最优点的优化算法,引入了二次方梯度校正。
        self.train_op = tf.train.AdamOptimizer(LEARNING_RATE).minimize(self.loss)

    def weight_variable(self, shape):  # 权重变量
        initial = tf.truncated_normal(shape)
        return tf.Variable(initial)

    def bias_variable(self, shape):  # 偏执变量,生成常量矩阵,是tensorflow中固定的机制
        initial = tf.constant(0.01, shape=shape)
        return tf.Variable(initial)

    def choose_action(self, observation):
        """
        选择动作 :这里的observation其实就是状态,当前的状态先传入state_input(也就相当于softmax网络的入口),
        softmax网络的输出是针对当前状态每个动作的概率,第一句就是运行了一个会话进行这个过程。
        #TODO prob_weights 应该是一个动作对应概率的矩阵,怎么查看数据类型来着忘了
        下一句就是依据概率选择动作了,选择概率最大的动作
        """

        prob_weights = self.session.run(self.all_act_prob, feed_dict={self.state_input: 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):  #
        """
        模型学习:通过蒙特卡洛完整序列采样,对神经网络进行调整。
        :return:
        """
        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 * GAMMA + self.ep_rs[t]  #
            discounted_ep_rs[t] = running_add

        discounted_ep_rs -= np.mean(discounted_ep_rs)
        discounted_ep_rs /= np.std(discounted_ep_rs)  # 到这一步就实现了

        # train on episode
        self.session.run(self.train_op, feed_dict={
            self.state_input: np.vstack(self.ep_obs),
            self.tf_acts: np.array(self.ep_as),
            self.tf_vt: discounted_ep_rs,
        })  # 到这一步就计算完成了,给她传进会话让他进行下面的计算吧

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []  # 每步结束之后清空这三个值


# main函数里面会用到的一些超级参量
ENV_NAME = 'CartPole-v0'  # 定义一个超级参量,小车杆子的游戏环境名称
EPISODE = 3000  # 3000个回合
STEP = 3000  # 每个回合里面最多执行3000步
TEST = 20  # 每一百个回合做一次测试,每次10次测试取一次平均


def main():
    env = gym.make(ENV_NAME)
    agent = Policy_Gradient(env)  # 定义了一个智能体

    for episode in range(EPISODE):  # 开始回合更新
        state = env.reset()  # 初始化状态

        for step in range(STEP):  # 开始单步更新
            action = agent.choose_action(state)  # 根据当前的状态随机选择动作
            next_state, reward, done, _ = env.step(action)  # 得到执行动作后的回报,以及下一个状态
            agent.store_transition(state, action, reward)  # 序列采样
            state = next_state  # 更新状态,准备下一步更新,下一个状态即为下一步中的当前状态
            if done:
                # 蒙特卡罗法里面价值函数的计算,一般是从后向前算,这样前面的价值的计算可以利用后面的价值作为中间结果,简化计算
                agent.learn()  # 完成一个回合之后计算价值函数
                break  # 达到终止条件的时候退出当前循环,开启下一回合

        # 完成100个回合下面开始测试
        if episode % 100 == 0:
            total_reward = 0  # 初始化回报
            for i in range(TEST):
                state = env.reset()  # 初始化状态
                for j in range(STEP):
                    env.render()  # env.render()函数用于渲染出当前的智能体以及环境的状态
                    action == agent.choose_action(state)  # 根据状态选择动作
                    state, reward, done, _ = env.step(action)  # 根据action执行step,得到三状态
                    total_reward += reward  # 为了十次取一次平均,先加后除
                    if done:  # 如果达到了终止条件,则退出
                        break
            ave_reward = total_reward / TEST  # 求平均
            print('episode:', episode, 'Evaluation Average Reward:', ave_reward)


if __name__ == '__main__':
    main()


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值