Files
easy-rl/projects/notebooks/1.QLearning.ipynb
T
2022-08-15 22:31:37 +08:00

92 KiB

1、定义算法

强化学习算法的模式都比较固定,一般包括sample(即训练时采样动作),predict(测试时预测动作),update(算法更新)以及保存模型和加载模型等几个方法,其中对于每种算法samle和update的方式是不相同,而其他方法就大同小异。

In [1]:
import numpy as np
import math
import torch
from collections import defaultdict

class QLearning(object):
    def __init__(self,n_states,
                 n_actions,cfg):
        self.n_actions = n_actions 
        self.lr = cfg.lr  # 学习率
        self.gamma = cfg.gamma  
        self.epsilon = cfg.epsilon_start
        self.sample_count = 0  
        self.epsilon_start = cfg.epsilon_start
        self.epsilon_end = cfg.epsilon_end
        self.epsilon_decay = cfg.epsilon_decay
        self.Q_table  = defaultdict(lambda: np.zeros(n_actions)) # 用嵌套字典存放状态->动作->状态-动作值(Q值)的映射,即Q表
    def sample(self, state):
        ''' 采样动作,训练时用
        '''
        self.sample_count += 1
        self.epsilon = self.epsilon_end + (self.epsilon_start - self.epsilon_end) * \
            math.exp(-1. * self.sample_count / self.epsilon_decay) # epsilon是会递减的,这里选择指数递减
        # e-greedy 策略
        if np.random.uniform(0, 1) > self.epsilon:
            action = np.argmax(self.Q_table[str(state)]) # 选择Q(s,a)最大对应的动作
        else:
            action = np.random.choice(self.n_actions) # 随机选择动作
        return action
    def predict(self,state):
        ''' 预测或选择动作,测试时用
        '''
        action = np.argmax(self.Q_table[str(state)])
        return action
    def update(self, state, action, reward, next_state, done):
        Q_predict = self.Q_table[str(state)][action] 
        if done: # 终止状态
            Q_target = reward  
        else:
            Q_target = reward + self.gamma * np.max(self.Q_table[str(next_state)]) 
        self.Q_table[str(state)][action] += self.lr * (Q_target - Q_predict)
    def save(self,path):
        import dill
        torch.save(
            obj=self.Q_table,
            f=path+"Qleaning_model.pkl",
            pickle_module=dill
        )
        print("保存模型成功!")
    def load(self, path):
        import dill
        self.Q_table =torch.load(f=path+'Qleaning_model.pkl',pickle_module=dill)
        print("加载模型成功!")

2、定义训练

强化学习算法的训练方式也比较固定,如下:

for i_ep in range(train_eps): # 遍历每个回合
    state = env.reset()  # 重置环境,即开始新的回合
    while True: # 对于一些比较复杂的游戏可以设置每回合最大的步长,例如while ep_step<100,就是每回合最大步长为100。
        action = agent.sample(state)  # 根据算法采样一个动作
        next_state, reward, done, _ = env.step(action)  # 与环境进行一次动作交互
        agent.memory.push(state, action, reward, next_state, done) # 记录memory
        agent.update(state, action, reward, next_state, done)  # 算法更新
        state = next_state  # 更新状态
        if done:
            break

首先对于每个回合,回合开始时环境需要重置,好比我们每次开一把游戏需要从头再来一样。我们可以设置智能体在每回合数的最大步长,尤其是对于比较复杂的游戏,这样做的好处之一就是帮助智能体在训练中快速收敛,比如我们先验地知道最优解的大概步数,那么理论上智能体收敛时也应该是这个步数附近,设置最大步数可以方便智能体接近这个最优解。在每个回合中,智能体首先需要采样(sample),或者说采用探索策略例如常见的$\varepsilon$-greedy策略或者UCB探索策略等等。采样的过程是将当前的状态state作为输入,智能体采样输出动作action。然后环境根据采样出来的动作反馈出下一个状态以及相应的reward等信息。接下来对于具有memory的智能体例如包含replay memory的DQN来说,需要将相应的transition(记住这个词,中文不好翻译,通常是状态、动作、奖励等信息)。紧接着就是智能体更新,对于深度强化学习此时一般从memory中随机采样一些transition进行更新,对于Q learning一般是采样上一次的transition。更新公式是比较关键的部分,但是也很通用,一般基于值的算法更新公式都是一个套路如下:


y_{j}= \begin{cases}r_{j} & \text { for terminal } s_{t+1} \\ r_{j}+\gamma \max _{a^{\prime}} Q\left(s_{t+1}, a^{\prime} ; \theta\right) & \text { for non-terminal } s_{t+1}\end{cases}

智能体更新完之后,通常需要更新状态,即state = next_state,然后会检查是否完成了这一回合的游戏,即done==True,注意完成并不代表这回合成功,也有可能是失败的太离谱,等同学们有了自定义强化学习环境的经验就知道了(等你长大就知道了XD)。 如果需要记录奖励、损失等等的话可以再加上,如下方代码,实际项目中更多地使用tensorboard来记录相应的数据,甚至于笔者就在这些教学代码中使用过,但是看起来有些繁琐,容易给大家增加不必要的学习难度,因此学有余力以及需要在项目研究中做强化学习的可以去看看,也很简单。 此外稍微复杂一些的强化学习不是一次性写完代码就能收敛的,这时需要我们做一个调参侠。为了检查我们参数调得好不好,可以在终端print出奖励、损失以及epsilon等随着回合数的变化,这点说明一下强化学习的训练过程一般都是先探索然后收敛的,官方的话就是权衡exploration and exploitation。e-greedy策略的做法就是前期探索,然后逐渐减小探索率至慢慢收敛,也就是这个epsilon。这个值越大比如0.9就说明智能体90%的概率在随机探索,通常情况下会设置三个值,epsilon_start、epsilon_end以及epsilon_decay,即初始值、终止值和衰减率,其中初始值一般是0.95不变,终止值是0.01,也就是说即使在收敛阶段也让智能体保持很小概率的探索,这样做的原因就是智能体已经学出了一个不错的策略,但是保不齐还有更好的策略,好比我们知道要出人头地学历高比较重要,但是“人还是要有梦想的,万一实现了呢”,总是存在意外的可能,对吧。回归正题,比较关键的是epsilon_decay这个衰减率,这个epsilon衰减太快了学来的策略往往过拟合,好比一条只能选择一朵花的花道上,你早早选择了一朵看起来还可以的花,却错过了后面更多的好花。但是衰减的太慢会影响收敛的速度,好比你走过了花道的尽头也还没选出一朵花来,相比前者不如更甚。当然强化学习的调参相比于深度学习只能说是有过之无不及,比较复杂,不止epsilon这一个,这就需要同学们的耐心学习了。 强化学习测试的代码跟训练基本上是一样的,因此我放到同一个代码段里。相比于训练代码,测试代码主要有以下几点不同:1、测试模型的过程是不需要更新的,这个是不言而喻的;2、测试代码不需要采样(sample)动作,相比之代替的是预测(sample)动作,其区别就是采样动作时可能会使用各种策略例如$\varepsilon$-greedy策略,而预测动作不需要,只需要根据训练时学习好的Q表或者网络模型代入状态得到动作即可;3、测试过程终端一般只需要看奖励,不需要看epislon等,反正它在测试中也是无意义的。

In [2]:
def train(cfg,env,agent):
    print('开始训练!')
    print(f'环境:{cfg.env_name}, 算法:{cfg.algo_name}, 设备:{cfg.device}')
    rewards = []  # 记录奖励
    for i_ep in range(cfg.train_eps):
        ep_reward = 0  # 记录每个回合的奖励
        state = env.reset()  # 重置环境,即开始新的回合
        while True:
            action = agent.sample(state)  # 根据算法采样一个动作
            next_state, reward, done, _ = env.step(action)  # 与环境进行一次动作交互
            agent.update(state, action, reward, next_state, done)  # Q学习算法更新
            state = next_state  # 更新状态
            ep_reward += reward
            if done:
                break
        rewards.append(ep_reward)
        print(f"回合:{i_ep+1}/{cfg.train_eps},奖励:{ep_reward:.1f},Epsilon:{agent.epsilon}")
    print('完成训练!')
    return {"rewards":rewards}
def test(cfg,env,agent):
    print('开始测试!')
    print(f'环境:{cfg.env_name}, 算法:{cfg.algo_name}, 设备:{cfg.device}')
    rewards = []  # 记录所有回合的奖励
    for i_ep in range(cfg.test_eps):
        ep_reward = 0  # 记录每个episode的reward
        state = env.reset()  # 重置环境, 重新开一局(即开始新的一个回合)
        while True:
            action = agent.predict(state)  # 根据算法选择一个动作
            next_state, reward, done, _ = env.step(action)  # 与环境进行一个交互
            state = next_state  # 更新状态
            ep_reward += reward
            if done:
                break
        rewards.append(ep_reward)
        print(f"回合数:{i_ep+1}/{cfg.test_eps}, 奖励:{ep_reward:.1f}")
    print('完成测试!')
    return {"rewards":rewards}

3、定义环境

OpenAI Gym中其实集成了很多强化学习环境,足够大家学习了,但是在做强化学习的应用中免不了要自己创建环境,比如在本项目中其实不太好找到Qlearning能学出来的环境,Qlearning实在是太弱了,需要足够简单的环境才行,因此本项目写了一个环境,大家感兴趣的话可以看一下,一般环境接口最关键的部分即使reset和step。

In [3]:
import gym
import turtle
import numpy as np

# turtle tutorial : https://docs.python.org/3.3/library/turtle.html

def GridWorld(gridmap=None, is_slippery=False):
    if gridmap is None:
        gridmap = ['SFFF', 'FHFH', 'FFFH', 'HFFG']
    env = gym.make("FrozenLake-v0", desc=gridmap, is_slippery=False)
    env = FrozenLakeWapper(env)
    return env


class FrozenLakeWapper(gym.Wrapper):
    def __init__(self, env):
        gym.Wrapper.__init__(self, env)
        self.max_y = env.desc.shape[0]
        self.max_x = env.desc.shape[1]
        self.t = None
        self.unit = 50

    def draw_box(self, x, y, fillcolor='', line_color='gray'):
        self.t.up()
        self.t.goto(x * self.unit, y * self.unit)
        self.t.color(line_color)
        self.t.fillcolor(fillcolor)
        self.t.setheading(90)
        self.t.down()
        self.t.begin_fill()
        for _ in range(4):
            self.t.forward(self.unit)
            self.t.right(90)
        self.t.end_fill()

    def move_player(self, x, y):
        self.t.up()
        self.t.setheading(90)
        self.t.fillcolor('red')
        self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit)

    def render(self):
        if self.t == None:
            self.t = turtle.Turtle()
            self.wn = turtle.Screen()
            self.wn.setup(self.unit * self.max_x + 100,
                          self.unit * self.max_y + 100)
            self.wn.setworldcoordinates(0, 0, self.unit * self.max_x,
                                        self.unit * self.max_y)
            self.t.shape('circle')
            self.t.width(2)
            self.t.speed(0)
            self.t.color('gray')
            for i in range(self.desc.shape[0]):
                for j in range(self.desc.shape[1]):
                    x = j
                    y = self.max_y - 1 - i
                    if self.desc[i][j] == b'S':  # Start
                        self.draw_box(x, y, 'white')
                    elif self.desc[i][j] == b'F':  # Frozen ice
                        self.draw_box(x, y, 'white')
                    elif self.desc[i][j] == b'G':  # Goal
                        self.draw_box(x, y, 'yellow')
                    elif self.desc[i][j] == b'H':  # Hole
                        self.draw_box(x, y, 'black')
                    else:
                        self.draw_box(x, y, 'white')
            self.t.shape('turtle')

        x_pos = self.s % self.max_x
        y_pos = self.max_y - 1 - int(self.s / self.max_x)
        self.move_player(x_pos, y_pos)


class CliffWalkingWapper(gym.Wrapper):
    def __init__(self, env):
        gym.Wrapper.__init__(self, env)
        self.t = None
        self.unit = 50
        self.max_x = 12
        self.max_y = 4

    def draw_x_line(self, y, x0, x1, color='gray'):
        assert x1 > x0
        self.t.color(color)
        self.t.setheading(0)
        self.t.up()
        self.t.goto(x0, y)
        self.t.down()
        self.t.forward(x1 - x0)

    def draw_y_line(self, x, y0, y1, color='gray'):
        assert y1 > y0
        self.t.color(color)
        self.t.setheading(90)
        self.t.up()
        self.t.goto(x, y0)
        self.t.down()
        self.t.forward(y1 - y0)

    def draw_box(self, x, y, fillcolor='', line_color='gray'):
        self.t.up()
        self.t.goto(x * self.unit, y * self.unit)
        self.t.color(line_color)
        self.t.fillcolor(fillcolor)
        self.t.setheading(90)
        self.t.down()
        self.t.begin_fill()
        for i in range(4):
            self.t.forward(self.unit)
            self.t.right(90)
        self.t.end_fill()

    def move_player(self, x, y):
        self.t.up()
        self.t.setheading(90)
        self.t.fillcolor('red')
        self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit)

    def render(self):
        if self.t == None:
            self.t = turtle.Turtle()
            self.wn = turtle.Screen()
            self.wn.setup(self.unit * self.max_x + 100,
                          self.unit * self.max_y + 100)
            self.wn.setworldcoordinates(0, 0, self.unit * self.max_x,
                                        self.unit * self.max_y)
            self.t.shape('circle')
            self.t.width(2)
            self.t.speed(0)
            self.t.color('gray')
            for _ in range(2):
                self.t.forward(self.max_x * self.unit)
                self.t.left(90)
                self.t.forward(self.max_y * self.unit)
                self.t.left(90)
            for i in range(1, self.max_y):
                self.draw_x_line(
                    y=i * self.unit, x0=0, x1=self.max_x * self.unit)
            for i in range(1, self.max_x):
                self.draw_y_line(
                    x=i * self.unit, y0=0, y1=self.max_y * self.unit)

            for i in range(1, self.max_x - 1):
                self.draw_box(i, 0, 'black')
            self.draw_box(self.max_x - 1, 0, 'yellow')
            self.t.shape('turtle')

        x_pos = self.s % self.max_x
        y_pos = self.max_y - 1 - int(self.s / self.max_x)
        self.move_player(x_pos, y_pos)
In [4]:
import gym
def env_agent_config(cfg,seed=1):
    '''创建环境和智能体
    Args:
        cfg ([type]): [description]
        seed (int, optional): 随机种子. Defaults to 1.
    Returns:
        env [type]: 环境
        agent : 智能体
    '''    
    env = gym.make(cfg.env_name)  
    env = CliffWalkingWapper(env)
    env.seed(seed) # 设置随机种子
    n_states = env.observation_space.n # 状态维度
    n_actions = env.action_space.n # 动作维度
    agent = QLearning(n_states,n_actions,cfg)
    return env,agent

4、设置参数

到这里所有qlearning模块就算完成了,下面需要设置一些参数,方便大家“炼丹”,其中默认的是笔者已经调好的~。另外为了定义了一个画图函数,用来描述奖励的变化。

In [5]:
import datetime
import argparse
import matplotlib.pyplot as plt
import seaborn as sns
def get_args():
    """ 
    """
    curr_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")  # 获取当前时间
    parser = argparse.ArgumentParser(description="hyperparameters")      
    parser.add_argument('--algo_name',default='Q-learning',type=str,help="name of algorithm")
    parser.add_argument('--env_name',default='CliffWalking-v0',type=str,help="name of environment")
    parser.add_argument('--train_eps',default=400,type=int,help="episodes of training") # 训练的回合数
    parser.add_argument('--test_eps',default=20,type=int,help="episodes of testing") # 测试的回合数
    parser.add_argument('--gamma',default=0.90,type=float,help="discounted factor") # 折扣因子
    parser.add_argument('--epsilon_start',default=0.95,type=float,help="initial value of epsilon") #  e-greedy策略中初始epsilon
    parser.add_argument('--epsilon_end',default=0.01,type=float,help="final value of epsilon") # e-greedy策略中的终止epsilon
    parser.add_argument('--epsilon_decay',default=300,type=int,help="decay rate of epsilon") # e-greedy策略中epsilon的衰减率
    parser.add_argument('--lr',default=0.1,type=float,help="learning rate")
    parser.add_argument('--device',default='cpu',type=str,help="cpu or cuda")                
    args = parser.parse_args([])                          
    return args
curr_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") # 获取当前时间

def smooth(data, weight=0.9):  
    '''用于平滑曲线,类似于Tensorboard中的smooth

    Args:
        data (List):输入数据
        weight (Float): 平滑权重,处于0-1之间,数值越高说明越平滑,一般取0.9

    Returns:
        smoothed (List): 平滑后的数据
    '''
    last = data[0]  # First value in the plot (first timestep)
    smoothed = list()
    for point in data:
        smoothed_val = last * weight + (1 - weight) * point  # 计算平滑值
        smoothed.append(smoothed_val)                    
        last = smoothed_val                                
    return smoothed

def plot_rewards(rewards,cfg, tag='train'):
    sns.set()
    plt.figure()  # 创建一个图形实例,方便同时多画几个图
    plt.title("learning curve on {} of {} for {}".format(
        cfg.device, cfg.algo_name, cfg.env_name))
    plt.xlabel('epsiodes')
    plt.plot(rewards, label='rewards')
    plt.plot(smooth(rewards), label='smoothed')
    plt.legend()
    plt.show()

5、我准备好了!

到现在我们真的可以像海绵宝宝那样大声说出来“我准备好了!“,跟着注释来看下效果吧~。

In [6]:
# 获取参数
cfg = get_args() 
# 训练
env, agent = env_agent_config(cfg)
res_dic = train(cfg, env, agent)
 
plot_rewards(res_dic['rewards'], cfg, tag="train")  
# 测试
res_dic = test(cfg, env, agent)
plot_rewards(res_dic['rewards'], cfg, tag="test")  # 画出结果
开始训练!
环境:CliffWalking-v0, 算法:Q-learning, 设备:cpu
回合:1/400,奖励:-1668.0,Epsilon:0.3771901652370099
回合:2/400,奖励:-2328.0,Epsilon:0.03210668110464856
回合:3/400,奖励:-152.0,Epsilon:0.02331928797825333
回合:4/400,奖励:-296.0,Epsilon:0.014965661602689185
回合:5/400,奖励:-168.0,Epsilon:0.012836430915462094
回合:6/400,奖励:-149.0,Epsilon:0.011726126490407173
回合:7/400,奖励:-274.0,Epsilon:0.010963239247691907
回合:8/400,奖励:-127.0,Epsilon:0.010630787152305933
回合:9/400,奖励:-356.0,Epsilon:0.010267816440118822
回合:10/400,奖励:-105.0,Epsilon:0.0101887270555826
回合:11/400,奖励:-162.0,Epsilon:0.01010998036181645
回合:12/400,奖励:-124.0,Epsilon:0.010072745604688937
回合:13/400,奖励:-125.0,Epsilon:0.010047956858279448
回合:14/400,奖励:-69.0,Epsilon:0.010038103335373512
回合:15/400,奖励:-146.0,Epsilon:0.010023421049147612
回合:16/400,奖励:-99.0,Epsilon:0.010016837948094095
回合:17/400,奖励:-102.0,Epsilon:0.010011984751749595
回合:18/400,奖励:-114.0,Epsilon:0.010008195909220538
回合:19/400,奖励:-95.0,Epsilon:0.010005971322860786
回合:20/400,奖励:-50.0,Epsilon:0.010005054615675078
回合:21/400,奖励:-179.0,Epsilon:0.010002783294099886
回合:22/400,奖励:-51.0,Epsilon:0.010002348167306314
回合:23/400,奖励:-53.0,Epsilon:0.010001967902958245
回合:24/400,奖励:-126.0,Epsilon:0.01000129300438042
回合:25/400,奖励:-105.0,Epsilon:0.010000911164786836
回合:26/400,奖励:-55.0,Epsilon:0.010000758536131584
回合:27/400,奖励:-112.0,Epsilon:0.010000522203364875
回合:28/400,奖励:-81.0,Epsilon:0.01000039863934062
回合:29/400,奖励:-187.0,Epsilon:0.010000297294659517
回合:30/400,奖励:-176.0,Epsilon:0.01000022999489198
回合:31/400,奖励:-71.0,Epsilon:0.010000181524464132
回合:32/400,奖励:-77.0,Epsilon:0.010000140432053464
回合:33/400,奖励:-82.0,Epsilon:0.010000106846201706
回合:34/400,奖励:-95.0,Epsilon:0.010000077845318887
回合:35/400,奖励:-53.0,Epsilon:0.010000065238977184
回合:36/400,奖励:-30.0,Epsilon:0.010000059030667672
回合:37/400,奖励:-122.0,Epsilon:0.010000039306520976
回合:38/400,奖励:-37.0,Epsilon:0.010000034745744355
回合:39/400,奖励:-100.0,Epsilon:0.01000002489641374
回合:40/400,奖励:-201.0,Epsilon:0.010000017720528442
回合:41/400,奖励:-62.0,Epsilon:0.010000014411941012
回合:42/400,奖励:-61.0,Epsilon:0.010000011760233133
回合:43/400,奖励:-57.0,Epsilon:0.010000009725232207
回合:44/400,奖励:-73.0,Epsilon:0.0100000076246806
回合:45/400,奖励:-39.0,Epsilon:0.010000006695197199
回合:46/400,奖励:-71.0,Epsilon:0.010000005284213373
回合:47/400,奖励:-77.0,Epsilon:0.010000004088005098
回合:48/400,奖励:-53.0,Epsilon:0.010000003425989836
回合:49/400,奖励:-88.0,Epsilon:0.010000002555012459
回合:50/400,奖励:-65.0,Epsilon:0.01000000205729175
回合:51/400,奖励:-41.0,Epsilon:0.010000001794495218
回合:52/400,奖励:-67.0,Epsilon:0.010000001435323749
回合:53/400,奖励:-38.0,Epsilon:0.010000001264559407
回合:54/400,奖励:-50.0,Epsilon:0.010000001070426428
回合:55/400,奖励:-35.0,Epsilon:0.010000000952552966
回合:56/400,奖励:-74.0,Epsilon:0.010000000744325952
回合:57/400,奖励:-75.0,Epsilon:0.010000000579681634
回合:58/400,奖励:-31.0,Epsilon:0.010000000522772152
回合:59/400,奖励:-38.0,Epsilon:0.010000000460576537
回合:60/400,奖励:-51.0,Epsilon:0.01000000038857222
回合:61/400,奖励:-64.0,Epsilon:0.010000000313922366
回合:62/400,奖励:-78.0,Epsilon:0.010000000242050338
回合:63/400,奖励:-41.0,Epsilon:0.010000000211131054
回合:64/400,奖励:-62.0,Epsilon:0.010000000171710922
回合:65/400,奖励:-58.0,Epsilon:0.010000000141525377
回合:66/400,奖励:-34.0,Epsilon:0.010000000126361357
回合:67/400,奖励:-52.0,Epsilon:0.010000000106251867
回合:68/400,奖励:-28.0,Epsilon:0.010000000096783744
回合:69/400,奖励:-57.0,Epsilon:0.010000000080036202
回合:70/400,奖励:-39.0,Epsilon:0.010000000070279423
回合:71/400,奖励:-55.0,Epsilon:0.01000000005850696
回合:72/400,奖励:-33.0,Epsilon:0.010000000052412531
回合:73/400,奖励:-62.0,Epsilon:0.010000000042626625
回合:74/400,奖励:-56.0,Epsilon:0.010000000035368174
回合:75/400,奖励:-34.0,Epsilon:0.01000000003157858
回合:76/400,奖励:-37.0,Epsilon:0.010000000027914485
回合:77/400,奖励:-149.0,Epsilon:0.0100000000236291
回合:78/400,奖励:-46.0,Epsilon:0.010000000020270076
回合:79/400,奖励:-28.0,Epsilon:0.010000000018463805
回合:80/400,奖励:-37.0,Epsilon:0.010000000016321432
回合:81/400,奖励:-64.0,Epsilon:0.01000000001318587
回合:82/400,奖励:-52.0,Epsilon:0.010000000011087433
回合:83/400,奖励:-22.0,Epsilon:0.010000000010303453
回合:84/400,奖励:-32.0,Epsilon:0.010000000009261004
回合:85/400,奖励:-74.0,Epsilon:0.010000000007236559
回合:86/400,奖励:-33.0,Epsilon:0.010000000006482756
回合:87/400,奖励:-39.0,Epsilon:0.010000000005692478
回合:88/400,奖励:-40.0,Epsilon:0.010000000004981906
回合:89/400,奖励:-33.0,Epsilon:0.010000000004462961
回合:90/400,奖励:-47.0,Epsilon:0.010000000003815783
回合:91/400,奖励:-45.0,Epsilon:0.010000000003284274
回合:92/400,奖励:-28.0,Epsilon:0.010000000002991612
回合:93/400,奖励:-45.0,Epsilon:0.010000000002574904
回合:94/400,奖励:-56.0,Epsilon:0.010000000002136451
回合:95/400,奖励:-31.0,Epsilon:0.010000000001926707
回合:96/400,奖励:-38.0,Epsilon:0.010000000001697481
回合:97/400,奖励:-50.0,Epsilon:0.010000000001436887
回合:98/400,奖励:-41.0,Epsilon:0.010000000001253341
回合:99/400,奖励:-41.0,Epsilon:0.01000000000109324
回合:100/400,奖励:-13.0,Epsilon:0.010000000001046878
回合:101/400,奖励:-45.0,Epsilon:0.010000000000901057
回合:102/400,奖励:-19.0,Epsilon:0.01000000000084576
回合:103/400,奖励:-44.0,Epsilon:0.010000000000730383
回合:104/400,奖励:-23.0,Epsilon:0.010000000000676478
回合:105/400,奖励:-40.0,Epsilon:0.010000000000592037
回合:106/400,奖励:-52.0,Epsilon:0.010000000000497817
回合:107/400,奖励:-38.0,Epsilon:0.010000000000438592
回合:108/400,奖励:-24.0,Epsilon:0.01000000000040487
回合:109/400,奖励:-32.0,Epsilon:0.010000000000363909
回合:110/400,奖励:-38.0,Epsilon:0.010000000000320614
回合:111/400,奖励:-52.0,Epsilon:0.01000000000026959
回合:112/400,奖励:-22.0,Epsilon:0.010000000000250527
回合:113/400,奖励:-38.0,Epsilon:0.010000000000220721
回合:114/400,奖励:-33.0,Epsilon:0.01000000000019773
回合:115/400,奖励:-29.0,Epsilon:0.010000000000179511
回合:116/400,奖励:-56.0,Epsilon:0.010000000000148944
回合:117/400,奖励:-20.0,Epsilon:0.010000000000139338
回合:118/400,奖励:-31.0,Epsilon:0.010000000000125658
回合:119/400,奖励:-33.0,Epsilon:0.01000000000011257
回合:120/400,奖励:-39.0,Epsilon:0.010000000000098846
回合:121/400,奖励:-26.0,Epsilon:0.010000000000090641
回合:122/400,奖励:-31.0,Epsilon:0.010000000000081742
回合:123/400,奖励:-40.0,Epsilon:0.010000000000071538
回合:124/400,奖励:-33.0,Epsilon:0.010000000000064086
回合:125/400,奖励:-46.0,Epsilon:0.010000000000054977
回合:126/400,奖励:-28.0,Epsilon:0.010000000000050078
回合:127/400,奖励:-23.0,Epsilon:0.010000000000046382
回合:128/400,奖励:-30.0,Epsilon:0.010000000000041968
回合:129/400,奖励:-24.0,Epsilon:0.010000000000038742
回合:130/400,奖励:-36.0,Epsilon:0.01000000000003436
回合:131/400,奖励:-28.0,Epsilon:0.010000000000031298
回合:132/400,奖励:-28.0,Epsilon:0.01000000000002851
回合:133/400,奖励:-35.0,Epsilon:0.01000000000002537
回合:134/400,奖励:-27.0,Epsilon:0.010000000000023187
回合:135/400,奖励:-30.0,Epsilon:0.01000000000002098
回合:136/400,奖励:-35.0,Epsilon:0.01000000000001867
回合:137/400,奖励:-31.0,Epsilon:0.010000000000016837
回合:138/400,奖励:-27.0,Epsilon:0.010000000000015387
回合:139/400,奖励:-48.0,Epsilon:0.010000000000013113
回合:140/400,奖励:-23.0,Epsilon:0.010000000000012145
回合:141/400,奖励:-29.0,Epsilon:0.010000000000011026
回合:142/400,奖励:-21.0,Epsilon:0.01000000000001028
回合:143/400,奖励:-22.0,Epsilon:0.010000000000009553
回合:144/400,奖励:-42.0,Epsilon:0.010000000000008306
回合:145/400,奖励:-21.0,Epsilon:0.010000000000007744
回合:146/400,奖励:-141.0,Epsilon:0.010000000000006733
回合:147/400,奖励:-43.0,Epsilon:0.010000000000005834
回合:148/400,奖励:-44.0,Epsilon:0.010000000000005038
回合:149/400,奖励:-18.0,Epsilon:0.010000000000004745
回合:150/400,奖励:-23.0,Epsilon:0.010000000000004394
回合:151/400,奖励:-24.0,Epsilon:0.010000000000004056
回合:152/400,奖励:-30.0,Epsilon:0.010000000000003671
回合:153/400,奖励:-27.0,Epsilon:0.010000000000003355
回合:154/400,奖励:-15.0,Epsilon:0.01000000000000319
回合:155/400,奖励:-19.0,Epsilon:0.010000000000002994
回合:156/400,奖励:-50.0,Epsilon:0.010000000000002535
回合:157/400,奖励:-22.0,Epsilon:0.010000000000002356
回合:158/400,奖励:-28.0,Epsilon:0.010000000000002146
回合:159/400,奖励:-27.0,Epsilon:0.010000000000001962
回合:160/400,奖励:-13.0,Epsilon:0.010000000000001879
回合:161/400,奖励:-33.0,Epsilon:0.010000000000001683
回合:162/400,奖励:-24.0,Epsilon:0.010000000000001553
回合:163/400,奖励:-30.0,Epsilon:0.010000000000001405
回合:164/400,奖励:-19.0,Epsilon:0.010000000000001319
回合:165/400,奖励:-22.0,Epsilon:0.010000000000001227
回合:166/400,奖励:-32.0,Epsilon:0.010000000000001102
回合:167/400,奖励:-35.0,Epsilon:0.01000000000000098
回合:168/400,奖励:-32.0,Epsilon:0.010000000000000881
回合:169/400,奖励:-21.0,Epsilon:0.010000000000000822
回合:170/400,奖励:-27.0,Epsilon:0.010000000000000751
回合:171/400,奖励:-22.0,Epsilon:0.010000000000000698
回合:172/400,奖励:-22.0,Epsilon:0.010000000000000649
回合:173/400,奖励:-34.0,Epsilon:0.01000000000000058
回合:174/400,奖励:-22.0,Epsilon:0.010000000000000538
回合:175/400,奖励:-27.0,Epsilon:0.010000000000000491
回合:176/400,奖励:-13.0,Epsilon:0.01000000000000047
回合:177/400,奖励:-29.0,Epsilon:0.010000000000000427
回合:178/400,奖励:-20.0,Epsilon:0.010000000000000401
回合:179/400,奖励:-22.0,Epsilon:0.010000000000000371
回合:180/400,奖励:-33.0,Epsilon:0.010000000000000333
回合:181/400,奖励:-20.0,Epsilon:0.010000000000000312
回合:182/400,奖励:-26.0,Epsilon:0.010000000000000286
回合:183/400,奖励:-22.0,Epsilon:0.010000000000000266
回合:184/400,奖励:-29.0,Epsilon:0.010000000000000241
回合:185/400,奖励:-25.0,Epsilon:0.010000000000000222
回合:186/400,奖励:-16.0,Epsilon:0.01000000000000021
回合:187/400,奖励:-28.0,Epsilon:0.010000000000000191
回合:188/400,奖励:-23.0,Epsilon:0.010000000000000177
回合:189/400,奖励:-31.0,Epsilon:0.01000000000000016
回合:190/400,奖励:-17.0,Epsilon:0.010000000000000151
回合:191/400,奖励:-22.0,Epsilon:0.01000000000000014
回合:192/400,奖励:-18.0,Epsilon:0.010000000000000132
回合:193/400,奖励:-34.0,Epsilon:0.010000000000000118
回合:194/400,奖励:-32.0,Epsilon:0.010000000000000106
回合:195/400,奖励:-14.0,Epsilon:0.0100000000000001
回合:196/400,奖励:-23.0,Epsilon:0.010000000000000094
回合:197/400,奖励:-23.0,Epsilon:0.010000000000000087
回合:198/400,奖励:-28.0,Epsilon:0.01000000000000008
回合:199/400,奖励:-24.0,Epsilon:0.010000000000000073
回合:200/400,奖励:-21.0,Epsilon:0.010000000000000068
回合:201/400,奖励:-15.0,Epsilon:0.010000000000000064
回合:202/400,奖励:-16.0,Epsilon:0.010000000000000061
回合:203/400,奖励:-22.0,Epsilon:0.010000000000000057
回合:204/400,奖励:-28.0,Epsilon:0.010000000000000052
回合:205/400,奖励:-25.0,Epsilon:0.010000000000000049
回合:206/400,奖励:-16.0,Epsilon:0.010000000000000045
回合:207/400,奖励:-13.0,Epsilon:0.010000000000000044
回合:208/400,奖励:-31.0,Epsilon:0.01000000000000004
回合:209/400,奖励:-25.0,Epsilon:0.010000000000000037
回合:210/400,奖励:-21.0,Epsilon:0.010000000000000033
回合:211/400,奖励:-26.0,Epsilon:0.010000000000000031
回合:212/400,奖励:-13.0,Epsilon:0.01000000000000003
回合:213/400,奖励:-15.0,Epsilon:0.010000000000000028
回合:214/400,奖励:-23.0,Epsilon:0.010000000000000026
回合:215/400,奖励:-23.0,Epsilon:0.010000000000000024
回合:216/400,奖励:-13.0,Epsilon:0.010000000000000023
回合:217/400,奖励:-21.0,Epsilon:0.010000000000000021
回合:218/400,奖励:-28.0,Epsilon:0.01000000000000002
回合:219/400,奖励:-24.0,Epsilon:0.010000000000000018
回合:220/400,奖励:-20.0,Epsilon:0.010000000000000018
回合:221/400,奖励:-13.0,Epsilon:0.010000000000000016
回合:222/400,奖励:-15.0,Epsilon:0.010000000000000016
回合:223/400,奖励:-27.0,Epsilon:0.010000000000000014
回合:224/400,奖励:-18.0,Epsilon:0.010000000000000014
回合:225/400,奖励:-20.0,Epsilon:0.010000000000000012
回合:226/400,奖励:-27.0,Epsilon:0.010000000000000012
回合:227/400,奖励:-18.0,Epsilon:0.01000000000000001
回合:228/400,奖励:-15.0,Epsilon:0.01000000000000001
回合:229/400,奖励:-19.0,Epsilon:0.010000000000000009
回合:230/400,奖励:-20.0,Epsilon:0.010000000000000009
回合:231/400,奖励:-13.0,Epsilon:0.010000000000000009
回合:232/400,奖励:-28.0,Epsilon:0.010000000000000007
回合:233/400,奖励:-38.0,Epsilon:0.010000000000000007
回合:234/400,奖励:-17.0,Epsilon:0.010000000000000007
回合:235/400,奖励:-22.0,Epsilon:0.010000000000000005
回合:236/400,奖励:-13.0,Epsilon:0.010000000000000005
回合:237/400,奖励:-20.0,Epsilon:0.010000000000000005
回合:238/400,奖励:-18.0,Epsilon:0.010000000000000005
回合:239/400,奖励:-14.0,Epsilon:0.010000000000000005
回合:240/400,奖励:-13.0,Epsilon:0.010000000000000005
回合:241/400,奖励:-28.0,Epsilon:0.010000000000000004
回合:242/400,奖励:-13.0,Epsilon:0.010000000000000004
回合:243/400,奖励:-23.0,Epsilon:0.010000000000000004
回合:244/400,奖励:-17.0,Epsilon:0.010000000000000004
回合:245/400,奖励:-14.0,Epsilon:0.010000000000000004
回合:246/400,奖励:-22.0,Epsilon:0.010000000000000004
回合:247/400,奖励:-15.0,Epsilon:0.010000000000000004
回合:248/400,奖励:-19.0,Epsilon:0.010000000000000004
回合:249/400,奖励:-17.0,Epsilon:0.010000000000000004
回合:250/400,奖励:-27.0,Epsilon:0.010000000000000002
回合:251/400,奖励:-21.0,Epsilon:0.010000000000000002
回合:252/400,奖励:-23.0,Epsilon:0.010000000000000002
回合:253/400,奖励:-15.0,Epsilon:0.010000000000000002
回合:254/400,奖励:-15.0,Epsilon:0.010000000000000002
回合:255/400,奖励:-13.0,Epsilon:0.010000000000000002
回合:256/400,奖励:-15.0,Epsilon:0.010000000000000002
回合:257/400,奖励:-13.0,Epsilon:0.010000000000000002
回合:258/400,奖励:-28.0,Epsilon:0.010000000000000002
回合:259/400,奖励:-13.0,Epsilon:0.010000000000000002
回合:260/400,奖励:-13.0,Epsilon:0.010000000000000002
回合:261/400,奖励:-23.0,Epsilon:0.010000000000000002
回合:262/400,奖励:-13.0,Epsilon:0.010000000000000002
回合:263/400,奖励:-24.0,Epsilon:0.010000000000000002
回合:264/400,奖励:-17.0,Epsilon:0.010000000000000002
回合:265/400,奖励:-19.0,Epsilon:0.010000000000000002
回合:266/400,奖励:-13.0,Epsilon:0.010000000000000002
回合:267/400,奖励:-25.0,Epsilon:0.010000000000000002
回合:268/400,奖励:-15.0,Epsilon:0.01
回合:269/400,奖励:-15.0,Epsilon:0.01
回合:270/400,奖励:-21.0,Epsilon:0.01
回合:271/400,奖励:-13.0,Epsilon:0.01
回合:272/400,奖励:-13.0,Epsilon:0.01
回合:273/400,奖励:-22.0,Epsilon:0.01
回合:274/400,奖励:-15.0,Epsilon:0.01
回合:275/400,奖励:-13.0,Epsilon:0.01
回合:276/400,奖励:-19.0,Epsilon:0.01
回合:277/400,奖励:-13.0,Epsilon:0.01
回合:278/400,奖励:-18.0,Epsilon:0.01
回合:279/400,奖励:-14.0,Epsilon:0.01
回合:280/400,奖励:-126.0,Epsilon:0.01
回合:281/400,奖励:-15.0,Epsilon:0.01
回合:282/400,奖励:-19.0,Epsilon:0.01
回合:283/400,奖励:-13.0,Epsilon:0.01
回合:284/400,奖励:-25.0,Epsilon:0.01
回合:285/400,奖励:-13.0,Epsilon:0.01
回合:286/400,奖励:-119.0,Epsilon:0.01
回合:287/400,奖励:-15.0,Epsilon:0.01
回合:288/400,奖励:-15.0,Epsilon:0.01
回合:289/400,奖励:-14.0,Epsilon:0.01
回合:290/400,奖励:-13.0,Epsilon:0.01
回合:291/400,奖励:-13.0,Epsilon:0.01
回合:292/400,奖励:-15.0,Epsilon:0.01
回合:293/400,奖励:-33.0,Epsilon:0.01
回合:294/400,奖励:-19.0,Epsilon:0.01
回合:295/400,奖励:-13.0,Epsilon:0.01
回合:296/400,奖励:-15.0,Epsilon:0.01
回合:297/400,奖励:-13.0,Epsilon:0.01
回合:298/400,奖励:-132.0,Epsilon:0.01
回合:299/400,奖励:-13.0,Epsilon:0.01
回合:300/400,奖励:-13.0,Epsilon:0.01
回合:301/400,奖励:-13.0,Epsilon:0.01
回合:302/400,奖励:-14.0,Epsilon:0.01
回合:303/400,奖励:-15.0,Epsilon:0.01
回合:304/400,奖励:-13.0,Epsilon:0.01
回合:305/400,奖励:-13.0,Epsilon:0.01
回合:306/400,奖励:-13.0,Epsilon:0.01
回合:307/400,奖励:-13.0,Epsilon:0.01
回合:308/400,奖励:-13.0,Epsilon:0.01
回合:309/400,奖励:-13.0,Epsilon:0.01
回合:310/400,奖励:-13.0,Epsilon:0.01
回合:311/400,奖励:-15.0,Epsilon:0.01
回合:312/400,奖励:-13.0,Epsilon:0.01
回合:313/400,奖励:-13.0,Epsilon:0.01
回合:314/400,奖励:-13.0,Epsilon:0.01
回合:315/400,奖励:-15.0,Epsilon:0.01
回合:316/400,奖励:-14.0,Epsilon:0.01
回合:317/400,奖励:-13.0,Epsilon:0.01
回合:318/400,奖励:-13.0,Epsilon:0.01
回合:319/400,奖励:-13.0,Epsilon:0.01
回合:320/400,奖励:-21.0,Epsilon:0.01
回合:321/400,奖励:-19.0,Epsilon:0.01
回合:322/400,奖励:-13.0,Epsilon:0.01
回合:323/400,奖励:-13.0,Epsilon:0.01
回合:324/400,奖励:-13.0,Epsilon:0.01
回合:325/400,奖励:-13.0,Epsilon:0.01
回合:326/400,奖励:-14.0,Epsilon:0.01
回合:327/400,奖励:-15.0,Epsilon:0.01
回合:328/400,奖励:-13.0,Epsilon:0.01
回合:329/400,奖励:-13.0,Epsilon:0.01
回合:330/400,奖励:-13.0,Epsilon:0.01
回合:331/400,奖励:-13.0,Epsilon:0.01
回合:332/400,奖励:-13.0,Epsilon:0.01
回合:333/400,奖励:-14.0,Epsilon:0.01
回合:334/400,奖励:-13.0,Epsilon:0.01
回合:335/400,奖励:-113.0,Epsilon:0.01
回合:336/400,奖励:-13.0,Epsilon:0.01
回合:337/400,奖励:-13.0,Epsilon:0.01
回合:338/400,奖励:-13.0,Epsilon:0.01
回合:339/400,奖励:-13.0,Epsilon:0.01
回合:340/400,奖励:-13.0,Epsilon:0.01
回合:341/400,奖励:-15.0,Epsilon:0.01
回合:342/400,奖励:-23.0,Epsilon:0.01
回合:343/400,奖励:-13.0,Epsilon:0.01
回合:344/400,奖励:-13.0,Epsilon:0.01
回合:345/400,奖励:-13.0,Epsilon:0.01
回合:346/400,奖励:-13.0,Epsilon:0.01
回合:347/400,奖励:-13.0,Epsilon:0.01
回合:348/400,奖励:-13.0,Epsilon:0.01
回合:349/400,奖励:-13.0,Epsilon:0.01
回合:350/400,奖励:-13.0,Epsilon:0.01
回合:351/400,奖励:-13.0,Epsilon:0.01
回合:352/400,奖励:-13.0,Epsilon:0.01
回合:353/400,奖励:-13.0,Epsilon:0.01
回合:354/400,奖励:-13.0,Epsilon:0.01
回合:355/400,奖励:-13.0,Epsilon:0.01
回合:356/400,奖励:-13.0,Epsilon:0.01
回合:357/400,奖励:-13.0,Epsilon:0.01
回合:358/400,奖励:-13.0,Epsilon:0.01
回合:359/400,奖励:-13.0,Epsilon:0.01
回合:360/400,奖励:-13.0,Epsilon:0.01
回合:361/400,奖励:-13.0,Epsilon:0.01
回合:362/400,奖励:-13.0,Epsilon:0.01
回合:363/400,奖励:-13.0,Epsilon:0.01
回合:364/400,奖励:-13.0,Epsilon:0.01
回合:365/400,奖励:-13.0,Epsilon:0.01
回合:366/400,奖励:-13.0,Epsilon:0.01
回合:367/400,奖励:-13.0,Epsilon:0.01
回合:368/400,奖励:-13.0,Epsilon:0.01
回合:369/400,奖励:-13.0,Epsilon:0.01
回合:370/400,奖励:-13.0,Epsilon:0.01
回合:371/400,奖励:-13.0,Epsilon:0.01
回合:372/400,奖励:-14.0,Epsilon:0.01
回合:373/400,奖励:-13.0,Epsilon:0.01
回合:374/400,奖励:-15.0,Epsilon:0.01
回合:375/400,奖励:-13.0,Epsilon:0.01
回合:376/400,奖励:-13.0,Epsilon:0.01
回合:377/400,奖励:-13.0,Epsilon:0.01
回合:378/400,奖励:-13.0,Epsilon:0.01
回合:379/400,奖励:-13.0,Epsilon:0.01
回合:380/400,奖励:-117.0,Epsilon:0.01
回合:381/400,奖励:-13.0,Epsilon:0.01
回合:382/400,奖励:-13.0,Epsilon:0.01
回合:383/400,奖励:-13.0,Epsilon:0.01
回合:384/400,奖励:-13.0,Epsilon:0.01
回合:385/400,奖励:-13.0,Epsilon:0.01
回合:386/400,奖励:-13.0,Epsilon:0.01
回合:387/400,奖励:-13.0,Epsilon:0.01
回合:388/400,奖励:-13.0,Epsilon:0.01
回合:389/400,奖励:-13.0,Epsilon:0.01
回合:390/400,奖励:-13.0,Epsilon:0.01
回合:391/400,奖励:-13.0,Epsilon:0.01
回合:392/400,奖励:-13.0,Epsilon:0.01
回合:393/400,奖励:-13.0,Epsilon:0.01
回合:394/400,奖励:-13.0,Epsilon:0.01
回合:395/400,奖励:-13.0,Epsilon:0.01
回合:396/400,奖励:-13.0,Epsilon:0.01
回合:397/400,奖励:-13.0,Epsilon:0.01
回合:398/400,奖励:-15.0,Epsilon:0.01
回合:399/400,奖励:-13.0,Epsilon:0.01
回合:400/400,奖励:-13.0,Epsilon:0.01
完成训练!
开始测试!
环境:CliffWalking-v0, 算法:Q-learning, 设备:cpu
回合数:1/20, 奖励:-13.0
回合数:2/20, 奖励:-13.0
回合数:3/20, 奖励:-13.0
回合数:4/20, 奖励:-13.0
回合数:5/20, 奖励:-13.0
回合数:6/20, 奖励:-13.0
回合数:7/20, 奖励:-13.0
回合数:8/20, 奖励:-13.0
回合数:9/20, 奖励:-13.0
回合数:10/20, 奖励:-13.0
回合数:11/20, 奖励:-13.0
回合数:12/20, 奖励:-13.0
回合数:13/20, 奖励:-13.0
回合数:14/20, 奖励:-13.0
回合数:15/20, 奖励:-13.0
回合数:16/20, 奖励:-13.0
回合数:17/20, 奖励:-13.0
回合数:18/20, 奖励:-13.0
回合数:19/20, 奖励:-13.0
回合数:20/20, 奖励:-13.0
完成测试!