📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉强化学习专栏:

       【强化学习】(28)---《分层演员-评论家(Hierarchical Actor-Critic )算法》

分层演员-评论家(Hierarchical Actor-Critic )算法

目录

1. Hierarchical Actor-Critic (HAC) 的核心思想

2. HAC的网络结构

(1) 高层策略:

(2) 低层策略:

3. HAC的关键公式

4. HAC的学习流程

[Python] Q-learning实现

环境要求

算法训练代码 

算法测试代码

[Notice]  说明:

5. HAC的优点与挑战

6. HAC的应用场景


        分层演员-评论家,Hierarchical Actor-Critic (HAC) 算法是一种用于分层强化学习(Hierarchical Reinforcement Learning, HRL)的算法,由Levy等人在2019年提出。HAC的目的是通过分层结构,将复杂任务分解为不同的时间尺度的子任务,从而更高效地学习策略。该算法使用了两层的Actor-Critic架构来实现策略和值函数的学习,并通过子任务的分解来降低学习的难度。

        背景:分层比非分层有潜力以更高的样本效率解决顺序决策任务,因为分层可以将任务分解为只需要短序列决策的子任务集。为了实现这种快速学习的潜力,分层需要能够并行学习它们的多层策略,以便这些更简单的子问题可以同时解决。然而,并行学习多层策略是困难的,因为它本质上是不稳定的:在层次结构的一个层次上的策略变化可能会导致层次结构中更高层次上的过渡和奖励函数的变化,这使得联合学习多层策略变得困难。

        上图是一个简单玩具例子的情节轨迹。轨迹上的抽搐痕迹显示 每个原始动作执行后机器人的下一个状态。粉色圆圈显示了最初的子目标 行动。灰色的圆圈显示了在低级别的最多H个动作之后达到的子目标状态策略。 


1. Hierarchical Actor-Critic (HAC) 的核心思想

         引入了一种新的分层强化学习(HRL)框架,即分层行为者-批评家(HAC),它可以克服当智能体试图共同学习多层策略时出现的不稳定性问题。HAC的主要思想是独立于较低层次来训练每一层,就好像较低层次的策略已经是最优的一样。作用是可以显著加速学习。HAC的核心思想是将任务分解为高层次(high-level)和低层次(low-level)两个层次:

  • 高层策略(High-Level Policy):负责高层的目标设定,操作在抽象的状态空间中。它选择低层策略的子目标,以使低层策略在原始状态空间中逐步接近完成。
  • 低层策略(Low-Level Policy):负责在更具体的动作空间中执行高层设定的目标,每一步采取实际的动作,学习如何接近高层指定的子目标。

        通过分层结构,HAC能够更有效地在长时间跨度的任务中进行学习,适应复杂任务并更快收敛。


2. HAC的网络结构

        HAC的网络结构使用了两层的Actor-Critic架构:

  • 高层Actor-Critic:负责基于当前的状态选择子目标,时间跨度较长(例如10步)。
  • 低层Actor-Critic:负责基于高层策略设定的子目标选择动作,执行具体的动作序列,通常每一步都进行更新。

(1) 高层策略

  • 高层Actor选择一个子目标作为低层策略的输入。
  • 高层Critic对其所选择的子目标进行评估,生成相应的值函数,帮助高层策略优化目标选择。

(2) 低层策略

  • 低层Actor使用高层设定的子目标作为输入,选择当前时间步的具体动作。
  • 低层Critic根据低层策略的表现,生成相应的值函数反馈给低层Actor,指导其策略更新。

3. HAC的关键公式

        HAC采用了标准的Actor-Critic更新方法,同时将目标选择和动作选择分为不同层次。

(1) 高层策略的目标生成

        高层策略在时间步(t)选择一个子目标 (g_t) ,并将其交给低层策略。高层策略的优化目标是最大化未来期望回报,公式为:

[ Q_{high}(s_t, g_t) \leftarrow r_t + \gamma \cdot \mathbb{E}{g' \sim \pi{high}(s_{t+k})} [Q_{high}(s_{t+k}, g')] ]

其中:

  • ( Q_{high}(s_t, g_t) )为高层策略的值函数。
  • ( r_t )是从环境中获得的奖励。
  • ( \gamma )为折扣因子。
  • ( k )为高层时间地平线(高层策略选择目标的时间跨度)。

(2) 低层策略的动作选择

        低层策略在给定目标(g_t)的条件下,选择动作(a_t) 。低层策略的更新公式为:

[ Q_{low}(s_t, a_t | g_t) \leftarrow r_t^{intrinsic} + \gamma \cdot \mathbb{E}{a' \sim \pi{low}(s_{t+1}, g_t)} [Q_{low}(s_{t+1}, a' | g_t)] ]

其中:

  • ( Q_{low}(s_t, a_t | g_t) )为低层策略的值函数。
  • ( r_t^{intrinsic} )为低层策略的内在奖励,用来度量其在当前时间步内朝着目标(g_t)的逼近程度。
  • ( a' \sim \pi_{low}(s_{t+1}, g_t) )表示低层策略的下一步动作。

(3) 内在奖励机制

        内在奖励( r_t^{intrinsic} )用于评估低层策略在时间步(t)的表现。通常用来度量低层策略的动作是否成功逼近高层策略设定的目标。

一种内在奖励的计算方式为:

[ r_t^{intrinsic} = -d(s_t, g_t) ]

其中,( d(s_t, g_t) )为状态( s_t )和目标 ( g_t )之间的距离,越小越好。其目的是指导低层策略选择能更快接近目标的动作。


4. HAC的学习流程

HAC的学习流程可以描述如下:

  1. 高层策略选择目标:高层策略通过高层Actor-Critic的网络,根据当前状态选择子目标 (g_t)。
  2. 低层策略执行动作:低层策略根据高层策略设定的子目标,采取具体动作,尽量逼近目标。
  3. 低层策略更新:低层策略通过内在奖励机制更新其策略。低层Critic评估低层策略的表现,并通过Q-learning或Actor-Critic的方式来更新其值函数。
  4. 高层策略更新:高层策略在时间地平线结束后,基于全局环境的奖励信号进行更新。高层Critic对高层Actor生成的目标进行评估,进而优化高层策略。
  5. 重复迭代:随着时间步的推进,高层策略和低层策略都在各自的时间尺度上进行更新和优化。

[Python] Q-learning实现

        Hierarchical Actor-Critic (HAC) 是一种结合分层结构和 Actor-Critic 算法的强化学习方法。在 HAC 中:

  • 高层(Manager):负责设定子目标。
  • 低层(Worker):根据高层给定的子目标执行具体的动作,并学习策略。

        每个层次都有自己的 Actor-Critic 网络,高层的策略会向低层提供子目标,而低层根据子目标执行具体动作。这样,HAC 可以处理复杂任务,通过分层决策简化策略学习。

        🔥若是下面代码复现困难或者有问题,欢迎评论区留言;需要以整个项目形式的代码,请在评论区留下您的邮箱📌,以便于及时分享给您(私信难以及时回复)。

环境要求

pip install gym torch numpy

算法训练代码 

"""《Hierarchical Actor-Critic (HAC) 算法项目》
    时间:2024.10.11
    环境:CartPole
    作者:不去幼儿园
"""
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import random

# 超参数
GAMMA = 0.99
LEARNING_RATE = 0.001
EPSILON_DECAY = 0.995
MIN_EPSILON = 0.1
NUM_EPISODES = 500
HIGH_LEVEL_UPDATE_FREQUENCY = 10  # 高层更新频率

# Actor-Critic 网络
class ActorCritic(nn.Module):
	def __init__(self, state_dim, action_dim):
		super(ActorCritic, self).__init__()
		self.actor = nn.Sequential(
			nn.Linear(state_dim, 128),
			nn.ReLU(),
			nn.Linear(128, action_dim),
			nn.Softmax(dim=-1)
		)
		self.critic = nn.Sequential(
			nn.Linear(state_dim, 128),
			nn.ReLU(),
			nn.Linear(128, 1)
		)

	def forward(self, state):
		action_probs = self.actor(state)
		state_value = self.critic(state)
		return action_probs, state_value

# Hierarchical Actor-Critic 智能体
class HACAgent:
	def __init__(self, state_dim, action_dim, goal_dim):
		# 高层 Actor-Critic
		self.high_level_net = ActorCritic(state_dim, goal_dim)
		# 低层 Actor-Critic
		self.low_level_net = ActorCritic(state_dim + 1, action_dim)
		# 优化器
		self.high_level_optimizer = optim.Adam(self.high_level_net.parameters(), lr=LEARNING_RATE)
		self.low_level_optimizer = optim.Adam(self.low_level_net.parameters(), lr=LEARNING_RATE)
		self.epsilon = 1.0

	def select_high_level_goal(self, state, epsilon):
		if random.random() < epsilon:
			return random.choice([0, 1])  # 随机选择目标
		else:
			state = torch.FloatTensor(state).unsqueeze(0)
			action_probs, _ = self.high_level_net(state)
			return torch.argmax(action_probs).item()

	def select_low_level_action(self, state, goal, epsilon):
		if random.random() < epsilon:
			return random.choice([0, 1])  # 随机选择动作
		else:
			state_goal = torch.cat((torch.FloatTensor(state).unsqueeze(0), torch.FloatTensor([[goal]])), dim=-1)
			action_probs, _ = self.low_level_net(state_goal)
			return torch.argmax(action_probs).item()

	# 修改后的 update_high_level 方法
	def update_high_level(self, state, goal, reward, next_state):
		state = torch.FloatTensor(state).unsqueeze(0)
		next_state = torch.FloatTensor(next_state).unsqueeze(0)

		# 分别提取动作概率和状态值
		_, state_value = self.high_level_net(state)
		_, next_state_value = self.high_level_net(next_state)

		# 确保仅对状态值使用 detach
		next_state_value = next_state_value.detach()

		# 计算TD目标值
		target_value = reward + GAMMA * next_state_value
		loss_critic = nn.functional.mse_loss(state_value, target_value)

		# 计算高层策略损失
		action_probs, _ = self.high_level_net(state)
		log_prob = torch.log(action_probs[0, goal])
		advantage = target_value - state_value
		loss_actor = -log_prob * advantage

		loss = loss_critic + loss_actor
		self.high_level_optimizer.zero_grad()
		loss.backward()
		self.high_level_optimizer.step()

	# 修改后的 update_low_level 方法
	def update_low_level(self, state, goal, action, reward, next_state):
		state_goal = torch.cat((torch.FloatTensor(state).unsqueeze(0), torch.FloatTensor([[goal]])), dim=-1)
		next_state_goal = torch.cat((torch.FloatTensor(next_state).unsqueeze(0), torch.FloatTensor([[goal]])), dim=-1)

		# 分别提取动作概率和状态值
		_, state_value = self.low_level_net(state_goal)
		_, next_state_value = self.low_level_net(next_state_goal)

		# 确保仅对状态值使用 detach
		next_state_value = next_state_value.detach()

		# 计算TD目标值
		target_value = reward + GAMMA * next_state_value
		loss_critic = nn.functional.mse_loss(state_value, target_value)

		# 计算低层策略损失
		action_probs, _ = self.low_level_net(state_goal)
		log_prob = torch.log(action_probs[0, action])
		advantage = target_value - state_value
		loss_actor = -log_prob * advantage

		loss = loss_critic + loss_actor
		self.low_level_optimizer.zero_grad()
		loss.backward()
		self.low_level_optimizer.step()

	def train(self, env, num_episodes):
		goal_dim = 2  # 目标维度设定为2,直接设定

		for episode in range(num_episodes):
			state, _ = env.reset()  # 修改后的reset返回值
			goal = self.select_high_level_goal(state, self.epsilon)  # 高层选择目标
			done = False
			episode_reward = 0
			steps = 0

			while not done:
				steps += 1
				action = self.select_low_level_action(state, goal, self.epsilon)  # 低层选择动作
				next_state, reward, done, _, _ = env.step(action)  # 修改后的step返回值

				# 更新低层
				self.update_low_level(state, goal, action, reward, next_state)

				# 每隔 HIGH_LEVEL_UPDATE_FREQUENCY 更新一次高层
				if steps % HIGH_LEVEL_UPDATE_FREQUENCY == 0:
					new_goal = self.select_high_level_goal(next_state, self.epsilon)
					self.update_high_level(state, goal, reward, next_state)
					goal = new_goal

				state = next_state
				episode_reward += reward

			self.epsilon = max(MIN_EPSILON, self.epsilon * EPSILON_DECAY)
			print(f"Episode {episode + 1}: Total Reward: {episode_reward}")


# 创建 CartPole 环境用于训练,不渲染动画
env = gym.make('CartPole-v1')  # 不设置 render_mod
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
goal_dim = 2  # 目标维度设为2(简单划分目标)
agent = HACAgent(state_dim, action_dim, goal_dim)
agent.train(env, NUM_EPISODES)

算法测试代码

# 测试 Hierarchical Actor-Critic 智能体并显示动画
def test_hac_agent(agent, env, num_episodes=5):
	for episode in range(num_episodes):
		state, _ = env.reset()  # 修改后的reset返回值
		goal = agent.select_high_level_goal(state, epsilon=0.0)  # 高层选择目标
		done = False
		total_reward = 0
		env.render()

		while not done:
			env.render()
			action = agent.select_low_level_action(state, goal, epsilon=0.0)  # 低层选择动作
			next_state, reward, done, _, _ = env.step(action)  # 修改后的step返回值
			state = next_state
			total_reward += reward

		print(f"Test Episode {episode + 1}: Total Reward: {total_reward}")
	env.close()


# 创建 CartPole 环境用于测试,显示动画
env = gym.make('CartPole-v1', render_mode='human')
test_hac_agent(agent, env)

[Notice]  说明:

  1. 高层(Manager)网络:高层负责设定子目标,并根据目标进行策略更新。
  2. 低层(Worker)网络:低层网络执行具体的动作,学习完成高层给定的子目标。
  3. Actor-Critic:每个层次都使用 Actor-Critic 算法来学习策略和价值函数。

训练与测试:

  • 训练:在 train 方法中,高层每隔一定步数设定目标,低层则持续执行动作并更新策略。
  • 测试:在 test_hac_agent 方法中,使用训练好的模型对智能体进行测试,并显示动画。

        由于博文主要为了介绍相关算法的原理应用的方法,缺乏对于实际效果的关注,算法可能在上述环境中的效果不佳,一是算法不适配上述环境,二是算法未调参和优化,三是等等。上述代码用于了解和学习算法足够了,但若是想直接将上面代码应用于实际项目中,还需要进行修改。


5. HAC的优点与挑战

(1) 优点
  • 适应长时间跨度的任务:通过分层结构,HAC能够处理长时间跨度的任务,尤其在多步决策任务中表现出色。
  • 内在奖励机制:低层策略可以根据内在奖励进行优化,减少全局奖励稀疏带来的学习挑战。
  • 易于扩展:HAC可以扩展为多层策略架构,增加层数以应对更复杂的任务。
(2) 挑战
  • 子目标设定的设计:合理地设定低层策略的目标是一个关键问题。如果目标不合理,低层策略可能无法学到有效的策略。
  • 层次依赖性:不同层次策略之间的依赖关系可能会影响算法的稳定性,需要仔细设计层次之间的交互。
  • 时间尺度的选择:高层和低层策略的时间地平线需要调试和优化,以适应特定的任务场景。

6. HAC的应用场景

HAC适用于复杂的长时间跨度任务,特别是在以下几种场景中表现优异:

  • 机器人控制:例如机械臂的操作,机器人导航等,分层结构可以将任务分解为较小的可管理子任务。
  • 视频游戏:特别是需要多步策略的游戏,如探索类游戏、回合制策略游戏等。
  • 多步骤规划任务:在这些任务中,HAC可以通过高层次的分解使得复杂的任务更具可解性和学习效率。

参考文献:

Levy, Andrew, et al. "Learning Multi-Level Hierarchies with Hindsight." arXiv preprint arXiv:1712.00948 (2017).

  🔥想了解更多分层强化学习的文章,请查看文章:

【RL Latest Tech】分层强化学习(Hierarchical RL)


     文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者关注VX公众号:Rain21321,联系作者。✨

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐