探索与利用
• 12 min read • 2309 words
Tags: Re-Le
Categories: Introduction to Artificial Intelligence
探索与利用
1. 相关概念
在强化学习中,智能体的目标是学习一个最优策略来最大化长期回报。为了达成此目标,智能体必须在两个核心行为之间做出权衡:
- 探索 (Exploration): 尝试当前看起来并非最优的动作,目的是为了收集更多关于环境的信息,发现潜在的、更优的行动选择。
- 利用 (Exploitation): 执行当前已知能够带来最大回报的动作,以获取即时奖励。
“充分的探索” 是学习到最优策略的必要条件。如果智能体从不探索,它可能会满足于一个局部最优解,而错过了全局最优策略。在探索和利用之间取得恰当的平衡是强化学习中的一个核心挑战。
2. ε-贪心策略 (ε-Greedy Policies)
ε-贪心策略是一种在探索和利用之间进行权衡的简单方法。它通过一个参数 () 来控制探索的程度。
基本思想
智能体的行动策略如下:
- 以 概率 进行探索:在所有可能的动作中随机选择一个。
- 以 概率 进行利用:选择当前Q值估计最高的动作。
import random
def choose_action_epsilon_greedy(q_values, epsilon):
"""
Select an action based on given Q-values and epsilon value.
:param q_values: Estimated Q-values for all actions in the current state (e.g., a dict or list)
:param epsilon: Exploration probability
:return: Selected action
"""
if random.random() < epsilon:
# Exploration: randomly select an action
return random.choice(list(q_values.keys()))
else:
# Exploitation: select the action with the highest Q-value
return max(q_values, key=q_values.get)
策略的挑战
尽管实现简单,但ε-贪心策略的核心挑战在于 值的选择和调优:
- 值过大: 智能体将过于频繁地进行随机探索,即使已经学到了接近最优的策略,其行为依然会表现出很大的随机性,导致无法稳定地获得高回报。
- 值过小: 智能体探索不足,可能导致学习过程非常缓慢,或者过早地收敛到局部最优解。
为了解决这个问题,通常需要手动调整 ,使其在学习过程中随着时间的推移而逐渐衰减。
3. 探索函数
探索函数提供了一种更优雅的、自动化的方法来平衡探索与利用,避免了手动调优 的麻烦。其核心思想是修改Q值的更新规则,对访问次数较少的“状态-动作”对给予一定的“奖励”或“加成”。
更新规则
探索函数修改了传统的Q学习更新公式,将标准的 替换为一个函数 :
其中 是一个探索函数。一个常用的探索函数形式如下:
- : 当前的Q值估计。
- : “状态-动作”对 被访问的次数。
- : 一个预先设定的常数,用于控制探索的权重。
自动平衡机制
探索函数通过其内在的机制自动地平衡探索与利用:
- 鼓励探索: 当一个“状态-动作”对 被访问的次数 很少时, 项会很大。这个“探索奖励”会显著提高 的值,使得智能体更有可能选择这个被探索较少的动作,即使其当前的Q值估计不高。
- 回归利用: 随着学习的进行,所有“状态-动作”对的访问次数 都会增加,导致 项逐渐趋近于0。此时,探索函数 的值将主要由 决定,智能体的行为便自然地从探索过渡到了利用。
智能体在决策时,总是选择使 值最大的动作,从而将探索的需求直接编码到了决策过程中。
def choose_action_exploration_function(q_values, visit_counts, k):
"""
Select an action using the exploration function.
:param q_values: Q-values for all actions in the current state (dict)
:param visit_counts: Visit counts for all (state, action) pairs (dict)
:param k: Exploration weight constant
:return: Selected action
"""
best_action = None
max_f_value = -float('inf')
for action, q_value in q_values.items():
# Default visit count to 1 to avoid division by zero
n_sa = visit_counts.get(action, 1)
f_value = q_value + k / n_sa
if f_value > max_f_value:
max_f_value = f_value
best_action = action
return best_action