文章目录
- 实现时序差分学习
- 前期准备
- 实现步骤
- 工作原理
- 构建强化学习中的蒙特卡洛预测和控制算法
- 前期准备
- 实现步骤
- 工作原理
实现时序差分学习
时序差分(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算法的实现。
-
实现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() }
-
实现_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结束。 -
定义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开始。 -
实现一个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不能穿过墙壁(或任何不可通过的状态),并且在尝试超出网格边界时也不会移动。如果代理尝试移动到这些位置,它将保持在当前位置。
-
实现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的最大长度。 -
继续实现时序差分学习算法,首先使用一个二维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
-
定义折扣因子gamma、学习率alpha、将done初始化为false。
v = grid_state_values gamma = 0.99 # Discount factor alpha = 0.01 # learning rate
-
定义外部主循环,使其运行max_episode次,并在每个回合开始时将环境状态重置为初始值。
for episode in range(max_episodes): state = env.reset()
-
实现内循环,其中使用一行代码进行时序差分学习更新。
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是下一个状态。
-
学习收敛后,希望能够可视化GridworldV2环境中每个状态的状态值。为此可以使用 value_function_utils()函数中的visualize_grid_state_values()函数
visualize_grid_state_values(grid_state_values.reshape((3, 4)))
-
主函数中运行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)
-
运行max_episodes个回合的时序差分学习,然后产生的图可以展示GridworldV2环境的网格单元坐标和状态值,每个状态根据右边显示的刻度着色。
工作原理
状态是线性化的,用一个整数表示环境中的12个不同状态。
构建强化学习中的蒙特卡洛预测和控制算法
与时序差分学习算法类似,蒙特卡洛学习算法可用于学习状态函数和动作价值函数。
- 二者都可以用来估计强化学习中的状态价值函数(V函数)和动作价值函数(Q函数)。状态价值函数预测从某个状态出发,遵循某种策略所能获得的期望回报;动作价值函数预测在某个状态下采取特定动作后所能获得的期望回报。
- 时序差分学习算法和蒙特卡洛学习算法的主要区别在于,时序差分学习不需要完整的回合来更新价值函数,它可以通过单步转移来更新;而蒙特卡洛方法需要等待一个回合结束后,使用该回合的全部经验来更新价值函数。
由于蒙特卡洛学习方法是从真实经验的完整回合中学习,而没有近似预测,所以蒙特卡洛方法是无偏的。
- 蒙特卡洛方法基于实际完成的回合数据(即从状态到最终回报的完整序列),因此它的估计不依赖于任何模型或预测,只依赖于实际发生的事件。这使得蒙特卡洛方法在理论上能够提供无偏的估计,即它的长期平均估计将准确反映真实的价值函数。
这个方法适用于需要良好收敛性的应用。
- 随着经验的积累,蒙特卡洛方法估计的价值函数将越来越接近真实的价值函数。因此,当应用场景要求算法最终能够收敛到正确的解决方案时,蒙特卡洛方法是一个合适的选择。
前期准备
import numpy as np
实现步骤
首先实现monte_carlo_prediction算法,并在GridworldV2环境中学习到的每个状态的价值函数进行可视化。随后实现epsilon-greedy策略和monte_carlo_control算法,构造一个可以在强化学习环境中行动的智能体
-
导入必要的Python模块
import numpy as np from envs.gridworldv2 import GridworldV2Env from value_function_utils import ( visualize_grid_action_values, visualize_grid_state_values, )
-
定义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
-
实现外部循环。外部循环在所有强化学习智能体代码中都很常见
for episode in range(max_episodes): g_t = 0 state = env.reset() done = False trajectory = []
-
实现内部循环
while not done: action = env.action_space.sample() # random policy next_state, reward, done = env.step(action) trajectory.append((state, reward)) state = next_state
-
计算网络中的状态值
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)∣1g∈G(s)∑g。这个代码使用了蒙特卡洛预测方法来估计环境中的状态价值,通过多次模拟(随机策略)来收集足够的数据,并计算每个状态的平均回报。这种方法适用于具有确定性的环境,其中状态转换和奖励是已知的。
-
运行蒙特卡洛预测期
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)
-
生成图表显示GridworldV2环境和状态值。
-
实现一个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
- 最大动作日志概率的索引:
设 ( 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] - 计算 ε 衰减因子:
设 ( ϵ \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={1∑i=1nai2if ϵdecay=0otherwise] - 为每个动作分配概率:
对于每个动作 ( 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) 四舍五入到小数点后三位。 - 修正概率分布:
设 ( 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=1npi−1]
计算每个概率需要减去的平均误差 ( 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′=p−residual]
其中 ( p ′ \mathbf{p'} p′) 的每个元素 ( p i ′ p'_i pi′) 都被减去了平均误差 ( residual \text{residual} residual),以确保概率总和为 1。
通过这些数学表述,我们可以清晰地理解 ε-贪婪策略的概率分配机制,以及如何通过四舍五入和修正来确保概率分布的有效性。
生成一个 ε-贪婪策略的概率分布,基于给定的动作日志概率(action logits)和一个 ε 参数
这个函数最终返回一个数组,其中包含了根据 ε-贪婪策略计算出的每个动作的概率。ε-贪婪策略确保了最优动作(具有最高日志概率的动作)以较高的概率被选择,同时也有一定的概率选择随机动作,以便进行探索。通过四舍五入和修正,确保了概率总和为 1,从而构成一个有效的概率分布。
- 最大动作日志概率的索引:
-
实现强化学习的蒙特卡洛控制算法。首先定义函数以及状态-动作价值的初始值
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
-
继续所有可能的状态-动作的回报进行初始化
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] = []
-
为每个回合定义外部循环,然后为回合中的每个单步定义内部循环。这样就可以收集经验轨迹直到一个回合结束。
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
-
通过内循环获得一个回合的完整轨迹,可以实现蒙特卡洛控制并更新状态-动作价值
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 s∈S 和 a ∈ A a \in A a∈A,除了 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)∣1∑g∈G(s,a)g。
- 一旦外部循环结束,就可以使用value_function_utils脚本中的辅助函数visualize_grid_action_values()可视化状态-动作价值
visualize_grid_action_values(grid_state_action_values)
-
运行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 V←an 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} s∈S:对于所有可能的状态 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 G←return 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}
s∈S和对应的动作
a
∈
A
(
s
)
a\in\mathcal{A}(s)
a∈A(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 R←return 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) a∗←argmaxaQ(s,a):选择在状态 s s s下具有最大 Q Q Q值的动作 a ∗ a^{*} a∗。
- For all
a
∈
A
(
s
)
:
a\in\mathcal{A}(s)\colon
a∈A(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)∣。
- 如果
a
=
a
∗
a=a^{*}
a=a∗(即动作
a
a
a是当前状态
s
s
s下最优的动作),则:
- 更新策略
π
\pi
π,根据以下规则:
这个过程会不断重复,随着智能体收集更多的轨迹, Q Q Q函数会越来越准确地反映状态-动作的真实价值,策略 π \pi π也会逐渐改进,使得在给定的强化学习环境中智能体的行为更加优化。