ns3-gym使用指南与简单原理解析

在csdn上进行了简单的调研,目前主要还是如何跑起来,但不含为啥能跑起来的简单解析。

我接下来会讲述使用过程中对项目逻辑的理解,错漏之处留言提醒。

基本信息

网址:https://github.com/tkn-tub/ns3-gym

简介: OpenAI Gym 是一个用于强化学习 (RL) 的工具包,广泛应用于研究领域。网络模拟器 ns-3 是网络协议和通信技术领域学术界和工业界的实际标准。ns3-gym 是一个集成了 OpenAI Gym 和 ns-3 的框架,旨在促进在网络研究中使用强化学习。

通俗的来说,原先ns-3无法一边运行一边RL获得信息一边操作一边获得奖励,action并一步步获得符合预期的结果,现在ns3-gym把RL的工具gym和ns3做了一个集成的框架,可以一边运行一边训练一边获得好的结果,省去了手搓的麻烦。

目录结构:

doc是说明文件readme

example是ns3-gym做的结合例子------事实上通用性很强

helper是对ns3来说提前准备的一些方便使用的helper

model是生成库的原文件,在example里面的可执行文件都是基于这里面的内容

enev是我用python3的时候做的虚拟环境,无需关注

test不常用,是用来测试系统OK的

复制代码
/ns-3.40/contrib/opengym$ tree -L 3
.
├── CMakeLists.txt
├── doc
│   ├── figures
│   │   ├── cognitive-radio-learning.png
│   │   └── interferer-pattern.png
│   └── opengym.rst
├── examples
│   ├── CMakeLists.txt
│   ├── interference-pattern
│   │   ├── cognitive-agent-v1.py
│   │   ├── mygym.cc
│   │   ├── mygym.h
│   │   ├── sim.cc
│   │   └── simple_test.py
│   ├── linear-mesh
│   │   ├── backpressure_v1.py
│   │   ├── dqn-agent-v1.py
│   │   ├── dqn-agent-v2.py
│   │   ├── my_random2.py
│   │   ├── my_random.py
│   │   ├── no_op2.py
│   │   ├── no_op.py
│   │   ├── qfull.py
│   │   ├── qfull_working.py
│   │   ├── qlearn_full.py
│   │   ├── qlearn.py
│   │   └── sim.cc
│   ├── linear-mesh-2
│   │   ├── mygym.cc
│   │   ├── mygym.h
│   │   ├── sim.cc
│   │   ├── simple_test.py
│   │   └── test.py
│   ├── multi-agent
│   │   ├── agent1.py
│   │   ├── agent2.py
│   │   ├── mygym.cc
│   │   ├── mygym.h
│   │   └── sim.cc
│   ├── opengym
│   │   ├── sim.cc
│   │   ├── simple_test.py
│   │   └── test.py
│   ├── opengym-2
│   │   ├── mygym.cc
│   │   ├── mygym.h
│   │   ├── sim.cc
│   │   ├── simple_test.py
│   │   └── test.py
│   └── rl-tcp
│       ├── sim.cc
│       ├── tcp_base.py
│       ├── tcp_newreno.py
│       ├── tcp-rl.cc
│       ├── tcp-rl-env.cc
│       ├── tcp-rl-env.h
│       ├── tcp-rl.h
│       ├── test.py
│       └── test_tcp.py
├── helper
│   ├── opengym-helper.cc
│   └── opengym-helper.h
├── LICENSE
├── model
│   ├── container.cc
│   ├── container.h
│   ├── messages.pb.cc
│   ├── messages.pb.h
│   ├── messages.proto
│   ├── ns3gym
│   │   ├── build
│   │   ├── LICENSE
│   │   ├── MANIFEST.in
│   │   ├── ns3gym
│   │   ├── ns3gym.egg-info
│   │   ├── README.md
│   │   ├── requirements.txt
│   │   └── setup.py
│   ├── opengym_env.cc
│   ├── opengym_env.h
│   ├── opengym_interface.cc
│   ├── opengym_interface.h
│   ├── spaces.cc
│   └── spaces.h
├── ns3gym-venv
│   ├── bin
│   │   ├── activate
│   │   ├── activate.csh
│   │   ├── activate.fish
│   │   ├── Activate.ps1
│   │   ├── f2py
│   │   ├── numpy-config
│   │   ├── pip
│   │   ├── pip3
│   │   ├── pip3.12
│   │   ├── python -> python3
│   │   ├── python3 -> /usr/bin/python3
│   │   └── python3.12 -> python3
│   ├── include
│   │   └── python3.12
│   ├── lib
│   │   └── python3.12
│   ├── lib64 -> lib
│   └── pyvenv.cfg
├── NS3-VERSION
├── protobuf-generate.cmake
├── README.md
├── test
│   └── opengym-test-suite.cc
└── VERSION

简单的安装流程:

与前人的其实区别不大

https://blog.csdn.net/qq_37177958/article/details/121294751https://blog.csdn.net/qq_37177958/article/details/121294751不过我还是再重新从Readme里面重新组织一遍:

Install all dependencies required by ns-3.(ns3依赖)

复制代码
# minimal requirements for C++:
apt-get install gcc g++ python3 python3-pip cmake

Install ZMQ, Protocol Buffers and pkg-config libs(ns3-gym的依赖库)

复制代码
sudo apt-get update
apt-get install libzmq5 libzmq3-dev
apt-get install libprotobuf-dev
apt-get install protobuf-compiler
apt-get install pkg-config

Download and install ns3(下载ns3.40------当然你也完全可以官网下载,没有区别)

复制代码
wget https://www.nsnam.org/releases/ns-allinone-3.40.tar.bz2
tar xf ns-allinone-3.40.tar.bz2
cd ns-allinone-3.40

Clone ns3-gym repository into contrib directory and change the branch(把ns3-gym放到ns3目录下,一会一起编译)

复制代码
cd ./ns-3.40/contrib
git clone https://github.com/tkn-tub/ns3-gym.git ./opengym
cd opengym/
git checkout app-ns-3.36+

Configure and build ns-3 project(全局编译ns3,同时就会把ns3-gym一起编译)

复制代码
cd ../../
./ns3 configure --enable-examples
./ns3 build

Install ns3gym located in model/ns3gym (Python3 required)(安装完成后,任何 Python 脚本,无论在哪个目录,都能 import ns3gym------所以我推荐搞一个虚拟环境,安装后同时会安装requirement

复制代码
python3 -m venv ns3gym-venv
source ./ns3gym-venv/bin/activate
pip3 install ./model/ns3gym

requirement.txt如下,会直接装好。

复制代码
pyzmq
numpy
protobuf==3.20.3
gym

(Optional) Start ns-3 simulation script and Gym agent separately in two terminals (useful for debugging):测试(推荐分开测试)

复制代码
# Terminal 1
./ns3 run "opengym"

# Terminal 2
cd ./contrib/opengym/examples/opengym/ 
./test.py --start=0

从Makefile开始理解项目最清晰了

有项目有两个CmakeLists.txt

一个前提(总的来说ns3-gym提供gym控制ns3的框架,具体些就是python可以控制gym,也可以通过预埋在ns3可执行程序内部的"daemon"或者说"hook",等待python通过调用回调函数获取状态或通过调用回调函数控制动作)

架构由两个主要软件模块组成,分别是 OpenAI Gym 和 ns-3 网络模拟器。遵循强化学习的命名法,Gym 框架用于实现代理,而 ns-3 则作为环境。这项工作的主要贡献是设计和实现了 OpenAI Gym 与 ns-3 之间的通用接口,实现了这两个框架的无缝集成。该接口负责管理 NS-3 仿真过程生命周期,并在 Gym 代理与仿真环境之间传递状态和动作信息。

ns3-gym 是一个工具包,由两个模块组成(一个用 C++ 编写,另一个用 Python 编写),作为现有 ns-3 和 OpenAI Gym 框架的附加组件,支持它们之间的信息交换。通信通过 ZMQsockets 实现,使用协议缓冲库进行消息序列化。然而,这被用户隐藏在易于使用的 API 背后。

理解了ns3-gym的作用就可以看代码了

顶层makfile

复制代码
include(FindPkgConfig)
if(NOT PKG_CONFIG_FOUND)
    message(STATUS "pkgconf not found")
    return()
endif()

pkg_check_modules(ZMQ libzmq)
if(NOT ZMQ_FOUND)
    message(STATUS "zeromq not found")
    return()
endif()

find_package(Protobuf REQUIRED)
if(NOT Protobuf_FOUND)
    message(STATUS "protobuf not found")
  return()
endif()

可以看到先进行以下的库检查

|------------|----------------------------------|-----------|-----------------------------|
| 检查项 | 代码 | 类型 | 失败后果 |
| pkg-config | FindPkgConfig + PKG_CONFIG_FOUND | 构建工具 | 直接 return(),跳过整个 opengym 模块 |
| libzmq | pkg_check_modules(ZMQ libzmq) | 系统库 (C++) | 直接 return(),跳过整个 opengym 模块 |
| protobuf | find_package(Protobuf REQUIRED) | 系统库 (C++) | 直接 return(),跳过整个 opengym 模块 |

库的作用如下------这也是ns3gym的核心,用于python控制C++:

|------|--------------------|-------------|-----------------|
| 层面 | C++(apt-get) | Python(pip) | 互通方式 |
| 网络通信 | libzmq | pyzmq | 通过TCP/IPC协议自动互通 |
| 序列化 | libprotobuf+protoc | protobuf | 通过相同的.proto定义互通 |
| 构建工具 | pkg-config | - | 仅用于编译期查找库 |

复制代码
set(proto_source_files
    model/messages.proto
)

set(source_files
    helper/opengym-helper.cc
    model/container.cc
    model/opengym_env.cc
    model/opengym_interface.cc
    model/spaces.cc
    ${proto_source_files}
)

set(header_files
    helper/opengym-helper.h
    model/container.h
    model/opengym_env.h
    model/opengym_interface.h
    model/spaces.h
)

build_lib(
  LIBNAME opengym
  SOURCE_FILES ${source_files}
  HEADER_FILES ${header_files}
  LIBRARIES_TO_LINK
    ${libcore}
    ${ZMQ_LIBRARIES}
    protobuf::libprotobuf
  TEST_SOURCES
    test/opengym-test-suite.cc
)

这一段声明了C++列表和.h列表然后编译成c++的lib,形成lib的时候还需要链接ns3的core和apt-get到的zmq lib,同时通过protobuf把对应的proto文件转换为cc文件(到这只有proto,下一步转cc)编译到总的lib。

build_lib() 接收这个列表时,.proto 文件会被 CMake 识别为需要特殊处理的源文件

前面的 protobuf_generate() 已经在 configure 阶段将 .proto 编译成了 messages.pb.ccmessages.pb.h

build_lib 内部实际上会自动替换或追加生成的 .pb.cc 到编译列表中

复制代码
# need protobuf_generate func to generate messages
check_function_exists(protobuf_generate protobuf_generate_exists)
if(${protobuf_generate_exists})
    message(STATUS "protobuf_generate command found")
else()
  message(STATUS "protobuf_generate command not found -> use a local copy from ${CMAKE_CURRENT_SOURCE_DIR}/protobuf-generate.cmake")
  include(${CMAKE_CURRENT_SOURCE_DIR}/protobuf-generate.cmake)
endif()


protobuf_generate(
  TARGET ${libopengym-obj}
  IMPORT_DIRS model/
  LANGUAGE cpp
  PROTOC_OUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/model
)

protobuf_generate(
  TARGET ${libopengym-obj}
  IMPORT_DIRS model/
  LANGUAGE python
  PROTOC_OUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/model/ns3gym/ns3gym
)

调用 protoc 编译器生成 messages.pb.ccmessages.pb.h

将生成的 .pb.cc 自动添加到 ${libopengym-obj} 的源文件列表中

"Note: Opengym Protocol Buffer messages (C++ and Python) are build during configure."(通过上面一个CMakeLists.txt,C++部分的通信库已经有了,python部分的在pip3 install ./model/ns3gym的时候建立好了)

pip3 install ./model/ns3gym之后 ,ns3gym就在当前环境注册好了,注册后效果

任何 Python 脚本,无论在哪个目录,都能 import ns3gym、命令行可以用 pip show ns3gym 查看包信息、可以用 pip uninstall ns3gym 卸载

requirement.txt如下,会直接装好。

复制代码
pyzmq
numpy
protobuf==3.20.3
gym

与C++对应关系:

|------------------|------------------|------------------------|
| Python 包 | 对应 C++ 库 | 作用 |
| pyzmq | libzmq (系统) | Python 端的 ZMQ 绑定 |
| protobuf==3.20.3 | libprotobuf (系统) | Python 端的 protobuf 运行时 |
| gym | 无 | OpenAI Gym API 接口 |
| numpy | 无 | 数组处理(状态/动作) |

因此此时已经可以跨python和C++,通过python调用gym、控制ns3了,因此接下来就是对应例子了

example的makefile

复制代码
build_lib_example(
  NAME interference-pattern
  SOURCE_FILES interference-pattern/mygym.cc
               interference-pattern/sim.cc
  LIBRARIES_TO_LINK
    ${libcore}
    ${libinternet}
    ${libopengym}
    ${libwifi}
)

build_lib_example(
  NAME linear-mesh
  SOURCE_FILES linear-mesh/sim.cc
  LIBRARIES_TO_LINK
    ${libapplications}
    ${libcore}
    ${libinternet}
    ${libopengym}
    ${libwifi}
)

build_lib_example(
  NAME linear-mesh-2
  SOURCE_FILES linear-mesh-2/sim.cc
               linear-mesh-2/mygym.cc
  LIBRARIES_TO_LINK
    ${libapplications}
    ${libcore}
    ${libinternet}
    ${libopengym}
    ${libwifi}
)

build_lib_example(
  NAME opengym
  SOURCE_FILES opengym/sim.cc
  LIBRARIES_TO_LINK
    ${libcore}
    ${libopengym}
)

build_lib_example(
  NAME opengym-2
  SOURCE_FILES opengym-2/sim.cc
               opengym-2/mygym.cc
  LIBRARIES_TO_LINK
    ${libcore}
    ${libopengym}
)

build_lib_example(
  NAME rl-tcp
  SOURCE_FILES rl-tcp/sim.cc
               rl-tcp/tcp-rl-env.cc
               rl-tcp/tcp-rl.cc
  LIBRARIES_TO_LINK
    ${libapplications}
    ${libcore}
    ${libflow-monitor}
    ${libinternet}
    ${libopengym}
    ${libpoint-to-point-layout}
    ${libptp}
)

其实到这反而没啥好说的了,就是不同的cc对应不同的目标文件,需要不同的链接库。

标准接口讲解与使用首先需要满足的准则

任何 ns-3 模拟脚本都可以用作GYM环境。这只需实例化 OpenGymInterface并实现包含列出的函数的 ns3-gym C++ 接口。注意,这些函数可以单独定义,也可以在继承自 GymEnv 基类的对象内组合。换言之正如上面描述的,通过socket控制C++也就是说ns3编译出来的可执行文件,需要ns3编译可执行文件的时候绑定触发关系,让对应函数等在那里,等着socket触发。

以下需要实例化:

cpp 复制代码
Ptr<OpenGymInterface> openGymInterface =
    CreateObject<OpenGymInterface> (openGymPort);
Ptr<MyGymEnv> myGymEnv = CreateObject<MyGymEnv> ();
myGymEnv->SetOpenGymInterface(openGymInterface);

以下需要实现的函数接口

cpp 复制代码
Ptr<OpenGymSpace> GetObservationSpace();
Ptr<OpenGymSpace> GetActionSpace();
Ptr<OpenGymDataContainer> GetObservation();
float GetReward();
bool GetGameOver();
std::string GetExtraInfo();
bool ExecuteActions(Ptr<OpenGymDataContainer> action);
相关推荐
小草cys2 小时前
【有问题未解决】Ubuntu arm版的桌面分辨率修改
linux·arm开发·ubuntu
爱编程的小吴12 小时前
通义灵码输出软件设计文档实例1
arm开发·ai写作
szxinmai主板定制专家14 小时前
基于 PC 的控制技术+ethercat+linux实时系统,助力追踪标签规模化生产,支持国产化
arm开发·人工智能·嵌入式硬件·yolo·fpga开发
切糕师学AI16 小时前
ARM 汇编器中的伪指令(Assembler Directives)
开发语言·arm开发·c#
陌上花开缓缓归以19 小时前
OPENWRT 端口link问题
linux·arm开发
VekiSon1 天前
Linux内核驱动——Ubuntu 网络启动环境配置与操作
linux·arm开发·嵌入式硬件·ubuntu
ONLYOFFICE1 天前
如何在 Fedora 43 ARM 架构设备上安装 ONLYOFFICE 桌面编辑器
arm开发·编辑器
陌上花开缓缓归以1 天前
insmod 报错问题定位纪要
linux·arm开发
byte轻骑兵3 天前
ARM 嵌入式处理器内核与架构深度剖析(3): ARM嵌入式处理器的架构组成
arm开发