动手实践丨基于ModelAtrs使用A2C算法制作登月器着陆小游戏

news2024/11/21 2:37:12
摘要:在本案例中,我们将展示如何基于A2C算法,训练一个LunarLander小游戏。

本文分享自华为云社区《使用A2C算法控制登月器着陆》,作者:HWCloudAI 。

LunarLander是一款控制类的小游戏,也是强化学习中常用的例子。游戏任务为控制登月器着陆,玩家通过操作登月器的主引擎和副引擎,控制登月器降落。登月器平稳着陆会得到相应的奖励积分,如果精准降落在着陆平台上会有额外的奖励积分;相反地如果登月器坠毁会扣除积分。

A2C全称为Advantage Actor-Critic,在本案例中,我们将展示如何基于A2C算法,训练一个LunarLander小游戏。

整体流程:基于gym创建LunarLander环境->构建A2C算法->训练->推理->可视化效果

A2C算法的基本结构

A2C是openAI在实现baseline过程中提出的,是一种结合了Value-based (比如 Q learning) 和 Policy-based (比如 Policy Gradients) 的强化学习算法。

Actor目的是学习策略函数π(θ)以得到尽量高的回报。 Critic目的是对当前策略的值函数进行估计,来评价。

  • Policy Gradients

Policy Gradient算法的整个过程可以看作先通过策略π(θ)让agent与环境进行互动,计算每一步所能得到的奖励,并以此得到一局游戏的奖励作为累积奖励G,然后通过调整策略π,使得G最大化。所以使用了梯度提升的方法来更新网络参数θ,利用更新后的策略再采集数据,再更新,如此循环,达到优化策略的目的。

  • Actor Critic

agent在于环境互动过程中产生的G值本身是一个随机变量,可以通过Q函数去估计G的期望值,来增加稳定性。即Actor-Critic算法在PG策略的更新过程中使用Q函数来代替了G,同时构建了Critic网络来计算Q函数,此时Actor相关参数的梯度为:

而Critic的损失函数使用Q估计和Q实际值差的平方损失来表示:

  • A2C算法

A2C在AC算法的基础上使用状态价值函数给Q值增加了基线V,使反馈可以为正或者为负,因此Actor的策略梯变为:

同时Critic网络的损失函数使用实际状态价值和估计状态价值的平方损失来表示:

LunarLander-v2游戏环境简介

LunarLander-v2,是基于gym和box2d提供的游戏环境。游戏任务为玩家通过操作登月器的喷气主引擎和副引擎来控制登月器降落。

gym:开源强化学习python库,提供了算法和环境交互的标准API,以及符合该API的标准环境集。

box2d:gym提供的一种环境集合

注意事项

  1. 本案例运行环境为 TensorFlow-1.13.1,且需使用 GPU 运行,请查看《ModelAtrs JupyterLab 硬件规格使用指南》了解切换硬件规格的方法;
  2. 如果您是第一次使用 JupyterLab,请查看《ModelAtrs JupyterLab使用指导》了解使用方法;
  3. 如果您在使用 JupyterLab 过程中碰到报错,请参考《ModelAtrs JupyterLab常见问题解决办法》尝试解决问题。

实验步骤

1. 程序初始化

第1步:安装基础依赖

要确保所有依赖都安装成功后,再执行之后的代码。如果某些模块因为网络原因导致安装失败,直接重试一次即可。

!pip install gym
!conda install swig -y
!pip install box2d-py
!pip install gym[box2d]

第2步:导入相关的库

import os
import gym
import numpy as np
import tensorflow as tf
import pandas as pd

2. 参数设置¶

本案例设置的 游戏最大局数 MAX_EPISODE = 100,保存模型的局数 SAVE_EPISODES = 20,以便快速跑通代码。

你也可以调大 MAX_EPISODE 和 SAVE_EPISODES 的值,如1000和100,可以达到较好的训练效果,训练耗时约20分钟。

MAX_EPISODE = 100 # 游戏最大局数
DISPLAY_REWARD_THRESHOLD = 100 # 开启可视化的reward阈值
SAVE_REWARD_THRESHOLD = 100 # 保存模型的reward阈值
MAX_EP_STEPS = 2000 # 每局最大步长
TEST_EPISODE = 10 # 测试局
RENDER = False # 是否启用可视化(耗时)
GAMMA = 0.9 # TD error中reward衰减系数
RUNNING_REWARD_DECAY=0.95 # running reward 衰减系数
LR_A = 0.001 # Actor网络的学习率
LR_C = 0.01 # Critic网络学习率
NUM_UNITS = 20 # FC层神经元个数
SEED = 1 # 种子数,减小随机性
SAVE_EPISODES = 20 # 保存模型的局数
model_dir = './models' # 模型保存路径

3. 游戏环境创建

def create_env():
    env = gym.make('LunarLander-v2')
 # 减少随机性
 env.seed(SEED)
    env = env.unwrapped
 num_features = env.observation_space.shape[0]
 num_actions = env.action_space.n
 return env, num_features, num_actions

4. Actor-Critic网络构建¶

class Actor:
 """
    Actor网络
    Parameters
    ----------
 sess : tensorflow.Session()
 n_features : int
 特征维度
 n_actions : int
 动作空间大小
 lr : float
 学习率大小
    """
 def __init__(self, sess, n_features, n_actions, lr=0.001):
 self.sess = sess
 # 状态空间
 self.s = tf.placeholder(tf.float32, [1, n_features], "state")
 # 动作空间
 self.a = tf.placeholder(tf.int32, None, "action")
 # TD_error
 self.td_error = tf.placeholder(tf.float32, None, "td_error")
 # actor网络为两层全连接层,输出为动作概率
 with tf.variable_scope('Actor'):
            l1 = tf.layers.dense(
                inputs=self.s,
                units=NUM_UNITS,
                activation=tf.nn.relu,
 kernel_initializer=tf.random_normal_initializer(0., .1),
 bias_initializer=tf.constant_initializer(0.1),
                name='l1'
 )
 self.acts_prob = tf.layers.dense(
                inputs=l1,
                units=n_actions,
                activation=tf.nn.softmax,
 kernel_initializer=tf.random_normal_initializer(0., .1),
 bias_initializer=tf.constant_initializer(0.1),
                name='acts_prob'
 )
 with tf.variable_scope('exp_v'):
 log_prob = tf.log(self.acts_prob[0, self.a])
 # 损失函数
 self.exp_v = tf.reduce_mean(log_prob * self.td_error)
 with tf.variable_scope('train'):
 # minimize(-exp_v) = maximize(exp_v)
 self.train_op = tf.train.AdamOptimizer(lr).minimize(-self.exp_v)
 def learn(self, s, a, td):
        s = s[np.newaxis, :]
 feed_dict = {self.s: s, self.a: a, self.td_error: td}
        _, exp_v = self.sess.run([self.train_op, self.exp_v], feed_dict)
 return exp_v
 # 生成动作
 def choose_action(self, s):
        s = s[np.newaxis, :]
        probs = self.sess.run(self.acts_prob, {self.s: s}) 
 return np.random.choice(np.arange(probs.shape[1]), p=probs.ravel())
class Critic:
 """
    Critic网络
    Parameters
    ----------
 sess : tensorflow.Session()
 n_features : int
 特征维度
 lr : float
 学习率大小
    """
 def __init__(self, sess, n_features, lr=0.01):
 self.sess = sess
 # 状态空间
 self.s = tf.placeholder(tf.float32, [1, n_features], "state")
 # value值 
 self.v_ = tf.placeholder(tf.float32, [1, 1], "v_next")
 # 奖励 
 self.r = tf.placeholder(tf.float32, None, 'r')
 # critic网络为两层全连接层,输出为value值
 with tf.variable_scope('Critic'):
            l1 = tf.layers.dense(
                inputs=self.s,
 # number of hidden units
                units=NUM_UNITS,
                activation=tf.nn.relu, 
 kernel_initializer=tf.random_normal_initializer(0., .1), 
 bias_initializer=tf.constant_initializer(0.1), 
                name='l1'
 )
 self.v = tf.layers.dense(
                inputs=l1,
 # output units
                units=1,
                activation=None,
 kernel_initializer=tf.random_normal_initializer(0., .1), 
 bias_initializer=tf.constant_initializer(0.1), 
                name='V'
 )
 with tf.variable_scope('squared_TD_error'):
 self.td_error = self.r + GAMMA * self.v_ - self.v
 # TD_error = (r+gamma*V_next) - V_eval
 self.loss = tf.square(self.td_error)
 with tf.variable_scope('train'):
 self.train_op = tf.train.AdamOptimizer(lr).minimize(self.loss)
 def learn(self, s, r, s_):
        s, s_ = s[np.newaxis, :], s_[np.newaxis, :]
        v_ = self.sess.run(self.v, {self.s: s_})
 td_error, _ = self.sess.run([self.td_error, self.train_op],
 {self.s: s, self.v_: v_, self.r: r})
 return td_error

5. 创建训练函数

def model_train():
    env, num_features, num_actions = create_env()
    render = RENDER
 sess = tf.Session()
    actor = Actor(sess, n_features=num_features, n_actions=num_actions, lr=LR_A)
    critic = Critic(sess, n_features=num_features, lr=LR_C)
 sess.run(tf.global_variables_initializer())
    saver = tf.train.Saver()
 for i_episode in range(MAX_EPISODE+1):
 cur_state = env.reset()
 cur_step = 0
 track_r = []
 while True:
 # notebook暂不支持该游戏的可视化
 # if RENDER:
 # env.render()
            action = actor.choose_action(cur_state)
 next_state, reward, done, info = env.step(action)
 track_r.append(reward)
 # gradient = grad[reward + gamma * V(next_state) - V(cur_state)]
 td_error = critic.learn(cur_state, reward,
 next_state)
 # true_gradient = grad[logPi(cur_state,action) * td_error]
 actor.learn(cur_state, action, td_error) 
 cur_state = next_state
 cur_step += 1
 if done or cur_step >= MAX_EP_STEPS:
 ep_rs_sum = sum(track_r)
 if 'running_reward' not in locals():
 running_reward = ep_rs_sum
 else:
 running_reward = running_reward * RUNNING_REWARD_DECAY + ep_rs_sum * (1-RUNNING_REWARD_DECAY)
 # 判断是否达到可视化阈值
 # if running_reward > DISPLAY_REWARD_THRESHOLD:
 #     render = True
 print("episode:", i_episode, "  reward:", int(running_reward), "  steps:", cur_step)
 break
 if i_episode > 0 and i_episode % SAVE_EPISODES == 0:
 if not os.path.exists(model_dir):
 os.mkdir(model_dir)
 ckpt_path = os.path.join(model_dir, '{}_model.ckpt'.format(i_episode))
 saver.save(sess, ckpt_path)

6. 开始训练

训练一个episode大约需1.2秒

print('MAX_EPISODE:', MAX_EPISODE)
model_train()
# reset graph
tf.reset_default_graph()

7.使用模型推理

由于本游戏内核可视化依赖于OpenGL,需要桌面化操作系统的窗口显示,但当前环境暂不支持弹窗,因此无法可视化,您可将代码下载到本地,取消 env.render() 这行代码的注释,查看可视化效果。

def model_test():
    env, num_features, num_actions = create_env()
 sess = tf.Session()
    actor = Actor(sess, n_features=num_features, n_actions=num_actions, lr=LR_A)
 sess.run(tf.global_variables_initializer())
    saver = tf.train.Saver()
 saver.restore(sess, tf.train.latest_checkpoint(model_dir))
 for i_episode in range(TEST_EPISODE):
 cur_state = env.reset()
 cur_step = 0
 track_r = []
 while True:
 # 可视化
 # env.render()
            action = actor.choose_action(cur_state)
 next_state, reward, done, info = env.step(action)
 track_r.append(reward)
 cur_state = next_state
 cur_step += 1
 if done or cur_step >= MAX_EP_STEPS:
 ep_rs_sum = sum(track_r)
 print("episode:", i_episode, "  reward:", int(ep_rs_sum), "  steps:", cur_step)
 break
model_test()
episode: 0   reward: -31   steps: 196
episode: 1   reward: -99   steps: 308
episode: 2   reward: -273   steps: 533
episode: 3   reward: -5   steps: 232
episode: 4   reward: -178   steps: 353
episode: 5   reward: -174   steps: 222
episode: 6   reward: -309   steps: 377
episode: 7   reward: 24   steps: 293
episode: 8   reward: -121   steps: 423
episode: 9   reward: -194   steps: 286

8.可视化效果

下面的视频为训练1000 episode模型的推理效果,该视频演示了在三个不同的地形情况下,登月器都可以安全着陆

https://modelarts-labs-bj4-v2.obs.cn-north-4.myhuaweicloud.com/course/modelarts/reinforcement_learning/a2c_lunarlander/A2C_lunarlander.mp4

点击关注,第一时间了解华为云新鲜技术~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# dll代码混淆加密

目录 一、需求 二、用法 1.新建C#项目 2.开始加密 3.常见的错误 4.添加加密规则 5.导出加密dll 6.调用加密dll 结束 一、需求 C# 项目生成 dll,在反编译工具下,好比皇帝的新装,dll 内部的代码看的一清二楚,在这里推荐一…

关于Cy5.5 alkyne,Cyanine7 alkyne和1628790-37-3,1998119-13-3两者的区别

外观以及性质: Cy5.5 alkyne和Cy7alkyne 都含有荧光基团,其中氰基7的炔烃衍生物,近红外荧光团,Cy7的类似物,Cyanine5.5 alkyne用于点击化学标记的远红外/近红外染料炔烃,炔烃可以通过铜催化的点击化学与多种…

Ubuntu 22.04 一次及其繁琐的 允许 Traceroute 探测漏洞修复之旅

前言:允许 Traceroute 探测是绿盟漏洞扫描器报出来的一个漏洞,如下图: 我的系统是ubuntu 22.04,但由于是用户提供的虚拟机,会有些定制的部分,具体定制了哪部分就不知道了,直接描述问题。 解决问…

【服务器数据恢复】LINUX误删除、误格式化的数据恢复

Linux误删除及误格式化的数据恢复方案针对的文件系统: 1 、基于EXT2/EXT3/EXT4文件系统 ; 2 、基于Reiserfs文件系统; 3 、基于Xfs文件系统。 Linux误删除及误格式化的数据恢复解决方案: 一、故障检测: 1、检测是否存在…

java学习day56(Spring Boot)Spring Boot

主要内容: 1.Spring Boot基本应用 2.Spring Boot原理深入及源码剖析 3.Spring Boot数据访问 4.Spring Boot视图技术 5.Spring Boot实战演练 6.Spring Boot项目部署 1. SpringBoot基本应用 1.1 约定优于配置Build Anything with Spring Boot:Spring Boot …

【数据结构】堆的实现及排序

目录一、树的相关概念及其特殊二叉树1、数的相关概念2、特殊二叉树二、堆1、堆的实现1.1、堆向下调整算法和向上调整算法的时间复杂度1.2、堆的构建1.3、堆的插入1.4、堆的删除1.5、取堆顶的数据、堆的个数及堆的判空2、堆的排序一、树的相关概念及其特殊二叉树 讲堆之前&#…

透视虎牙斗鱼三季报:游戏直播在各自“求变”中见分晓

游戏直播行业,依然硝烟弥漫。 经历千播大战、熊猫出局的洗礼后,虎牙和斗鱼双方缠斗升级,另有B站和抖音、快手等视频平台来势汹汹,抢夺仅有的市场蛋糕。 而在游戏行业遇冷、政策趋严等因素多重考验下,这场争夺战无疑将…

fsync

由于目前操作系统都具有延迟写(delayed write)功能, fwrite/write并不会直接把数据写到磁盘上, 而是在buffer满时才开始写入到磁盘。 要想把数据写到磁盘上,需要调用fsync函数 open(fd) write(fd) fsync(fd) close(fd) 或者 fopen(fp…

金仓数据库KingbaseES查询计划剖析

目录 1、KingbaseES数据库中的查询生命周期 2、数据设置 3、KingbaseES解释一个查询 4、什么是数据库中的缓冲区和缓存? 5、VERBOSE 命令参数 6、KingbaseES中的 FORMAT 解释 7、总结EXPLAIN使用方式 8、执行计划查看 了解KingbaseES查询计划对于开发人员和…

HarmonyOS应用API手势方法-绑定手势方法

述:为组件绑定不同类型的手势事件,并设置事件的响应方法。 Api:从API Version 7开始支持 一、绑定手势识别: 通过如下属性给组件绑定手势识别,手势识别成功后可以通过事件回调通知组件。 名称参数类型默认值描述ge…

银河麒麟V10+达梦数据库8保姆级安装教程

银河麒麟V10达梦数据库8保姆级安装教程 一、系统和数据库的下载 银河麒麟V10版本: 首页 → 桌面操作系统 → 银河麒麟桌面操作系统V10 → 试用(填写信息) → 点击地址进行下载(X86centos7) #如果不想进行上面的操作,…

Casbin——Java版本(笔记)

文章目录一、Casbin 是什么?二、快速开始2.1 载入配置2.2 如何判断权限2.3 model.conf2.3.1 基本格式2.3.2 SpringBoot下的使用2.3.3 匹配的函数内置函数自定义函数2.3.4 基于角色的访问控制角色的层次区分用户和角色隐式角色权限域内RBAC角色与函数2.3.5 优先级模型…

react事件系统(老版本)

带着问题阅读探索 React 为什么有自己的事件系统?什么是事件合成 ?如何实现的批量更新?事件系统如何模拟冒泡和捕获阶段?如何通过 dom 元素找到与之匹配的fiber?为什么不能用 return false 来阻止事件的默认行为&…

python【PyQt5】的环境搭建和使用(全网最全)其一

什么是pyQT pyqt是一个用于创建GUI应用程序的跨平台工具包,它将python与qt库融为一体。也就是说,pyqt允许使用python语言调用qt库中的API。这样做的最大好处就是在保存了qt高运行效率的同时,大大提高开发效率。因为,使用python语言…

城市路边停车收费系统/停车收费管理系统

摘 要 近年来,随着社会的进步和发展,车辆也在迅速增加,城市交通的瓶颈不仅体现在道路交通的拥挤上,也体现在传统停车场管理效率和安全性大大滞后于社会的需要,给人们的生活带来了极大的不便。尤其,随着汽车…

二、MongoDB简介及基本操作

mongodb是一个基于文档的强大、灵活、易于扩展的通用型数据库。是基于分布式文件存储的数据库。其由 C 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。 mongodb也是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富&…

运动健身买什么耳机好用、最优秀的健身耳机推荐分享

冬天绝对是个减肥的好季节,因为这个季节天气比较冷,我们在运动过程中消耗的热量也就会更多,因此选择一款不错的运动耳机来用坚持就显得尤为重要了。这款运动耳机要能稳定在耳朵上,还要具备防水功能,同时音质上也要有保…

闲人闲谈PS之三十四——项目成本费用控制阈值

**惯例闲话:**最近有小伙伴问闲人有没有PS顾问资源,闲人问了一圈,结果发现都没有档期,不免让闲人有些失落,好心答应帮忙,结果帮不上…但是隐隐约约觉得在几年前说的话被应验了,PS模块一定是个热…

Ubuntu G++ 编译C++源文件

工程项目代码简短的时候使用 G 进行功能模块测试 过程分为: 预处理:展开头文件,去掉主食,条件编译和文件包含编译:检查语法,生成汇编代码汇编:汇编代码转换成机器码链接:Link 主要是…

王学岗音视频开发(一)—————配置NDK开发环境

Android studio准备 Android studio需要下载Android6.0版本(Android SDK Platform 23),最小支持Android6.0 NDK 下载 cmake下载安装 Android studio 代理配置 dl.google.com可能会被屏蔽,首先查下其IP地址。查到IP地址后修改etc/hosts文件。 Andr…