在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/121294751
https://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.cc 和 messages.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.cc 和 messages.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);