ROS开发笔记(10)——ROS 深度强化学习dqn应用之tensorflow版本(double dqn/dueling dqn/prioritized replay dqn)

ROS开发笔记(10)——ROS 深度强化学习dqn应用之tensorflow版本(double dqn/dueling dqn/prioritized replay dqn)
在ROS开发笔记(9)中keras版本DQN算法基础上,参考莫烦强化学习的视频教程与代码,编写了应用在ROS中的tensorflow版本DQN算法,本部分代码包含了原始dqn、double dqn、dueling dqn、prioritized replay dqn四种版本的实现:

1、原始DQN

DQN利用神经网络计算Q值,拥有 经验回放(Experience replay) 和 周期性冻结 target 网络参数(Fixed Q-targets)的特性,Experience replay可以充分利用历史数据,Fixed Q-targets可以切断相关性,网络结构图如下:

2、double dqn

double dqn 是用来解决过估计的,其与原始dqn的结构基本相同,只是计算q_target的方法不同,具体参见代码。

3、prioritized replay dqn

前面两种dqn在经验回放时是随机采样经验池中的数据,prioritized replay dqn是按照 Memory 中的样本优先级来抽取,以便能更有效地找到需要学习的样本。

这里用( Q现实 - Q估计 )来规定优先学习的程度. 如果 其差 越大, 就代表预测精度还有很多上升空间, 那么这个样本就越需要被学习, 也就是优先级 p 越高。

4、dueling dqn

dueling dqn算法主要改变是将Q值分为两部分,一部分是状态本身带来的Q值,下图中用value表示,一部分是这个状态下不同的动作产生的不同的Q值,下图中用advantage表示,然后将两种相加得到最终的Q值。

dueling dqn与prioritized replay dqn在一些特定的场合会体现出相对优越性,在我们这个应用场景中效果差不多,这里主要是实现了这几种算法结构,具体的代码及注释如下:

#!/usr/bin/env python
#-*- coding:utf-8   -*-

import rospy
import random
import time
import tensorflow as tf
import numpy as np
import json
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))
from collections import deque
from std_msgs.msg import Float32MultiArray

# 导入 Env
from src.turtlebot3_dqn.environment_stage_1 import Env

# 采用莫烦强化学习教程中的实现
class SumTree(object):
    data_pointer = 0
    def __init__(self,capacity):
        # capacity 为回放经验的条数
        self.capacity=capacity
        # 初始化tree
        self.tree=np.zeros(2*capacity-1)
        # 初始化回放经验数据
        self.data=np.zeros(capacity,dtype=object)
    
    def add(self,p,data):
        # tree_idx 为所加data在树中的索引号
        self.tree_idx=self.data_pointer+self.capacity-1
        self.data[self.data_pointer]=data
        # 更新树
        self.update(self.tree_idx,p)
        self.data_pointer+=1
        if self.data_pointer>=self.capacity:
            self.data_pointer=0

    def update(self,tree_idx,p):
        change=p-self.tree[tree_idx]
        self.tree[tree_idx]=p
        # 更新tree的p
        while tree_idx!=0:
            # 更新父节点的p值
            tree_idx = (tree_idx - 1) // 2
            self.tree[tree_idx] += change

    def get_leaf(self,v):
        parent_idx = 0
        # 根据V寻找对应的叶子节点
        while True:    
            cl_idx = 2 * parent_idx + 1        
            cr_idx = cl_idx + 1
            # 判断是否达到树的底部
            if cl_idx >= len(self.tree):       
                leaf_idx = parent_idx
                break
            else:       
                if v <= self.tree[cl_idx]:
                    parent_idx = cl_idx
                else:
                    v -= self.tree[cl_idx]
                    parent_idx = cr_idx

        data_idx = leaf_idx - self.capacity + 1
        # 输出叶子节点序号,p值,以及对应的数据
        return leaf_idx, self.tree[leaf_idx], self.data[data_idx]
    
    @property
    def total_p(self):
        return self.tree[0] 


# 采用莫烦强化学习教程中的实现
class Memory(object):
    # 实际保存数据的条数
    saved_size=0
    epsilon = 0.01  # 避免 0 priority
    alpha = 0.6  # [0~1] 将 importance of TD error转化为 priority
    beta = 0.4  # importance-sampling 从这个初始值增加到1
    beta_increment_per_sampling = 0.001 
    abs_err_upper = 50.      
    def __init__(self,capacity):
        self.tree=SumTree(capacity)

    def store(self,transition):
        # 将新加入的transition 优先级p设为最高
        max_p=np.max(self.tree.tree[-self.tree.capacity:])
        if max_p==0:
            max_p=self.abs_err_upper
        self.tree.add(max_p,transition)
        if self.saved_size<self.tree.capacity:
            self.saved_size+=1
    
    def sample(self,n):
        # 初始化 b_idx, b_memory, ISWeights
        b_idx,  ISWeights = np.empty((n,), dtype=np.int32),  np.empty((n, 1))
        b_memory=[]
        self.beta=np.min([1.,self.beta+self.beta_increment_per_sampling])
        min_prob = np.min(self.tree.tree[self.tree.capacity-1:self.tree.capacity-1+self.saved_size]) / self.tree.total_p
        # print(self.tree.tree[self.tree.capacity-1:self.tree.capacity-1+self.saved_size]) 

        # 将total_p分为n份,每一份为pri_seg
        pri_seg = self.tree.total_p / n  
        for i in range(n):
            a,b= pri_seg*i, pri_seg*(i+1)
            v=random.uniform(a,b)
            idx, p, data=self.tree.get_leaf(v)
            prob=p/self.tree.total_p
            ISWeights[i, 0]
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值