【MADRL】多智能体深度确定性策略梯度(MADDPG )算法

        本篇文章是博主强化学习RL领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在强化学习专栏:

       强化学习(6)---《【MADRL】多智能体深度确定性策略梯度(MADDPG )算法》

【MADRL】多智能体深度确定性策略梯度(MADDPG )算法

目录

1.MADDPG算法详解

2.背景与动机

3.算法结构

4.具体公式

5.算法流程

6.优势与应用场景

7.结论

 [Python] MADDPG实现(可移植)


1.MADDPG算法详解

        MADDPG (Multi-Agent Deep Deterministic Policy Gradient) 是一种用于多智能体强化学习环境的算法。它由2017年发布的论文《Multi-Agent Actor-Critic for Mixed Cooperative-Competitive Environments》提出。MADDPG结合了深度确定性策略梯度(DDPG)算法的思想,并对多智能体场景进行了扩展,能够处理混合的协作与竞争环境。

链接:《Multi-Agent Actor-Critic for Mixed Cooperative-Competitive Environments》

代码:  MADRL多智能体深度确定性策略梯度(MADDPG )算法 


2.背景与动机

        在多智能体系统中,多个智能体同时作用于同一个环境,相互之间可能是竞争的、协作的,或者二者兼有。这类环境下,单智能体算法如DDPG往往无法取得较好的效果,因为每个智能体的行为都会影响其他智能体的状态和奖励。为了解决这一问题,MADDPG采用了一种中心化训练,去中心化执行的架构。

  • 中心化训练:训练期间,每个智能体可以观察所有其他智能体的动作和状态,从而学到更有效的策略。
  • 去中心化执行:在执行阶段,智能体只依赖其自身的观测来做出决策,保持分布式控制的特性。


3.算法结构

        MADDPG是基于Actor-Critic结构的,其中每个智能体都有自己的Actor和Critic模型。Actor用于输出动作策略,而Critic用于评估动作的价值。该算法的独特之处在于,Critic模型是全局的,即Critic不仅依赖于单个智能体的状态和动作,还使用所有智能体的状态和动作。


4.具体公式

MADDPG扩展了DDPG的公式,针对多智能体环境进行如下改动:

  1. 环境设定

    • 状态( s \in S ) 表示整个环境的状态。
    • 对于每个智能体( i ),它的观测值( o_i \in O ) 是全局状态的一部分。
    • 每个智能体采取动作 ( a_i \in A )
    • 每个智能体根据其策略( \pi_i(o_i) ) 选择动作。
  2. 目标:每个智能体的目标是最大化其期望累积回报( R_i = \mathbb{E}[\sum_t \gamma^t r_i^t] ),其中( r_i^t ) 是时刻( t )智能体 ( i ) 的即时奖励,( \gamma )是折扣因子。

  3. Critic网络:每个智能体 ( i )的 Critic 网络( Q_i(s, a_1, ..., a_N) )估计全局的状态和所有智能体动作的联合Q值。这个Q值函数可以通过Bellman方程进行更新:(或者其他方式)

    [ L(\theta_i) = \mathbb{E}_{s,a,r,s'} \left[ \left( Q_i(s, a_1, ..., a_N; \theta_i) - y \right)^2 \right] ]

    其中目标值( y ) 为:

    [ y = r_i + \gamma Q'_i(s', a'_1, ..., a'_N; \theta'_i) ]

    这里,( Q'_i )是目标Critic网络,动作( a'_j )是通过各自的目标Actor策略选出的动作。

  4. Actor网络:每个智能体( i ) 的Actor策略是通过最大化其Critic函数的期望来更新的:

    [ \nabla_{\theta_{\pi_i}} J(\pi_i) = \mathbb{E}{s, a} \left[ \nabla{a_i} Q_i(s, a_1, ..., a_N) \nabla_{\theta_{\pi_i}} \pi_i(o_i) \right] ]

    通过策略梯度法对Actor网络的参数 ( \theta_{\pi_i} )进行更新。

  5. 去中心化执行:在实际执行过程中,每个智能体根据其自身的观测值( o_i ) 通过策略( \pi_i(o_i) ) 选择动作。


5.算法流程

  1. 初始化:为每个智能体( i )初始化Actor网络( \pi_i )和Critic网络( Q_i ) 以及对应的目标网络( \pi'_i )( Q'_i )

  2. 交互:智能体与环境进行交互,在每个时刻 ( t ),每个智能体根据其策略( \pi_i(o_i) )选择动作( a_i ),环境返回下一个状态和奖励( r_i )

  3. 存储经验:将状态、动作、奖励和下一个状态存入经验回放池。

  4. 采样与更新:从经验回放池中采样一个批次,使用前述的公式更新每个智能体的Critic和Actor网络。

  5. 软更新目标网络:以慢速的方式更新目标网络的参数:

    [ \theta'_i \leftarrow \tau \theta_i + (1 - \tau) \theta'_i ]

  6. 重复:重复交互和更新过程,直到训练完成。


6.优势与应用场景

  • 解决多智能体环境中的非平稳性问题:由于多个智能体的存在,环境对每个智能体来说是非平稳的。MADDPG通过中心化的Critic结构来应对这一问题,确保在训练过程中,每个智能体都能有效学习到策略。

  • 处理协作与竞争混合的环境:MADDPG非常适合混合了协作和竞争的多智能体环境,因为它允许智能体通过全局视角进行策略学习,但在执行时保持去中心化。


7.结论

        MADDPG是一种针对多智能体系统的强化学习算法,结合了Actor-Critic框架和中心化训练去中心化执行的思想,能够有效处理协作与竞争共存的复杂环境。通过引入全局信息进行训练,它显著提高了多智能体环境下的学习效果,同时保留了分布式控制的灵活性。


 [Python] MADDPG实现(可移植)

        若是下面代码复现困难或者有问题,欢迎评论区留言;需要以整个项目形式的代码,请在评论区留下您的邮箱,以便于及时分享给您(私信难以及时回复)。

主文件:MADDPG_MATD3_main

import torch
import numpy as np
from torch.utils.tensorboard import SummaryWriter
from environment import Env
import argparse
from replay_buffer import ReplayBuffer
from maddpg import MADDPG
from matd3 import MATD3
import copy


class Runner:
    def __init__(self, args, env_name, number, seed):
        self.args = args
        self.env_name = env_name
        self.number = number
        self.seed = seed
        # Create env
        self.env = Env(env_name, discrete=False)  # Continuous action space
        self.env_evaluate = Env(env_name, discrete=False)
        self.args.N = self.env.n  # The number of agents
        self.args.obs_dim_n = [self.env.observation_space[i].shape[0] for i in range(self.args.N)]  # obs dimensions of N agents
        self.args.action_dim_n = [self.env.action_space[i].shape[0] for i in range(self.args.N)]  # actions dimensions of N agents
        print("observation_space=", self.env.observation_space)
        print("obs_dim_n={}".format(self.args.obs_dim_n))
        print("action_space=", self.env.action_space)
        print("action_dim_n={}".format(self.args.action_dim_n))

        # Set random seed
        np.random.seed(self.seed)
        torch.manual_seed(self.seed)

        # Create N agents
        if self.args.algorithm == "MADDPG":
            print("Algorithm: MADDPG")
            self.agent_n = [MADDPG(args, agent_id) for agent_id in range(args.N)]
        elif self.args.algorithm == "MATD3":
            print("Algorithm: MATD3")
            self.agent_n = [MATD3(args, agent_id) for agent_id in range(args.N)]
        else:
            print("Wrong!!!")

        self.replay_buffer = ReplayBuffer(self.args)

        # Create a tensorboard
        self.writer = SummaryWriter(log_dir='runs/{}/{}_env_{}_number_{}_seed_{}'.format(self.args.algorithm, self.args.algorithm, self.env_name, self.number, self.seed))

        self.evaluate_rewards = []  # Record the rewards during the evaluating
        self.total_steps = 0

        self.noise_std = self.args.noise_std_init  # Initialize noise_std

    def run(self, ):
        self.evaluate_policy()

        while self.total_steps < self.args.max_train_steps:
            obs_n = self.env.reset()
            for _ in range(self.args.episode_limit):
                # Each agent selects actions based on its own local observations(add noise for exploration)
                a_n = [agent.choose_action(obs, noise_std=self.noise_std) for agent, obs in zip(self.agent_n, obs_n)]
                # --------------------------!!!注意!!!这里一定要deepcopy,MPE环境会把a_n乘5-------------------------------------------
                obs_next_n, r_n, done_n, _ = self.env.step(copy.deepcopy(a_n))
                # Store the transition
                self.replay_buffer.store_transition(obs_n, a_n, r_n, obs_next_n, done_n)
                obs_n = obs_next_n
                self.total_steps += 1

                # Decay noise_std
                if self.args.use_noise_decay:
                    self.noise_std = self.noise_std - self.args.noise_std_decay if self.noise_std - self.args.noise_std_decay > self.args.noise_std_min else self.args.noise_std_min

                if self.replay_buffer.current_size > self.args.batch_size:
                    # Train each agent individually
                    for agent_id in range(self.args.N):
                        self.agent_n[agent_id].train(self.replay_buffer, self.agent_n)

                if self.total_steps % self.args.evaluate_freq == 0:
                    self.evaluate_policy()

                if all(done_n):
                    break

        self.env.close()
        self.env_evaluate.close()

    def evaluate_policy(self, ):
        evaluate_reward = 0
        for _ in range(self.args.evaluate_times):
            obs_n = self.env_evaluate.reset()
            episode_reward = 0
            for _ in range(self.args.episode_limit):
                a_n = [agent.choose_action(obs, noise_std=0) for agent, obs in zip(self.agent_n, obs_n)]  # We do not add noise when evaluating
                obs_next_n, r_n, done_n, _ = self.env_evaluate.step(copy.deepcopy(a_n))
                episode_reward += r_n[0]
                obs_n = obs_next_n
                if all(done_n):
                    break
            evaluate_reward += episode_reward

        evaluate_reward = evaluate_reward / self.args.evaluate_times
        self.evaluate_rewards.append(evaluate_reward)
        print("total_steps:{} \t evaluate_reward:{} \t noise_std:{}".format(self.total_steps, evaluate_reward, self.noise_std))
        self.writer.add_scalar('evaluate_step_rewards_{}'.format(self.env_name), evaluate_reward, global_step=self.total_steps)
        # Save the rewards and models
        np.save('./data_train/{}_env_{}_number_{}_seed_{}.npy'.format(self.args.algorithm, self.env_name, self.number, self.seed), np.array(self.evaluate_rewards))
        for agent_id in range(self.args.N):
            self.agent_n[agent_id].save_model(self.env_name, self.args.algorithm, self.number, self.total_steps, agent_id)


if __name__ == '__main__':
    parser = argparse.ArgumentParser("Hyperparameters Setting for MADDPG and MATD3 in MPE environment")
    parser.add_argument("--max_train_steps", type=int, default=int(1e6), help=" Maximum number of training steps")
    parser.add_argument("--episode_limit", type=int, default=25, help="Maximum number of steps per episode")
    parser.add_argument("--evaluate_freq", type=float, default=5000, help="Evaluate the policy every 'evaluate_freq' steps")
    parser.add_argument("--evaluate_times", type=float, default=3, help="Evaluate times")
    parser.add_argument("--max_action", type=float, default=1.0, help="Max action")

    parser.add_argument("--algorithm", type=str, default="MATD3", help="MADDPG or MATD3")
    parser.add_argument("--buffer_size", type=int, default=int(1e6), help="The capacity of the replay buffer")
    parser.add_argument("--batch_size", type=int, default=1024, help="Batch size")
    parser.add_argument("--hidden_dim", type=int, default=64, help="The number of neurons in hidden layers of the neural network")
    parser.add_argument("--noise_std_init", type=float, default=0.2, help="The std of Gaussian noise for exploration")
    parser.add_argument("--noise_std_min", type=float, default=0.05, help="The std of Gaussian noise for exploration")
    parser.add_argument("--noise_decay_steps", type=float, default=3e5, help="How many steps before the noise_std decays to the minimum")
    parser.add_argument("--use_noise_decay", type=bool, default=True, help="Whether to decay the noise_std")
    parser.add_argument("--lr_a", type=float, default=5e-4, help="Learning rate of actor")
    parser.add_argument("--lr_c", type=float, default=5e-4, help="Learning rate of critic")
    parser.add_argument("--gamma", type=float, default=0.95, help="Discount factor")
    parser.add_argument("--tau", type=float, default=0.01, help="Softly update the target network")
    parser.add_argument("--use_orthogonal_init", type=bool, default=True, help="Orthogonal initialization")
    parser.add_argument("--use_grad_clip", type=bool, default=True, help="Gradient clip")
    # --------------------------------------MATD3--------------------------------------------------------------------
    parser.add_argument("--policy_noise", type=float, default=0.2, help="Target policy smoothing")
    parser.add_argument("--noise_clip", type=float, default=0.5, help="Clip noise")
    parser.add_argument("--policy_update_freq", type=int, default=2, help="The frequency of policy updates")

    args = parser.parse_args()
    args.noise_std_decay = (args.noise_std_init - args.noise_std_min) / args.noise_decay_steps

    env_names = ["simple_speaker_listener", "simple_spread"]
    env_index = 0
    runner = Runner(args, env_name=env_names[env_index], number=1, seed=0)
    runner.run()

环境文件:environment

# Please write down your environment Settings
# Pay attention to the input and output of parameters
class Env:
	def __init__(self, args, discrete):
		self.args = args
		self.discrete = discrete

移植事项:

1.注意环境参数的设置格式

2.注意环境的返回值利用

3.注意主运行流程的runner.run()的相关设置,等

可借鉴:【MADRL】基于MADRL的单调价值函数分解(QMIX)算法​​​​​​ 中关于 QMIX算法移植的注意事项和代码注释。


     文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者关注VX公众号:Rain21321,联系作者。

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

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

相关文章

Java专栏介绍

专栏导读 在当今这个技术飞速发展的时代&#xff0c;Java作为一门成熟且广泛应用的编程语言&#xff0c;一直是软件开发领域的中坚力量。本“Java技术”专栏旨在帮助读者深入理解Java编程语言的精髓&#xff0c;掌握其核心概念与高级特性&#xff0c;并通过实战案例提升编程技…

MLM:多模态大型语言模型的简介、微调方法、发展历史及其代表性模型、案例应用之详细攻略

MLM&#xff1a;多模态大型语言模型的简介、微调方法、发展历史及其代表性模型、案例应用之详细攻略 目录 相关文章 AI之MLM&#xff1a;《MM-LLMs: Recent Advances in MultiModal Large Language Models多模态大语言模型的最新进展》翻译与解读 MLM之CLIP&#xff1a;CLIP…

012.Oracle-索引

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

LLM 模型压缩之三: FoldGPT

0. 资源链接 论文: FoldGPT: Simple and Effective Large Language Model Compression Scheme 项目: to be released. 1. 背景动机 现有的大语言模型推理存在以下问题&#xff1a; LLM 模型因为有大量的参数&#xff0c;以及 next token 的预测方式&#xff0c;导致 LLM 模…

攻防世界 unseping

unseping 攻防世界web新手练习 -unseping_攻防世界web新手题unseping-CSDN博客 这道题对我来说还是有点难&#xff0c;什么oct绕过命令执行第一次遇到捏&#xff0c;所以基本是跟着别人的wp写的&#xff0c;一点点记录吧 先对源码进行分析 <?php highlight_file(__FILE…

OrangePi AIpro 香橙派 昇腾 Ascend C 算子开发 与 调用 - 通过aclnn调用的方式调用AddCustom算子

OrangePi AIpro 香橙派 昇腾 Ascend C 算子开发 与 调用 通过aclnn调用的方式调用 - AddCustom算子 - 单算子API执行(aclnn) 多种算子调用方式 *开发时间使用场景调用方式运行硬件基于Kernel直调工程&#xff08;快速&#xff09;少单算子调用&#xff0c;快速验证算法逻辑IC…

打造个性化时装购物平台:Spring Boot框架的实践

第1章 绪论 1.1背景及意义 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们生活水平的不断提高&#xff0c;日常生活中人们对时装购物系统方面的要求也在不断提高&#xff0c;喜欢购物的人数更是不断增加&#xff0c;使得时装购物系统的开发成为必需而且紧迫的…

面试必备:接口自动化测试精选面试干货

一、 请问你是如何做接口测试的&#xff1f; 大体来说&#xff0c;经历以下过程&#xff1a;接口需求调研、接口测试工具选择、接口测试用例编写、接口测试执行、接口测试回归、接口测试自动化持续集成。具体来说&#xff0c;接口测试流程分成以下九步&#xff1a; 第一步&am…

2024年,女生到底适合转行ui设计还是软件测试?

作为2024年的就业选择来说&#xff0c;软件测试和UI设计发展都挺不错的 选择这两个方向转行的女生很多。但具体选择测试还是UI设计&#xff0c;最好还是根据你个人的兴趣爱好以及长期的发展路径去选择 比如&#xff1a;薪资、工作稳定性、后续晋升空间、学习难度等等方面~ 如…

Kafka【十三】消费者消费消息的偏移量

偏移量offset是消费者消费数据的一个非常重要的属性。默认情况下&#xff0c;消费者如果不指定消费主题数据的偏移量&#xff0c;那么消费者启动消费时&#xff0c;无论当前主题之前存储了多少历史数据&#xff0c;消费者只能从连接成功后当前主题最新的数据偏移位置读取&#…

论文解读 | KDD2024 演化图上的森林矩阵快速计算

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者直播讲解回放&#xff01; 作者简介 孙浩鑫&#xff0c;复旦大学博士生&#xff0c;主要研究方向为大规模图上快速算法设计。 概述 森林矩阵在网络科学、观点动力学和机器学习相关应用中…

(一)十分简易快速 自己训练样本 opencv级联haar分类器 车牌识别

🍂1、不说废话,现象展示 🍃图片识别 🍃视频识别 自己训练样本 十分简易快速 opencv级联ha

系统架构师考试学习笔记第三篇——架构设计高级知识(19)嵌入式系统架构设计理论与实践

本章考点&#xff1a; 第19课时主要学习嵌入式系统架构设计的理论和工作中的实践。根据新版考试大纲&#xff0c;本课时知识点会涉及案例分析题&#xff08;25分&#xff09;。在历年考试中&#xff0c;案例题对该部分内容都有固定考查&#xff0c;综合知识选择题目中有固定分值…

关于C++数组越界的异常

数组越界一般是很难发现的,而且并不是每次都会崩溃. 比如说定义一个数字 #DEFINE MAX_ARRAY 5 int m_IntArray[MAX_ARRAY]; 我们在初始化的时候,故意给他越界,这个时候一般是不会报错的. for(int i0;i<15;i) { m_IntArray[i]0; } 尤其是全局变量,居然一点提示都没有,局部变…

基于约束大于规范的想法,封装缓存组件

架构&#xff1f;何谓架构&#xff1f;好像并没有一个准确的概念。以前我觉得架构就是搭出一套完美的框架&#xff0c;可以让其他开发人员减少不必要的代码开发量&#xff1b;可以完美地实现高内聚低耦合的准则;可以尽可能地实现用最少的硬件资源&#xff0c;实现最高的程序效率…

jmeter执行python脚本,python脚本的Faker库

jmeter安装 jython的插件jar包 通过如下地址下载jython-standalone-XXX.jar包并放到jmeter的XXX\lib\ext目录下面 Downloads | JythonThe Python runtime on the JVMhttps://www.jython.org/download.html 重启jmeter在JSR223中找到jython可以编写python代码执行 python造数据…

Minimax-秋招正式批-面经(SQL相关)

1. 谈谈对聚簇索引的理解 聚簇索引 InnoDB通过主键聚集数据&#xff0c;如果没有定义主键&#xff0c;InnoDB会选择非空的唯一索引代替。如果没有这样的索引&#xff0c;InnoDB会隐式定义一个主键来作为聚簇索引聚簇索引就是按照每张表的主键构造一颗B树&#xff0c;同时叶子…

redis之缓存淘汰策略

1.查看redis的最大占用内存 使用redis-cli命令连接redis服务端&#xff0c;输入命令&#xff1a;config get maxmemory 输出的值为0&#xff0c;0代表redis的最大占用内存等同于服务器的最大内存。 2.设置redis的最大占用内存 编辑redis的配置文件&#xff0c;并重启redis服务…

【软考】设计模式之代理模式

目录 1. 说明2. 应用场景3. 结构图4. 构成5. 适用性6. 优点7. 缺点8. java示例 1. 说明 1.代理模式&#xff08;Proxy Pattern&#xff09;。2.意图&#xff1a;为其他对象提供一种代理以控制对这个对象的访问。3.通过提供与对象相同的接口来控制对这个对象的访问。4.是设计模…

WordPress独立资源下载页面插件美化版

插件介绍&#xff1a; xydown是一款wordpress的独立下载页面插件&#xff0c;主要适用于wp建站用户使用&#xff0c;有些用户在发布文章的时候想要添加一些下载资源&#xff0c;使用这款插件可以把下载的内容独立出来&#xff0c;支持添加本地下载或者百度网盘蓝奏网盘的网址&…