李宏毅机器学习课程——Reinforcement learning学习笔记

强化学习(Reinforcement learning),通俗一点讲,看一理解为教会机器如何利用现有的奖惩规则卷一个高高的分数,通过趋利避害来起到较好的无监督学习效果,缺点也是可以类比得到,机器可能会钻规则的空子,成为一个高分的“卷王”,但是没有学到实际的本领。

基本概念

强化学习需要先理解几个概念。

  • 强化学习有两个主体:

agent:代理人(agent)是采取行动的主体,代理人在\(s_t\)根据策略\(\pi\)选择出动作\(a_t\),将\(a_t\)反馈给环境,这一部分是我们需要训练的。

environment:环境定义了state的表示方法和不同state之间的转移规则,并且根据agent在\(s_t\)的动作\(a_t\),将状态转换为\(s_{t+1}\)​,这一部分常常是一个固定的,需要人为设定。

  • 上述两个主体的描述中,涉及到以下三个词汇:

动作(\(action\)​​)\(a\)​​:在一个\(s\)(一个向量)上由agent给出\(a\),环境接收\(s\)\(a\),并且能够作用得到\(s_{t+1}\)​(另一个向量)。

状态(\(state\)​​)\(s\)​​:使用一个向量\(s\)表示一个状态。

策略(\(policy\)​​​)\(\pi\)​​​:agent根据\(s_t\)​​得到\(a_t\)​​的方法,例如一个\(Neuron\ Network\)​。

  • 由动作、状态与策略便可以得到轨迹\(trajectory\)

轨迹(\(trajectory\)​​​​)\(\tau\)​​​​:在一定的策略\(\pi\)​下,得到的\(\{s_0,a_0,s_1,a_1,...,s_T,a_T(stop)\}\)​​​。​

  • reward函数

这个通常由环境给定,可以直接对行为定义reward,也可以针对状态定义reward,或二者兼而有之。

  • 收益函数

类似于其他的模型训练过程中使用的损失函数,这里要对\(\theta\)进行梯度上升,使得我们的收益最大化,需要训练的参数是\(\theta\) ,是我们的策略。精确的\(R\)应当理解为在\(\theta\)\(reward\)的数学期望,即所有可能的轨迹\(\tau\)的概率\(P(\tau)\)与对应的\(reward\)\(R(\tau)\)​​的乘积再求和。​​

\(\bar R_{\theta} = \Sigma_{\tau}R(\tau)P(\tau|\theta)\)

求梯度得到如下公式:

\(\nabla \bar R_{\theta}=\Sigma_{\tau}R(\tau)P(\tau|\theta) \nabla log P(\tau|\theta)=E_{\tau \sim \pi_{\theta} }(R(\tau)\nabla log P(\tau|\theta))\)

实际中所有的轨迹不可能做到穷举,通过蒙特卡洛方法对均值进行估计:

\(\nabla \bar R_{\theta} \approx \frac{1}{N} \Sigma_{n=1}^N R(\tau^n) \nabla log P(\tau^n|\theta)\)

这里的n表示随机采样,在\(\pi_\theta\)​的策略下进行\(N\)​次,得到\(\{\tau^1,\tau^2,...,\tau^N\}\)​。​

Reinforcement Learning with Baseline

适合函数\(\nabla R\approx \frac{1}{N}\Sigma_{n=1}^{N} \Sigma_{t=1}^{Tn}(\Sigma_{t'=t}^{Tn} \gamma^{t'-t}r_{t'}-b) \nabla log p(a_t^n|s_t^n,\theta)\)

其中\(b\)​​是baseline,可以训练一个值函数\(Q^{\pi_\theta}(s)\)​来表示,即采取策略\(\pi_\theta\)\(s\)​开始能够取得的平均\(reward\)

Coding

这部分是实现过程,不需要了解细节则可以跳过。

这一部分针对于作业的具体实现,我实现了Reinforcement Learning with Baseline.

  • 定义一个值函数
class QNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.f1 = nn.Linear(8, 20)
        self.f2 = nn.Linear(20, 20)
        self.f3 = nn.Linear(20, 1)

    def forward(self, state):
        hid = torch.relu(self.f1(state))
        hid = torch.relu(self.f2(hid))
        return self.f3(hid)
  • 代理人类
class PolicyGradientAgent():

    def __init__(self, network, Qnetwork):
        self.network = network
        self.Qnetwork = Qnetwork
        self.optimizer = torch.optim.SGD(self.network.parameters(),lr = 0.001)
        self.optimizerQ = torch.optim.SGD(self.Qnetwork.parameters(),lr = 0.001)

    # 训练值函数
    def learnQfun(self, rewards, baselines):
        lossQ = torch.sqrt((rewards-baselines)*(rewards-baselines)).sum() / len(rewards)
        self.optimizerQ.zero_grad()
        lossQ.backward(retain_graph=True)
        self.optimizerQ.step()

    # 根据得到的各个动作的梯度和rewards更新network
    def learn(self, log_probs, rewards, baselines):
        loss = (-log_probs * (rewards-baselines)).sum()
        self.optimizer.zero_grad()
        loss.backward(retain_graph=True)
        self.optimizer.step()
        self.learnQfun(rewards.clone(),baselines.clone())

    def sample(self, state):
        action_prob = self.network(torch.FloatTensor(state))
        action_dist = Categorical(action_prob)
        action = action_dist.sample()
        log_prob = action_dist.log_prob(action)
        return action.item(), log_prob

    def calculateQ(self, state):
        # 计算Q值
        return self.Qnetwork(torch.FloatTensor(state))
  • 训练代码
agent.network.train()  # 训练前,先确保 network 处在 training 模式
EPISODE_PER_BATCH = 5  # 每搜集 5 个 episodes 更新一次 agent
NUM_BATCH = 600        # 总共更新 600 次
gamma = 0.98           # 折扣因子

avg_total_rewards, avg_final_rewards = [], []

prg_bar = tqdm(range(NUM_BATCH))

for batch in prg_bar:
    log_probs, rewards = [], []
    baselines = []
    total_rewards, final_rewards = [], []
    # 每个batch运行5个episode更新一次agent
    for episode in range(EPISODE_PER_BATCH):
        
        state = env.reset()
        total_reward, total_step = 0, 0

        step_reward = [] # 记录每一步的单步reward
        while True:

            action, log_prob = agent.sample(state)
            # 这里需要调用新的reward计算函数
            next_state, reward, done, _ = env.step(action)

            # 计算当前状态而不是下一个状态的Q值
            baseline = agent.calculateQ(state)

            baselines.append(baseline[0])
            
            log_probs.append(log_prob)
            state = next_state
            total_reward += reward
            step_reward.append(reward)
            total_step += 1

            if done:
                final_rewards.append(reward)
                total_rewards.append(total_reward)
                # 每一步往后累积起来的reward
                accu_rewards = [0 for _ in range(total_step)]
                for index in range(total_step-1,-1,-1):
                  if index == (total_step-1):
                    accu_rewards[index] = step_reward[index]
                  else:
                    accu_rewards[index] = step_reward[index] + gamma*accu_rewards[index+1]
                rewards.append(accu_rewards) 
                break

    # 记录训练过程
    avg_total_reward = sum(total_rewards) / len(total_rewards)
    avg_final_reward = sum(final_rewards) / len(final_rewards)
    avg_total_rewards.append(avg_total_reward)
    avg_final_rewards.append(avg_final_reward)
    prg_bar.set_description(f"Total: {avg_total_reward: 4.1f}, Final: {avg_final_reward: 4.1f}")

    # 更新网络
    rewards = np.concatenate(rewards, axis=0)
    rewards = (rewards - np.mean(rewards)) / (np.std(rewards) + 1e-9)

    # Q函数与策略耦合 协同训练
    agent.learn(torch.stack(log_probs),torch.from_numpy(rewards),torch.stack(baselines))
posted @ 2021-07-31 20:04  19376273  阅读(260)  评论(0编辑  收藏  举报