news 2026/7/7 3:47:41

强化学习QAC求最优策略的代码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
强化学习QAC求最优策略的代码实现

理论基础:

注意:

1. get_policy_by_state_value_net() 是额外写的一个基于Q的贪心策略,不属于QAC算法,得到的策略不一定是最优的,与get_policy_by_policy_net表现一致是偶然现象。

2. 图片中的伪代码并没有说要生成多条episode,但这个为了保证每个(s,a)pair都能被访问到,会生成多条episode。

代码可运行:

import numpy as np import torch from torch import nn from env import GridWorldEnv from utils import drow_policy class QAC(object): def __init__(self, env: GridWorldEnv, gamma=0.9, lr_actor=1e-2, lr_critic=1e-2): self.env = env self.action_space_size = self.env.num_actions self.state_space_size = self.env.num_states self.gamma = gamma self.pnet = nn.Sequential( # policy_net nn.Linear(2, 16), # s -> Π(a|s) nn.ReLU(), nn.Linear(16, self.action_space_size) ) self.qnet = nn.Sequential( # q_value_net nn.Linear(2, 16), # s -> q[s,a] nn.ReLU(), nn.Linear(16, self.action_space_size) ) self.value_optimizer = torch.optim.Adam(self.qnet.parameters(), lr=lr_critic) self.policy_optimizer = torch.optim.Adam(self.pnet.parameters(), lr=lr_actor) self.policy = np.zeros((self.state_space_size, self.action_space_size)) self.q_value = np.zeros((self.state_space_size, self.action_space_size)) def decode_state(self, state): ''' :param state: int :return: 归一化后的元组 ''' i = state // self.env.size j = state % self.env.size return torch.tensor((i / (self.env.size - 1), j / (self.env.size - 1)), dtype=torch.float32) def generate_action(self, state): ''' :param state: tuple :return: int,float ''' logits = self.pnet(state) action_probs = torch.softmax(logits, dim=0) # π(a|s,θ) action_dist = torch.distributions.Categorical(action_probs) # 按分布采样 action = action_dist.sample() log_prob = action_dist.log_prob(action) # In π(a|s,θ) 注意传入的是索引,会自动做log(action_probs[action_index]) return action.item(), log_prob def solve(self, num_episodes=200): for _ in range(num_episodes): state_int = self.env.reset() state = self.decode_state(state_int) done = False while not done: action, log_prob = self.generate_action(state) # a_t,s_t,In π(a_t|s_t,θ) next_state_int, reward, done = self.env.step(state_int, action) # s_t+1,r_t+1 next_state = self.decode_state(next_state_int) if not done: next_action, _ = self.generate_action(next_state) # a_t+1 else: next_action, action_prob = None, None # Critic (value update) qvalue = self.qnet(state)[action] # q(s_t,a_t) if done: td_target = torch.tensor(reward, dtype=torch.float32) else: with torch.no_grad(): # semi gradient qvalue_next = self.qnet(next_state)[next_action] # q(s_t+1,a_t+1) td_target = torch.tensor(reward, dtype=torch.float32) + self.gamma * qvalue_next delta = td_target - qvalue # TD error self.value_optimizer.zero_grad() critic_loss = 0.5 * delta.pow(2) critic_loss.backward() self.value_optimizer.step() # Actor (policy update) qvalue = qvalue.detach() # 避免梯度污染 self.policy_optimizer.zero_grad() actor_loss = -log_prob * qvalue actor_loss.backward() self.policy_optimizer.step() state_int = next_state_int state = next_state def get_policy_by_policy_net(self): for s in range(self.state_space_size): if s in self.env.terminal: self.policy[s,4]=1 break s_t = self.decode_state(s) logits = self.pnet(s_t) action_probs = torch.softmax(logits, dim=0) a=torch.argmax(action_probs) self.policy[s,a]=1 return self.policy def get_policy_by_state_value_net(self): for s in range(self.state_space_size): if s in self.env.terminal: self.policy[s,4]=1 break a = np.argmax(self.q_value[s]) self.policy[s, a] = 1 return self.policy def get_qvalues(self): for s in range(self.state_space_size): s_t = self.decode_state(s) logits = self.qnet(s_t).detach().numpy() # q(s,a)表示在状态s执行动作a后,未来所有折扣回报的期望值,不要取softmax然后取最大 self.q_value[s, :] = logits return self.q_value if __name__ == '__main__': env = GridWorldEnv( size=5, forbidden=[(1, 2), (3, 3)], terminal=[(4, 4)], r_boundary=-1, r_other=-0.04, r_terminal=1, r_forbidden=-1, r_stay=-0.1 ) # 注意samples要大一点,否则每个state被访问到的概率很小 vi = QAC(env=env) vi.solve(num_episodes=200) print("\n state value: ") print(vi.get_qvalues()) print("\n get policy by policy net:") drow_policy(vi.get_policy_by_policy_net(), env) print("\n get policy by state value net:") drow_policy(vi.get_policy_by_state_value_net(), env)

运行结果:

1. 表现一致(终点状态不是 . 是因为没有特殊处理,其他代码保持不变。由于表现一致的情况很少,因此不再继续展示特殊处理后的输出)

2. 表现不一致

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 7:23:18

N-乙酰-D-半乳糖胺——引领靶向递送新时代的关键糖分子 CAS:1811-31-0

在药物化学与递送系统飞速发展的今天,精准靶向已成为提高疗效、降低毒副作用的核心追求。N-乙酰-D-半乳糖胺(GalNAc),作为一种天然存在的氨基糖,正从基础生物化学研究走向生物医药应用的前沿,成为开发肝靶向…

作者头像 李华
网站建设 2026/7/7 17:47:40

【数据库】【Redis】基本概念和特点

Redis的基本概念和特点 Redis(Remote Dictionary Server)是一种开源的、基于内存的键值存储系统,支持多种数据结构(如字符串、哈希、列表、集合、有序集合等)。其核心特点包括: 高性能:数据存储…

作者头像 李华
网站建设 2026/7/7 17:12:05

基于Spring Boot 图书管理系统

基于Spring Boot 图书管理系统 一、系统背景与目的 随着信息技术发展和图书馆规模扩大,传统图书管理方式难以满足现代需求。基于 Spring Boot 开发的图书管理系统,旨在通过实现图书增删改查、用户管理、借阅管理等功能,提升管理效率与准确性…

作者头像 李华
网站建设 2026/7/7 5:53:07

Linux网络日志怎么查看?

Linux网络日志是排查网络故障、检测入侵行为的核心依据,但不同服务的日志分散在不同目录,且日志格式复杂,新手常陷入 找不到日志、看不懂内容的困境。那么Linux网络日志怎么查看?以下是详细内容介绍。Linux系统中的网络日志主要用于记录与网…

作者头像 李华
网站建设 2026/7/7 17:50:46

第十八篇:Day52-54 前端跨端开发进阶——从“多端适配”到“跨端统一”(对标职场“全栈化”需求)

一、前置认知:跨端开发的核心价值与职场痛点随着移动互联网、小程序、桌面应用等场景的爆发,企业面临“多端布局”与“研发成本”的矛盾:某电商平台需维护iOS、Android、H5、微信小程序4套代码,新增一个商品详情页需4个团队同步开…

作者头像 李华
网站建设 2026/7/7 6:01:49

内存金字塔:Ascend C中的多级存储体系与高效访存设计

目录 🎯 摘要 1. 🏗️ 技术原理:内存金字塔的架构哲学 1.1 达芬奇架构的内存层次设计 1.2 Unified Buffer的硬件级秘密 1.3 访存延迟的数学模型 2. ⚡ 实战部分:从理论到代码的跨越 2.1 基础数据搬运优化实战 2.1.1 DMA指…

作者头像 李华