Improving Deep Reinforcement Learning for Continuous Co
作者:禅与计算机程序设计艺术
1.简介
当前最热门的AI学习领域之一是连续控制问题(Continuous Control)。其中一种重要的研究方向是深度强化学习(Deep Reinforcement Learning, DRL),它在多个领域得到了广泛应用。具体来说,在OpenAI Gym提供的各类模拟环境中使用DRL算法能够有效训练模型,并取得了显著的效果。然而,尽管DRL算法在许多场景中表现优异,但研究表明其在连续控制任务中仍存在一定的局限性:
-
状态空间较大可能导致计算复杂度显著增加。
-
对于动态变化的环境难以实现快速响应。
-
缺乏有效的探索机制限制了其泛化能力。
-
训练过程中容易陷入局部最优解而无法找到全局最优策略。
-
对 reward函数的设计依赖较高且缺乏通用指导原则。
-
对于连续控制问题而言,在调节机械臂、飞行器或直升机等被调节参数(包括但不限于角度和距离)时,
由于这些参数通常难以实现离散化处理,
采用浮点数值表示的方式将导致评估函数(Value Function)计算变得复杂。 -
DRL算法通常需要构建基于连续状态空间的模型,
然而,
许多看似复杂的系统实际上可以通过离散化方法实现有效的管理。
特别是在样本数据集数量有限的情况下,
如何实现从持续性到分立性的转变仍是一个值得深入探讨的问题。 -
使用DRL算法训练得到的结果往往难以确保最终收敛至全局最优解,
因为当前所采用的方法仅能提供一个近似于实际操作的解决方案。
针对这一问题,研究者提出了一种新型强化学习算法DRL(Deep Reinforcement Learning),该算法整合了奖励机制与价值平滑技术。其通过引入离散化处理实现了对连续控制任务的有效模拟,并在此框架下设计了有效的价值网络训练策略以解决离散化后的控制难题。研究者采用了一种近似于连续动作空间的方法对状态-动作空间进行离散化处理,并在此框架下设计了有效的价值网络训练策略以解决离散化后的控制难题。本文将对此进行详细阐述。
2. 基本概念及术语说明
2.1 基础概念
连续控制任务即为决策过程中控制变量取值范围为实数而非离散值的情况。在此情形下, 控制变量的更新步长将依据系统内部的时间参数决定。因此, 为了更有效地处理连续控制任务, 当前的研究主要集中在将连续控制问题转化为离散控制问题的方法上
深度强化学习(Deep Reinforcement Learning, DRL)是机器学习领域的一个重要研究方向,在实际应用场景中通过大量模拟环境来实现这一过程。每个模拟环境都具有独特的状态空间与行动空间组合,并且包含相应的奖励机制与转移概率描述。其中,值函数模型能够描述系统在各个状态下可能采取的不同行动及其可能性;而策略函数则是在给定状态下决定采取哪种动作以最大化预期收益。
深度强化学习(DRL)算法作为一种机器学习方法,在当前领域中具有很高的流行度。
2.2 术语说明
2.2.1 离散控制问题
在连续控制问题中,控制变量通常取实数值且不可直接将其值域转换为离散形式。为了实现对连续控制系统的模拟或分析需求,则需要构建相应的状态空间模型和动作集。通常情况下,在这种框架下由两个主要部分组成:一个是有限或可数的状态空间S;另一个是有限或可数的动作集A。其中的状态空间S由一系列互斥且穷尽描述系统各个可能模式或条件的状态所组成的集合;而动作集A则由一系列互斥且穷尽描述系统各种可能干预手段的动作所构成
2.2.2 逼近策略
基于状态空间的连续性特征,在应用常规离散控制方法时(如PID控制器),其精度会受到限制而难以达到全局最优解。相比之下,在动态系统中采用近似策略是一种有效的方法。这种策略旨在通过优化在采样基础上的回报函数来趋近于真实的目标函数。
2.2.3 时域模糊
时域模糊的方法是将连续的状态转换为离散的状态;然而,在每一步模拟的过程中所使用的固定时间间隔可以有效避免计算资源的浪费。这种方法既能保留原始连续空间的信息特性又能充分利用数据集中的信息资源。在时域模糊策略的设计中通常采用预测网络和目标网络来进行策略求解;其中通过预测网络能够生成下一动作阶段的状态估计;而目标网络则利用误差函数来拟合真实的动作轨迹;从而最终能获得更加接近真实情况的策略描述。
2.2.4 奖励调制
奖励调制(Reward Modulation)是一种通过调节当前系统状态来决定奖励信号大小的技术手段...其主要目标是帮助系统学会执行有效行为。简而言之...它属于一种信号处理机制...其核心在于使系统通过失败的经验教训来提升表现。
2.2.5 值平滑
值平滑(Value Smoothing)用于在估算状态价值函数时采用移动窗口方法替代完全期望值。该技术有助于降低估计结果的波动性,并可防止出现过高的评估结果和过大的负面惩罚。
3. 方法
3.1 算法流程
首先建立连续控制模型随后通过时域模糊方法对其进行模糊处理接着设计一个基于奖励调节与值平滑结合的深度强化学习算法
在时域模糊这一过程中,在深度学习领域中被定义为一种基于神经网络的时间域模糊方法。其中涉及到两个神经网络模型——即预测性神经元组P(θ)与目标性神经元组T(θ)。该方法的核心思想是利用真实系统的动态特性去推断其潜在的状态发展路径。具体而言,在时间步t的基础上基于当前的状态信息推测未来一步的状态变化。为了实现这一目标,在实际应用中我们通常会设计一个损失函数,并通过最小化该损失函数来优化P(θ)参数使其能够准确地预判系统下一时间点的表现特征。同时引入的目标性神经元组T(θ)则负责直接推断真实系统的输出轨迹并将其反馈至系统内部以便持续迭代优化整个系统的运行效率
其次, 建立奖励调节机制方案。在持续控制过程中, 若未能正确识别现有状态下会导致错误行为发生的情况, 因此, 作者旨在增强系统对现有状态的准确识别能力, 提出了奖励调节机制方案。由于现有状态下不可避免的噪声影响, 作者认为通过调节奖励信号来优化系统的决策过程以避免错误行为的发生, 并从中总结经验教训以提高系统的准确性。为此, 作者设计了一个 rewards regulating module R(θ),该模块接受当前状态作为输入, 并根据预设的规则计算出相应的 reward 调整值, 这些调整值将被用于生成最终的 reward 输出值进行反馈调节。最后采用强化学习算法中的 Q-Learning 或 Actor-Critic 方法来训练价值网络模型 V(θ) 。该价值网络模型用于评估每个状态下不同动作的价值程度, 并选择能带来最大收益的动作以实现最优决策过程
3.2 模型原理
3.2.1 时域模糊
时域模糊具体表现为对连续状态空间进行离散化转换过程,并且所有模拟步骤均采用同步设置以确保时间一致性。其机制基于两层神经网络体系分别用于状态预测和目标识别,并按照设定流程依次完成各项运算步骤。
对于输入状态序列X[t]而言,我们构建了一个预测网络模型P(θ),其输出由函数f(θ^p, X[t])生成。其中θ^p代表预测网络的参数向量,在此任务中被用来描述系统的动态特性。该激活函数f(θ_p, x)在实际应用中通常采用非线性变换来增强模型的表达能力。为了使该模型能够有效学习系统行为模式,在训练过程中我们使用了真实输出序列作为监督信号,并通过最小化损失函数J_pre = ||Y - f(θ_p, X)||²来进行优化。其中真实输出序列Y与目标网络的预测结果\tilde{Y} = f(\theta_t, X+1)之间存在对应关系。
第二步,在构建目标网络模型T(θ)(X)=f(θ_t,X)时,我们定义了其中参数向量θ_t代表目标网络的学习参数。该模型的主要功能是生成真实的目标序列,并通过最小化二次损失函数J tar等于f(θ t,X)与真实序列Y之间的差的平方范数来优化模型参数。具体而言,在该框架中真实的目标序列Y满足关系式Y = f(θ t, X +1)。
通过实施对原始状态序列的连续模糊处理,并生成新的状态序列Z=[z_1,…,z_N]。其中每个元素z_i代表经过模糊处理后的第i个状态。将该状态序列作为输入,并用于对两个神经网络模型P(θ)和T(θ)的更新迭代过程。
时域模糊的优势在于它保持了连续空间的信息,并且能够有效利用数据集。然而其缺点在于消耗较高的资源,并且引入了噪声这可能导致估计结果不一定准确
3.2.2 奖励调制
奖励调制(Reward Modulation)是一种根据系统当前状态调整奖励强度的方法,其核心目标是帮助系统学会执行有效行为。简而言之,这种机制可以被视为一种信号处理技术,在此过程中,系统通过失败经历不断汲取教训以提升表现质量。
作者提出了一种奖励调制模块R(θ)(x),其结构如下所示:
在其中的变量x代表输入的状态,在深度学习模型中通常用来描述系统的当前状况或环境特征。参数θ用于调节奖励的分配程度,在强化学习框架中起到关键作用。具体而言,在神经网络模型中通过函数R(θ)(x)计算出的是基于状态x计算出的修正后的奖励值。本质上来说,在这个机制中我们引入了一种称为"奖励调制"的技术,在这个机制中我们引入了一种称为"奖励调制"的技术
研究结果表明,在成功任务中设置较大的奖励,在失败任务中设置较小的奖励能够有效促进系统的快速学习和对成功知识的掌握。然而,在连续控制任务中由于奖励信息是动态变化的这一特点使得难以准确分辨成功与失败因此作者提出了更具通用性的奖励调节方法以克服这一局限性
奖励调制可被视为一种进化的机制。即通过自然选择改变了动物的基因进而导致学习行为更加符合环境需求。 rewards modulations can also be viewed as a substitute for traditional reward-based learning methods. By treating reward signals as fitness functions they can adapt dynamically to environmental changes thereby enhancing the system's ability to evolve.
作者构建了调节机制R(θ)(x),该调节机制可划分为两类模式:一类为一次型调节机制(即线性奖励调制),另一类为非一次型调节机制(即非线性奖励调制)。
3.2.2.1 线性奖励调制
在采用线性调节机制的情况下进行奖励信号调节时其幅值仅受当前状态的影响具体而言其幅值由以下等式确定:
R(\theta)(x)=Ax+b
其中A与b分别代表相应的参数变量。
进一步分析可得:
若矩阵A为单位矩阵则有:
R(\theta)(x)=x
此时函数值保持不变;
若矩阵A为负定矩阵则有:
R(\theta)(x)=-x
此时函数值取反;
而当参数A被设定为一个随机分布的数值范围时系统将呈现出一定的不确定性和动态特性。
3.2.2.2 非线性奖励调制
基于非线性的奖励调节机制下计算出的奖励信号大小,在确定时不仅需要考虑当前状态的影响因素,在计算过程中还需综合历史数据的影响。其结构如下所示:
其中φ(θ,h)代表经过调制后的激活函数,在接收输入状态x以及历史轨迹h作为输入的基础上,并经由该过程产生相应的奖励信号。在这里面,
φ(θ,h)所包含的参数组中的θ与h均是由模型参数组中的θ以及历史轨迹组中的h所构成,
其中变量序列h=[\ldots]中每一个元素都代表前一个时间段的状态信息。
采用非线性奖励调节策略后开发了一种基于Q-Learning机制的深度强化学习(DRL)算法,并构建了一个新的奖励调节模块。在训练过程中,在每一轮迭代中首先利用未经调节的真实环境反馈信息作为当前状态下的即时回报值输入到Q-Learning模型中作为目标值计算后续状态的价值函数估计值;随后再利用经过调节后的即时反馈信息同样作为新的目标值输入网络以更新价值函数估计值。这一系列操作有助于提升系统的整体性能表现和稳定性。在测试过程中则直接采用未经任何处理的真实环境反馈信息输入到系统中用于生成相应的预测结果并根据具体需求对预测结果进行分析比较评估系统的实际应用效果。
4. 代码实例与解释
4.1 时域模糊
import torch
from torch import nn
class Predictor(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super().__init__()
self.input_layer = nn.Linear(input_size, hidden_size)
self.hidden_layer = nn.Linear(hidden_size, hidden_size)
self.output_layer = nn.Linear(hidden_size, output_size)
def forward(self, x):
x = self.input_layer(x)
x = torch.relu(x)
x = self.hidden_layer(x)
x = torch.relu(x)
return self.output_layer(x)
class TargetNet(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super().__init__()
self.input_layer = nn.Linear(input_size + 1, hidden_size)
self.hidden_layer = nn.Linear(hidden_size, hidden_size)
self.output_layer = nn.Linear(hidden_size, output_size)
def forward(self, x, prev_states):
states = torch.cat((prev_states, x[:, None]), dim=-1)
x = self.input_layer(states)
x = torch.relu(x)
x = self.hidden_layer(x)
x = torch.relu(x)
return self.output_layer(x)
class Smoother():
def __init__(self, predictor, targetnet):
self.predictor = predictor
self.targetnet = targetnet
self.criterion = nn.MSELoss()
self.optim = torch.optim.Adam(list(self.predictor.parameters())
+ list(self.targetnet.parameters()), lr=1e-3)
def train(self, X, Y):
N = len(X)
T = Y.shape[-1]
# forward pass to get predicted state sequences
prev_states = []
z_pred = [None]*T
for t in range(T):
if t == 0:
inputs = X[0][:, None]
else:
inputs = z_pred[t-1].view(-1, 1)
predict_state = self.predictor(inputs).squeeze()
prev_states.append(predict_state)
z_pred[t] = predict_state
# backward pass to train the two neural networks
loss_p = 0.0
loss_t = 0.0
for n in range(N):
cur_x = X[n]
cur_y = Y[n]
outputs_pred = []
targets = []
for t in range(T):
inputs_pred = prev_states[t]
pred_output = self.predictor(inputs_pred).squeeze()
target_output = self.targetnet(cur_x[:, None], prev_states[:t]).squeeze()
outputs_pred.append(pred_output)
targets.append(cur_y[t])
loss_p += self.criterion(torch.stack(outputs_pred), torch.stack(targets))
inputs_pred = prev_states[-1]
pred_output = self.predictor(inputs_pred).squeeze()
loss_t += self.criterion(pred_output, cur_y[-1])
total_loss = (loss_p / N) + (loss_t / N)
self.optim.zero_grad()
total_loss.backward()
self.optim.step()
def predict(self, X):
_, T = X.shape
Z_pred = np.zeros([len(X), T, X.shape[1]])
prev_states = []
for t in range(T):
if t == 0:
inputs = X[:, :, None]
else:
inputs = Z_pred[:, t-1].reshape([-1, 1, X.shape[1]])
predict_state = self.predictor(inputs).squeeze().detach()
prev_states.append(predict_state)
Z_pred[:, t] = predict_state.cpu().numpy()
return Z_pred
代码解读
4.2 奖励调制
python import numpy as np import torch from torch import nn
class NonlinearRewardModulator(nn.Module): def **init**(self, hidden_size, num_layers): super().**init**()
第1个全连接层由nn库中的Linear函数实现,默认输入通道数为hidden_size乘以num_layers;激活函数采用ReLU激活函数;第2个全连接层由nn库中的Linear函数实现,默认输出通道数为隐藏单元数量的一半;第3个全连接层由nn库中的Linear函数实现,默认输出通道数为1。
def forward(self, h):
通过全连接层fc1计算得到输出特征向量 out。
经过非线性激活函数处理后得到新的输出值 out。
接着通过全连接层fc2进一步变换得到更新后的特征向量 out。
再次经过非线性激活函数处理后得到最终的输出值 out。
最后将经过三层全连接处理后的结果传递给全连接层fc3完成前向传播。
代码解读
class QLearner(): def **init**(self, modulator, gamma=0.99, epsilon=0.1, alpha=0.001, update_freq=100, use_double=False, device='cuda'): self.gamma = gamma self.epsilon = epsilon self.alpha = alpha self.update_freq = update_freq self.use_double = use_double self.device = device
self.modulator = modulator
self.qnetwork = {}
self.qnetwork_target = {}
self.optimizer = {}
def init_model(self, obs_space, act_space, seed=None):
''' Initialize model with parameters of observation space, action space,
number of episodes to run during training and random seed'''
for i in range(act_space):
qnet = self._create_q_network(obs_space)
self.qnetwork[i] = qnet.to(self.device)
初始化为Adam优化器的参数。
self.optimizer[i] 设置为 opt。
if self.use_double:
# generate a duplicate of the network architecture specifically for double Q learning
target_qnet = self._create_q_network(obs_space)
self.qnetwork_target[i] = target_qnet.transfer_to(self.device)
将复制网络的权重初始化为与原始网络相同的值
self.qnetwork_target[i].load_state_dict(self.qnetwork[i].state_dict())
def _create_q_network(self, obs_space):
"""Helper method for constructing the Q-Network"""
layers = []
layer_sizes = [obs_space] + [256]*3 + [1]
for i in range(len(layer_sizes)-2):
layers += [nn.Linear(layer_sizes[i], layer_sizes[i+1]), nn.ReLU()]
layers.append(nn.Linear(layer_sizes[-2], layer_sizes[-1]))
net = nn.Sequential(*layers)
return net
def choose_action(self, obs):
''' Choose an action according to ε-greedy policy based on current observation '''
actions = {k: self._select_action(obs, k) for k in self.qnetwork.keys()}
action_values = list(actions.values())
best_action = max(zip(action_values, actions))[1]
return actions[best_action], best_action
def _select_action(self, obs, key):
'''Helper method to select action from a specific action value network instance.'''
eps = self.epsilon
with torch.no_grad():
q_values = self.qnetworkkey
random_val = np.random.uniform()
if (random_val < eps) or (not self.training):
action = randomly select an action from the available actions
else:
action = get the integer index of the action with the highest Q-value
return int(action)
def learn(self, batch, logger=None):
''' Train the model on the provided data batch '''
raise NotImplementedError('Implement this method')
@property
def training(self):
''' 标志位指示如果代理处于训练状态 '''
return self._trainable
代码解读
