【机器学习】强化学习(2)——捋清深度强化学习的思路

news/2025/2/26 19:27:30

在之前学习的过程中我了解到深度学习中很重要的一个概念是反向传播,最近看论文发现深度强化学习(DRL)有各种各样的方法,但是却很难区分他们的损失函数的计算以及反向传播的过程有何不同。在有监督的学习中,损失可以理解为预测值和真实值之间的距离,那么在这里的损失指的是什么?是否也涉及到两个值之间的差距呢,具体是哪两个东西之间的拟合(学习)?如何拟合?这里通过举例对几种强化学习方法进行比较。

问题设计

在这里插入图片描述
假设有一个3×3的迷宫(如上图),用S表示起点(入口)、E表示终点(出口)、O表示通路、W表示墙壁,目标是从S到E找到一条通路。

Q-learning

原理

Q-learning是一种基于值函数的强化学习方法,其核心思想是通过更新和维护动作值函数 Q ( s , a ) Q(s,a) Q(s,a)来间接推导出最优策略,使用Q-table存储每个状态-动作对的期望奖励。与深度学习中的反向传播不同,Q-learning在传统实现中并不依赖反向传播。
Q ( s , a ) Q(s,a) Q(s,a)的更新公式为贝尔曼方程:
Q ( s , a ) ← Q ( s , a ) + α [ r + γ max ⁡ a ′ Q ( s ′ , a ′ ) − Q ( s , a ) ] Q(s,a)←Q(s,a)+α[r+γ\max_{a'}Q(s',a')-Q(s,a)] Q(s,a)Q(s,a)+α[r+γamaxQ(s,a)Q(s,a)]
其中, α α α是学习率, γ γ γ是折扣因子, r r r是当前奖励, s ′ s' s是下一个状态。这是一个迭代更新公式,直接对Q-table进行更新,无需显式的梯度计算或反向传播,Q-table存储了所有状态-动作对的值,更新过程是逐个元素地调整表格中的值。

模拟

参数设计

  1. 奖励规则:到达终点奖励+100;到达墙壁或超出迷宫奖励-10;其他情况奖励分值为6-到出口最短路线距离(假设这些距离提前都计算好了)。比如走到(1,0)+3,走到(2,2)+4,走到(0,1)-10,走到(0,2)+100。
  2. 贝尔曼方程参数: α = 0.8 α=0.8 α=0.8 γ = 0.2 γ=0.2 γ=0.2

Q-table初始化

初始化一个Q-table,大小为状态数×行为数。对于3×3的迷宫,状态数为9(每个格子为一个状态),行为数为4(上下左右)。初始化Q-table为0:
在这里插入图片描述

学习过程

第一次

状态和状态转移:

状态s行为(随机)下一个状态s’
(0,0)UP×

更新Q-table:

原始Q[(0,0), UP]奖励下一状态能获得的最大奖励更新后的Q[(0,0), UP]
0-100-8

结果:
在这里插入图片描述

第二次

状态和状态转移:

状态s行为(随机)下一个状态s’
(0,0)DOWN(1,0)

更新Q-table:

原始Q[(0,0), DOWN]奖励下一状态能获得的最大奖励更新后的Q[(0,0), DOWN]
0+302.4

结果:
在这里插入图片描述

第三次
状态s行为(随机)下一个状态s’原始Q[(1,0), RIGHT]奖励下一状态能获得的最大奖励更新后的Q[(1,0), RIGHT]
(1,0)RIGHT(1,1)0+403.2

结果:
在这里插入图片描述

中间省略1000次
状态s行为(随机)下一个状态s’原始Q[(1,1), LEFT]奖励下一状态能获得的最大奖励更新后的Q[(1,1), LEFT]
(1,1)LEFT(1,0)0+33.22.912
状态s行为(随机)下一个状态s’原始Q[(1,0), DOWN]奖励下一状态能获得的最大奖励更新后的Q[(1,0), DOWN]
(1,0)DOWN(2,0)0+201.6

自己抽签和计算太麻烦了,于是写了代码大致模拟了一下。

# Dangerous
import random

keys = [(0,0,'up'), (0,0,'down'), (0,0,'left'), (0,0,'right'),
        (0,1,'up'), (0,1,'down'), (0,1,'left'), (0,1,'right'),
        (0,2,'up'), (0,2,'down'), (0,2,'left'), (0,2,'right'),
        (1,0,'up'), (1,0,'down'), (1,0,'left'), (1,0,'right'),
        (1,1,'up'), (1,1,'down'), (1,1,'left'), (1,1,'right'),
        (1,2,'up'), (1,2,'down'), (1,2,'left'), (1,2,'right'),
        (2,0,'up'), (2,0,'down'), (2,0,'left'), (2,0,'right'),
        (2,1,'up'), (2,1,'down'), (2,1,'left'), (2,1,'right'),
        (2,2,'up'), (2,2,'down'), (2,2,'left'), (2,2,'right')]
values = [-8,2.4,0,0,0,0,0,0,0,0,0,0,0,0,0,3.2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]  # 经历三次学习后的值

rewards = [[2, -10, 100], [3, 4, 5], [2, -10, 4]]

action_list = ['up', 'down', 'left', 'right']

qTable = dict(zip(keys, values))  # 创建初始列表

alpha = 0.8
gamma = 0.2

now_x = 1
now_y = 1

def transfer_x(x, act):
        if act == 'up': return x-1
        elif act == 'down': return x+1
        else: return x

def transfer_y(y, act):
        if act == 'left': return y-1
        elif act == 'right': return y+1
        else: return y

for i in range(1000):  # 学习1000次
        action = random.choice(action_list)  # 行为

        next_x = transfer_x(now_x, action)  # 下一个状态s'
        next_y = transfer_y(now_y, action)

        before_q = qTable[(now_x, now_y, action)]  # 原始Q

        if next_x not in [0,1,2] or next_y not in [0,1,2]:  # 奖励
                reward = -10
        else: reward = rewards[next_x][next_y]

        if next_x not in [0, 1, 2] or next_y not in [0, 1, 2]:  # 下一状态能获得的最大奖励
                max_reward = 0
        else:
                max_reward = 0
                for a in action_list:
                        r = qTable[(next_x, next_y, a)]
                        if r > max_reward: max_reward = r

        qTable[(now_x, now_y, action)] = before_q + alpha * (reward + gamma * max_reward - before_q)  # 更新后的Q值

        random_start_list = [(0,0), (1,0), (1,1), (1,2), (2,0), (2,2)]
        random_start = random.choice(random_start_list)
        random_p = random.randint(1,10)
        random_flag = True if random_p == 1 else False
        if next_x == 0 and next_y == 2:  # 如果走到终点就从随机位置开始
                now_x = random_start[0]
                now_y = random_start[1]
        elif next_x not in [0, 1, 2] or next_y not in [0, 1, 2]:
                # 如果走出去就不改变当前位置(以0.1的概率随机初始位置)
                if random_flag:
                        now_x = random_start[0]
                        now_y = random_start[1]
        elif next_y == 1 and (next_x == 0 or next_x == 2):
                # 如果走到墙上就不改变当前位置(以0.1的概率随机初始位置)
                if random_flag:
                        now_x = random_start[0]
                        now_y = random_start[1]
        else:  # 或者以0.1的概率随机初始位置
                now_x = next_x
                now_y = next_y
                if random_flag:
                        now_x = random_start[0]
                        now_y = random_start[1]

# 打印Q表
for key in qTable:
        print("key:" + str(key) + "   " + str(qTable[key]))

结果

得到结果如下:
在这里插入图片描述
其中阴影部分是墙和终点的位置,由于无法到达墙、到达终点后游戏结束,所以这两个位置不会更新Q值。
上表的解释:在(0,0)位置时(对应当前状态),Q值在行为"down"处最大为4.8,因此应该向下走,下一个状态是(1,0)。其余位置类似。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0ec1305e93dc432bbcbab2fb9bbd238d.png
红色箭头表示每一个状态的最优行为,绿色箭头表示用该方法计算得出的最优路线。

DQN(深度Q-learning)

DQN和Q学习的主要区别在于如何表示和更新Q值,DQN使用神经网络来近似Q值函数,而不是使用表格。

经验回放

经验回放(Experience Replay)是强化学习中的一个重要技术,主要用于解决强化学习算法中的一些问题,提高算法的稳定性和学习效率。
在这里插入图片描述
具体来说,就是不每次都立刻进行Q值计算和反向传播,而是将每次的<状态、动作、状态转移>(称为经验样本或经验元组)先放到缓冲区,然后每次从缓冲区取一部分一次性计算。类似计算机视觉中同时对数据集中的多张图片进行处理,大小表示为batch_size。

原理

其实就是将Q学习中需要查Q-table的时候都用网络替换。旧的Q表值和奖励共同作用下更新为新的Q表值。

(我以前一直以为是要让Q值越来越拟合奖励,所以很奇怪,明明奖励的公式我们已经知道了,还要怎么去学习呢,其实奖励只是作为一个已知的数值加入到计算中,并不是说我们要去模拟奖励的生成方式。)

Q-learning中的贝尔曼方程:
Q ( s , a ) ← Q ( s , a ) + α [ r + γ max ⁡ a ′ Q ( s ′ , a ′ ) − Q ( s , a ) ] Q(s,a)←Q(s,a)+α[r+γ\max_{a'}Q(s',a')-Q(s,a)] Q(s,a)Q(s,a)+α[r+γamaxQ(s,a)Q(s,a)]
可以写为:
Q ( s , a ) ← ( 1 − α ) Q ( s , a ) + α [ r + γ max ⁡ a ′ Q ( s ′ , a ′ ) ] Q(s,a)←(1-α)Q(s,a)+α[r+γ\max_{a'}Q(s',a')] Q(s,a)(1α)Q(s,a)+α[r+γamaxQ(s,a)]
就像加权求和,它在原来Q的基础上加上了一部分奖励作用下的分数。

深度Q-learning中的损失函数:
L ( θ ) = E s , a , r , s ′ [ ( Q θ ( s , a ) − ( r + γ max ⁡ a ′ Q θ − ( s ′ , a ′ ) ) ) 2 ] L(θ)=\mathbb{E}_{s,a,r,s'}[(Q_θ(s,a)-(r+γ\max_{a'}Q_{θ^-}(s',a')))^2] L(θ)=Es,a,r,s[(Qθ(s,a)(r+γamaxQθ(s,a)))2]

它就是使计算得到的Q值逐渐趋于稳定,基本上等于那个奖励作用下的分数,这个分数不仅考虑了当前奖励,还考虑了下一步能够得到的分数。注意上式中有两组参数,分别为 θ θ θ θ − θ^- θ,对应两个网络(结构一样)。

  • Q θ ( s , a ) Q_θ(s,a) Qθ(s,a)通过主网络训练得到
    主网络(Main Network)也称为在线网络(Online Network)或当前网络(Current Network)。主网络负责学习环境中的状态-动作值函数(Q函数),即预测在给定状态下采取某个动作所能获得的预期回报。主网络通过梯度下降等优化算法不断更新其参数,以最小化预测Q值和实际Q值之间的差距。主网络直接与环境交互,根据采集到的经验(状态、动作、奖励、下一个状态)进行学习。
  • max ⁡ a ′ Q θ − ( s ′ , a ′ ) \max_{a'}Q_{θ^-}(s',a') maxaQθ(s,a)由目标网络计算
    目标网络(Target Network)是主网络的一个延迟更新版本,其参数定期从主网络复制过来。目标网络不直接参与学习,而是为主网络提供一个稳定的训练目标。在计算Q值的目标值时,使用目标网络来预测下一个状态下的Q值,这样可以减少学习过程中的方差,使学习更加稳定。目标网络的更新频率通常低于主网络,例如,每几千个时间步更新一次。

说明通过神经网络得到的Q值不仅体现了当前决策的奖励,还综合了未来的奖励。

模拟

参数设计

  1. 奖励规则:到达终点奖励+100;到达墙壁或超出迷宫奖励-10;其他情况奖励分值为6-到出口最短路线距离(假设这些距离提前都计算好了)。比如走到(1,0)+3,走到(2,2)+4,走到(0,1)-10,走到(0,2)+100。迷宫格内的奖励矩阵可以表示为:
    在这里插入图片描述
  2. 贝尔曼方程参数: α = 0.001 α=0.001 α=0.001 γ = 0.99 γ=0.99 γ=0.99
  3. 网络输入:状态 s s s,由二维坐标表示。从上往下三行的行号分别为0、1、2,从左到右三列的列标号分别为0,1,2,(0,0)是起点位于左上角,(0,2)是终点位于右上角。
  4. 网络输出:每个动作的Q值。
  5. 隐藏层架构:1层,16个神经元,激活函数为ReLU。
  6. ε-贪婪策略:初始阶段,以较高概率ϵ(设置为1.0)随机选择动作。随着训练进行,逐渐降低ϵ(最后衰减到0.01),更多地依赖网络预测的动作。
  7. 经验回放:缓冲区大小为 10 , 000 10,000 10,000 b a t c h s i z e = 32 batch_{size}=32 batchsize=32
  8. 同步目标网络步长为100。

学习过程

  1. 初始化将智能体放置在起点(0,0)
  2. 选择动作。使用ε-贪婪策略选择动作a。如果 r a n d o m < ϵ random<ϵ random<ϵ,随机选择动作。否则,选择 a r g max ⁡ a Q θ ( s , a ) arg\max_aQ_θ(s,a) argmaxaQθ(s,a)
  3. 执行动作:根据选定的动作 a a a,更新智能体的位置 s ′ s′ s。如果超出迷宫范围或撞到障碍墙,给予奖励 -10 并结束回合。如果到达终点 (0, 2),给予奖励 100 并结束回合。否则,根据奖励矩阵 R R R给出奖励 r r r
  4. 存储经验:将经验存入缓冲区。
  5. 采样并更新网络:从缓冲区中随机采样一批数据计算目标值。
    更新主网络参数 θ θ θ以最小化损失函数 L ( θ ) L(θ) L(θ)
  6. 同步目标网络:每隔若干步,将主网络参数复制到目标网络。
  7. 测试(关闭探索,使用网络预测的动作观察智能体是否能够成功从起点走到终点)。

【欢迎指正】

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

相关文章

什么是死锁?构成死锁的条件如何解决

什么是死锁&#xff1f;构成死锁的条件&如何解决 1. 什么是死锁 在计算机科学中&#xff0c;死锁是一种非常常见且棘手的问题。从线程和锁的角度来看&#xff0c;死锁主要存在三种典型情况&#xff1a;一线程一锁、两线程两锁以及 M 线程 N 锁。接下来&#xff0c;我们将…

微信小程序源码逆向 MacOS

前言 日常工作中经常会遇到对小程序的渗透测试&#xff0c;微信小程序的源码是保存在用户客户端本地&#xff0c;在渗透的过程中我们需要提取小程序的源码进行问题分析&#xff0c;本篇介绍如何在苹果电脑 MacOS 系统上提取微信小程序的源码。 0x01 微信小程序提取 在苹果电…

HTML解析 → DOM树 CSS解析 → CSSOM → 合并 → 渲染树 → 布局 → 绘制 → 合成 → 屏幕显示

一、关键渲染流程 解析 HTML → 生成 DOM 树 浏览器逐行解析 HTML&#xff0c;构建**DOM&#xff08;文档对象模型&#xff09;**树状结构 遇到 <link> 或 <style> 标签时会暂停 HTML 解析&#xff0c;开始加载 CSS 解析 CSS → 生成 CSSOM 将 CSS 规则解析为**…

Pycharm-Version: 2024.3.3导入conda环境

打开一个新项目&#xff0c;点击File->Settings 找到Project->python interpreter 新增环境&#xff0c;点击add interpreter->add local interpreter 点击select existing->conda&#xff0c;选择地址为&#xff1a;anoconda/library/bin/conda.bat&#xff0c…

Fisher散度:从信息几何到机器学习的隐藏利器

Fisher散度&#xff1a;从信息几何到机器学习的隐藏利器 在机器学习和统计学中&#xff0c;比较两个概率分布的差异是常见任务&#xff0c;比如评估真实分布与模型预测分布的差距。KL散度&#xff08;Kullback-Leibler Divergence&#xff09;可能是大家熟悉的选择&#xff0c…

C++ | 高级教程 | 信号处理

&#x1f47b; 概念 信号 —— 操作系统传给进程的中断&#xff0c;会提早终止程序有些信号不能被程序捕获&#xff0c;有些则可以被捕获&#xff0c;并基于信号采取适当的动作 信号描述SIGABRT程序的异常终止&#xff0c;如调用 abortSIGFPE错误的算术运算&#xff0c;比如除…

文件上传漏洞学习笔记

一、漏洞概述 定义 文件上传漏洞指未对用户上传的文件进行充分安全校验&#xff0c;导致攻击者可上传恶意文件&#xff08;如Webshell、木马&#xff09;&#xff0c;进而控制服务器或执行任意代码。 危害等级 ⚠️ 高危漏洞&#xff08;通常CVSS评分7.0&#xff09;&#xff…

PDF转HTML 超级好用 免费在线转换PDF 完美转换格式

PDF转HTML 超级好用 免费在线转换PDF 完美转换格式&#xff0c;PDF已成为一种广泛使用的文件格式&#xff0c;用于保存和分享文档。然而&#xff0c;PDF文件在某些场景下可能不够灵活&#xff0c;特别是在需要在网页上直接展示其内容时。为了满足这一需求&#xff0c;小白工具推…