强化学习(1):Q-Learning 算法

news/2024/5/18 21:44:08 标签: 强化学习, q-learning, on-policy, off-policy

最近自己会把自己个人博客中的文章陆陆续续的复制到CSDN上来,欢迎大家关注我的 个人博客,以及我的github。

本文主要讲解有关 Q-Learning 算法的内容,主要包括 on-policyoff-policy 的概念、Q-Learning 算法的基本思想和算法流程,最后还会讲解一个莫烦大神的例子。

1. on-policyoff-policy

on-policy(同策略): 智能体在自己做的过程中学习,即选择动作的策略和更新值函数的策略是同一个策略。;

off-policy(异策略): 智能体在看别人做的过程中学习,即选择动作的策略和更新值函数的策略不是同一个策略。;

上述两种也被译作在线学习和离线学习。

同策略时间差分: sarsa、sarsa( λ \lambda λ)

异策略时间差分: 重要性采样、Q-learning、Deep Q Network

关于时间(时序)差分(TD)算法这里只提一句我的理解:时间差分是和蒙特卡洛(MC)方法相对应的,后者是对一个回合(episode)的数据采样,而前者是对一步或多步的数据采样。采样完毕之后再去计算数据的均值啊之类的。

2. Q-Learning 算法

Q-Learning 就是创造一个 Q 表来指导智能体的行动,Q 表的行是状态,列是动作。一个状态对应的动作的数值越大,则智能体采用该动作的概率越大。Q 表的每个值就是在上篇文章中提到的动作值函数 Q(s,a)。

Q 表更新公式如下:
Q ( S t , A t ) ← Q ( S t , A t ) + α [ R t + 1 + γ ⋅ max ⁡ Q ( S t + 1 ) − Q ( S t , A t ) ] Q(S_t,A_t)\leftarrow Q(S_t,A_t)+\alpha[R_{t+1}+\gamma\cdot\max Q(S_{t+1})-Q(S_t,A_t)] Q(St,At)Q(St,At)+α[Rt+1+γmaxQ(St+1)Q(St,At)]
其中 γ \gamma γ 为衰减值; α \alpha α 是学习率; max ⁡ Q ( S t + 1 ) \max Q(S_{t+1}) maxQ(St+1) 是状态 S t + 1 S_{t+1} St+1 下概率最大的动作对应的 Q 表值,但是在实际行动时并不一定采取该行动; R t + 1 + γ max ⁡ Q ( S t + 1 ) R_{t+1}+\gamma\max Q(S_{t+1}) Rt+1+γmaxQ(St+1) 是根据贝尔曼方程得到的 Q ( S t + 1 , A t + 1 ) Q(S_{t+1},A_{t+1}) Q(St+1,At+1) 的推导值,后面称为 Q-target;而 Q ( S t , A t ) Q(S_t,A_t) Q(St,At) Q ( S t + 1 , A t + 1 ) Q(S_{t+1},A_{t+1}) Q(St+1,At+1) 的估计值,后面称为 Q-eval。 R t + 1 + γ max ⁡ Q ( S t + 1 ) − Q ( S t , A t ) R_{t+1}+\gamma\max Q(S_{t+1})-Q(S_t,A_t) Rt+1+γmaxQ(St+1)Q(St,At) 就是两者的误差值,在后面的文章中也称其为 TD-error(时分误差)。


根据动作值函数的定义(见上一篇文章)有:
Q ( S 1 ) = R 2 + γ Q ( S 2 ) = R 2 + γ [ R 3 + γ Q ( S 3 ) ] Q(S_1)=R_2+\gamma Q(S_2)=R_2+\gamma [R_3+\gamma Q(S_3)] Q(S1)=R2+γQ(S2)=R2+γ[R3+γQ(S3)]

= R 2 + γ [ R 3 + γ [ R 4 + γ Q ( S 4 ) ] ] = . . . =R_2+\gamma [R_3+\gamma [R_4+\gamma Q(S_4)]]=... =R2+γ[R3+γ[R4+γQ(S4)]]=...

所以:
Q ( S 1 ) = R 2 + γ R 3 + γ 2 R 4 + γ 3 R 5 + . . . Q(S_1)=R_2+\gamma R_3+\gamma^2 R_4+\gamma^3 R_5+... Q(S1)=R2+γR3+γ2R4+γ3R5+...
γ = 1 \gamma=1 γ=1 时:
Q ( S 1 ) = R 2 + R 3 + R 4 + R 5 + . . . Q(S_1)=R_2+R_3+R_4+R_5+... Q(S1)=R2+R3+R4+R5+...
也就是动作值函数与该状态之后的所有奖励有关,并且其权重相等。

γ = 0 \gamma=0 γ=0 时:
Q ( S 1 ) = R 2 Q(S_1)=R_2 Q(S1)=R2
也就是动作值函数只与该状态的前后一个奖励有关。

0 < γ < 1 0<\gamma<1 0<γ<1 时:
Q ( S 1 ) = R 2 + γ R 3 + γ 2 R 4 + γ 3 R 5 + . . . Q(S_1)=R_2+\gamma R_3+\gamma^2 R_4+\gamma^3 R_5+... Q(S1)=R2+γR3+γ2R4+γ3R5+...
也就是说 Q 表实现了奖励值的衰减,离当前状态越远的奖励衰减的越严重。

3. Q-Learning 算法流程

Q-Learning

(1)初始化 Q 表(值全为 0 )

(2)根据当前状态选择一个 Action

(3)执行 Action 并获得相应的奖励,以及下一个状态

(4)按照公式更新 Q 表

(5)将下一个状态设为当前状态

(6)重复 2-5 步

值得注意的是在 Q-Learning 算法中有两个“ 策略”,一个是选取动作的策略,另一个是更新 Q 表的策略。这两个策略分别采用的是 ϵ \epsilon ϵ贪婪算法和最大值算法,所以 Q-Learning 是 off-policy 的。

4. 探索-利用困境

如果智能体仅仅按照 Q 表的最大概率指导行动的话,很多状态可能根本没办法达到,学习效率是比较低的,这就是探索-利用困境(Explore-Exploit dilemma)。可以用 ϵ \epsilon ϵ 贪婪( ϵ − G r e e d y \epsilon-Greedy ϵGreedy)方法解决。

ϵ \epsilon ϵ 贪婪方法就是设定一个 0 < ϵ < 1 0<\epsilon<1 0<ϵ<1,并以 ϵ \epsilon ϵ 的概率按照 Q 表数值最大的动作行动,以 1 − ϵ 1-\epsilon 1ϵ 的概率随机行动。

5. Q-Learning 版寻找宝藏的例子

以下代码实现了一个智能体(用字符 ‘o’ 表示)寻找宝藏(用字符 ‘T’ 表示)的强化学习过程,所用的算法是 Q-Learning 算法。当智能体找到宝藏时奖励值为 1,反之为 0。智能体的动作只有两个—— left 和 right,即向左移动和向右移动。程序会显示智能体和宝藏的位置、每个回合的奖励值以及终止状态时 Q 表的情况。

import numpy as np
import pandas as pd
import time

np.random.seed(2)

N_STATES = 6
ACTIONS = ['left', 'right']
EPSILON = 0.9
ALPHA = 0.1
GAMMA = 0.9
MAX_EPISODES = 10  # 回合数
FRESH_TIME = 0.3


def build_q_table(n_states, actions):  # 初始化 Q 表
    table = pd.DataFrame(
        np.zeros((n_states, len(actions))),
        columns=actions,  # 列的名称
    )
    return table


def choose_action(state, q_table):  # 根据当前状态和 Q 表选择一个动作
    # 如果随机数的值大于 EPSIlON 或者 Q 表的当前列都是 0 (即第一次到达该状态)
    if (np.random.uniform() > EPSILON or (q_table.iloc[state, :] == 0).all()):
        action_name = np.random.choice(ACTIONS)  # 随机选择一个动作
    else:
        action_name = q_table.iloc[state, :].idxmax()  # 选择当前状态对应的值最大的动作
    return action_name


def get_env_feedback(S, A):  # 获取新的状态和对应的奖励
    R = 0
    if A == "right":  # 往右
        S_ = S + 1
    else:  # 往左
        S_ = S - 1
        if S_ < 0:  # 如果到达最左端
            S_ = 0
    if S_ == N_STATES - 1:  # 如果找到宝藏
        S_ = "terminal"
        R = 1
    return S_, R


def update_env(S, episode, step_counter):  # 更新环境,主要是用来显示,可以不必搞懂
    env_list = ['-'] * (N_STATES - 1) + ['T']
    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 q_learning():  # Q-Learning 算法
    q_table = build_q_table(N_STATES, ACTIONS)
    for episode in range(MAX_EPISODES):
        S = 0
        step_counter = 0 # 共走了多少步
        is_terminal = False
        update_env(S, episode, step_counter)
        while not is_terminal:
            A = choose_action(S, q_table)
            S_, R = get_env_feedback(S, A)
            # 下面的代码是为了更新 Q 表
            q_predict = q_table.loc[S, A]
            if S_ != 'terminal':
                q_target = R + GAMMA * q_table.iloc[S_, :].max()
            else:  # 终止状态
                q_target = R
                is_terminal = True
            q_table.loc[S, A] += ALPHA * (q_target - q_predict)  # 根据公式更新
            S = S_
            step_counter += 1
            update_env(S, episode, step_counter)
    return q_table


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

http://www.niftyadmin.cn/n/968526.html

相关文章

GetProcAddress的二分查找

只要稍微熟悉PE结构就能很快写出来&#xff0c;GetProcAddress的原型如下 FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName) hModule是指模块的基地址&#xff0c;比如用LoadLibrary加载dll返回的地址 lpProcName顾名思义就是函数或者变量的名称&#xff0c;…

019-请你说一下app性能测试的指标

1、内存&#xff1a;内存消耗测试节点的设计目标是为了让应用不占用过多的系统资源&#xff0c;且及时释放内存&#xff0c;保障整个系统的稳定性。当然关于内存测试&#xff0c;在这里我们需要引入几个概念&#xff1a;空闲状态、中等规格、满规格。空闲状态&#xff1a;打开应…

强化学习(2):Sarsa 算法及 Sarsa(lambda) 算法

最近自己会把自己个人博客中的文章陆陆续续的复制到CSDN上来&#xff0c;欢迎大家关注我的 个人博客&#xff0c;以及我的github。 本文主要讲解 Sarsa 算法以及 Sarsa(λ\lambdaλ) 算法的相关内容&#xff0c;同时还会分别附上一个莫烦大神写的例子。 一、Sarsa 算法 Sarsa…

GFORTRAN

GFORTRAN - 维基百科&#xff0c;自由的百科全书GFORTRAN 维基百科&#xff0c;自由的百科全书跳转到&#xff1a; 导航、 搜索gfortran是GCC中的GNU Fortran编译器。从GCC4.0版开始&#xff0c;gfortran取代了g77成为GCC中的fortran编译器。gfortran目前仍在开发中&#xff0c…

Robot Framework(2)——简单运行案例

1.打开RIDE 之前介绍的3种方式都可以 2.创建工程和测试套件 1>点击File-New Project ①Name&#xff1a;工程命名 ②Parent Directory&#xff1a;上级目录&#xff0c;工程会创建在这个目录下&#xff0c;创建时要注意&#xff0c;默认是上一次的目录 ③Created Path&#…

强化学习(3):Deep Q Network(DQN)算法

最近自己会把自己个人博客中的文章陆陆续续的复制到CSDN上来&#xff0c;欢迎大家关注我的 个人博客&#xff0c;以及我的github。 本文主要讲解有关 Deep Q Network&#xff08;DQN&#xff09;算法的相关内容。 1. DQN 的基本思想 传统的 Q-Learning 算法当 Q 表过大时不仅…

perl编写ping脚本

我的第一个用于生产环境的perl脚本,虽然不是很优秀,但也迈出了扎实的一步 :) 领导有任务,给一批IP列表,ping每一台机器,如果没有响应就发邮件通知,通知的邮件需要分开,不能通知一个列表,得一封一封的通知. 用到email::send模块,因为需要用到Gmail #!/usr/bin/perl use warning…

Android应用程序架构

2019独角兽企业重金招聘Python工程师标准>>> 1、src/ &#xff1a; java源代码目录 2、gen/ : 自动生成目录 gen目录中存放所有由Android开发工具自动生成的文件。目录最重要的就是R.java文件。这个文件由Android开发工具自动产生的。Android开发工具会自动根据…