强化学习ROS实战-RLagent解析(下)
来源:互联网 发布:软件开发分录 编辑:程序博客网 时间:2024/04/29 22:10
2.深入了解Agent
2.1.agent整体架构
由于统一接口的需要,ROS端的agent接口全部可以由agent.cpp提供交互,其中提供了可以由命令行参数修改的各种引擎配置。其自带引擎有:
- DiscretizationAgent
- QLearner
- ModelBasedAgent
- SavedPolicy
- Dyna
- Sarsa
接口提供了两个publisher,分别为
- out_rl_action 发布由引擎决策的下一部动作 发布在topic rl_agent/rl_action 消息类型为RLAction
- out_exp_infp 在每一个周期结束时候发布训练信息 发布在topic rl_agent/rl_experiment_info 消息类型为RLExperimentInfo
三个subscriber,分别为:
- rl_description 获取环境基本信息 订阅rl_env/rl_env_description 消息类型为 RLEnvDescription
- rl_state 获取当前环境的状态 订阅rl_env/rl_state_reward
- rl_seed 订阅rl_env/rl_seed
processEnvDescription:
初始化引擎中的环境信息,一般所有状态的价值都先假定初始为0
重置迭代状态,episode_number和episode_reward为0
设置firstAction标记为true
processState:
输入环境反馈的当前状态,返回一个决策动作
如果当前动作为第一个动作,则调用引擎first_action方法直接反馈决策
若当前动作不为第一个
累加状态收益
如果当前状态为结束状态,则调用last_action方法输出动作,并输出该次迭代结果
否则 调用next_action 并发布下一步动作
processSeed:
提供一系列的经验 用来初始化引擎。
2.2.SARSA Agent
了解大概的架构之后,让我们再深入对一个引擎进行了解。在这里,先选择SARSA算法的实现作为例子。在之前的文章已经介绍过了,sara是一种在线时间差分控制算法。他在状态转换是一个马尔科夫过程的前提下,通过单个的状态经验进行动作-状态价值函数的估计并决定最佳动作。
2.2.1.sarsa 引擎结构
SARSA引擎的初始化定义: Sarsa(int numactions, float gamma,
float initialvalue, float alpha, float epsilon, float lambda,
Random rng = Random())
参数列表及其解释:
- \param numactions 可能采取的动作的数目
- \param gamma 衰减系数(0~1)
- \param initialvalue 每个动作收益评价Q(s,a)的初始值
- \param alpha 学习率
- \param epsilon 采取随机策略的概率
- \param rng 随机数种子
提供方法:
virtual int first_action(const std::vector &s);
引擎初始时刻调用,输入初始状态,输出决策动作
virtual int next_action(float r, const std::vector &s);
引擎工作时刻调用,输入奖励和状态s,输出决策动作
virtual void last_action(float r);
状态链结束时刻调用,输出最终动作
virtual void setDebug(bool d);
debug模式标记
virtual void seedExp(std::vector);
预训练模型框架
virtual void savePolicy(const char* filename);
存储策略
void printState(const std::vector &s);
打印当前状态
float getValue(std::vector state);
获得当前状态的收益值
2.2.2.状态定义
首先需要解决的是状态量化问题,在很多问题中状态的数目可能是无穷多个的,但是计算机没有办法处理无穷个状态,所以需要想办法把状态量化到有穷单位上面去。
SARSA agent用了一个set表达所有遇到过的状态,
std::set<std::vector<float> > statespace;
并且提供了的Sarsa::state_t Sarsa::canonicalize(const std::vector &s) 函数来维护状态的数目,的设计哲学在于:只维护已知的状态,也就是说只在状态列表里面管理出现过的状态。由此状态-动作函数的Q矩阵和追踪迹矩阵eligible也相应的只维护出现过的状态,在出现新状态的时候会对map做插入处理。
Sarsa::state_t Sarsa::canonicalize(const std::vector<float> &s) { const std::pair<std::set<std::vector<float> >::iterator, bool> result = statespace.insert(s); state_t retval = &*result.first; // Dereference iterator then get pointer if (result.second) { // s is new, so initialize Q(s,a) for all a std::vector<float> &Q_s = Q[retval]; Q_s.resize(numactions,initialvalue); std::vector<float> &elig = eligibility[retval]; elig.resize(numactions,0); } return retval; }
接下来就是对于状态-动作函数的Q矩阵以及状态-动作概率的eligible矩阵的维护。
SARSA使用一个map
同理,另一个map
这两个结构初始化的时候都是0,并且在前面也提到过,只有在新状态加入的时候才进行结构的扩充和初始化,从而节约存储资源。
2.2.3.状态维护
Q矩阵和eligible矩阵的更新其实是随着经验和动作决策一起进行的,主要在int Sarsa::next_action(float r, const std::vector &s)函数中进行。这个函数主要做了两件事,一件当然就是判断当前状态不同动作的价值,并作出正确动作选择。另一个当然就是动作的更新了。
动作的更新过程是随着得到的状态和收益来的,这里需要解决这个几个问题:
- 了解上一个状态是什么(在ROS实现里实际上考虑了好几个之前的状态并附加权重)
- 了解现在状态的收益
让我们从next-action函数的一段来分析:
// Update value for all with positive eligibilityfor (std::map<state_t, std::vector<float> >::iterator i = eligibility.begin(); i != eligibility.end(); i++){state_t si = (*i).first;std::vector<float> & elig_s = (*i).second;for (int j = 0; j < numactions; j++){ if (elig_s[j] > 0.0){ if (ELIGDEBUG) { cout << "updating state " << (*((*i).first))[0] << ", " << (*((*i).first))[1] << " act: " << j << " with elig: " << elig_s[j] << endl; } // update Q[si][j] += alpha * elig_s[j] * (r + gamma * (*a) - Q[si][j]); elig_s[j] *= lambda; }}}// Set elig to 1eligibility[st][a-Q_s.begin()] = 1.0;
这段代码有两个比较值得注意的地方,其一是状体更新函数:
Q[si][j] += alpha * elig_s[j] * (r + gamma * (*a) - Q[si][j]) 这个是很典型的
在之前的讨论中也发现了,想要估算某个状态的价值,基于马尔科夫假设必须知道其前几个状态是什么,elig矩阵正是为了记录这个而存在的。我们可以看到,在每次状态更新的时候,都会把不为0的元素做elig_s[j] *= lambda这是为了降低权重,也就是离这个状态越久远的状态,对其影响应该是越低的。而且,在每次更新完毕之后,都会把当前接收到状态的权置1,这样,当新状态前来更新的时候,这个状态就是“上一个状态”了,并且此时它的权值是最高的。
2.2.3.动作维护
动作决策使用的是
// Choose an actionconst std::vector<float>::iterator a =rng.uniform() < epsilon? Q_s.begin() + rng.uniformDiscrete(0, numactions - 1): max;
2.3.Q-learing
Q-learing引擎的初始化定义,参数列表和sarsa的意义一致,这样,也就是数据更新的方式不一样咯。所以有兴趣的请自己参阅代码就好啦。
2.深入了解Enviroment
呃。。。这个因为和实际情况贴合比较多,所以就不详细讲了,比较值得在意的一点就是动作的reward和状态的reward会叠加在在一起返回而已。
- 强化学习ROS实战-RLagent解析(下)
- 强化学习ROS实战-RLagent解析(上)
- 强化学习RL实战篇
- 强化学习-无模型控制(下)
- TensorFlow实战13:实现策略网络(强化学习一)
- 深度强化学习实战:Tensorflow实现DDPG
- 强化学习(一)
- 强化学习(二)
- TensorFlow实战14:实现估值网络(强化学习二)
- Deeplearning4j 实战 (9):强化学习 -- Cartpole任务的训练和效果测试
- ros学习笔记(ova1)CMake语句解析
- Tensorflow实战学习(三十七)【实现强化学习策略网络】
- ros下的plugin学习
- 深度强化学习系列(一):强化学习概述
- 深度强化学习系列(二):强化学习基础
- 浅谈强化学习(一)
- 强化学习基础(二)
- 强化学习(一) ----- 基本概念
- F29-项目总结
- 【计算机视觉】Visual Tracking 领域最新进展(论文与源码)
- 《App 后台开发运维和架构实践》完整目录
- 谈C#中的Delegate
- 1.数据结构--线性表之数组实现
- 强化学习ROS实战-RLagent解析(下)
- 第七次上机(上机)
- C++作业7
- C++ 第七次实验
- c++:计算长方柱体的体积
- C++第七次上机实验—数组素数排序
- 2016_6_5 学习日志
- JavaWeb系列(一)——入门篇
- Linux内核中ioremap映射的透彻理解