《TF2.x》强化学习手册-P47-P59-TD时序差分-Monte_carlo蒙特卡洛预测与控制算法

news2024/9/23 19:21:40

文章目录

    • 实现时序差分学习
      • 前期准备
      • 实现步骤
      • 工作原理
    • 构建强化学习中的蒙特卡洛预测和控制算法
      • 前期准备
      • 实现步骤
      • 工作原理

实现时序差分学习

时序差分(Temporal Difference ,TD)算法。TD算法是一种预测值或目标值校正的方法,用于强化学习中的值函数(如Q函数)的估计。它通过将当前估计的值将来更新的值进行比较来工作。

V ( S t ) ← V ( S t ) + α ( R t + 1 + γ V ( S t + 1 ) − V ( S t ) ) V(S_t)\leftarrow V(S_t)+\alpha\left(R_{t+1}+\gamma V(S_{t+1})-V(S_t)\right) V(St)V(St)+α(Rt+1+γV(St+1)V(St))

其中 S t 是当前状态, R t + 1 是下一个状态的即时奖励, S t + 1 是下一个状态。 \text{其中}S_t\text{是当前状态,}R_{t+1}\text{是下一个状态的即时奖励,}S_{t+1}\text{是下一个状态。} 其中St是当前状态,Rt+1是下一个状态的即时奖励,St+1是下一个状态。

允许渐进式地从不完整的经验片段中学习(TD算法不需要等待一个完整的任务周期结束才进行学习,它可以逐步地从每次交互中学习。这意味着,它不需要等到下一个时间步的奖励才能更新其值函数的估计,而是可以使用当前的观察和奖励来更新。)这意味着要解决在线学习的问题。

  • 在线学习是指算法在与环境互动的过程中即时学习。

适用于无模型强化学习,因为它不依赖于马尔科夫决策过程的转移模型和奖励模型。

  • 无模型强化学习(Model-Free Reinforcement Learning)是一种强化学习方法,它不需要知道环境的内部模型,即不需要知道未来的状态转移概率和奖励分布。这与模型驱动的强化学习(Model-Based Reinforcement Learning)形成对比,后者需要一个环境的模型来做出决策。
  • 无模型强化学习算法,如Q学习(Q-Learning)、深度Q网络(Deep Q-Network,DQN)、策略梯度(Policy Gradient)和演员-评论家(Actor-Critic)方法,可以直接从传感器接收输入并采取行动,而不需要了解这些行动如何影响环境的具体机制。

前期准备

import numpy as np
import matplotlib.pyplot as plt

实现步骤

第一部分是GridworldV2的实现。

第二部分是TD算法的实现。

  1. 实现GridworldV2,定义GridworldV2Env()类

    class GridworldV2Env(gym.Env):
        def __init__(self, step_cost=-0.2, max_ep_length=500, explore_start=False):
            self.index_to_coordinate_map = {
                "0": [0, 0],
                "1": [0, 1],
                "2": [0, 2],
                "3": [0, 3],
                "4": [1, 0],
                "5": [1, 1],
                "6": [1, 2],
                "7": [1, 3],
                "8": [2, 0],
                "9": [2, 1],
                "10": [2, 2],
                "11": [2, 3],
            }
            self.coordinate_to_index_map = {
                str(val): int(key) for key, val in self.index_to_coordinate_map.items()
            }
    
  2. 实现_init_()函数,定义Gridworld大小、目标位置、墙体位置和炸弹位置等必要的值

    self.map = np.zeros((3, 4))
    self.observation_space = gym.spaces.Discrete(12)
    self.distinct_states = [str(i) for i in range(12)]
    self.goal_coordinate = [0, 3]
    self.bomb_coordinate = [1, 3]
    self.wall_coordinate = [1, 1]
    self.goal_state = self.coordinate_to_index_map[str(self.goal_coordinate)]  # 3
    self.bomb_state = self.coordinate_to_index_map[str(self.bomb_coordinate)]  # 7
    self.map[self.goal_coordinate[0]][self.goal_coordinate[1]] = 1
    self.map[self.bomb_coordinate[0]][self.bomb_coordinate[1]] = -1
    self.map[self.wall_coordinate[0]][self.wall_coordinate[1]] = 2
    
    self.exploring_starts = explore_start
    self.state = 8
    self.done = False
    self.max_ep_length = max_ep_length
    self.steps = 0
    self.step_cost = step_cost
    self.action_space = gym.spaces.Discrete(4)
    self.action_map = {"UP": 0, "RIGHT": 1, "DOWN": 2, "LEFT": 3}
    self.possible_actions = list(self.action_map.values())
    

    这个环境定义了基本的网格世界,其中代理可以在网格中移动,以到达目标位置,同时避免炸弹和墙壁。每一步都会收到一个负的step_cost,当达到目标或炸弹位置时,episode结束。

  3. 定义reset()函数,它将在每一个回合的开始被调用,包括第一个回合

    def reset(self):
        self.done = False
        self.steps = 0
        self.map = np.zeros((3, 4))
        self.map[self.goal_coordinate[0]][self.goal_coordinate[1]] = 1
        self.map[self.bomb_coordinate[0]][self.bomb_coordinate[1]] = -1
        self.map[self.wall_coordinate[0]][self.wall_coordinate[1]] = 2
    
        if self.exploring_starts:
            self.state = np.random.choice([0, 1, 2, 4, 6, 8, 9, 10, 11])
        else:
            self.state = 8
        return self.state
    

    在强化学习中,reset方法通常在每个episode开始时被调用,以重置环境状态并获取初始观察。在这个环境中,初始状态可能取决于是否进行探索开始,如果进行探索,则从一组排除特定状态(如墙壁)的状态中随机选择初始状态;如果不进行探索,则始终从状态8开始。

  4. 实现一个get_next_state()函数,以便获取下一个状态

    def get_next_state(self, current_position, action):
    
        next_state = self.index_to_coordinate_map[str(current_position)].copy()
    
        if action == 0 and next_state[0] != 0 and next_state != [2, 1]:
            # Move up
            next_state[0] -= 1
        elif action == 1 and next_state[1] != 3 and next_state != [1, 0]:
            # Move right
            next_state[1] += 1
        elif action == 2 and next_state[0] != 2 and next_state != [0, 1]:
            # Move down
            next_state[0] += 1
        elif action == 3 and next_state[1] != 0 and next_state != [1, 2]:
            # Move left
            next_state[1] -= 1
        else:
            pass
        return self.coordinate_to_index_map[str(next_state)]
    

    这个方法确保了Agent不能穿过墙壁(或任何不可通过的状态),并且在尝试超出网格边界时也不会移动。如果代理尝试移动到这些位置,它将保持在当前位置。

  5. 实现GridworldV2环境中的主要的step()函数。它实现了强化学习环境中的关键部分,即在给定动作的情况下执行一步并返回新的状态、奖励和是否完成。

    def step(self, action):
        assert action in self.possible_actions, f"Invalid action:{action}"
    
        current_position = self.state
        next_state = self.get_next_state(current_position, action)
    
        self.steps += 1
    
        if next_state == self.goal_state:
            reward = 1
            self.done = True
    
        elif next_state == self.bomb_state:
            reward = -1
            self.done = True
        else:
            reward = self.step_cost
    
        if self.steps == self.max_ep_length:
            self.done = True
    
        self.state = next_state
        return next_state, reward, self.done
    

    step方法在强化学习算法中非常重要,因为它定义了代理如何与环境互动。每次调用step方法时,代理都会根据所选动作在环境中前进一步,并获得相应的奖励,同时检查是否达到目标或遇到炸弹,或者是否达到了episode的最大长度。

  6. 继续实现时序差分学习算法,首先使用一个二维numpy数组初始化网络的状态值,然后设置目标位置和炸弹状态的值。

    def temporal_difference_learning(env, max_episodes):
        grid_state_values = np.zeros((len(env.distinct_states), 1))
        grid_state_values[env.goal_state] = 1
        grid_state_values[env.bomb_state] = -1
    
  7. 定义折扣因子gamma、学习率alpha、将done初始化为false。

    v = grid_state_values
    gamma = 0.99  # Discount factor
    alpha = 0.01  # learning rate
    
  8. 定义外部主循环,使其运行max_episode次,并在每个回合开始时将环境状态重置为初始值。

    for episode in range(max_episodes):
        state = env.reset()
    
  9. 实现内循环,其中使用一行代码进行时序差分学习更新。

    while not done:
        action = env.action_space.sample()  # random policy
        next_state, reward, done = env.step(action)
    
        # State-value function updates using TD(0)
        v[state] += alpha * (reward + gamma * v[next_state] - v[state])
        state = next_state
    

    这里实现了TD(0)更新规则,它更新状态价值函数v。更新的公式是:

    V ( S t ) ← V ( S t ) + α ( R t + 1 + γ V ( S t + 1 ) − V ( S t ) ) V(S_t)\leftarrow V(S_t)+\alpha\left(R_{t+1}+\gamma V(S_{t+1})-V(S_t)\right) V(St)V(St)+α(Rt+1+γV(St+1)V(St))

    其中 S t 是当前状态, R t + 1 是下一个状态的即时奖励, S t + 1 是下一个状态。 \text{其中}S_t\text{是当前状态,}R_{t+1}\text{是下一个状态的即时奖励,}S_{t+1}\text{是下一个状态。} 其中St是当前状态,Rt+1是下一个状态的即时奖励,St+1是下一个状态。

  10. 学习收敛后,希望能够可视化GridworldV2环境中每个状态的状态值。为此可以使用 value_function_utils()函数中的visualize_grid_state_values()函数

    visualize_grid_state_values(grid_state_values.reshape((3, 4)))
    
  11. 主函数中运行temporal_difference_learning函数

    if __name__ == "__main__":
        max_episodes = 4000
        env = GridworldV2Env(step_cost=-0.1, max_ep_length=30)
        temporal_difference_learning(env, max_episodes)
    
  12. 运行max_episodes个回合的时序差分学习,然后产生的图可以展示GridworldV2环境的网格单元坐标和状态值,每个状态根据右边显示的刻度着色。
    在这里插入图片描述

工作原理

状态是线性化的,用一个整数表示环境中的12个不同状态。

构建强化学习中的蒙特卡洛预测和控制算法

与时序差分学习算法类似,蒙特卡洛学习算法可用于学习状态函数和动作价值函数。

  • 二者都可以用来估计强化学习中的状态价值函数(V函数)和动作价值函数(Q函数)。状态价值函数预测从某个状态出发,遵循某种策略所能获得的期望回报;动作价值函数预测在某个状态下采取特定动作后所能获得的期望回报。
  • 时序差分学习算法和蒙特卡洛学习算法的主要区别在于,时序差分学习不需要完整的回合来更新价值函数,它可以通过单步转移来更新;而蒙特卡洛方法需要等待一个回合结束后,使用该回合的全部经验来更新价值函数。

由于蒙特卡洛学习方法是从真实经验的完整回合中学习,而没有近似预测,所以蒙特卡洛方法是无偏的。

  • 蒙特卡洛方法基于实际完成的回合数据(即从状态到最终回报的完整序列),因此它的估计不依赖于任何模型或预测,只依赖于实际发生的事件。这使得蒙特卡洛方法在理论上能够提供无偏的估计,即它的长期平均估计将准确反映真实的价值函数。

这个方法适用于需要良好收敛性的应用。

  • 随着经验的积累,蒙特卡洛方法估计的价值函数将越来越接近真实的价值函数。因此,当应用场景要求算法最终能够收敛到正确的解决方案时,蒙特卡洛方法是一个合适的选择。

前期准备

import numpy as np

实现步骤

首先实现monte_carlo_prediction算法,并在GridworldV2环境中学习到的每个状态的价值函数进行可视化。随后实现epsilon-greedy策略和monte_carlo_control算法,构造一个可以在强化学习环境中行动的智能体

  1. 导入必要的Python模块

    import numpy as np
    from envs.gridworldv2 import GridworldV2Env
    from value_function_utils import (
        visualize_grid_action_values,
        visualize_grid_state_values,
    )
    
  2. 定义monte_carlo_prediction() 函数并初始化必要的对象

    def monte_carlo_prediction(env, max_episodes):
        returns = {state: [] for state in env.distinct_states}
        grid_state_values = np.zeros(len(env.distinct_states))
        grid_state_values[env.goal_state] = 1
        grid_state_values[env.bomb_state] = -1
        gamma = 0.99  # Discount factor
    
  3. 实现外部循环。外部循环在所有强化学习智能体代码中都很常见

    for episode in range(max_episodes):
            g_t = 0
            state = env.reset()
            done = False
            trajectory = []
    
  4. 实现内部循环

    while not done:
        action = env.action_space.sample()  # random policy
        next_state, reward, done = env.step(action)
        trajectory.append((state, reward))
        state = next_state
    
  5. 计算网络中的状态值

    for idx, (state, reward) in enumerate(trajectory[::-1]):
            g_t = gamma * g_t + reward
            # first visit Monte-Carlo prediction
            if state not in np.array(trajectory[::-1])[:, 0][idx + 1 :]:
                returns[str(state)].append(g_t)
                grid_state_values[state] = np.mean(returns[str(state)])
    visualize_grid_state_values(grid_state_values.reshape((3, 4)))
    

    对于轨迹 τ \tau τ中的每个状态 s s s和奖励 r r r,从后向前执行以下步骤:a.更新累积回报 G t = γ G t + r G_t=\gamma G_t+r Gt=γGt+r。b.如果 s s s是轨迹 τ \tau τ中该位置之后首次出现的状态,则执行以下操作:i.将 G t G_t Gt添加到 G ( s ) G(s) G(s)。ii.更新状态价值
    V ( s ) = 1 ∣ G ( s ) ∣ ∑ g ∈ G ( s ) g 。 V(s)=\frac1{|G(s)|}\sum_{g\in G(s)}g\text{。} V(s)=G(s)1gG(s)g

    这个代码使用了蒙特卡洛预测方法来估计环境中的状态价值,通过多次模拟(随机策略)来收集足够的数据,并计算每个状态的平均回报。这种方法适用于具有确定性的环境,其中状态转换和奖励是已知的。

  6. 运行蒙特卡洛预测期

    if __name__ == "__main__":
        max_episodes = 4000
        env = GridworldV2Env(step_cost=-0.1, max_ep_length=30)
        print(f"===Monte Carlo Prediction===")
        monte_carlo_prediction(env, max_episodes)
    
  7. 生成图表显示GridworldV2环境和状态值。

    在这里插入图片描述

  8. 实现一个epsilon-greddy策略的函数

    def epsilon_greedy_policy(action_logits, epsilon=0.2):
        idx = np.argmax(action_logits)
        probs = []
        epsilon_decay_factor = np.sqrt(sum([a ** 2 for a in action_logits]))
    
        if epsilon_decay_factor == 0:
            epsilon_decay_factor = 1.0
        for i, a in enumerate(action_logits):
            if i == idx:
                probs.append(round(1 - epsilon + (epsilon / epsilon_decay_factor), 3))
            else:
                probs.append(round(epsilon / epsilon_decay_factor, 3))
        residual_err = sum(probs) - 1
        residual = residual_err / len(action_logits)
    
        return np.array(probs) - residual
    
    1. 最大动作日志概率的索引
      设 ( a = [ a 1 , a 2 , . . . , a n ] \mathbf{a} = [a_1, a_2, ..., a_n] a=[a1,a2,...,an] ) 为动作日志概率向量,其中 ( a i a_i ai ) 表示第 ( i i i ) 个动作的日志概率。找到具有最大日志概率的动作的索引 ( i max i_{\text{max}} imax):
      [ i max = arg ⁡ max ⁡ i a i i_{\text{max}} = \arg\max_i a_i imax=argmaxiai]
    2. 计算 ε 衰减因子
      设 ( ϵ \epsilon ϵ) 为 ε-贪婪策略中的 ε 参数,计算 ε 衰减因子 ( ϵ decay \epsilon_{\text{decay}} ϵdecay):
      [ ϵ decay = ∑ i = 1 n a i 2 \epsilon_{\text{decay}} = \sqrt{\sum_{i=1}^{n} a_i^2} ϵdecay=i=1nai2 ]
      如果 ( ϵ decay = 0 \epsilon_{\text{decay}} = 0 ϵdecay=0 ),则将 ( ϵ decay \epsilon_{\text{decay}} ϵdecay) 设置为 1,以避免除以零:
      [ ϵ decay = { 1 if  ϵ decay = 0 ∑ i = 1 n a i 2 otherwise \epsilon_{\text{decay}} = \begin{cases} 1 & \text{if } \epsilon_{\text{decay}} = 0 \\ \sqrt{\sum_{i=1}^{n} a_i^2} & \text{otherwise} \end{cases} ϵdecay={1i=1nai2 if ϵdecay=0otherwise]
    3. 为每个动作分配概率
      对于每个动作 ( i i i ),计算其概率 ( p i p_i pi ):
      [ p i = { round ( 1 − ϵ + ϵ ϵ decay , 3 ) if  i = i max round ( ϵ ϵ decay , 3 ) otherwise p_i = \begin{cases} \text{round}\left(1 - \epsilon + \frac{\epsilon}{\epsilon_{\text{decay}}}, 3\right) & \text{if } i = i_{\text{max}} \\ \text{round}\left(\frac{\epsilon}{\epsilon_{\text{decay}}}, 3\right) & \text{otherwise} \end{cases} pi= round(1ϵ+ϵdecayϵ,3)round(ϵdecayϵ,3)if i=imaxotherwise]
      其中,( round ( x , 3 ) \text{round}(x, 3) round(x,3)) 表示将 ( x x x) 四舍五入到小数点后三位。
    4. 修正概率分布
      设 ( p = [ p 1 , p 2 , . . . , p n ] \mathbf{p} = [p_1, p_2, ..., p_n] p=[p1,p2,...,pn]) 为计算出的概率向量。计算概率总和与 1 的差值 ( residual_err \text{residual\_err} residual_err):
      [ residual_err = ∑ i = 1 n p i − 1 \text{residual\_err} = \sum_{i=1}^{n} p_i - 1 residual_err=i=1npi1]
      计算每个概率需要减去的平均误差 ( residual \text{residual} residual):
      [ residual = residual_err n \text{residual} = \frac{\text{residual\_err}}{n} residual=nresidual_err]
      最终修正的概率向量 ( p ′ \mathbf{p'} p) 为:
      [ p ′ = p − residual \mathbf{p'} = \mathbf{p} - \text{residual} p=presidual]
      其中 ( p ′ \mathbf{p'} p) 的每个元素 ( p i ′ p'_i pi) 都被减去了平均误差 ( residual \text{residual} residual),以确保概率总和为 1。
      通过这些数学表述,我们可以清晰地理解 ε-贪婪策略的概率分配机制,以及如何通过四舍五入和修正来确保概率分布的有效性。

    生成一个 ε-贪婪策略的概率分布,基于给定的动作日志概率(action logits)和一个 ε 参数

    这个函数最终返回一个数组,其中包含了根据 ε-贪婪策略计算出的每个动作的概率。ε-贪婪策略确保了最优动作(具有最高日志概率的动作)以较高的概率被选择,同时也有一定的概率选择随机动作,以便进行探索。通过四舍五入和修正,确保了概率总和为 1,从而构成一个有效的概率分布

  9. 实现强化学习的蒙特卡洛控制算法。首先定义函数以及状态-动作价值的初始值

    def monte_carlo_control(env, max_episodes):
        grid_state_action_values = np.zeros((12, 4))
        grid_state_action_values[3] = 1
        grid_state_action_values[7] = -1
    
  10. 继续所有可能的状态-动作的回报进行初始化

    possible_states = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]
    possible_actions = ["0", "1", "2", "3"]
    returns = {}
    for state in possible_states:
        for action in possible_actions:
            returns[state + ", " + action] = []
    
  11. 为每个回合定义外部循环,然后为回合中的每个单步定义内部循环。这样就可以收集经验轨迹直到一个回合结束。

    gamma = 0.99
    for episode in range(max_episodes):
        g_t = 0
        state = env.reset()
        trajectory = []
        while True:
            action_values = grid_state_action_values[state]
            probs = epsilon_greedy_policy(action_values)
            action = np.random.choice(np.arange(4), p=probs)  # random policy
    
            next_state, reward, done = env.step(action)
            trajectory.append((state, action, reward))
    
            state = next_state
            if done:
                break
    
  12. 通过内循环获得一个回合的完整轨迹,可以实现蒙特卡洛控制并更新状态-动作价值

    for step in reversed(trajectory):
        g_t = gamma * g_t + step[2]
        returns[str(step[0]) + ", " + str(step[1])].append(g_t)
        grid_state_action_values[step[0]][step[1]] = np.mean(
            returns[str(step[0]) + ", " + str(step[1])]
        )
    

    蒙特卡洛控制算法通过多次模拟(随机策略)来收集足够的数据,并计算每个状态-动作对的平均回报,从而估计状态-动作价值。这种方法适用于具有确定性的环境,其中状态转换、奖励和动作结果都是已知的。

    • 初始化: Q ( s , a ) = 0 Q(s, a) = 0 Q(s,a)=0对于所有 s ∈ S s \in S sS a ∈ A a \in A aA,除了 Q ( s goal , ⋅ ) = 1 Q(s_{\text{goal}}, \cdot) = 1 Q(sgoal,)=1 Q ( s bomb , ⋅ ) = − 1 Q(s_{\text{bomb}}, \cdot) = -1 Q(sbomb,)=1
    • 对于每个回合 e e e
      • 重置: G t = 0 G_t = 0 Gt=0 s = reset() s = \text{reset()} s=reset() τ = ∅ \tau = \emptyset τ=
      • done = False \text{done} = \text{False} done=False
        • 选择动作: a ∼ π ( ⋅ ∣ s ) a \sim \pi(\cdot|s) aπ(s)
        • 执行: s ′ , r , done = step ( a ) s', r, \text{done} = \text{step}(a) s,r,done=step(a)
        • 记录: τ ← τ ∪ { ( s , a , r ) } \tau \leftarrow \tau \cup \{(s, a, r)\} ττ{(s,a,r)}
        • 更新状态: s = s ′ s = s' s=s
      • 反向遍历轨迹 τ \tau τ
        • 更新累积回报: G t = γ G t + r G_t = \gamma G_t + r Gt=γGt+r
        • 更新回报列表: G ( s , a ) ← G ( s , a ) ∪ { G t } G(s, a) \leftarrow G(s, a) \cup \{G_t\} G(s,a)G(s,a){Gt}
        • 更新状态-动作价值: Q ( s , a ) = 1 ∣ G ( s , a ) ∣ ∑ g ∈ G ( s , a ) g Q(s, a) = \frac{1}{|G(s, a)|} \sum_{g \in G(s, a)} g Q(s,a)=G(s,a)1gG(s,a)g
    • 一旦外部循环结束,就可以使用value_function_utils脚本中的辅助函数visualize_grid_action_values()可视化状态-动作价值
    visualize_grid_action_values(grid_state_action_values)
    
  13. 运行monte_carlo_control函数,在GridworldV2环境中学习状态-动作价值,并展示学习到的值

    if __name__ == "__main__":
        max_episodes = 4000
        env = GridworldV2Env(step_cost=-0.1, max_ep_length=30)
        print(f"===Monte Carlo Control===")
        monte_carlo_control(env, max_episodes)
    

在这里插入图片描述

学习到的状态-动作价值函数的结果如图。其中网格单元中的每个三角形显示了在该网格状态下采取该方向动作的状态-动作价值。三角形的底边与动作的方向一致。

工作原理

对于回合任务,蒙特卡洛方法直接从一个回合获得的完整样本回报中学习。基于对首次访问进行平均来估计价值函数的蒙特卡洛预测

初始化:

  • π ← \pi\leftarrow πpolicy to be evaluated:选择一个要评估的策略 π \pi π

  • V ← V\leftarrow Van arbitrary state-value function:初始化一个任意的状态价值函数 V V V,可以是一个全零的向量或随机值。

  • R e t u r n s ( s ) ← Returns(s)\leftarrow Returns(s)an empty list, for all s ∈ S s\in\mathfrak{S} sS:对于所有可能的状态 s s s,创建一个空列表来存储每个状态的未来回报。

重复执行以下步骤:

  • Generate an episode using π \pi π:使用策略 π \pi π生成一个回合(或剧集),即从当前状态出发,根据策略选择动作,直到回合结束,得到一系列的状态、动作和奖励。

  • For each state s s s appearing in the episode:对于回合中出现的每一个状态 s s s

    • G ← G\leftarrow Greturn following the first occurrence of s s s:计算从状态 s s s首次出现之后直到回合结束的回报 G G G。回报 G G G是状态 s s s之后所有奖励的累加。
    • Append G G G to Returns(s):将计算得到的回报 G G G添加到状态 s s s的回报列表中。
    • V ( s ) ← V(s)\leftarrow V(s)average ( R e t u r n s ( s ) ) (Returns(s)) (Returns(s)):更新状态价值函数 V ( s ) V(s) V(s),通过计算到目前为止状态 s s s的所有回报的平均值。

通过不断重复上述过程,蒙特卡洛方法可以逐步逼近真实的价值函数。由于蒙特卡洛方法是基于实际经验(即回合)来更新价值估计的,它不依赖于模型,因此属于模型自由(model-free)的方法。
这个方法的关键在于它只考虑了首次访问的状态,即在一个回合中,只有状态 s s s的第一次出现会被用来计算回报并更新价值函数。这样做可以减少方差,使价值函数的估计更加稳定。

一旦智能体收集了一系列的轨迹,就可以利用蒙特卡洛控制算法中的转移信息来学习状态-动作价值函数。智能体可以使用该价值函数在给定的强化学习环境中工作

以下蒙特卡洛控制算法的过程,该算法用于学习状态-动作价值函数(通常表示为𝑄Q函数),并基于学到的价值函数来改进策略。

初始化:

  • 对于所有状态 s ∈ S s\in\mathcal{S} sS和对应的动作 a ∈ A ( s ) a\in\mathcal{A}(s) aA(s)
    • Q ( s , a ) ← Q(s,a)\leftarrow Q(s,a)arbitrary:初始化状态-动作价值函数 Q ( s , a ) Q(s,a) Q(s,a)为任意值,通常可以设置为0。

    • R e t u r n s ( s , a ) ← Returns(s,a)\leftarrow Returns(s,a)empty list:为每个状态-动作对创建一个空列表,用于存储后续的回报。

    • π ← \pi\leftarrow πan arbitrary ε \varepsilon ε-soft policy:初始化一个任意的 ε \varepsilon ε-软策略 π \pi π,这意味着所有动作都有非零的概率被选中,并且至少有一个动作被选中的概率是 1 − ε 1-\varepsilon 1ε加上平均分配给其他动作的概率 ε / ∣ A ( s ) ∣ \varepsilon/|\mathcal{A}(s)| ε/∣A(s)

重复执行以下步骤:
(a) Generate an episode using π \pi π:使用当前策略 π \pi π生成一个回合(或剧集),即从当前状态出发,根据策略选择动作,直到回合结束。
(b) For each pair s , a s,a s,a appearing in the episode:对于回合中出现的每一个状态-动作对 s , a s,a s,a

  • R ← R\leftarrow Rreturn following the first occurrence of s , a s,a s,a:计算从状态-动作对 s , a s,a s,a首次出现之后直到回合结束的回报 R R R
  • A p p e n d   R {\mathrm{Append~}}R Append R to R e t u r n s ( s , a ) Returns(s,a) Returns(s,a):将计算得到的回报 R R R添加到状态-动作对 s , a s,a s,a的回报列表中。
  • Q ( s , a ) ← Q(s,a)\leftarrow Q(s,a)average ( Returns ( s , a ) ) ( \textit{Returns}( s, a) ) (Returns(s,a)):更新状态-动作价值函数 Q ( s , a ) Q(s,a) Q(s,a),通过计算到目前为止状态-动作对 s , a s,a s,a的所有回报的平均值。
    © For each s s s in the episode:对于回合中出现的每一个状态 s s s
  • a ∗ ← arg ⁡ max ⁡ a Q ( s , a ) a^{*}\leftarrow\arg\max_{a}Q(s,a) aargmaxaQ(s,a):选择在状态 s s s下具有最大 Q Q Q值的动作 a ∗ a^{*} a
  • For all a ∈ A ( s )  ⁣ : a\in\mathcal{A}(s)\colon aA(s): 对于所有可能的动作 a a a
    • 更新策略 π \pi π,根据以下规则:
      • 如果 a = a ∗ a=a^{*} a=a(即动作 a a a是当前状态 s s s下最优的动作),则:
        π ( s , a ) ← 1 − ε + ε / ∣ A ( s ) ∣ \pi(s,a)\leftarrow 1-\varepsilon+\varepsilon/|\mathcal{A}(s)| π(s,a)1ε+ε/∣A(s)
        这意味着最优动作被选中的概率是 1 − ε 1-\varepsilon 1ε加上每个非最优动作平均分配的概率 ε / ∣ A ( s ) ∣ \varepsilon/|\mathcal{A}(s)| ε/∣A(s)
      • 如果 a ≠ a ∗ a\neq a^{*} a=a(即动作 a a a不是当前状态 s s s下最优的动作),则:
        π ( s , a ) ← ε / ∣ A ( s ) ∣ \pi(s,a)\leftarrow \varepsilon/|\mathcal{A}(s)| π(s,a)ε/∣A(s)
        这意味着非最优动作被选中的概率是每个动作平均分配的概率 ε / ∣ A ( s ) ∣ \varepsilon/|\mathcal{A}(s)| ε/∣A(s)

这个过程会不断重复,随着智能体收集更多的轨迹, Q Q Q函数会越来越准确地反映状态-动作的真实价值,策略 π \pi π也会逐渐改进,使得在给定的强化学习环境中智能体的行为更加优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1933934.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JRT实体视图查询

JRT的设计目标就是多数据库支持,对于爬行周边数据提供DolerGet解决爬取多维数据问题。但是对于通过父表字段筛选子表数据就不能通过DolerGet取数据了,因为查询到的父表数据没有子表数据的ID。 比如下面表: 我需要按登记号查询这个登记号的报…

tree组件实现折叠与展开功能(方式2 - visible计算属性)

本示例节选自vue3最新开源组件实战教程大纲(持续更新中)的tree组件开发部分。考察Vue3 Composition API形式的计算属性的用法,computed可以单独用在ts文件中,实现ts的计算属性类型的定义。 父节点属性 在IFlatTreeNode中定义父节…

Blackbox AI:你的智能编程伙伴

目录 Blackbox AI 产品介绍 Blackbox AI 产品使用教程 Blackbox AI体验 AI问答 代码验证 实时搜索 探索&代理 拓展集成 总结 Blackbox AI 产品介绍 Blackbox是专门为程序员量身定制的语言大模型,它针对20多种编程语言进行了特别训练和深度优化,在AI代…

MySQL JDBC

JDBC:Java的数据库编程 JDBC,即Java Database Connectivity,java数据库连接。是一种用于执行SQL语句的Java API,它是 Java中的数据库连接规范。这个API由 java.sql.*,javax.sql.* 包中的一些类和接口组成,它为Java 开…

MySQL:基础操作(增删查改)

目录 一、库的操作 创建数据库 查看数据库 显示创建语句 修改数据库 删除数据库 备份和恢复 二、表的操作 创建表 查看表结构 修改表 删除表 三、表的增删查改 新增数据 插入否则更新 插入查询的结果 查找数据 为查询结果指定别名 结果去重 where 条件 结…

tree组件实现折叠与展开功能(方式1 - expandedTree计算属性)

本示例节选自vue3最新开源组件实战教程大纲(持续更新中)的tree组件开发部分。考察响应式对象列表封装和computed计算属性的使用,以及数组reduce方法实现结构化树拍平处理的核心逻辑。 实现思路 第一种方式:每次折叠或展开后触发…

经纬恒润全新第二代行泊一体域控制器成功量产

随着L2自动驾驶功能的普及,整车架构的升级,传统分布式控制器已不能适应市场的发展,如何以低成本高性能实现高阶自动驾驶功能的落地, 成为了众多整车厂的迫切需求,行泊一体域控制器应运而生。据高工数据显示,2023年仅1-…

NVIDIA GPU 监控观测最佳实践

1、DCGM 介绍 DCGM(Data Center GPU Manager)即数据中心 GPU 管理器,是一套用于在集群环境中管理和监视 Tesla™GPU 的工具。它包括主动健康监控,全面诊断,系统警报以及包括电源和时钟管理在内的治理策略。它可以由系…

TypeScript 基础类型(一)

简介 它是 JavaScript 的超集,具有静态类型检查和面向对象编程的特性。TypeScript 的出现,为开发者提供了一种更加严谨和高效的开发方式。 主要特点: 、静态类型检查。 通过静态类型检查,开发者可以在编译时发现错误&#xff0…

大气热力学(8)——热力学图的应用之一(气象要素求解)

本篇文章源自我在 2021 年暑假自学大气物理相关知识时手写的笔记,现转化为电子版本以作存档。相较于手写笔记,电子版的部分内容有补充和修改。笔记内容大部分为公式的推导过程。 文章目录 8.1 复习斜 T-lnP 图上的几种线8.1.1 等温线和等压线8.1.2 干绝热…

搬运5款我觉得超级好用的软件

​ 今天再来推荐5个超级好用的效率软件,无论是对你的学习还是办公都能有所帮助,每个都堪称神器中的神器,用完后觉得不好用你找我。 1.PDF阅读——Sumatra PDF ​ Sumatra PDF 是一款 PDF 阅读器,它的界面简洁,使用起…

乐尚代驾一项目概述

前言 2024年7月17日,最近终于在低效率的情况下把java及其生态的知识点背的差不多了,投了两个礼拜的简历,就一个面试,总结了几点原因。 市场环境不好 要知道,前两年找工作,都不需要投简历,把简历…

DevExpress WPF中文教程 - 为项目添加GridControl并将其绑定到数据

DevExpress WPF拥有120个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…

小程序-3(页面导航+页面事件+生命周期+WXS)

目录 1.页面导航 声明式导航 导航到tabBar页面 导航到非tabBar页面 后退导航 编程式导航 后退导航 导航传参 声明式导航传参 编程式导航传参 在onload中接收导航参数 2.页面事件 下拉刷新 停止下拉刷新的效果 ​编辑 上拉触底 配置上拉触底距离 上拉触底的节…

函数返回右值的一点学习研究

https://zhuanlan.zhihu.com/p/511371573?utm_mediumsocial&utm_oi939219201949429760 下面情况下不会调用: DPoint3d fun1() {return DPoint3d{1,2,3}; // 默认构造 }int main() {DPoint3d&& a fun1();a.y 20;int i 0;i; } 下面情况下&#xff0c…

【内网穿透】如何本地搭建Whisper语音识别模型并配置公网地址

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] &#x1f4f1…

数据库管理的艺术(MySQL):DDL、DML、DQL、DCL及TPL的实战应用(下:数据操作与查询)

文章目录 DML数据操作语言1、新增记录2、删除记录3、修改记录 DQL数据查询语言1、查询记录2、条件筛选3、排序4、函数5、分组条件6、嵌套7、模糊查询8、limit分页查询 集合操作union关键字和运算符in关键字any关键字some关键字all关键字 联合查询1、广义笛卡尔积2、等值连接3、…

【.NET全栈】ASP.NET开发Web应用——站点导航技术

文章目录 前言一、站点地图1、定义站点地图文件2、使用SiteMapPath控件3、SiteMap类4、URL地址映射 二、TreeView控件1、使用TreeView控件2、以编程的方式添加节点3、使用TreeView控件导航4、绑定到XML文件5、按需加载节点6、带复选框的TreeView控件 三、Menu控件1、使用Menu控…

【BUG】已解决:ModuleNotFoundError: No module named ‘cv2’

已解决:ModuleNotFoundError: No module named ‘cv2’ 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰,211科班出身,就职于医疗科技公司,热衷分享知识,武汉城市开…

C语言中常见库函数(1)——字符函数和字符串函数

文章目录 前言1.字符分类函数2.字符转换函数3.strlen的使用和模拟实现4.strcpy的使用和模拟实现5.strcat的使用和模拟实现6.strncmp的使用和模拟实现7.strncpy函数的使用8.strncat函数的使用9.strncmp函数的使用10.strstr的使用和模拟实现11.strtok函数的使用12.strerror函数的…