• ns3-gym入门(三):在opengym基础上实现一个小小的demo


    因为官方给的"opengym""opengym-2"这两个例子都很简单,所以自己改了一个demo,把reward-action-state相互影响的关系表现出来

    一、准备工作

    在ns3.35/scratch目录下创建一个文件夹:
    (后续的运行指令后面都需要转移到这个文件夹路径下)

    1. #Terminal1
    2. cd ~/source/ns3.35
    3. sudo ./waf --run "demo11"
    4. #Terminal2
    5. cd ~/source/ns3.35/demo11
    6. PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python ./test11.py --start=0

    二、主要思路

    • Action:离散空间[0,1,2,3],使用ε-贪心策略选择
    • ExecuteActions:赋值x=action
    • Obs\State:基于action定义一组数,关于x的线性函数
    • Reward:对state中的所有数据进行处理,取平均数得到r

    PS.发现一个问题,这个框架如果脱离了具体的网络环境其实并不好定义,因为这些要素相互依赖的关系非常抽象,尤其是state是通过全网状态搜集得到的,在这里没有定义具体的网络环境,所以暂时用全局变量来表示一下这种隐性关系

    三、关键实现步骤

    mygym.cc(定义了存储决策和状态的全局变量,增加了收集状态、执行动作、计算奖励的函数)
    ①全局变量

    1. static float deci = 0.0; // 全局变量,用于存储决策
    2. std::vector<float> state;// 全局变量,用于存储状态

    ②创建状态空间(只是初始化一个容器,定义好维度就行)

    1. //初始化一般不用大改,建立一个存储空间就行
    2. Ptr
    3. MyGymEnv::GetObservationSpace()
    4. {
    5. uint32_t nodeNum = 8;
    6. float low = 0.0;
    7. float high = 100.0;
    8. std::vector<uint32_t> shape = {nodeNum,};
    9. std::string dtype = TypeNameGet<uint32_t> ();
    10. Ptr space = CreateObject(low, high, shape, dtype);
    11. NS_LOG_UNCOND ("MyGetObservationSpace: " << space);
    12. return space;
    13. }

    ③创建动作空间(离散)

    1. // 离散空间[0,1,2,3]
    2. Ptr
    3. MyGymEnv::GetActionSpace()
    4. {
    5. uint32_t nodeNum = 4;
    6. Ptr space = CreateObject (nodeNum);
    7. NS_LOG_UNCOND ("MyGetActionSpace: " << space);
    8. return space;
    9. }

    ④执行选定的动作

    1. // action存储到全局变量deci
    2. bool
    3. MyGymEnv::ExecuteActions(Ptr action)
    4. {
    5. Ptr discrete = DynamicCast(action);
    6. NS_LOG_UNCOND ("MyExecuteActions: " << action);
    7. deci = discrete->GetValue();
    8. return true;
    9. }

    ⑤收集网络状态

    1. Ptr
    2. MyGymEnv::GetObservation()
    3. {
    4. uint32_t nodeNum = 8;
    5. std::vector<uint32_t> shape = {nodeNum,};
    6. Ptruint32_t> > box = CreateObjectuint32_t> >(shape);
    7. for (uint32_t i=0;i
    8. uint32_t value = GetValue(i);
    9. box->AddValue(value);
    10. }
    11. }
    12. // 将 box 的值放入全局变量 state
    13. state.clear();
    14. for (uint32_t i = 0; i < nodeNum; i++) {
    15. state.push_back(box->GetValue(i)); // 获取 box 中的值并添加到 state 中
    16. }
    17. NS_LOG_UNCOND ("MyGetObservation: " << box);
    18. return box;
    19. }
    1. // 搜集网络状态的函数
    2. float
    3. MyGymEnv::GetValue(uint32_t index)
    4. {
    5. float value = deci*index;
    6. return value;
    7. }

    ⑥根据状态计算奖励

    1. // 对state进行处理
    2. float
    3. MyGymEnv::GetAverage( std::vector<float> state)
    4. {
    5. uint32_t sum = 0;
    6. for (uint32_t value : state) {
    7. sum += value;
    8. }
    9. return static_cast<double>(sum) / state.size();
    10. }
    11. /*
    12. Define reward function
    13. */
    14. float
    15. MyGymEnv::GetReward()
    16. {
    17. float reward = GetAverage(state);
    18. NS_LOG_UNCOND ("MyGetReward: " << reward);
    19. return reward;
    20. }

    mygym.h(声明全局变量,添加自定义函数到private类)

    extern std::vector<float> state;// 全局变量,用于存储状态
    1. private:
    2. void ScheduleNextStateRead();
    3. float GetValue(uint32_t index);
    4. float GetAverage( std::vector<float> state);

    sim.cc(这一块没有什么要改的,注意总仿真时间和仿真次数的关系,相当于实际的step受到两个地方的参数影响,另一个在创建环境时定义的isGameOver函数中)

    1. double simulationTime = 3; //seconds, 控制仿真次数的位置2
    2. double envStepTime = 0.1; //seconds, ns3gym env step time interval

    test.py(这里主要的改动是使用了ε-贪心策略)

    1. # Choose action
    2. if np.random.rand( ) < epsilon:
    3. action = env.action_space.sample()
    4. print("random")
    5. else:
    6. for action in range(env.action_space.n):#离散动作空间的定义
    7. Q_value = estimate(action,ob_space)
    8. if Q_value > best_value:
    9. best_value = Q_value
    10. best_action = action
    11. action = best_action
    12. print("maximum Q")

    简单模拟了一下Q值的估计(基于action估计reward)

    1. def estimate(action,ob_space):
    2. state = []
    3. for i in range(ob_space.shape[0]):{
    4. state.append(action * i)
    5. }
    6. reward = np.mean(state)
    7. Q_value =reward
    8. return Q_value

    简单运行了一下:
    ns3端:

    python端

    PS.要注意ns3-gym传递的数据类型可能无法直接用len()等函数,要去查看定义的具体数据类型

    这个demo只是先按照我的理解大致实现了各个环节的衔接,但是reward对action的调整作用还没有体现出来,强化学习的精髓还没有融合进去,还有一些细节问题可能没有发现,下一个demo见

  • 相关阅读:
    怎么恢复永久删除的文件?这3个方法很实用!
    【LeetCode454. 四数相加 II】——map型哈希表
    【 OpenGauss源码学习 —— 列存储(CU)(二)】
    Webpack打包时Bable解决浏览器兼容问题
    说说对React中类组件和函数组件的理解?有什么区别?
    领探是什么
    webpack5 使用cache对Eslint和Babel缓存提升打包构建速度
    八股文第八天
    提升微服务稳定性与性能:深入剖析Netflix Hystrix框架
    What are the advantages of pipes over temporary files?
  • 原文地址:https://blog.csdn.net/zoe2222226666/article/details/140417147