从零使用强化学习训练AI玩儿游戏(3)

本文目前主要是写给自己的一个笔记,接下来这段时间会逐步记录我是怎么通过学习使用TensorFlow+Keras训练神经网络自己玩儿游戏,如果能间接帮助到他人就最好不过了,不喜勿喷。

上一篇我们已经找到了需要输入神经网络的数据(也就是observation 是GYM提供的代表一定意义的数,每个游戏不同),和神经网络需要输出的值(也就是action 需要控制游戏的值)

这一篇我们就来看看怎么样写一个强化学习的简单算法Q-Learn,并且运用到之前的最简单的游戏中。

在这里找到一个莫烦大神优酷的视频集锦,上面不止讲了Keras,还讲了各种关于机器学习的视频,简单易懂,非常有帮助!

看了一个DQN的视频,非常简短有力的介绍了我们需要怎么样搭建一个神经网络来玩游戏。

接下来开始用Q-learning来写程序,如图所示是Q-learning算法的伪码。

import numpy as npimport pandas as pdimport timenp.random.seed(2)  # reproducibleN_STATES = 6   # the length of the 1 dimensional worldACTIONS = ['left', 'right']     # available actionsEPSILON = 0.9   # greedy policeALPHA = 0.1     # learning rateGAMMA = 0.9    # discount factorMAX_EPISODES = 13   # maximum episodesFRESH_TIME = 0.3    # fresh time for one movedef build_q_table(n_states, actions):    table = pd.DataFrame(        np.zeros((n_states, len(actions))),     # q_table initial values        columns=actions,    # actions's name    )    # print(table)    # show table    return tabledef choose_action(state, q_table):    # This is how to choose an action    state_actions = q_table.iloc[state, :]    if (np.random.uniform() > EPSILON) or ((state_actions == 0).all()):  # act non-greedy or state-action have no value        action_name = np.random.choice(ACTIONS)    else:   # act greedy        action_name = state_actions.idxmax()    # replace argmax to idxmax as argmax means a different function in newer version of pandas    return action_namedef get_env_feedback(S, A):    # This is how agent will interact with the environment    if A == 'right':    # move right        if S == N_STATES - 2:   # terminate 只有到达终点才有奖励            S_ = 'terminal'            R = 1        else:            S_ = S + 1            R = 0    else:   # move left走左边的奖励永远是0        R = 0        if S == 0:            S_ = S  # reach the wall        else:            S_ = S - 1    return S_, Rdef update_env(S, episode, step_counter):    # This is how environment be updated    env_list = ['-']*(N_STATES-1) + ['T']   # '---------T' our environment    if S == 'terminal':        interaction = 'Episode %s: total_steps = %s' % (episode+1, step_counter)        print('\r{}'.format(interaction), end='')        time.sleep(2)        print('\r                                ', end='')    else:        env_list[S] = 'o'        interaction = ''.join(env_list)        print('\r{}'.format(interaction), end='')        time.sleep(FRESH_TIME)def rl():    # main part of RL loop    q_table = build_q_table(N_STATES, ACTIONS)  # 创建一个全为0的q表,用的是pandas    for episode in range(MAX_EPISODES):         # 主循环,看一共需要训练多少次,也就是一共成功找到宝藏多少次        step_counter = 0        S = 0        is_terminated = False        update_env(S, episode, step_counter)    # 在环境中更新状态        while not is_terminated:                # 如果没找到宝藏就要一直找            A = choose_action(S, q_table)       # 通过q表来选择 下一步的动作            S_, R = get_env_feedback(S, A)      # 用这个动作来走,并且得到他的奖励            q_predict = q_table.loc[S, A]       # 得到q表的预测值,也就是走这一步之前会先看看不走也就是不更新q表会是什么情况 其实也就是前一个状态执行这个动作的q值            if S_ != 'terminal':                q_target = R + GAMMA * q_table.iloc[S_, :].max()   # GAMMA是衰减率 乘上实际应该走的q值里最大的            else:                q_target = R     # next state is terminal                is_terminated = True    # terminate this episode            q_table.loc[S, A] += ALPHA * (q_target - q_predict)  # update 更新的值实际上是q_predict在q表中的值,也就是上一个状态执行这个动作的q值            S = S_  # move to next state            update_env(S, episode, step_counter+1)            step_counter += 1    return q_tableif __name__ == "__main__":    q_table = rl()    print('\r\nQ-table:\n')    print(q_table)

只是一个非常简单的Q-learning运用,具体的讲解可以看莫烦大神的视频,我再程序上又加了一些中文注释以便理解

接下来改写莫烦大神的视频,使用Q-learning玩儿之前的CartPole-v0游戏。

由于这款游戏传入的状态值是一个连续性变量,不是固定数量的状态值,导致Q-learning算法中的q表一直在更新新的值,不能达到算法的最初目的,所以这样做是不行的。不过还是po一下源码,为以后的算法做准备。

# -*- coding: UTF-8 -*-from Qlearning import QLearningTableimport gymif __name__ == '__main__':    print('开始学习')    RL = QLearningTable(actions=list(range(2))) # 得到Q-learning算法类的实例,可以修改学习率等参数    env = gym.make('CartPole-v1')    # env = gym.make('AirRaid-ram-v0')    for i_episode in range(2000):        observation = env.reset()        for t in range(1000):            env.render()            # print(observation)            action = RL.choose_action(str(observation)) # 使用q表来选择 下一步的动作            # action = env.action_space.sample()            # print(action)            observation_, reward, done, info = env.step(action) # 把当前动作传入环境中,得到真实的奖励和观测            RL.learn(str(observation), action, reward, str(observation_)) # 通过真实的奖励观测和估计的奖励 更新q表            observation = observation_                      # 真正的走下一步            if done:                print("Episode finished after {} timesteps".format(t + 1))                break

这个是Q-learning算法模块代码:

# -*- coding: UTF-8 -*-import numpy as npimport pandas as pdclass QLearningTable:    def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9):        self.actions = actions  # a list        self.lr = learning_rate        self.gamma = reward_decay        self.epsilon = e_greedy        self.q_table = pd.DataFrame(columns=self.actions, dtype=np.float64)    def choose_action(self, observation):        self.check_state_exist(observation)        # action selection        if np.random.uniform() < self.epsilon:            # choose best action            state_action = self.q_table.loc[observation, :]            state_action = state_action.reindex(np.random.permutation(state_action.index))     # some actions have same value            action = state_action.idxmax()        else:            # choose random action            action = np.random.choice(self.actions)        return action    def learn(self, s, a, r, s_):        self.check_state_exist(s_)        q_predict = self.q_table.loc[s, a]        if s_ != 'terminal':            q_target = r + self.gamma * self.q_table.loc[s_, :].max()  # next state is not terminal        else:            q_target = r  # next state is terminal        self.q_table.loc[s, a] += self.lr * (q_target - q_predict)  # update    def check_state_exist(self, state):        if state not in self.q_table.index:            # append new state to q table            self.q_table = self.q_table.append(                pd.Series(                    [0]*len(self.actions),                    index=self.q_table.columns,                    name=state,                )            )

根据实践检测Q-learning算法只适合在有限量的状态值下运用,对于连续值没有什么用,其实看懂了算法应该就很容易理解这一点,只是觉得做个试验也不能所以就做了。

这一篇学了Q-learning,发现对我们玩儿游戏这种状态值超级多的情况并不适用。就对走迷宫有点用,但是走迷宫又有dfs深搜这样的算法,所以感觉Q-learning只能算强化学习里面比较启发式的算法吧,没什么实际用。不过我一个初学者也不知道。哈哈哈~

这篇是真的不喜勿喷了。

下一篇我们将使用Sarsa和Sarsa-lambda来玩一个迷宫游戏。

(0)

相关推荐