强化学习笔记(1)-找金币小游戏

使用gym实现的第一个强化学习的问题,简单来说就是一个找金币的问题。

该网格世界一共8个状态,其中6和8是死亡区域,状态7是金币区域,机器人的初始位置为网格中的任意一个状态,机器人从初始状态出发寻找金币,机器人每探索一步,进入死亡区域或找到金币本次探索结束。
状态空间 S = { 1, 2, 3, 4, 5, 6, 7, 8},动作空间是 A = {上,下,左, 右}, 找到金币回报为1, 进入死亡区域回报为-1,在状态1和5中切换的时候,回报为0。

这里写图片描述

代码实现部分,实现的框架使用的是gym,关于如何安装和使用的相关基础知识参考网络上的其他资料
import numpy
import random
from gym import spaces
import gym

gym.Env是gym的世界模拟的世界类,要使用gym库来实现相关功能的模拟,必须继承该类实现相关的接口,主要的接口包含reset和step等,在不同的gym版本中函数的名称已经有了一定的变化,如在以前你在实现Env类的子类的时候,需要实现的接口大都在前面有一个下划线_如_step,请注意使用的gym版本不同,相关的实现代码会有一定的变化。

class GridEnv(gym.Env):
    #相关的全局配置
    metadata = {
        'render.modes':['human', 'rgb_array'],
        'video.frames_per_second': 2
    }

    def __init__(self):
        self.states = [1, 2, 3, 4, 5, 6, 7, 8] #状态空间列表
        self.x = [140, 220, 300, 380, 460, 140, 300, 460] #用于绘图的每个状态的位置
        self.y = [250, 250, 250, 250, 250, 150, 150, 150]
        self.terminate_states = dict() #终结状态
        self.terminate_states[6] = 1
        self.terminate_states[7] = 1
        self.terminate_states[8] = 1

        self.actions = ['up', 'down', 'left', 'right']

        self.rewards = dict(); #回报
        self.rewards['1_down'] = -1.0
        self.rewards['3_down'] = 1.0
        self.rewards['5_down'] = -1.0

        self.t = dict(); #状态转移表
        self.t['1_down'] = 6
        self.t['1_right'] = 2
        self.t['2_left'] = 1
        self.t['2_right'] = 3
        self.t['3_down'] = 7
        self.t['3_left'] = 2
        self.t['3_right'] = 4
        self.t['4_left'] = 3
        self.t['4_right'] = 5
        self.t['5_down'] = 8
        self.t['5_left'] = 4

        self.gamma = 0.8 #择扣因子
        self.viewer = None #视图对象
        self.state = None  #初始状态

    def getTerminal(self):
        """
        获取终结状态
        """
        return self.terminate_states

    def getGamma(self):
        """
        获取折扣因子
        """
        return self.gamma

    def getStates(self):
        """
        得到状态空间
        """
        return self.states

    def getActions(self):
        """
        得到行为空间
        """
        return self.actions

    def setState(self, s):
        """
        设置当前状态
        """
        self.state = s

    def seed(self, seed=None):
        self.np_random, seed = random.seeding.np_random(seed)
        return [seed]

    def step(self, action):
        """
        迭代动作函数
        """
        state = self.state
        if state in self.terminate_states:
            #返回的结果参数中(1)下一个状态,(2)回报 (3)是否终结 (4)调试信息
            return state, 0, True, {}
        key = "{state}_{action}".format(state = state, action = action)
        #状态切换
        next_state = self.t[key] if key in self.t else state
        self.state = next_state
        #是否是终结态
        is_terminal = (next_state in self.terminate_states)
        if key not in self.rewards:
            r = 0.0
        else:
            r = self.rewards[key]
        return next_state, r, is_terminal, {}

    def reset(self):
        """
        重置原始状态
        """
        self.state = self.states[random.randint(0, len(self.states) - 1)]
        return self.state

    def render(self, mode='human', close=False):
        """
        渲染场景的函数
        """
        #关闭视图
        if close:
            if self.viewer is not None:
                self.viewer.close()
                self.viewer = None

        #视图的大小
        screen_width = 600
        screen_height = 400

        from gym.envs.classic_control import rendering
        if self.viewer is None:
            self.viewer = rendering.Viewer(screen_width, screen_height)

        #创建网格的世界
        self.line1 = rendering.Line((100,300),(500,300))
        self.line2 = rendering.Line((100, 200), (500, 200))
        self.line3 = rendering.Line((100, 300), (100, 100))
        self.line4 = rendering.Line((180, 300), (180, 100))
        self.line5 = rendering.Line((260, 300), (260, 100))
        self.line6 = rendering.Line((340, 300), (340, 100))
        self.line7 = rendering.Line((420, 300), (420, 100))
        self.line8 = rendering.Line((500, 300), (500, 100))
        self.line9 = rendering.Line((100, 100), (180, 100))
        self.line10 = rendering.Line((260, 100), (340, 100))
        self.line11 = rendering.Line((420, 100), (500, 100))
        #创建第一个骷髅
        self.kulo1 = rendering.make_circle(40) #刚创建时,该圆的圆心坐标原点为(0,0)
        self.circletrans = rendering.Transform(translation=(140,150))
        self.kulo1.add_attr(self.circletrans) #平移
        self.kulo1.set_color(0, 0, 0) #设置颜色

        #创建第2个骷髅
        self.kulo2 = rendering.make_circle(40)
        self.circletrans = rendering.Transform(translation=(460, 150))
        self.kulo2.add_attr(self.circletrans)
        self.kulo2.set_color(0, 0, 0)

        #创建金条
        self.gold = rendering.make_circle(40)
        self.circletrans = rendering.Transform(translation = (300, 150))
        self.gold.add_attr(self.circletrans)
        self.gold.set_color(1, 0.9, 0)

        #创建机器人
        self.robot = rendering.make_circle(30)
        self.robottrans = rendering.Transform()
        self.robot.add_attr(self.robottrans)
        self.robot.set_color(0.8, 0.6, 0.4)

        self.line1.set_color(0, 0, 0)
        self.line2.set_color(0, 0, 0)
        self.line3.set_color(0, 0, 0)
        self.line4.set_color(0, 0, 0)
        self.line5.set_color(0, 0, 0)
        self.line6.set_color(0, 0, 0)
        self.line7.set_color(0, 0, 0)
        self.line8.set_color(0, 0, 0)
        self.line9.set_color(0, 0, 0)
        self.line10.set_color(0, 0, 0)
        self.line11.set_color(0, 0, 0)

        #注意这里添加要绘制的对象的时候,需要使用add_onetime的接口而不是add_geom的接口,不然绘制的对象会有重叠,影响效果和动作的观察。
        self.viewer.add_onetime(self.line1)
        self.viewer.add_onetime(self.line2)
        self.viewer.add_onetime(self.line3)
        self.viewer.add_onetime(self.line4)
        self.viewer.add_onetime(self.line5)
        self.viewer.add_onetime(self.line6)
        self.viewer.add_onetime(self.line7)
        self.viewer.add_onetime(self.line8)
        self.viewer.add_onetime(self.line9)
        self.viewer.add_onetime(self.line10)
        self.viewer.add_onetime(self.line11)
        self.viewer.add_onetime(self.kulo1)
        self.viewer.add_onetime(self.kulo2)
        self.viewer.add_onetime(self.gold)
        self.viewer.add_onetime(self.robot)

        if self.state is None: return None
        self.robottrans.set_translation(self.x[self.state - 1], self.y[self.state - 1])

        return self.viewer.render(return_rgb_array= mode == 'rgb_array')
在编写好自己的gym.Env环境类GridEnv后,需要将环境类注册,在很多博客中都需要对多个__init__的文件进行修改,其实这样操作很麻烦,通过查看gym的源代码,发现直接在自己的当前脚本文件中也是可以注册的,注册的entry_point参数赋值为你的环境类便可以了,如下代码所示,但是如果下面的代码重复运行会有重复注册环境的异常,所以用try except代码块将注册代码包起来,方便脚本的运行。
from gym.envs.registration import register
try:
    register(id = "GridWorld-v2", entry_point=GridEnv, max_episode_steps = 200, reward_threshold=100.0)
except:
    pass
进行模拟的代码
from time import sleep
env = gym.make('GridWorld-v2')
env.reset()
actions = ['up', 'down', 'left', 'right']

#观察env到底是个什么东西的打印信息。
print(isinstance(env, GridEnv))
print(type(env))
print(env.__dict__)
print(isinstance(env.env, GridEnv))

for _ in range(1000):
    env.render()
    observation,reward,done,info = env.step(actions[random.randint(0, 3)])
    print(_)
    if done:
        sleep(0.5)
        env.render()
        env.reset()
        print("reset")
    sleep(0.5)
env.close()
模拟后的效果图

这里写图片描述

后面的博客中会通过相关的强化学习方法来真正训练小机器人
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值