深度强化学习DQN训练避障

目录

一.前言

二.代码

2.1完整代码

2.2运行环境

2.3动作空间

2.4奖励函数

2.5状态输入

2.6实验结果


一.前言

深度Q网络(DQN)是深度强化学习领域的一项革命性技术,它成功地将深度学习的强大感知能力与强化学习的决策能力相结合。在过去的几年里,DQN已经在许多复杂的问题上展示了其卓越的性能,从经典的Atari游戏到更复杂的机器人控制任务。特别值得一提的是,DQN在处理高维状态空间和动作空间的问题时表现出了显著的优势,使得它能够处理传统强化学习方法难以解决的难题。

二维环境避障问题是强化学习领域的一个经典问题,它要求智能体在二维空间中移动,同时避免与障碍物碰撞。这个问题看似简单,但实际上涉及到了许多复杂的因素,如环境的不确定性、部分可观察性、以及智能体的感知和决策能力限制等。因此,开发一种能够有效解决二维环境避障问题的方法具有重要的实际意义和应用价值。

近年来,随着深度学习和强化学习技术的不断发展,基于DQN的二维环境避障方法已经取得了显著的进展。通过利用深度学习的强大特征提取能力,DQN能够从原始的环境状态中学习到有用的特征表示,并基于这些特征进行高效的决策。此外,DQN还引入了经验回放和目标网络等关键技术,进一步提高了算法的稳定性和收敛速度。

本文研究如何让智能体在一个二维障碍物环境中进行避障。

二.代码

2.1完整代码

import gym  
import torch,copy
import torch.nn as nn
import torch.nn.functional as F
import numpy as np  
from gym import spaces  
from gym.utils import seeding  
import matplotlib.pyplot as plt  
#超参数
BATCH_SIZE = 32
LR = 0.01
EPSILON = 0.9 #随机选取的概率,如果概率小于这个随机数,就采取greedy的行为
GAMMA = 0.9
TARGET_REPLACE_ITER = 100
MEMORY_CAPACITY = 2000
N_ACTIONS=len(np.arange(0, 2*np.pi, 0.1))
N_STATES=4
ENV_A_SHAPE =0
class Net(nn.Module):
    def __init__(self, ):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(N_STATES, 500)
        self.fc1.weight.data.normal_(0, 0.1)   # initialization
        self.out = nn.Linear(500, N_ACTIONS)
        self.out.weight.data.normal_(0, 0.1)   # initialization
    def forward(self, x):
        x = self.fc1(x)
        x = F.relu(x)
        actions_value = self.out(x)
        return actions_value
class DQN(object):
    def __init__(self):
        #DQN是Q-Leaarning的一种方法,但是有两个神经网络,一个是eval_net一个是target_net
        #两个神经网络相同,参数不同,是不是把eval_net的参数转化成target_net的参数,产生延迟的效果
        self.eval_net=Net()
        self.target_net =copy.deepcopy(self.eval_net)
        self.learn_step_counter = 0 #学习步数计数器
        self.memory_counter = 0 #记忆库中位值的计数器
        self.memory = np.zeros((MEMORY_CAPACITY,N_STATES * 2 + 2)) #初始化记忆库
        #记忆库初始化为全0,存储两个state的数值加上一个a(action)和一个r(reward)的数值
        self.optimizer = torch.optim.Adam(self.eval_net.parameters(),lr = LR)
        self.loss_func = nn.MSELoss() #优化器和损失函数    
    #接收环境中的观测值,并采取动作
    def choose_action(self,x):
        #x为观测值
        x = torch.unsqueeze(torch.FloatTensor(x),0)
        if np.random.uniform() < EPSILON:
            #随机值得到的数有百分之九十的可能性<0.9,所以该if成立的几率是90%
            #90%的情况下采取actions_value高的作为最终动作
            actions_value = self.eval_net.forward(x)
            action = torch.max(actions_value,1)[1].data.numpy()
            action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE) # return the argmax index
        else:
            #其他10%采取随机选取动作
            action = np.random.randint(0,N_ACTIONS) #从动作中选一个动作
            action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
        return action    
    #记忆库,存储之前的记忆,学习之前的记忆库里的东西
    def store_transition(self,s,a,r,s_):

        transition = np.hstack((s, [a, r], s_))
        # 如果记忆库满了, 就覆盖老数据
        index = self.memory_counter % MEMORY_CAPACITY
        self.memory[index, :] = transition
        self.memory_counter += 1
    def learn(self):
         # target net 参数更新,每隔TARGET_REPLACE_ITE更新一下
        if self.learn_step_counter % TARGET_REPLACE_ITER == 0:
            self.target_net.load_state_dict(self.eval_net.state_dict())
        self.learn_step_counter += 1
        #targetnet是时不时更新一下,evalnet是每一步都更新
 
        # 抽取记忆库中的批数据
        sample_index = np.random.choice(MEMORY_CAPACITY, BATCH_SIZE)
        b_memory = self.memory[sample_index, :] 
        #打包记忆,分开保存进b_s,b_a,b_r,b_s
        b_s = torch.FloatTensor(b_memory[:, :N_STATES])
        b_a = torch.LongTensor(b_memory[:, N_STATES:N_STATES+1].astype(int))
        b_r = torch.FloatTensor(b_memory[:, N_STATES+1:N_STATES+2])
        b_s_ = torch.FloatTensor(b_memory[:, -N_STATES:])
 
        # 针对做过的动作b_a, 来选 q_eval 的值, (q_eval 原本有所有动作的值)
        q_eval = self.eval_net(b_s).gather(1, b_a)  # shape (batch, 1)
        q_next = self.target_net(b_s_).detach()     # q_next 不进行反向传递误差, 所以 detach
        q_target = b_r + GAMMA * q_next.max(1)[0]   # shape (batch, 1)
        loss = self.loss_func(q_eval, q_target)
 
        # 计算, 更新 eval net
        self.optimizer.zero_grad()
        loss.backward() #误差反向传播
        self.optimizer.step()

class RobotEnv(gym.Env):  
    metadata = {'render.modes': ['human']}  
  
    def __init__(self):  
        super(RobotEnv, self).__init__()  
        
        self.grid_size = 1000  
        self.viewobs = np.zeros((self.grid_size, self.grid_size))  
        self.robot_radius = 10  
        self.obstacle_radius = 50  
        self.robot_pos = np.array([self.grid_size // 8, self.grid_size // 2])  
        self.obstacle_pos = np.array([self.grid_size *3// 4, self.grid_size // 2])  
        self.target_pos = np.array([self.grid_size *7 // 8, self.grid_size // 2])  
        self.action_space =np.arange(0, 2*np.pi, 0.1)  
        self.observation_space = spaces.Box(low=0, high=1, shape=(self.grid_size, self.grid_size))  
        self._seed()  
    def _reset(self):
        self.robot_pos = np.array([self.grid_size  // 8, self.grid_size // 2])  
        self.obstacle_pos = np.array([self.grid_size *3// 4, self.grid_size // 2])  
        self.observation_space = spaces.Box(low=0, high=1, shape=(self.grid_size, self.grid_size))  
        return self._get_obs()
    def _seed(self, seed=None):  
        self.np_random, seed = seeding.np_random(seed)  
        return [seed]  
  
    def _step(self, action):  
        angle = action*0.1  

        dx = self.robot_radius * np.cos(angle)  
        dy = self.robot_radius * np.sin(angle)  
        new_pos = self.robot_pos + np.array([dx, dy])  

        if np.linalg.norm(new_pos - self.obstacle_pos) <= self.obstacle_radius:  
            reward = -1
            done = True  
        elif self.robot_pos[0]<=self.robot_radius+self.robot_radius or self.robot_pos[0]>=self.grid_size-self.robot_radius-self.robot_radius:
            reward=-1
            done = True  
        elif self.robot_pos[1]<=self.robot_radius+self.robot_radius or self.robot_pos[1]>=self.grid_size-self.robot_radius-self.robot_radius:
            reward=-1
            done = True  
        else:  
            reward = 1 / (1 + np.linalg.norm(new_pos - self.target_pos))  
            done = False  
        self.robot_pos = new_pos  
        return self._get_obs(), reward, done, {}  
  
    def _get_obs(self):  
        self.viewobs = np.zeros((self.grid_size, self.grid_size))  


        self.viewobs[int(self.robot_pos[0])][int(self.robot_pos[1])] = 1.0
        self.viewobs[int(self.obstacle_pos[0] - self.obstacle_radius):int(self.obstacle_pos[0] + self.obstacle_radius),   
           int(self.obstacle_pos[1] - self.obstacle_radius):int(self.obstacle_pos[1] + self.obstacle_radius)] = 0.5  
        obs=[self.robot_pos[0],self.robot_pos[1],self.obstacle_pos[0],self.obstacle_pos[1]]
        return obs

  
    def _render(self, mode='human', close=False):  
        if close:  
            return  
        plt.imshow(self.viewobs, cmap='gray')  
        plt.scatter(self.robot_pos[1], self.robot_pos[0], c='red')  
        plt.scatter(self.obstacle_pos[1], self.obstacle_pos[0], c='blue')  
        plt.xlim([0, self.grid_size])  
        plt.ylim([0, self.grid_size])  
        #plt.show()  
        plt.pause(0.01)  
        plt.clf()  
  
if __name__ == "__main__":  
    env = RobotEnv()  
    dqn = DQN()
    for i in range(400000):
        s=env.reset()
        for j in range(300):  # Run for 100 steps as an example  
            action  = dqn.choose_action(s) 
            s_, reward, done, info = env.step(action)  
            print(reward)
            env.render()  
            dqn.store_transition(s,action,reward,s_)
            if dqn.memory_counter > MEMORY_CAPACITY:
                dqn.learn()
            if done:  
                print("Episode finished after {} timesteps".format(i+1))  
                break
            s = s_ # 现在的状态赋值到下一个状态上去

2.2运行环境

gym== 0.7.0

torch==2.1.1

2.3动作空间

    在深度强化学习领域中,动作空间的设计对于智能体的决策能力和学习效果具有至关重要的影响。针对连续动作空间的问题,一种常见的处理方式是将其离散化,以便应用离散动作空间的强化学习算法。本实验提出了一种将0-2π的连续动作空间等分为63个离散动作的方法。

    通过采用等分为63个离散动作的策略。使得实验在保留了足够的动作分辨率的同时,避免了过度离散化可能带来的维度灾难问题。通过将动作空间划分为足够细密的离散区间,智能体能够更精确地控制自身的行为,从而在面对复杂环境时实现更好的性能。

2.4奖励函数

在本研究中,我们设计的奖励函数主要基于两个核心原则:

  1. 靠近障碍物的奖励:当智能体靠近障碍物后方时,将获得一个与距离大小成反比的奖励值。具体而言,随着智能体逐渐接近障碍物,奖励值将逐渐增大,以鼓励智能体保持与障碍物的安全距离。这种设计策略旨在通过提供即时的正反馈来促使智能体学习避免与障碍物发生碰撞的行为。
  2. 违反仿真边界或进入障碍物区域的惩罚:一旦智能体离开仿真边界或进入障碍物区域,将获得一个负奖励(惩罚),并且仿真将立即停止。这种严厉的惩罚机制确保了智能体能够清晰地认识到这些行为的不可取性,从而在学习过程中避免重复犯下相同的错误。

2.5状态输入

    在本研究中,我们将智能体的当前位置以及障碍物的位置信息作为状态输入。具体来说,状态空间包括智能体的二维坐标和障碍物的二维坐标。这样的设计使得智能体能够直接感知到周围环境的信息,并根据这些信息做出相应的决策。

2.6实验结果

    无论是在静态还是动态环境中,智能体都能够准确地感知到障碍物的存在,并有效地规划出避开障碍物的路径。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/274093.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BloombergGPT—金融领域大模型

文章目录 背景BloombergGPT数据集金融领域数据集通用数据集分词 模型模型结构模型相关参数训练配置训练过程 模型评估评估任务分布模型对比金融领域评估通用领域评估 背景 GPT-3的发布证明了训练非常大的自回归语言模型&#xff08;LLM&#xff09;的强大优势。GPT-3有1750亿个…

Java并发编程(一)

1.什么是线程和进程&#xff0c;区别是什么? 进程&#xff1a;进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从创建&#xff0c;运行到消亡的过程。 线程&#xff1a;线程与进程相似&#xff0…

亿欧智库详解2023人力资源数字化,红海云解决方案受关注

近日&#xff0c;亿欧智库发布《2023中国人力资源数字化企业需求分析》报告&#xff0c;基于调研结果对开展人力资源数字化转型的企业进行画像分析&#xff0c;揭示了不同企业下人力资源数字化转型需求的差异性&#xff0c;同时为企业人力资源数字化转型路径、方法及平台工具选…

springboot带微信端小程序智慧校园电子班牌系统源码

随着时代进步&#xff0c;数字信息化不断发展&#xff0c;很多学校都开始了数字化的转变。智慧校园电子班牌系统源码是电子班牌集合信息化技术、物联网、智能化&#xff0c;电子班牌以云平台、云服务器为基础&#xff0c;融合了班级文化展示、课程管理、物联控制、教务管理、考…

如何配置TLSv1.2版本的ssl

1、tomcat配置TLSv1.2版本的ssl 如下图所示&#xff0c;打开tomcat\conf\server.xml文件&#xff0c;进行如下配置&#xff1a; 注意&#xff1a;需要将申请的tomcat版本的ssl认证文件&#xff0c;如server.jks存放到tomcat\conf\ssl_file\目录下。 <Connector port"1…

【Vue篇】基础篇—Vue指令,Vue生命周期

&#x1f38a;专栏【JavaSE】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;Vue概述&#x1f384;快速入门&#x1f33a;Vue指令⭐v-…

LTD257次升级 | 商品库存能提醒 • 商品运费批量改 • 小程序官网发视频 • 网页地址可设中文

1、 商城新增库存提醒&#xff0c;支持批量改运费&#xff1b; 2、 极速官微支持发布视频&#xff1b; 3、 官微中心登录新增公众号验证码验证&#xff1b; 4、 编辑器页面地址支持设置为中文&#xff1b; 5、 其他已知问题修复与优化&#xff1b; 01 商城 1) 新增商品库存提醒…

SpringMVC:SSM(Spring+SpringMVC+MyBatis)代码整理

文章目录 SpringMVC - 07SSM 框架代码整理一、准备工作1. 分析需求、准备数据库2. 新建一个项目&#xff0c;导入依赖&#xff1a;pom.xml3. 用 IDEA 连接数据库 二、MyBatis 层1. 外部配置文件&#xff1a;db.properties2. MyBatis 核心配置文件&#xff1a;mybatis-config.xm…

fpga xvc 调试实现,支持多端口同时调试多颗FPGA芯片

xilinx 推荐的实现结构方式如下&#xff1a; 通过一个ZYNQ运行xvc服务器&#xff0c;然后通过zynq去配置其他的FPGA&#xff0c;具体参考设计可以参考手册xapp1251&#xff0c;由于XVC运行的协议是标准的TCP协议&#xff0c;这种方式需要ZYNQ运行TCP协议&#xff0c;也就需要运…

单片机外设矩阵键盘之行列扫描识别原理与示例

单片机外设矩阵键盘之行列扫描识别原理与示例 1.概述 这篇文章介绍单片机通过行列扫描的方式识别矩阵键盘的按键&#xff0c;通过程序执行相应的操作。 2.行列扫描识别原理 2.1.独立按键识别原理 为什么需要矩阵按键 独立按键操作简单&#xff0c;当数量较多时候会占用单片机…

win10: 搭建本地pip镜像源

前言&#xff1a; windows下和linux下都可以搭建本地pip镜像源。操作流程上一样&#xff0c;但是细节上存在一些差异。建议在linux上搭建本地镜像&#xff0c;流程简单很多。在windows系统上&#xff0c;会在多个地方存在问题&#xff08;比如不识别.symlink文件&#xff0c;一…

【MySQL】索引特性

文章目录 一、索引的概念二、MySQL与磁盘三、索引的理解观察主键索引现象推导主键索引结构的构建索引结构可以采用的数据结构聚簇索引 VS 非聚簇索引 四、索引操作创建主键索引创建唯一索引创建普通索引创建全文索引查询索引删除索引索引创建原则 一、索引的概念 数据库表中存…

PostgreSQL | FunctionProcedure | 函数与存储过程的区别

文章目录 PostgreSQL | Function&Procedure | 函数与存储过程的区别1. 简述书面说法大白话讲 2. 函数&#xff08;Function&#xff09;2.1 定义2.2 用途2.3 执行2.4 事务处理2.5 说点例子1. 当参数都是IN类时2. 参数中出现OUT、INOUT参数时 3. 存储过程&#xff08;Proced…

【Java】工业园区高精准UWB定位系统源码

UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术&#xff0c;它不采用正弦载波&#xff0c;而是利用纳秒级的非正弦波窄脉冲传输数据&#xff0c;因此其所占的频谱范围很宽。UWB定位系统依托在移动通信&#xff0c;雷达&#xff0c;微波电路&#xff0c;云计算与大数据…

02之Python运算符与if结构

Day02之Python运算符与if结构 一、昨日回顾 1、回顾昨天的课程内容 略 2、回顾昨天的作业 定义变量&#xff0c;c1 ‘可乐’&#xff0c;c2 ‘牛奶’&#xff0c;通过Python代码把c1内容调整为牛奶&#xff0c;c2调整为可乐。 # 1、定义两个变量 c1 可乐 c2 牛奶# 2、…

以源码为驱动:Java版工程项目管理系统平台助力工程企业迈向数字化管理的巅峰

随着企业规模的不断扩大和业务的快速发展&#xff0c;传统的工程项目管理方式已经无法满足现代企业的需求。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;企业需要借助先进的数字化技术进行转型。本文将介绍一款采用Spring CloudSpring BootMybat…

[Linux] MySQL数据库的备份与恢复

一、数据库备份的分类和备份策略 1.1 数据库备份的分类 1&#xff09;物理备份 物理备份&#xff1a;对数据库操作系统的物理文件&#xff08;如数据文件、日志文件等&#xff09;的备份。 物理备份方法&#xff1a; 冷备份(脱机备份) &#xff1a;是在关闭数据库的时候进…

Text-to-SQL小白入门(十)RLHF在Text2SQL领域的探索实践

本文内容主要基于以下开源项目探索实践&#xff0c; Awesome-Text2SQL:GitHub - eosphoros-ai/Awesome-Text2SQL: Curated tutorials and resources for Large Language Models, Text2SQL, Text2DSL、Text2API、Text2Vis and more.DB-GPT-Hub&#xff1a;GitHub - eosphoros-ai…

Java 对象内存布局

在虚拟机中&#xff0c;Java对象在内存中的布局可以分为三块&#xff1a; 对象头&#xff08;Header&#xff09; &#xff1a;包含 markword 标记字段和类型指针&#xff0c;32 位上大小是 8 个字节&#xff0c;64 位 16 个字节&#xff0c;实例数据&#xff08;Instance Dat…

特殊求和(C++)

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…