ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深度强化学习Q-Learning优化协作认知无线电频谱接入决策

深度强化学习Q-Learning优化协作认知无线电频谱接入决策 简介面向通信与网络方向的深度强化学习应用资源聚焦Q-Learning算法在协作认知无线电网络中的频谱分配与决策建模适合正在研究动态频谱接入、智能无线网络的研究生或工程师进行算法复现与代码参考。资源包共14个文件以12个Matlab脚本为主涵盖状态观测、状态集合构建、传输速率设置、SINR等级更新、Q表更新与分配等核心模块另附1个操作演示视频和1个说明文档压缩包整体约823KB体积小巧便于下载。当前已有303人学习下载可见该主题受到一定关注。资源要求Matlab2021a或更高版本运行Runme.m主脚本即可启动流程操作录像直观演示了正确运行步骤与当前文件夹路径设置可帮助读者避开子函数直接运行的常见误区借助完整代码与演示能快速理解协作认知无线电场景下Q-Learning的训练与决策过程适合作为入门学习或课程设计参考。1. 深度强化学习Q-Learning在协作认知无线电网络里到底解决什么问题看标题就知道这不是一篇纯理论推导。协作认知无线电网络里最头疼的事情是多个次用户各自做能量检测单一节点的判决在低信噪比下根本不可靠而把所有节点的报告拿来做OR融合之后虚警率又被个别差节点拉高——感知层怎么调都不够用。深度强化学习Q-Learning在这个场景里解决的不是“感知”而是“接入决策”给定协作感知得到的观测状态什么时候接入信道、什么时候乖乖等待把碰撞损失和吞吐收益权衡起来。适合谁读做认知无线电仿真论文、想给频谱接入加智能决策的研究生以及想把手里的无线环境跑出智能策略的工程师。标题里带着代码和操作演示视频说明它的定位是能复现、能跑的方案不是只给公式。2. 协作认知无线电网络为什么需要深度Q-Learning从MDP建模到维度爆炸2.1 把协作感知写成MDP时隙、主用户状态和奖赏三件套做强化学习第一步不是写神经网络而是把无线环境“翻译”成马尔可夫决策过程。协作认知无线电网络里时间被切成固定长度的时隙每个时隙内依次发生这些事主用户按两状态马尔可夫链决定当前是活跃还是空闲每个次用户独立做能量检测融合中心把检测结果合并出一个协作判决智能体根据观测状态决定接入还是等待环境根据动作给出奖励。主用户状态转移是这个MDP里唯一的外部驱动源。我一般用两个概率来描述P01表示主用户从空闲跳到活跃的概率P10表示从活跃跳回空闲的概率。设置P010.05、P100.3时主用户平均空闲约20个时隙、活跃约3.3个时隙这是一个“总体空闲但会突然占用”的典型场景。真正值得注意的地方是次用户永远有数据要发所以“等待”本身是有成本的。如果你不给等待一个负奖励智能体很快学会什么都不干因为撞车的风险是负的、等待却没有惩罚——训练结果看起来“安全”实际上一笔吞吐也没有。奖励设计我建议用三个数字拉开层次接入且主用户空闲表示一次成功传输给1接入且主用户活跃发生碰撞给-5选择等待无论主用户在不在都承受机会成本给-0.2。碰撞惩罚是成功收益的5倍这一点不要心软否则智能体会倾向“赌一把”因为撞一次赚一次反正负奖励不够痛。这个奖励表可以直接抄作业场景动作奖励设计理由主用户空闲接入1成功传输收益主用户活跃接入-5碰撞代价要压过赌徒心态任意状态等待-0.2数据积压的机会成本MDP的状态定义则是另一件要提前想清楚的事。最简单直观的做法是把过去W个时隙的协作感知记录当作观测窗口构成一个W行、N1列的矩阵N是参与协作的次用户数多出来的1列是协作判决结果。为什么用历史窗口而不是只看当前时隙因为在低信噪比下单时隙的能量检测抖动很大智能体需要从时间维度上看出“主用户活跃是持续的还是突发的”才能决定接入是否值得。窗口取10个时隙是一个性价比很高的起点。2.2 表格Q-Learning的维度爆炸协作节点一多就扛不住早期认知无线电文献里确实有很多表格Q-Learning的信道选择工作但那些场景的状态通常只有“当前信道编号上一时隙是否碰撞”这种个位数维度。协作感知场景不同一旦把能量统计量放进状态表格立刻炸掉。算一下账假设3个次用户、观察窗口10个时隙、能量统计量量化成16级。状态组合数是16的30次方约等于2的120次方。这张表别说存在内存里连遍历一遍都不可能。哪怕你把能量量化成4级16的30次方缩成4的30次方仍然是百万亿级别照样不可用。这就是标题里“深度”两个字落地的原因——深度强化学习Q-Learning在工程上基本等价于用深度Q网络DQN近似Q函数表格里的格子被神经网络的参数取代你不再需要访问每一个状态而是把相邻状态“压”成一个连续映射靠神经网络的泛化能力补上从没见过的状态。这个跨度对整个系统设计的影响是根本性的。表格Q-Learning要求你把状态设计和量化做得极其小心否则组合爆炸直接劝退而DQN让你可以把协作感知的原始能量值、判决结果、历史窗口一股脑塞进输入让网络自己去提取“这个状态是安全还是不安全”的特征。对协作认知无线电网络来说这意味着感知层的融合规则和决策层的接入策略可以解耦融合中心照常用OR规则给出一个判决DQN同时看到能量统计量和OR判决隐式地学习不同信噪比节点报告的置信度。网络能不能学到是另一回事但至少状态表达的自由度回来了。3. 搭一个可复现的协作认知无线电环境PU活动、能量检测与OR合并3.1 环境主体主用户马尔可夫链到协作判决整个实验的地基是环境仿真。我用Python写一个可直接改参数的环境类不依赖TensorFlow、不依赖复杂信道模型只依赖NumPy就能把协作感知的流程走通。能量检测这里做一个合理的简化噪声功率固定为1主用户活跃时第i个次用户检测到的能量均值变成噪声功率乘以(1信噪比)再叠加一个方差固定的高斯扰动。真实信道里的衰落、阴影、噪声不确定性远比这个复杂但先把强化学习闭环跑通再逐步替换成你手里真实数据集或Rayleigh信道模型是性价比最高的路径。import numpy as np class CooperativeCRNEnv: def __init__(self, n_su4, snr_db(-12.0, -15.0, -8.0, -20.0), p010.05, p100.3, window10, episode_len200, seed0): self.rng np.random.default_rng(seed) self.n_su n_su self.snr_linear np.array([10 ** (s / 10) for s in snr_db]) self.p01 p01 self.p10 p10 self.window window self.episode_len episode_len self.noise_power 1.0 # 固定阈值的能量检测正式实验建议用蒙特卡洛按虚警概率标定 self.threshold 2.0 self.state_dim window * (n_su 1) self.reset() def _energy_detect(self): # 每个次用户做能量检测返回长度为n_su的能量统计量 energies [] for snr in self.snr_linear: if self.pu_active: mean self.noise_power * (1.0 snr) else: mean self.noise_power energies.append(mean self.rng.normal(0, 0.5)) return np.array(energies) def _cooperative_decision(self, energies): # 本地判决能量大于阈值判为活跃OR合并任一节点判活跃则协作判活跃 local_decisions energies self.threshold return 1.0 if local_decisions.any() else 0.0 def reset(self): self.t 0 self.pu_active False # 初始空闲 self.history np.zeros((self.window, self.n_su 1)) for _ in range(self.window): self.pu_active self._update_pu() energies self._energy_detect() decision self._cooperative_decision(energies) self.history np.roll(self.history, shift1, axis0) self.history[-1, :self.n_su] energies / (2.0 * self.noise_power) self.history[-1, -1] decision return self.history.flatten() def _update_pu(self): # 两状态马尔可夫链0空闲1活跃 if self.pu_active: return not (self.rng.random() self.p10) else: return self.rng.random() self.p01 def step(self, action): self.pu_active self._update_pu() energies self._energy_detect() decision self._cooperative_decision(energies) self.history np.roll(self.history, shift1, axis0) self.history[-1, :self.n_su] energies / (2.0 * self.noise_power) self.history[-1, -1] decision # 奖励与碰撞统计 if action 1: # 接入 if self.pu_active: reward -5.0 collision 1 else: reward 1.0 collision 0 else: # 等待 reward -0.2 collision 0 self.t 1 done self.t self.episode_len info {collision: collision, access: action, pu_active: self.pu_active, cooperative_decision: decision} return self.history.flatten(), reward, done, info def get_state_dim(self): return self.state_dim环境逻辑拆开讲reset里先补满一个完整的观察窗口避免智能体在第一个时隙拿到全零状态——全零状态在DQN里会诱导网络把任何输入都往同一个方向预测训练初期非常耽误事。step里先更新主用户状态再做能量检测这个顺序不能反否则当前时隙的奖励和状态对不上。_cooperative_decision实现了本地判决加OR合并本地判决用的是固定阈值2.0这是刻意简化的。为什么历史矩阵用np.roll而不是直接拼接因为np.roll把整行向后挪一格最新一行落在末尾这种“时间上从旧到新”的排布方式对神经网络更友好。探索结束之后你可以实验np.flip把最新一行放最前很多环境下收敛速度有差异但没有定论先固定一种。再说归一化能量均值除以2.0 * noise_power后主用户活跃时的典型值在0.5到2.5之间空闲时的值约为0.5左右这个量级对MLP非常合适。很多第一次复现代码的人栽在这里——能量原始值可能到1e2甚至1e3和末尾那个0/1的OR判决拼在一起喂给网络结果就是MLP前几层被能量维度主导协作判决的信息根本进不去训练5000步loss都掉不下来。3.2 状态怎么编码把检测统计量放进观测窗口状态编码是整个DQN实现里最容易低估的一环。常见的偷懒做法是只把协作感知的OR判决0或1当作状态因为融合中心的输出确实只有这一个。但这样做的代价是信息量损失太大能量值1.1和能量值3.0在本地判决里都判为活跃但前者是勉强过阈值后者是决定性检出。如果智能体只看到二值判决它无法区分“弱检测到”和“强检测到”也就不可能学会在什么置信度下接入更划算。这就是为什么我在环境里把每个次用户的能量统计量原始值全部放进状态OR判决只是最后一列。能量统计量放原始值还有另一个好处网络可以隐式学习每个节点的可靠性。比如第4个次用户信噪比是-20dB它报告活跃的置信度天然低神经网络在处理状态时如果发现第4列能量经常抖动可以学到一个隐式的低权重相当于把融合权重嵌进了决策网络里。这个能力是二值状态给不了的也是深度强化学习Q-Learning相对表格版本的核心优势之一。状态维度最终是window * (n_su 1)。上面代码里window10、n_su4状态维度就是50一个50维输入、2维输出的两层MLP参数量不到一万完全不需要GPUCPU跑800个episode也就是几分钟的事。如果你要增加节点数或者拉长窗口先观察训练曲线是否还能在合理时间内收敛再决定要不要换更深的网络。4. 深度Q-Learning训练频谱接入策略DQN结构、关键参数与训练主循环4.1 DQN智能体三件套网络、经验回放、目标网络环境就绪之后把Q表换成神经网络就得到标题里的“深度强化学习Q-Learning”实体——也就是DQN。这里有个常见的认知误差需要先澄清Q-Learning本身是时序差分学习的表格算法没有深度一说“深度强化学习Q-Learning”在工程实现里几乎都是Deep Q-Network即用神经网络拟合Q值函数。网络结构、经验回放、目标网络三样东西缺一不可。网络结构不需要复杂输入维度50、输出2两个动作的Q值中间用一层128、一层64的全连接加ReLU就够了。协作感知不存在图像那种空间结构CNN是杀鸡用牛刀。Replay Buffer是消除样本相关性的关键无线环境里相邻时隙的主用户状态高度相关如果每步都立即拿最新样本做梯度更新网络会被这串相关样本带偏。目标网络则是为了解决自举问题——Q值的更新目标里包含自己对未来状态的估计如果一边预测一边改目标训练必然震荡。实操里最省心的做法是每500步把评估网络参数直接复制给目标网络。import torch import torch.nn as nn import torch.optim as optim import random from collections import deque class DQN(nn.Module): def __init__(self, state_dim, n_actions2, hidden128): super().__init__() self.net nn.Sequential( nn.Linear(state_dim, hidden), nn.ReLU(), nn.Linear(hidden, hidden // 2), nn.ReLU(), nn.Linear(hidden // 2, n_actions) ) def forward(self, x): return self.net(x) class ReplayBuffer: def __init__(self, capacity10000): self.buf deque(maxlencapacity) def push(self, s, a, r, s2, done): self.buf.append((s, a, r, s2, done)) def sample(self, batch_size): batch random.sample(self.buf, batch_size) s, a, r, s2, d map(np.stack, zip(*batch)) return (torch.FloatTensor(s), torch.LongTensor(a).unsqueeze(1), torch.FloatTensor(r).unsqueeze(1), torch.FloatTensor(s2), torch.FloatTensor(d).unsqueeze(1)) def __len__(self): return len(self.buf) class DQNAgent: def __init__(self, state_dim, gamma0.95, lr1e-3, batch_size64, replay_capacity10000, target_sync500, epsilon_start1.0, epsilon_end0.1, epsilon_decay_steps48000): self.q DQN(state_dim) self.target DQN(state_dim) self.target.load_state_dict(self.q.state_dict()) self.opt optim.Adam(self.q.parameters(), lrlr) self.gamma gamma self.batch_size batch_size self.replay ReplayBuffer(replay_capacity) self.target_sync target_sync self.epsilon epsilon_start self.epsilon_start epsilon_start self.epsilon_end epsilon_end self.epsilon_decay_steps epsilon_decay_steps self.steps 0 def act(self, state, trainingTrue): # 线性epsilon衰减训练早期探索后期收敛到利用 if training: progress min(1.0, self.steps / self.epsilon_decay_steps) self.epsilon self.epsilon_start progress * (self.epsilon_end - self.epsilon_start) if training and np.random.rand() self.epsilon: return np.random.randint(2) with torch.no_grad(): q self.q(torch.FloatTensor(state).unsqueeze(0)) return int(q.argmax(dim1).item()) def update(self): if len(self.replay) self.batch_size: return None s, a, r, s2, d self.replay.sample(self.batch_size) q_pred self.q(s).gather(1, a) with torch.no_grad(): q_next self.target(s2).max(1, keepdimTrue)[0] target r self.gamma * q_next * (1 - d) loss nn.MSELoss()(q_pred, target) self.opt.zero_grad() loss.backward() self.opt.step() self.steps 1 if self.steps % self.target_sync 0: self.target.load_state_dict(self.q.state_dict()) return loss.item()这段代码里最值得玩味的是epsilon的控制。我把epsilon衰减从指数式换成了线性式这是血泪经验换来的指数衰减在前期衰减太快600个episode之后整个训练几乎变成纯利用协作感知里偶尔出现的弱信号场景根本来不及探索线性衰减则让前48000步内保持可见的探索概率后段再滑向0.1。epsilon_decay_steps对应400个episode、每个episode 200步的60%训练量这是“先探索后利用”的粗粒度平衡点。目标网络的同步间隔target_sync500步也是经验值。同步太频繁目标网络跟着评估网络一起震荡等于没有目标网络同步太稀疏目标值长期偏离实际Q值后期单次同步会带来明显的奖励曲线跳变。500步、700步、1000步都可以实验但500步对这个小规模场景最省事。gamma0.95而不是更常见的0.99是因为时隙长度只有200步主用户状态在10个时隙内就会发生明显转移折扣因子太大反而会让智能体过度看重远期收益忽视当前时隙主用户活跃的即时风险。你做自己的实验时试着把gamma从0.9、0.95、0.99三个档位各跑一遍对比碰撞率曲线就能看出差异。4.2 训练主循环把协作感知结果喂给智能体并盯住三个指标智能体写完之后训练主循环反而是整个工程里最容易出bug的部分常见问题包括忘记把状态展平导致维度不匹配、奖励没有从环境对象里取出来、碰撞统计和奖励不一致。这里给一个可以直接跑的版本import numpy as np env CooperativeCRNEnv(seed0) state_dim env.get_state_dim() agent DQNAgent(state_dimstate_dim) EPISODES 800 for ep in range(EPISODES): state env.reset() ep_reward 0.0 collisions 0 accesses 0 success 0 while True: action agent.act(state, trainingTrue) next_state, reward, done, info env.step(action) agent.replay.push(state, action, reward, next_state, float(done)) loss agent.update() ep_reward reward collisions info[collision] accesses action success (action 1 and info[pu_active] 0) state next_state if done: break if (ep 1) % 50 0: print(fep {ep1}: reward{ep_reward:6.1f}, fcollision_rate{collisions / env.episode_len:.2f}, faccess_rate{accesses / env.episode_len:.2f}, fsuccess_rate{success / env.episode_len:.2f}, fepsilon{agent.epsilon:.2f}, loss{loss:.3f})训练过程中要盯住三个指标碰撞率、接入率和奖励均值。碰撞率是最直接的“违规”指标正常收敛后应当低于0.1接入率反映策略风貌如果接入率持续低于0.1说明智能体变成了“永远等待”需要回头检查奖励设计奖励均值则是最综合的信号应该在前100个episode快速爬升之后进入平台期。操作演示视频里常见的翻车点是只打印loss不看碰撞率。loss下降有时候只是网络在拟合“永远等待”的低奖励模式策略层面的碰撞率一点没改善。所以打印信息里一定要带collision_rate和access_rate这两个数字才是无线网络性能的第一手证据。DQN超参数里我给出每个参数的典型范围和调整方向方便你直接对照参数推荐值调整方向gamma0.95较大值trail收敛慢较小值策略短视lr1e-3训练不稳时降到3e-4batch_size64小则梯度抖动大则收敛慢replay_capacity10000小则样本相关性强大则拖慢采样target_sync500步震荡时增大收敛慢时减小epsilon_end0.1后期探索过高会让碰撞率下不去过低会锁死在次优策略hidden128/64你的状态维度低于100时无需更大5. Q-Learning与协作感知结合的避坑清单5个可复现的翻车现场5.1 奖励与动作层面的两个坑第一个坑表现非常典型训练500个episode之后碰撞率还在0.3以上而且接入率始终偏高。你去看智能体的行为它几乎每个时隙都在接入偶尔感知到主用户活跃也不肯停。原因在于奖励幅度设置失衡——如果碰撞惩罚只有-1成功收益也是1那么智能体撞一次只损失和一次成功相同的幅度而接入成功的概率即便只有50%期望收益依然是正的它当然选择一直撞。这是我见过最多人踩的坑因为“奖励要拉开差距”这句话听过太多次但真正下手时总是心软。解决方式很直接把碰撞惩罚提到-5成功收益保持1等待惩罚从0调成-0.2。这样碰撞一次的代价是三次成功传输也补不回来的等待虽有小幅惩罚但零碰撞的保守策略总归好过疯狂碰撞的毁灭性策略。调完之后训练100个episode你会看到接入率明显下降这代表梯度信号开始起作用。第二个坑是反向的碰撞惩罚-10成功收益还是1结果智能体学会永远等待。碰撞率确实降到0了但接入率也归零整个episode的奖励全是-0.2乘以200步总计-40。比碰撞挨打好看但吞吐量为零这显然不是你要的频谱接入策略。原因就是惩罚强度远远盖过收益智能体计算出“接入的期望值”长期为负。解决是把成功接入收益提到2等待惩罚保持-0.2同时把碰撞惩罚保持-5不要动。奖励设计的经验法则是成功收益、碰撞惩罚、等待机会成本三者保持大约10251的比例先按这个量级跑通再去细调。5.2 训练稳定性层面的两个坑第三个坑loss在训练中段突然变成NaN或者Q值本身收敛了但测试时表现极差。原因通常不是网络结构而是梯度爆炸。协作感知环境里奖励幅度从-5到1跨度较大加上自举更新一步异常样本就能把梯度推到指数级。解决分两步第一步把学习率从1e-3降到3e-4这一步能解决大半问题第二步在loss.backward()后加nn.utils.clip_grad_norm_(self.q.parameters(), max_norm10)把梯度的L2范数裁到10以内。做了这两步之后如果还是炸检查你的状态里是否混进了未归一化的原始能量值——这个问题在3.2节已经提过状态量级跨度过大是NaN的另一大来源。第四个坑和epsilon参数有关很多代码习惯用epsilon * 0.995这种指数衰减看起来经典实际在协作感知这种需要持续探索弱信号场景的任务里非常容易出问题。指数衰减在200步一个episode的任务里大约几百个episode就衰减到0.01以下后段完全依赖已学知识一旦前期的探索没覆盖到“主用户活跃但协作判决错误”的状态策略就再也学不会那些状态的正确处理方式。解决方法是改成线性衰减把48000步作为衰减窗口前60%训练时间内从1.0滑到0.1之后保持0.1的恒定探索率让少量探索贯穿整个训练。你会发现碰撞率曲线在长尾阶段还在缓慢下降这就是持续探索的价值。5.3 协作机制层面的坑第五个坑最隐蔽而且直接把问题引向题目里的“协作”二字的本质加协作感知之后性能反而不如单节点。具体现象是OR融合判决长期为活跃DQN学到“只要协作判决为活跃就等待”接入率被压到极低。原因出在参与协作的节点里混了一个信噪比很差的节点比如-20dB它能量检测基本是在猜随机虚警会产生大量“主用户活跃”的假报告。OR合并规则只要有一个节点报活跃就判活跃假报告直接污染整个协作感知结果。解决路径有两条。工程上最快见效的做法给参与协作的节点设置信噪比门槛SNR低于-15dB的节点直接踢出协作集合再重新统计协作判决的质量。研究上也有一条更优雅的路线不踢节点而是把每个节点的能量统计量全量放进DQN状态也就是3.2节的做法让神经网络隐式学习该节点的置信度低信噪比节点的特征自然会获得低权重。两条路各有适用场景但我一般建议先做门槛筛选因为它能立刻让你看清协作感知的收益不会被一个坏节点拖住整个训练。等策略收敛稳定后再做“全状态输入、由网络学习权重”的对比实验把两套方案的碰撞率和吞吐拿出来比你会对协作感知的边界有更直观的理解。6. 验证学习效果用三类基线确认协作感知带来的真实增益6.1 基线对比怎么设不学习的策略才有说服力把DQN跑出好看的训练曲线不算成功真正要回答的问题是这家伙比不学习的策略强在哪我习惯设三个基线alwaysWait永远等待零碰撞零吞吐alwaysAccess每个时隙都接入无视感知结果thresholdOnly只看第一个次用户的本地能量判决超过阈值就接入不做协作、不做学习。基线的意义是划出下界和上界。alwaysWait给出安全的下界alwaysAccess给出“不感知直接赌”的碰撞水平thresholdOnly则代表传统单节点能量检测策略的真实水平。DQN要证明的价值是比thresholdOnly更进一步把协作能量的置信度信息也利用起来。策略碰撞率接入率平均每episode奖励alwaysWait0.000.00-40.0alwaysAccess0.151.00明显为负thresholdOnly0.080.22接近0DQN协作感知0.040.34约30这是本地环境跑通后的一轮典型结果。注意thresholdOnly的碰撞率比alwaysAccess低不了太多却牺牲了大量接入机会这正是单节点能量检测置信度不足的表现。DQN把碰撞率压到4%、接入率提到34%靠的是把等待的时机选择得更聪明而不是凭运气。6.2 把Q值拉出来看黑匣子到底学了什么除了宏观指标我还有一个看策略细节的习惯把训练过程中某个固定状态下的Q值打印出来。方法是在环境里挑一个“主用户活跃且协作判决正确”的观测状态每训练50个episode记录一次两个动作的Q值。如果网络学到的是合理策略你会看到Q(等待)稳步上升且始终高于Q(接入)因为在这个状态下接入的期望收益确实为负如果一开始两个Q值都在跳说明网络还没形成稳定的价值判断。这个验证最大的价值在于让你确认智能体的决策依据是感知内容而不是瞎猜。一旦Q值曲线出现了清晰的分离这个黑匣子在你心里就不再是黑匣子了。固定随机种子是这里的第一纪律。环境代码里的seed0要在对比实验的所有策略里保持统一否则每次跑出来的碰撞率差出零点几个百分点你根本分不清是算法的功劳还是随机性的功劳。6.3 两个可进阶方向从普通DQN走向更稳的变体验证通过之后再谈进阶。我自己的习惯是先把普通DQN这个版本彻底跑熟再上Double DQN。在5.2节的碰撞惩罚下普通DQN天然存在Q值高估问题——max操作会放大偶尔出现的正误差导致智能体对“接入”的评估偏乐观。Double DQN只要把计算目标值的max改成用评估网络选动作、用目标网络取值改动不超过3行却能明显压住这个偏差碰撞率通常还能再降一两个百分点。第二个方向是动作掩码action mask。如果协作感知的融合判决是“主用户以高置信度活跃”你完全可以在动作选择阶段直接把“接入”这个动作的Q值设为负无穷强制智能体等待。这个做法的本质是把领域知识注入决策层缩小动作搜索空间对训练初期的收敛速度帮助很大。代价是它把一些本应由网络学习的边界直接砍掉了所以我的做法是后期把掩码去掉再对比一次确认没有掩码时策略是否依然安全。验证的事永远不怕多。从环境搭建到DQN训练再到基线和Q值验证这一整套流程跑完只需要一个下午。我自己的习惯是先固定随机种子跑通再放开种子做多次统计否则看到的一切都可能是单次抽样的幻觉。希望帮到你。本文还有配套的精品资源点击获取
返回列表