【RL Latest Tech】离线强化学习:行为规范Actor Critic (BRAC) 算法
行为规范Actor Critic算法(Behavior Regularized Actor Critic,BRAC) 是一种专门为离线强化学习设计的算法,其主要目标是通过行为正则化(Behavior Regularization)来解决由于数据分布偏差导致的策略退化问题。BRAC 算法是由Yifan Wuet al. 在 2019 年的论文“Behavior Regularized Offline
📢本篇文章是博主强化学习RL领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉强化学习专栏:
【强化学习】(21)---《【离线强化学习:行为规范Actor Critic (BRAC) 算法》
离线强化学习:行为规范Actor Critic (BRAC) 算法
目录
1. 介绍
离线强化学习(Offline Reinforcement Learning)旨在从静态数据集中学习策略,而无须与环境进行交互。传统的强化学习方法依赖大量环境交互,这在某些情况下是不切实际或昂贵的。离线强化学习通过利用已有的数据,降低了这些需求。
行为规范Actor Critic 算法(Behavior Regularized Actor Critic,BRAC) 是一种专门为离线强化学习设计的算法,其主要目标是通过行为正则化(Behavior Regularization)来解决由于数据分布偏差导致的策略退化问题。 BRAC 算法是由Yifan Wu et al. 在 2019 年的论文“Behavior Regularized Offline Reinforcement Learning”中提出的。论文中讨论了在连续控制场景下,通过一种乐观保守的策略迭代方法来实现策略改进和探索。
如果你对原文感兴趣,可以通过下面链接查看文献全文:
Behavior Regularized Offline Reinforcement Learning
2. 算法背景
在离线强化学习中,模型只能依赖固定的历史数据集进行学习,而不能通过与环境的交互来探索新策略。由于数据是由某个行为策略(behavior policy)收集的,这个行为策略未必是最优策略,因此所学到的策略容易偏离数据中的实际分布,导致性能不理想。这个现象称为分布偏差问题(distributional shift)。
BRAC 算法的核心思想是通过限制策略优化过程中策略与行为策略的偏离,来减轻分布偏差带来的影响。这种方法通过引入行为正则化,使得学到的策略不会过度偏离生成离线数据的行为策略,从而保持策略的稳定性和鲁棒性。
3. 算法实现
BRAC 通过在策略优化过程中加入正则化项,将学习的策略限制在行为策略的附近。其基本架构可以看作是传统 Actor-Critic 方法的扩展,其中引入了一个基于行为策略的正则化机制,以控制策略的变化幅度。
3.1算法流程
-
数据收集:
从历史记录中获得离线数据集 。 -
价值函数估计:
使用批量数据训练一个价值函数,通常采用Bellman期望方程: 其中,为状态价值。 -
策略更新:
在策略更新阶段,使用一个行为正则项限制策略偏差:这里, 表示策略偏差度量,常用的如KL散度或MMD距离,是行为策略。这些正则化项的目标是控制策略偏离的程度,以确保模型的稳定性和对真实环境的泛化能力。 -
循环迭代:
重复以上过程,逐步优化策略直至收敛。
4. BRAC 的两种变体
BRAC 提出了两种不同的策略优化方式,分别为 BRAC-P 和 BRAC-V:
-
BRAC-P(Policy Regularization):在策略优化过程中对策略的变化进行直接约束。这种方法通过对 actor 的更新施加正则化项,确保其更新的方向不会过度偏离行为策略。
-
BRAC-V(Value Regularization):主要针对值函数进行正则化处理,限制值函数估计时对未见过的状态-动作对的过度估计。
两者的区别在于正则化的重点:BRAC-P 侧重于策略的更新,而 BRAC-V 则是通过对值函数的约束来间接影响策略学习。下面主要介绍BRAC-P的实现,BRAC-V主要修改对值函数的约束,大差不差。
[Python] BRAC算法实现
🔥若是下面代码复现困难或者有问题,欢迎评论区留言;需要以整个项目形式的代码,请在评论区留下您的邮箱📌,以便于及时分享给您(私信难以及时回复)。
BRAC算法伪代码实现:
便于理解BRAC算法的基本实现流程。
# BRAC算法的Python伪代码实现
def brac_algorithm(data, policy_network, value_network, beta_policy, num_iterations, lambda_reg):
"""
data: 离线数据集,格式为 (s, a, r, s')
policy_network: 策略网络,用于更新策略
value_network: 价值网络,用于估计价值函数
beta_policy: 行为策略
num_iterations: 迭代次数
lambda_reg: 正则化参数
"""
for _ in range(num_iterations):
# Step 1: 价值函数估计
for s, a, r, s_next in data:
v_next = max(value_network.predict(s_next))
q_value = r + gamma * v_next
value_network.update(s, a, q_value)
# Step 2: 策略更新
for s in data:
# 获取当前策略动作分布
action_distribution = policy_network.get_action_distribution(s)
# 计算行为正则项
behavior_regularization = compute_divergence(action_distribution, beta_policy.get_action_distribution(s))
# 更新策略网络,最小化负的Q值减去正则项
policy_network.update(s, lambda a: -value_network.predict(s, a) + lambda_reg * behavior_regularization)
return policy_network
def compute_divergence(dist1, dist2):
"""
计算两个分布之间的散度,如KL散度
"""
divergence = kl_divergence(dist1, dist2)
return divergence
def kl_divergence(p, q):
"""
计算KL散度
"""
return sum(p[i] * math.log(p[i] / q[i]) for i in range(len(p)))
BRAC算法pytorch实现:
BRAC算法的基本实现流程。离线强化学习的策略更新,并根据具体需求替换行为策略和价值网络的实现。
代码解释
- BRACPolicy:策略网络,使用PyTorch构建,包含两层隐藏层。网络输出策略的动作分布(使用Softmax归一化)。
- update:策略网络的更新函数。包括计算价值损失、KL散度正则化,并反向传播更新参数。
- BetaPolicy:用于模拟行为策略,提供动作分布。
- ValueNetwork:用于模拟Q值函数,返回伪随机的Q值。
主要部分
- KL散度计算:使用
torch.nn.functional.kl_div
来计算策略分布和行为策略分布的KL散度。 - 优化:通过
torch.optim.Adam
优化器来更新策略网络参数。
"""《BRAC算法的Pytorch实现》
时间:2024.09.25
环境:No
作者:不去幼儿园
"""
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
class BRACPolicy(nn.Module):
def __init__(self, state_dim, action_dim, beta_policy, lambda_reg, learning_rate=0.001):
super(BRACPolicy, self).__init__()
self.state_dim = state_dim
self.action_dim = action_dim
self.beta_policy = beta_policy
self.lambda_reg = lambda_reg
# 策略网络结构
self.policy_network = nn.Sequential(
nn.Linear(self.state_dim, 64),
nn.ReLU(),
nn.Linear(64, 64),
nn.ReLU(),
nn.Linear(64, self.action_dim),
nn.Softmax(dim=-1)
)
# 优化器
self.optimizer = optim.Adam(self.policy_network.parameters(), lr=learning_rate)
def forward(self, states):
return self.policy_network(states)
def update(self, states, value_network):
# 将状态转换为张量
states = torch.FloatTensor(states)
# 计算策略的动作分布
actions_probs = self.forward(states)
# 从行为策略获取动作分布
with torch.no_grad():
beta_actions_probs = self.beta_policy.get_action_distribution(states)
# 计算价值损失
q_values = value_network.predict(states)
value_loss = -torch.mean(torch.sum(q_values * actions_probs, dim=1))
# 计算正则化项 (KL散度)
kl_divergence = F.kl_div(actions_probs.log(), beta_actions_probs, reduction='batchmean')
# 总损失
loss = value_loss + self.lambda_reg * kl_divergence
# 反向传播和优化
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
def get_action_distribution(self, states):
states = torch.FloatTensor(states)
with torch.no_grad():
return self.forward(states).numpy()
# 示例用法
state_dim = 10
action_dim = 5
lambda_reg = 0.1
# 假设有一个预训练的行为策略
class BetaPolicy:
def get_action_distribution(self, states):
# 返回一些伪随机的动作分布
return torch.rand(states.shape[0], action_dim)
beta_policy = BetaPolicy()
# 创建BRAC-P策略对象
brac_policy = BRACPolicy(state_dim, action_dim, beta_policy, lambda_reg)
# 假设有一个简单的价值网络
class ValueNetwork:
def predict(self, states):
# 返回一些伪随机的Q值
return torch.rand(states.shape[0], action_dim)
value_network = ValueNetwork()
# 更新策略
states = torch.rand(32, state_dim) # 示例状态批次
brac_policy.update(states, value_network)
BRAC算法在CartPole中实现:
为了将BRAC算法应用于CartPole
环境中并测试结果,我们需要结合离线数据和PyTorch实现策略优化流程。以下是实现过程的详细步骤。
环境准备
首先,安装所需的库:
pip install gym torch numpy
完整代码实现
1. 环境与离线数据生成
我们将使用gym
的CartPole-v1
环境。为了模拟离线数据,先通过一个预训练策略生成一部分离线数据。随后,我们使用BRAC-P算法在此离线数据集上进行策略优化。
"""《BRAC算法的CartPole环境实现》
时间:2024.09.26
环境:CartPole
作者:不去幼儿园
"""
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import numpy as np
# 创建 CartPole 环境
env = gym.make('CartPole-v1')
# 生成离线数据
def generate_offline_data(env, policy, num_episodes=100):
data = []
for _ in range(num_episodes):
state, _ = env.reset()
done = False
while not done:
action = policy(torch.FloatTensor(state)).argmax().item()
next_state, reward, done, _, __ = env.step(action)
data.append((state, action, reward, next_state, done))
state = next_state
return data
# 随机策略用于生成离线数据
class RandomPolicy(nn.Module):
def forward(self, state):
return torch.tensor([0.5, 0.5]) # 50% 概率选择任一动作
# 使用随机策略生成离线数据
print("\033[38;5;11mINFO:\033[0m 随机策略生成离线数据", flush=True)
random_policy = RandomPolicy()
offline_data = generate_offline_data(env, random_policy)
2. BRAC-P 策略与价值网络实现
下面是策略网络和价值网络的实现,使用与之前类似的结构,但我们添加了BRAC-P中的正则化项。
# BRAC Policy 网络
class BRACPolicy(nn.Module):
def __init__(self, state_dim, action_dim, beta_policy, lambda_reg, learning_rate=0.001):
super(BRACPolicy, self).__init__()
self.state_dim = state_dim
self.action_dim = action_dim
self.beta_policy = beta_policy
self.lambda_reg = lambda_reg
# 策略网络结构
self.policy_network = nn.Sequential(
nn.Linear(self.state_dim, 64),
nn.ReLU(),
nn.Linear(64, 64),
nn.ReLU(),
nn.Linear(64, self.action_dim),
nn.Softmax(dim=-1)
)
# 优化器
self.optimizer = optim.Adam(self.policy_network.parameters(), lr=learning_rate)
def forward(self, states):
return self.policy_network(states)
def update(self, states, value_network):
# 将状态转换为张量
states = torch.FloatTensor(states)
# 计算策略的动作分布
actions_probs = self.forward(states)
# 从行为策略获取动作分布
with torch.no_grad():
beta_actions_probs = self.beta_policy.get_action_distribution(states)
# 计算价值损失
q_values = value_network.predict(states)
value_loss = -torch.mean(torch.sum(q_values * actions_probs, dim=1))
# 计算正则化项 (KL散度)
kl_divergence = F.kl_div(actions_probs.log(), beta_actions_probs, reduction='batchmean')
# 总损失
loss = value_loss + self.lambda_reg * kl_divergence
# 反向传播和优化
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
# 更新BRACPolicy类的get_action_distribution方法,转换列表为numpy array
def get_action_distribution(self, states):
states = torch.FloatTensor(np.array(states)) # 转换为 numpy array 再转换为 tensor
with torch.no_grad():
return self.forward(states).numpy()
# Value 网络
class ValueNetwork(nn.Module):
def __init__(self, state_dim, action_dim, learning_rate=0.001):
super(ValueNetwork, self).__init__()
self.network = nn.Sequential(
nn.Linear(state_dim, 64),
nn.ReLU(),
nn.Linear(64, 64),
nn.ReLU(),
nn.Linear(64, action_dim)
)
self.optimizer = optim.Adam(self.network.parameters(), lr=learning_rate)
def forward(self, states):
return self.network(states)
def predict(self, states):
return self.forward(torch.FloatTensor(states))
def update(self, states, actions, targets):
q_values = self.forward(torch.FloatTensor(states))
q_values = q_values.gather(1, torch.LongTensor(actions).unsqueeze(1)).squeeze(1)
loss = F.mse_loss(q_values, torch.FloatTensor(targets))
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
# 预训练行为策略
class BetaPolicy:
def get_action_distribution(self, states):
return torch.rand(states.shape[0], action_dim)
# 初始化网络
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
beta_policy = BetaPolicy()
value_network = ValueNetwork(state_dim, action_dim)
brac_policy = BRACPolicy(state_dim, action_dim, beta_policy, lambda_reg=0.1)
# 训练
def train_brac_policy(data, policy, value_network, num_epochs=100):
for _ in range(num_epochs):
for batch in data:
states, actions, rewards, next_states, dones = zip(*batch)
# 将列表转换为 numpy arrays
states = np.array(states)
next_states = np.array(next_states)
rewards = np.array(rewards, dtype=np.float32) # 确保 rewards 为 float 类型
dones = np.array(dones, dtype=np.float32) # 确保 dones 为 float 类型
# 更新价值网络
q_next = value_network.predict(next_states).max(dim=1)[0].detach() # 使用 detach() 防止梯度追踪
targets = rewards + 0.99 * q_next.numpy() * (1 - dones) # 使用 .numpy() 获取张量的值
value_network.update(states, actions, targets)
# 更新策略网络
policy.update(states, value_network)
# 数据批次处理
batch_size = 32
batches = [offline_data[i:i + batch_size] for i in range(0, len(offline_data), batch_size)]
# 训练策略
print("\033[38;5;11mINFO:\033[0m BRAC算法策略训练中", flush=True)
train_brac_policy(batches, brac_policy, value_network)
3. 测试 BRAC-P 策略
训练完成后,我们测试BRAC策略在CartPole
环境中的表现。
# 测试BRAC策略
def test_policy(policy, env, num_episodes=10):
total_rewards = []
for _ in range(num_episodes):
state, _ = env.reset()
done = False
episode_reward = 0
while not done:
action_probs = policy.get_action_distribution([state])
# 将 numpy.ndarray 转换为 tensor
action_probs = torch.FloatTensor(action_probs)
# 选择具有最大概率的动作
action = torch.argmax(action_probs).item()
next_state, reward, done, _, __ = env.step(action)
episode_reward += reward
state = next_state
total_rewards.append(episode_reward)
return total_rewards
# 测试BRAC策略在 CartPole 上的表现
print("\033[38;5;11mINFO:\033[0m BRAC算法策略测试中", flush=True)
test_rewards = test_policy(brac_policy, env)
print(f"\u001b[38;5;2mSUCCESS:\u001b[0m BRAC策略的平均奖励: {np.mean(test_rewards)}", flush=True)
[Results] 运行结果
论文部分运行结果:
在 CartPole-v1
环境中运行结果:
[Notice] 实现流程
1. 环境初始化与离线数据生成
我们使用gym
库中的CartPole-v1
环境来训练和测试策略。为了模拟离线强化学习的场景,我们首先通过一个随机策略生成了一些离线数据,这些数据包含多个状态、动作、奖励、下一个状态和是否终止的五元组。
- 离线数据生成:使用一个简单的随机策略(
RandomPolicy
)来与环境交互,生成离线数据。每次在环境中采取动作并记录状态、动作、奖励、下一状态以及是否结束的信息,最终组成一个离线数据集。
2. BRAC-P策略与价值网络实现
BRAC算法的核心是策略网络和价值网络。为了约束策略网络不偏离离线数据中的行为策略,我们在策略更新时引入了正则化项(如KL散度),对策略的变化进行限制。
-
策略网络(BRACPolicy):通过一个神经网络学习策略。网络输出动作的概率分布,更新时不仅考虑最大化奖励,还考虑正则化项,限制策略与离线行为策略的偏差。
-
价值网络(ValueNetwork):用于估计每个状态-动作对的Q值。Q值网络会根据离线数据更新,目标是最小化Q值与实际回报的误差。
3. 策略训练
我们将离线数据划分为多个批次(batches),并使用BRAC算法对策略进行迭代优化。每个批次的数据都用来更新价值网络和策略网络。
-
价值网络更新:对于每个状态-动作对,使用Bellman方程更新价值网络,使其预测的Q值更加准确。
-
策略网络更新:在更新策略时,除了最大化Q值,还要通过KL散度或其他度量方式,约束策略网络的输出不偏离离线行为策略。
4. 策略测试
训练完成后,我们在CartPole
环境中测试BRAC策略的表现。策略根据当前状态输出动作分布,然后选择最大概率的动作,并执行在环境中。我们记录每次测试的总奖励,计算策略的表现。
具体流程总结
- 离线数据生成:通过随机策略与环境交互,生成历史数据集。
- BRAC算法实现:
- 定义策略网络和价值网络。
- 策略更新时,加入行为正则化,约束策略不偏离行为策略。
- 策略训练:使用离线数据,通过多次迭代优化策略和价值函数。
- 策略测试:在
CartPole
环境中测试BRAC策略,观察策略的效果。
关键算法部分
-
行为正则化:通过KL散度度量策略与行为策略的差异,确保新学到的策略不与离线数据中的行为策略偏差过大。
-
价值估计:价值网络通过估计状态-动作对的Q值来指导策略网络的更新。
-
策略优化:策略不仅最大化价值函数,还通过正则化保持与行为策略的一致性。
实验结果
最终,通过测试我们可以评估BRAC策略在CartPole
环境中的表现,计算该策略在多次实验中的平均奖励,以观察其稳定性和有效性。
6. 实验与效果
文献中通过一系列实验验证了 BRAC 算法的有效性。实验结果表明,BRAC 在多个离线强化学习基准任务(例如 Mujoco 环境下的控制任务)上取得了优秀的性能,尤其在行为策略表现较差的情况下,BRAC 能够有效避免策略过度偏离,保持较高的鲁棒性。
与其他离线强化学习算法相比,BRAC 的优势在于其正则化机制使得策略在数据外推时更加保守,从而避免了过度高估值函数的问题。此外,BRAC 对不同的正则化方式表现出较好的适应性,可以根据任务需求选择不同的正则化度量。
7. 总结
BRAC 算法为离线强化学习中的分布偏差问题提供了一个有效的解决方案。通过引入行为正则化,BRAC 控制了策略优化时与行为策略的偏离程度,确保学习的策略在实际应用中更加稳定。它的两种变体(BRAC-P 和 BRAC-V)分别从不同角度对策略或值函数进行正则化,为离线强化学习中的策略学习提供了新的方向。
BRAC 的贡献在于其对分布偏差的有效处理和对离线数据的合理利用,是离线强化学习领域的重要进展之一。
相关知识点
-
行为克隆(Behavior Cloning):通过模仿现有策略直接构建新的策略。在离线RL中,BRAC通过行为正则项引入类似行为克隆的概念,但保留策略优化灵活性。
-
政策约束(Policy Constraint):限制新策略不偏离已知策略的机制,保证策略的稳定性。
-
价值平滑(Value Smoothing):通过将策略约束融入到价值估计中,避免过度乐观的价值估计。
文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者关注VX公众号:Rain21321,联系作者。✨
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)