强化学习之路1——Q-learning

Q-learning算法

最近在学强化学习,看了不少的教程,还是觉得莫烦大神的强化学习教程写的不错。所以,特意仔细研究莫烦的RL代码。在这贴上自己的理解。

莫烦RL教程:https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/

代码:https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow/tree/master/contents

1.Q-learning算法的决策

Q-learning算法是如何决策的呢?
原来Q-learning算法会生成一个Q表,agent每一次要采取的action,都会根据当前agent的state去Q表中查找奖励(reward)最高的动作。
就这样,agent每次采取动作都去Q表中查找.以此来决策agent的下一步的action。

2.Q-learning算法的更新

假如有如下的Q表

- a1 a2
s1 -2 1
s2 -4 2

现在agent在s1状态,根据前文说的算法决策方法Q(s1,a1) < Q(s1,a2),所以接下来会采取a2这个动作,并到达s2状态。
我们来更新Q表。接下来的我们没有在实际中采取任何动作,而是想想自己在S2状态下采取的动作,分别看看在S2状态下哪个动作的Q值最大。
比如说Q(s2,a2) > Q(s2,a1),所以把大的Q(s2,a2)乘一个gamma并加上到达s2时的奖励R,把这个作为现实中Q(s1,a2)的值。也就是 ‘Q现实’。 Q现实 = R + γ*maxQ(s2)
之前的根据Q表得到的Q(s1,a2)是Q表估计的值,也就是‘Q估计’。 Q估计 = Q(s1,a2)
有了 Q现实 和 Q估计,就可以更新Q(s1,a2)。

Q(s1,a2) = Q(s1,a2) + α * (Q现实 - Q估计)

但时刻记住, 我们虽然用 maxQ(s2) 估算了一下 s2 状态, 但还没有在 s2 做出任何的行为, s2 的行为决策要等到更新完了以后再重新另外做. 这就是 off-policy 的 Q learning 是如何决策和学习优化决策的过程.

3.Q-learning整体算法

[站外图片上传中...(image-6af5ac-1563434302631)]

这一张图概括了我们之前所有的内容. 这也是 Q learning 的算法, 每次更新我们都用到了 Q 现实和 Q 估计, 而且 Q learning 的迷人之处就是 在 Q(s1, a2) 现实 中, 也包含了一个 Q(s2) 的最大估计值, 将对下一步的衰减的最大估计和当前所得到的奖励当成这一步的现实, 很奇妙吧. 最后我们来说说这套算法中一些参数的意义. Epsilon greedy 是用在决策上的一种策略, 比如 epsilon = 0.9 时, 就说明有90% 的情况我会按照 Q 表的最优值选择行为, 10% 的时间使用随机选行为. alpha是学习率, 来决定这次的误差有多少是要被学习的, alpha是一个小于1 的数. gamma 是对未来 reward 的衰减值。

4.探索者小游戏——代码实现

会用 tabular Q-learning 的方法实现一个小例子, 例子的环境是一个一维世界, 在世界的右边有宝藏, 探索者只要得到宝藏尝到了甜头, 然后以后就记住了得到宝藏的方法, 这就是他用强化学习所学习到的行为.

-o---T
# T 就是宝藏的位置, o 是探索者的位置

4.1模块和参数

import numpy as np
import pandas as pd
import time

N_STATES = 6   # 1维世界的宽度 -o---T
ACTIONS = ['left', 'right']     # 动作列表
EPSILON = 0.9   # 贪婪度
ALPHA = 0.1     # 学习率
GAMMA = 0.9    # 奖励衰减值
MAX_EPISODES = 13   # 训练次数(回合数)/游戏运行次数
FRESH_TIME = 0.3    # 移动间隔时间

4.2创建Q表

## 创建Q表
def build_q_table(n_states, actions):
    table = pd.DataFrame(
        np.zeros((n_states, len(actions))),     #  初始化Q表,值为0
        columns=actions,    # 列的名字为动作的名称
    )
    #print(table)    # show table
    return table

4.3动作的选择

## 在某状态时,选择动作
def choose_action(state, q_table):
    # iloc 选择state行的 动作的值,类型还是 Dataframe
    state_actions = q_table.iloc[state, :]  
    ''' np.random.uniform(low=0.0, high=1.0, size=None) 随机数'''
    # 大于贪婪度 or 这个 state 未探索过, 则随机选择一个动作
    if (np.random.uniform() > EPSILON) or ((state_actions == 0).all()):
        action_name = np.random.choice(ACTIONS)
    else:   # 否则采取贪婪模式
        action_name = state_actions.idxmax()
    return action_name

4.4环境的反馈

## 游戏环境给我们的行为一个反馈(环境)
def 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 向左
        R = 0
        if S == 0:
            S_ = S  # reach the wall
        else:
            S_ = S - 1
    return S_, R

4.5游戏环境更新

## 游戏环境更新(环境)
def 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)

4.6Q-learning算法核心

## tabular Q learning 算法的核心
def rl():
    # main part of RL loop
    q_table = build_q_table(N_STATES, ACTIONS) # 创建Q表
    for episode in range(MAX_EPISODES):  # 游戏运行次数
        step_counter = 0                # 步数计数
        S = 0                           # agent 现在的 state
        is_terminated = False           # 游戏是否结束的 flag
        update_env(S, episode, step_counter)    # 更新游戏环境
        while not is_terminated:            # 只要游戏未结束

            A = choose_action(S, q_table)   # 根据现在的state 和 Q表 选择下一步的动作
            # 根据State 和 Action,来获得环境的反馈(下一步的State,奖励)
            S_, R = get_env_feedback(S, A)  
            q_predict = q_table.loc[S, A]   # Q估计——也就是之前储存在Q表中的Q(s,a)值
            if S_ != 'terminal':            # 接下来的state不是terminal,也就是游戏未结束
                q_target = R + GAMMA * q_table.iloc[S_, :].max()   # Q现实值,见Q-learning算法
            else:
                q_target = R     # S_接下来的state为terminal,也就是游戏结束,Q现实 = R
                is_terminated = True    # 游戏结束,flag置1

            q_table.loc[S, A] += ALPHA * (q_target - q_predict)  # 更新Q表的值
            S = S_  # state变为 下一步的state

            update_env(S, episode, step_counter+1)  # 更新游戏环境
            step_counter += 1   # 游戏步数计数
    return q_table

4.7主函数

if __name__ == "__main__":
    q_table = rl()
    print('\r\nQ-table:\n')
    print(q_table)

5.迷宫小游戏——代码实现

说说一个更具体的例子. 让探索者学会走迷宫. 黄色的是天堂 (reward 1), 黑色的地狱 (reward -1). 大多数 RL 是由 reward 导向的, 所以定义 reward 是 RL 中比较重要的一点.

[站外图片上传中...(image-fd9598-1563434302632)]

5.1Q-learning算法实现

import numpy as np
import pandas as pd

class QLearningTable:
    def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9):
        self.actions = actions  # 动作列表
        self.lr = learning_rate # 学习率
        self.gamma = reward_decay   #
        self.epsilon = e_greedy #贪婪度
        self.q_table = pd.DataFrame(columns=self.actions, dtype=np.float64) #Q表

    # 选择activate
    def choose_action(self, observation):
        self.check_state_exist(observation)
        # 选择动作
        if np.random.uniform() < self.epsilon:
            # 选择最佳动作
            state_action = self.q_table.loc[observation, :]
            '''
            这一行不好理解。np.max(state_action) 选出state_action中的最大值。
            state_action == np.max(state_action) 对应数据是否与max相等,返回bool值。True or False
            state_action[state_action == np.max(state_action) 筛选出最大值,可能是一个,也可能是两个
            之后随机挑选最大值的动作。(只有一个则就是它,如果max有多个数值相同,则随机挑选)
            '''
            action = np.random.choice(state_action[state_action == np.max(state_action)].index)
        else:
            # 贪婪 随机选择动作
            action = np.random.choice(self.actions)
        return action

    def learn(self, s, a, r, s_):
        # 检测S_是否存在
        self.check_state_exist(s_)
        # Q估计(Q表中存储的值)
        q_predict = self.q_table.loc[s, a]
        # Q现实(对下一状态的最大估计)
        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
        # 更新Q(s,a)
        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),  # 添加 动作数 个[0],初始 0 0
                    index=self.q_table.columns, # Series的index也就是 DataFrame 的columns,也就是index 对应action
                    name=state,                 # 设置q_table的index名称
                )
            )

这一段把Q-learning算法整合为一个类。

5.2主函数


from maze_env import Maze
from RL_brain import QLearningTable


def update():
    # 游戏运行次数
    for episode in range(100):
        # 初始化游戏环境
        observation = env.reset()
        # 时间步
        while True:
            # 更新游戏界面
            env.render()
            # 根据observation选择动作,这里的observation也就是state(位置坐标)
            action = RL.choose_action(str(observation))
            # agent采取这个action,并返回state、raward和游戏结束flag
            observation_, reward, done = env.step(action)
            # 根据经历(S,A,R,S_)更新Q表
            RL.learn(str(observation), action, reward, str(observation_))
            # 交换state,state进入下一循环
            observation = observation_
            # 如果游戏结束,则本回合结束
            if done:
                break

    # 结束游戏并关闭窗口
    print('game over')
    env.destroy()

if __name__ == "__main__":
    env = Maze()    # 建造游戏环境
    RL = QLearningTable(actions=list(range(env.n_actions))) # 使用0~3代表迷宫游戏的四个动作

    # 开始可视化环境 env
    env.after(100, update)
    env.mainloop()

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、什么是Q_learning Q_learning是强化学习中的一个决策算法,如果你还不知道什么是强化学习,可以...
    小道萧兮阅读 23,633评论 0 11
  • 一、什么是强化学习 强化学习是一类算法,是让计算机实现从一开始完全随机的进行操作,通过不断地尝试,从错误中学习,最...
    小道萧兮阅读 32,912评论 5 12
  • 一. 增强学习简介 1.1 什么是增强学习? 机器学习的算法可以分为三类:监督学习,非监督学习和增强学习。 增强学...
    阿阿阿阿毛阅读 31,362评论 0 25
  • 强化学习 元素:actor(我们可以控制,决策我们的行为),Env,Reward(我们不能控制环境)主要方法:mo...
    fada_away阅读 19,175评论 0 14
  • 有人说,最难熬的,其实不是奔跑时不小心跌倒在地上的瞬间——虽然会痛,但至少你会相信,好起来的时候,自己就能继续走下...
    走路带风的纪小姐阅读 182评论 0 1