📢本篇文章是博主强化学习RL领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉强化学习专栏: 【强化学习】(21)---《【离线强化学习:行为规范Actor Critic (BRAC) 算法》
离线强化学习(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
在离线强化学习中,模型只能依赖固定的历史数据集进行学习,而不能通过与环境的交互来探索新策略。由于数据是由某个行为策略(behavior policy)收集的,这个行为策略未必是最优策略,因此所学到的策略容易偏离数据中的实际分布,导致性能不理想。这个现象称为分布偏差问题(distributional shift)。
BRAC 算法的核心思想是通过限制策略优化过程中策略与行为策略的偏离,来减轻分布偏差带来的影响。这种方法通过引入行为正则化,使得学到的策略不会过度偏离生成离线数据的行为策略,从而保持策略的稳定性和鲁棒性。
BRAC 通过在策略优化过程中加入正则化项,将学习的策略限制在行为策略的附近。其基本架构可以看作是传统 Actor-Critic 方法的扩展,其中引入了一个基于行为策略的正则化机制,以控制策略的变化幅度。
3.1算法流程
。
其中,
为状态价值。
这里,
表示策略偏差度量,常用的如KL散度或MMD距离,
是行为策略。这些正则化项的目标是控制策略偏离的程度,以确保模型的稳定性和对真实环境的泛化能力。
BRAC 提出了两种不同的策略优化方式,分别为 BRAC-P 和 BRAC-V:
两者的区别在于正则化的重点:BRAC-P 侧重于策略的更新,而 BRAC-V 则是通过对值函数的约束来间接影响策略学习。下面主要介绍BRAC-P的实现,BRAC-V主要修改对值函数的约束,大差不差。
🔥若是下面代码复现困难或者有问题,欢迎评论区留言;需要以整个项目形式的代码,请在评论区留下您的邮箱📌,以便于及时分享给您(私信难以及时回复)。
便于理解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算法的基本实现流程。离线强化学习的策略更新,并根据具体需求替换行为策略和价值网络的实现。
代码解释
主要部分
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
环境中并测试结果,我们需要结合离线数据和PyTorch实现策略优化流程。以下是实现过程的详细步骤。
环境准备
首先,安装所需的库:
pip install gym torch numpy
完整代码实现
我们将使用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)
下面是策略网络和价值网络的实现,使用与之前类似的结构,但我们添加了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)
训练完成后,我们测试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)
论文部分运行结果:
在 CartPole-v1
环境中运行结果:
我们使用gym
库中的CartPole-v1
环境来训练和测试策略。为了模拟离线强化学习的场景,我们首先通过一个随机策略生成了一些离线数据,这些数据包含多个状态、动作、奖励、下一个状态和是否终止的五元组。
RandomPolicy
)来与环境交互,生成离线数据。每次在环境中采取动作并记录状态、动作、奖励、下一状态以及是否结束的信息,最终组成一个离线数据集。BRAC算法的核心是策略网络和价值网络。为了约束策略网络不偏离离线数据中的行为策略,我们在策略更新时引入了正则化项(如KL散度),对策略的变化进行限制。
我们将离线数据划分为多个批次(batches),并使用BRAC算法对策略进行迭代优化。每个批次的数据都用来更新价值网络和策略网络。
训练完成后,我们在CartPole
环境中测试BRAC策略的表现。策略根据当前状态输出动作分布,然后选择最大概率的动作,并执行在环境中。我们记录每次测试的总奖励,计算策略的表现。
CartPole
环境中测试BRAC策略,观察策略的效果。 最终,通过测试我们可以评估BRAC策略在CartPole
环境中的表现,计算该策略在多次实验中的平均奖励,以观察其稳定性和有效性。
文献中通过一系列实验验证了 BRAC 算法的有效性。实验结果表明,BRAC 在多个离线强化学习基准任务(例如 Mujoco 环境下的控制任务)上取得了优秀的性能,尤其在行为策略表现较差的情况下,BRAC 能够有效避免策略过度偏离,保持较高的鲁棒性。
与其他离线强化学习算法相比,BRAC 的优势在于其正则化机制使得策略在数据外推时更加保守,从而避免了过度高估值函数的问题。此外,BRAC 对不同的正则化方式表现出较好的适应性,可以根据任务需求选择不同的正则化度量。
BRAC 算法为离线强化学习中的分布偏差问题提供了一个有效的解决方案。通过引入行为正则化,BRAC 控制了策略优化时与行为策略的偏离程度,确保学习的策略在实际应用中更加稳定。它的两种变体(BRAC-P 和 BRAC-V)分别从不同角度对策略或值函数进行正则化,为离线强化学习中的策略学习提供了新的方向。
BRAC 的贡献在于其对分布偏差的有效处理和对离线数据的合理利用,是离线强化学习领域的重要进展之一。
文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者