计算机系统应用教程网站

网站首页 > 技术文章 正文

一文彻底搞懂Q-Lnearing算法实战 qz算法

btikc 2024-10-14 08:51:49 技术文章 8 ℃ 0 评论

上一节我们已经介绍了Q-Learning的算法理论,详见要知道OpenAI Q*算法,你需要先了解Q-Learning算法,为了让大家更好的理解Q-Learning,本节主要从代码实战方面给大家一个示例,以便帮助大家在实践中更好地理解与使用Q-Learning算法。由于篇幅有限,本节以Q-Learning在一维空间上的探索学习为示例,给大家讲解相关代码。相应地,二维空间、三维空间如何利用Q-Learning进行学习也是类似的原理,将不再赘述,有兴趣的同学,可以试着自己尝试。下面让我们开始吧。

问题

假设一个人,目标寻找一座金矿,但他只能执行向左或者向右移动两种动作,且每次只能向左或向右移动一步,当到达金矿目标地时,获得奖励reward=1,其他奖励都为零,reward=0。如下图:

分析

从上面的题目中,我们知道该智能体,即寻找金矿的人,从初始状态s0出发,其可以向左,或者向右移动,即actions = ['left', 'right'],且每次移动一步,当智能体从s5移动到s6时,获得奖励reward=1,其他情况下reward都为0,即状态动作奖励表如下图所示。同时,我们知道最佳策略是从s0状态出发,连续向右移动5步,即可到达目标,也是本问题的最佳算法策略,下面就让我们看看q_learning具体是怎么实现的吧。

代码实践

下面给出了Q-Learning完整的实现代码,Q-Learning代码主要包括上一节理论当中我们提到的那几步,主要包括1. 初始化一个q_table,2. 然后根据当前状态选择一个action,3. 再计算相应的reward,以及下一个可能的状态,4. 最后根据时序差分公式,更新q table。重复上面2,3,4的流程,直到达到预先设定好的最大采样序列数,停止探索学习,算法结束。大家可以将下面的代码直接拷贝到个人电脑上,直接运行,即可得到相应的结果。也可以直接git clone本人的github地址:https://github.com/louiss007/agi-x/blob/master/src/rl/q_learning.py

import pandas as pd
import numpy as np
import time


class QLearning:
    """ Q-learning Algorithm """
    fresh_time = 0.3

    def __init__(self, n_states, epsilon, alpha, gamma, actions):
        self.n_states = n_states        # number of states
        self.actions = actions
        self.n_action = len(actions)    # number of actions
        self.alpha = alpha              # learning rate
        self.gamma = gamma              # discount factor
        self.epsilon = epsilon          # hyper para of ε-greedy
        self.q_table = self.init_q_table()

    def init_q_table(self):
        """initiate q table"""
        table = pd.DataFrame(np.zeros([self.n_states, self.n_action]), columns=self.actions)
        return table

    def show_env(self, s, episode, step):
        """show current environment"""
        env_list = ['-'] * (self.n_states - 1) + ['T']
        if s == 'terminal':  # whether is getting terminal
            interaction = 'Episode %s: total_steps = %s' % (episode + 1, step)
            print(f'\r{interaction}')
            time.sleep(0.5)
        else:
            env_list[s] = 'o'
            interaction = ''.join(env_list)
            print(f'\r{interaction}', end='')
            time.sleep(self.fresh_time)  # set moving speed interval 0.3s

    def take_action(self, state):
        state_actions = self.q_table.iloc[state, :]
        if (np.random.uniform() > self.epsilon) or (state_actions == 0).all():
            # explore
            action = np.random.choice(self.actions)  # random to choose action
        else:
            # exploit
            action = state_actions.idxmax()  # choose the action with max_q value
        return action

    def reward_fn(self, state, action):
        """Given current state and action, compute reward and next state"""
        if action == 'right':
            if state == self.n_states - 2:  # whether is terminal or not
                state_n = 'terminal'
                r = 1  # yes reward
            else:
                state_n = state + 1
                r = 0  # no reward
        else:
            r = 0  # no reward
            state_n = max(0, state-1)
        return state_n, r

    def update(self, s, a, r, s_n):
        """update the values of q table"""
        if s_n != 'terminal':
            td_error = r + self.gamma * self.q_table.iloc[s_n, :].max() - self.q_table.loc[s, a]
        else:
            td_error = r
        self.q_table.loc[s, a] += self.alpha * td_error
        return s_n

    def run(self, max_episodes):
        for episode in range(max_episodes):
            step = 0
            s = 0  # initial state
            is_done = False     # a sign whether current exploration is over
            self.show_env(s, episode, step)
            while not is_done:
                a = self.take_action(s)         # choose action
                s_n, r = self.reward_fn(s, a)   # compute reward
                s = self.update(s, a, r, s_n)   # update q table
                if s == 'terminal':
                    is_done = True
                step += 1
                self.show_env(s_n, episode, step)

        return self.q_table


def main():
    max_episodes = 10
    n_states = 6
    epsilon = 0.9
    alpha = 0.1
    gamma = 0.9
    actions = ['left', 'right']
    np.random.seed(7)
    q_agent = QLearning(n_states, epsilon, alpha, gamma, actions)
    q_table = q_agent.run(max_episodes)
    print('\r\nQ-table:\n')
    print(q_table)
    return q_table


if __name__ == '__main__':
    main()

通过执行上面的代码,我们可以得到如下的运行结果:

通过上面的结果,我们可以看到,智能体利用q-learning算法,不断地与环境进行交互学习,最终获得了最佳的学习策略,相应地,我们也就能得到对应的q table表。

通过本实例,我们可以知道,q learning算法适合那种状态有限,动作也有限的离散场景,对于那种无限的场景,或者连续的场景,我们是没有办法直接构造一个状态动作q值表的,所以相应的改进算法也就被提出来了。后续章节,我们会介绍DQN算法,不过为了满足大家对Q*算法的好奇心,下一节,我会先介绍一下A*算法,有了Q-Learning和A*算法,大家也许对Q*有了一个初步的认知。不过,目前为止,OpenAI官方还没有公开承认Q*算法,个人也是根据网络搜集的信息以及加上个人的理解,给大家简单介绍其中的一二,如有纰缪之处,还望各位网友批评指正,本人不胜感激,在此感谢!

Reference

https://www.jianshu.com/p/78370c66e192

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表