快乐的强化学习1——Q_Learning及其实现方法

2023-10-27

快乐的强化学习1——Q_Learning及其实现方法

学习前言

刚刚从大学毕业,近来闲来无事,开始了机器学习的旅程,深度学习是机器学习的重要一环,其可以使得机器自我尝试,并通过结果进行学习。
在这里插入图片描述
在机器学习的过程中,我自网上了解到大神morvanzhou,一个从土木工程转向了计算机的“聪明绝顶”的、英语特好的男人。本篇文章便是按照他的深度学习教程中的Qlearning部分撰写的。
morvanzhou的python个人主页,请有兴趣的同学关注大神morvanzhou的python教程。

简介

Q-Learning是一种value-based算法,即通过判断每一步进行的价值value来进行下一步的动作,以人物的左右移动为例子,Q-Learning的核心Q-Table可以按照如下表示:

环境 'Left‘ ‘Right’
1 0 0.125
2 0.001 0.132
3 0.013 0.231

当人物处于环境1的时候,此时进行’Right‘步骤的得分为0.125,进行’Left‘步骤的得分为0,此时对于Q-Learning算法而言,其会优先选择进行’Right‘步骤,此时人物往右方向走一步,抵达同时新环境,在新环境下,Q-Learning算法会进行新的判断。在实际运用中,如果人物处于环境1,我们在进行算法初始化的时候给给予其一个e_greedy值,处于0-1之间,在e_greedy值的几率内,其会选择分值大的’Right‘步骤,如果不在则随机选择。这种设定可以让算法更多的进行尝试。

Q-Learning算法的实现

接下来我将以小男孩取得玩具为例子,讲述Q-Learning算法的执行过程。
小男孩取得玩具
在一开始的时候假设小男孩不知道玩具在哪里,他的Q_Table一片空白,此时他开始观测自己所处的环境,这个环境是环境1,并将这个环境加入到Q_Table中。此时,他不知道左右两个环境的情况,所以向左走向右走的得分都是0,这两个得分都是小男孩心中预测出来的,并不是真实的左右两个环境的得分,我们给这个得分一个名字叫做q_predict

环境 'Left‘ ‘Right’
1 0 0

他往左走往右走都是有可能的,如果他往左走,他会到达环境0,环境0是一个深渊,然后小男孩就挂了。此时环境会给他一个反馈得分,由于他掉入了深渊,所以他的得分是-1,这个得分是环境0的实际得分,与上面小男孩处于环境1对环境0的预测得分不同,我们给这个得分一个名字叫做q_target由于这个得分与上一步预测的环境0的得分不同,所以我们需要对上一个表格进行更新,这个得分会乘上学习率后在环境1的’Left’ Action得到体现。此时他的Q_Table表为。

环境 'Left‘ ‘Right’
1 -0.01 0

此时小男孩重生了,在这一轮他会选择往右走,此时他又到达了一个新环境,此时他开始观测自己所处的环境,这个环境是环境2,并将这个环境加入到Q_Table中。此时,他不知道这个新环境的情况,向左走和向右走对他来说是一样的,所以这个新环境的左右两个Actions得分都是0。

环境 'Left‘ ‘Right’
1 -0.01 0
2 0 0

此时他会随机选择一个方向走,之后不断重复探测新环境和走回旧环境的过程,如果他在不断测试中找到了最后的toys,他会得到正数得分,这个得分会一步一步驱使他走向toys。在经过许多次的尝试之后,小男孩会找到一条最快通向玩具的道路。假设环境4就是玩具,小男孩在经过多次尝试后,最后的Q_Table可能是这样。

环境 'Left‘ ‘Right’
1 -0.020 0.033
2 0.001 0.154
3 0.000 0.547

对于Q-Learning算法的主体而言,Q-Learning算法主要由两个对象组成,分别是Q-Learning的大脑大环境
Q-Learning的大脑包括以下部分,其对应的功能为

模块名称 作用/功能
初始化 初始化学习率、可执行动作、Q_table等参数
动作选择 根据小男孩当前所处的环境和Q_table进行动作选择
学习 根据小男孩当前所处的环境对其它环境的预测情况q_predict和下一步环境的实际情况q_target更新Q_table表
确认是否存在该环境 由于在学习之前环境是未知的,当进入一个新环境时,需要生成一个得分都为0的动作表格

大环境包括以下部分,其对应的功能为

模块名称 作用/功能
初始化 初始化环境参数、用于构建环境
图画更新 用于更新当前的图画,便于用户观察
环境观察 用于返回当前环境情况
终点观察 用于返回是否到达终点
更新坐标 用于更新当前所处位置
下一环境获取 用于获取下一步的环境的实际情况
参数归零 用于每一个世代坐标和当前行走步数的归零

在完成两个对象的构建后,需要有一个主函数将两个对象联系起来使用,主函数需要完成以下功能,我将以伪代码的形式呈现:

初始化测试环境对象
初始化Q-Learning的大脑对象
for episode in range(TIMES):
	环境观察
	图画更新
	while(1):
		终点观察
		if(到达终点):
			打印当前进行世代数,共使用多少步数
			参数归零
			break;
		动作选择
		获取下一步的环境的实际情况
		学习
		更新坐标
		图画更新

在观察完Q_Learning算法的伪代码形式我们可以发现,其大脑每次学习的过程都是在获取下一步的环境的实际情况之后的,学习函数对Q-Table表更新的重要参数之一就是获取下一步的环境的实际情况。具体来说,在进行学习过程时,Q-Learning的大脑对象会根据所处的当前环境对各个动作的预测得分下一步的环境的实际情况(最大得分)当前环境的Q-Table表进行更新,具体的代码如下所示:

 def learn(self,observation_now,action,score,observation_after,done):
     self.check_observation(observation_after)        #检查是否存在下一步的环境对应的方向状态
     q_predict = self.q_table.loc[observation_now,action]        #所处的当前环境对下一个动作的预测得分
     if done:
         q_influence = score     #如果完成了则下一个环境的实际情况得分为1
     else:
         q_influence = score + self.gamma * self.q_table.loc[observation_after, :].max()  #如果未完成则取下一个环境若干个动作中的最大得分作为这个环境的价值传递给当前环境
     self.q_table.loc[observation_now, action] += self.lr * (q_influence - q_predict)  #更新当前观测状态对应的Q值

具体实现代码

具体的实现代码分为三个部分,这是第一部分,Q-Learning的大脑:

import numpy as np
import pandas as pd

class QL:
    def __init__(self, actions, learning_rate=0.05, reward_decay=0.9, e_greedy=0.9):
        self.actions = actions      #初始化可以进行的各种行为,传入为列表
        self.lr = learning_rate     #学习率,用于更新Q_table的值
        self.gamma = reward_decay   #当没有到达终点时,下一环境对当前环境的影响
        self.epsilon = e_greedy     #随机选择几率为1-e_greedy,当处于e_greedy内时,不随机选择。
        self.q_table = pd.DataFrame(columns=self.actions, dtype=np.float64)     #生成q_table,列向量为columns

    def choose_action(self,observation):
        self.check_observation(observation)        #检测是否到达过这个点,如果没到达过,在Q表中增加这个节点
        action_list = self.q_table.loc[observation,:]           #取出当前observation所在的不同方向
        
        if(np.random.uniform() < self.epsilon):    #如果在epsilon几率内
            action = np.random.choice(action_list[action_list == np.max(action_list)].index)    #选出当前observation中Q值最大的方向
        else:
            action = np.random.choice(self.actions)      #如果不在epsilon内,则随机选择一个动作
        return action                                    #返回应当做的action

    def learn(self,observation_now,action,score,observation_after,done):
        self.check_observation(observation_after)        #检查是否存在下一环境对应的方向状态
        q_predict = self.q_table.loc[observation_now,action]        #获得当前状态下,当前所作动作所对应的预测得分
        if done:
            q_target = score     #如果完成了则q_target为下一个环境的实际情况得分,本例子中此时score为1
        else:
            q_target = score + self.gamma * self.q_table.loc[observation_after, :].max()  #如果未完成则取下一个环境若干个动作中的最大得分作为这个环境的价值传递给当前环境
        #根据所处的当前环境对各个动作的预测得分和下一步的环境的实际情况更新当前环境的q表
        self.q_table.loc[observation_now, action] += self.lr * (q_target - q_predict)  

    def check_observation(self,observation):
        if observation not in self.q_table.index:               #如果不存在 
            self.q_table = self.q_table.append(                 #则通过series函数生成新的一列
                pd.Series(
                    [0]*len(self.actions),
                    index=self.actions,
                    name=observation,)
            )

第二部分是环境的构建:

import numpy as np
import pandas as pd
import time 

class Env:
    def __init__(self,column,maze_column):
        self.column = column                        #表示地图的长度
        self.maze_column = maze_column - 1          #宝藏所在的位置
        self.x = 0                                  #初始化x
        self.map = np.arange(column)                #给予每个地点一个标号
        self.count = 0                              #用于技术一共走了多少步
        

    def draw(self):
        a = []
        for j in range(self.column) :               #更新图画
            if j == self.x:
                a.append('o')
            elif j == self.maze_column:
                a.append('m')
            else:
                a.append('_')
        interaction = ''.join(a)
        print('\r{}'.format(interaction),end = '')
        

    def get_observation(self):
        return self.map[self.x]                     #返回现在在所


    def get_terminal(self):
        if self.x == self.maze_column:              #如果得到了宝藏,则返回已经完成
            done = True
        else:
            done = False
        return done


    def update_place(self,action):
        self.count += 1                              #更新的时候表示已经走了一步
        if action == 'right':                                  
            if self.x < self.column - 1:
                self.x += 1
        elif action == 'left':   #left
            if self.x > 0:
                self.x -= 1

    def get_target(self,action):
        if action == 'right':                        #获得下一步的环境的实际情况
            if self.x + 1 == self.maze_column:
                score = 1
                pre_done = True
            else:
                score = 0
                pre_done = False
            return self.map[self.x + 1],score,pre_done
        elif action == 'left':   #left
            if self.x - 1 == self.maze_column:
                score = 1
                pre_done = Ture
            else:
                score = 0
                pre_done = False
            return self.map[self.x - 1],score,pre_done
        


    def retry(self):            #初始化
        self.x = 0
        self.count = 0

其运行的主函数为:

from Env import Env
from QL import QL
import numpy as np
import time

LONG = 6                    #总长度为6
MAZE_PLACE = 6              #宝藏在第六位
TIMES = 15                  #进行15次迭代

people = QL(['left','right'])       #生成QLearn主体的对象,包含left和right
site = Env(LONG,MAZE_PLACE)         #生成测试环境
for episode in range(TIMES):
    state = site.get_observation()  #观察初始环境
    site.draw()                     #生成图像
    time.sleep(0.3)                 #暂停
    while(1):
        done = site.get_terminal()  #判断当前环境是否到达最后
        if done:                    #如果到达,则初始化
            interaction = '\n第%s次世代,共使用步数:%s。'%(episode+1 ,site.count)
            print(interaction)
            site.retry()
            time.sleep(2)
            break
        action = people.choose_action(state)                        #获得下一步方向
        state_after,score,pre_done = site.get_target(action)    #获得下一步的环境的实际情况
        people.learn(state,action,score,state_after,pre_done)       #根据所处的当前环境对各个动作的预测得分和下一步的环境的实际情况更新当前环境的q表
        site.update_place(action)                                   #更新位置
        state = state_after                                         #状态更新
        site.draw()                                                 #更新画布
        time.sleep(0.3)
    

print(people.q_table)

每一段代码我都给予了详细的注释,三个文件的名称分别为 QL.pyEnv.pyTest.py
(不知道为什么这个编辑器给我生成了个什么网页……- -)

GITHUB下载连接

https://github.com/bubbliiiing/Reinforcement-Learning

希望得到朋友们的喜欢。

有不懂的朋友可以评论询问噢。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

快乐的强化学习1——Q_Learning及其实现方法 的相关文章

随机推荐

  • R语言回归模型中的训练集和测试集划分

    训练集和测试集划分 set seed 1234 nn 0 8 data iris length iris 1 sub lt sample 1 nrow data round nrow data nn length sub data trai
  • Word‘由于宏安全设置 无法找到宏’问题解决

    针对这个问题 尝试试很多网上的做法无果后 意外发现是自己电脑的杀毒软件把该文件误认为是病毒隔离起来 只需将其恢复到信任区即可 若仍无法解决 检查word是否启用宏
  • 我靠TikTok抖音赚到了人生第一桶金:这个风口行业,真的很赚钱

    现代人的 懒 简直超乎你想象 吃饭靠外卖 买东西靠快递 凡是一切你能想到的 麻烦 现代科技都能替你搞定 而这 恰恰是一种新型的赚钱方式 十年前的淘宝被人嘲笑 说这是马云的异想天开 十年后的淘宝 拼多多 京东告诉你 这一切都已成真 而且带着一
  • 虚拟机迁移原理

    我们常常遇到需要迁移虚拟机的问题 比如需要维护某台设备 会将设备上的一切应用迁移到另一台设备 但是如何将虚拟机进行迁移呢 好比说 虚拟机中正在运行一个程序 这个程序有源源不断的数据访问 怎么使得在不影响这些访问的情况下把虚拟机迁移到领一台服
  • C语言图形库——EasyX常用函数

    上节讲到贴出一张图片的过程 本节接着介绍一些基本的图形库函数 头文件 include
  • 深入浅出SSD--5.1PCIE基础知识

    深入浅出SSD 5 1PCIE基础知识 1 关于PCIE的速度 SSD使用PCIe接口比SATA快 下面是PCIE1 0 2 0 3 0速度 表中的带宽 比如PCIe3 0 1 带宽为2GB s 是指双向带宽 即读写带宽 如果单指读或者写
  • 本周最新文献速递20220522

    本周最新文献速递20220522 一 精细解读文献 一 文献题目 Single nucleus chromatin accessibility profiling highlights regulatory mechanisms of co
  • xml转换word文档

    点击下载 download value flag let this this this axios method get url url lengthMeasurementTwice params machineId this machin
  • http请求头origin、referer和host区别

    1 Host 描述请求将被发送的目的地 包括且仅仅包括域名和端口号 HTTP 1 1 的所有请求报文中必须包含一个Host头字段 且只能设置一个 2 Origin 请求头origin表明了请求来自于哪个站点 包括且仅仅包括协议 域名和端口
  • 创维机顶盒E900刷LinuxNas系统

    家里有一个一直没用的创维E900的机顶盒 芯片是海思 hi3798v100 的 本着废物利用的原则 我想将他刷成linux 没想到网上真的有教程 https histb com 我看了一下 以我现在的技术 问题不大 大不了变砖罢了 反正都是
  • js 中数字小数点末尾的0显示与否

    js 中数字小数点末尾的0显示与否 不显示0 显示0 数字格式化 不显示0 我们先来看一道例题 然后围绕其展开 零 的讨论 问题 得到一个随机数组成的数组 数组长度为10 结果类似于 0 243 0 162 0 701 0 501 此处封装
  • Learn OpenGL with Qt——模型加载:Qt搭建Assimp环境

    如果你是中途开始学习本教程的 即使你对OpenGL已经非常熟悉 请至少了解以下几个章节 因为Qt中提供了OpenGL的很多便捷操作 熟悉这些操作可以让我们在Qt中高效的使用OpenGL进行绘图 创建OpenGL窗口 着色器程序以及着色器的创
  • 如何克服看到别人优于自己而感到的焦虑和迷茫?

    文章目录 每日一句正能量 前言 简述自己的感受 怎么做 如何调整自己的心态 后记 每日一句正能量 行动是至于恐惧的良药 而犹豫 拖延 将不断滋养恐惧 前言 虽然清楚知识需要靠时间沉淀 但在看到自己做不出来的题别人会做 自己写不出的代码别人会
  • 使用Java显示图片

    之前学习C和C 时总是和数据打交道 也许是学的浅薄的关系 当时觉得显示界面和图像是如此的神秘 如今学习了一段时间的Java 发现其实界面什么的也不是那么的难懂 下面写一个简单的例子 让我们的java为我们展示张图片来看看吧 面板源码 jav
  • [LLVM教程]LLVM之第一个语言前端

    目录 LLVM教程 LLVM之第一个语言前端 LLVM教程 LLVM之第一个语言前端 万花筒 介绍与词法分析器 LLVM Tutorial Table of Contents LLVM 17 0 0git documentation LLV
  • 统计学习方法EM课后答案

    https sine x com statistical learning method 第9章 em算法及其推广 https blog csdn net weixin 35479108 article details 87894136 h
  • STM32入门——外部中断

    中断系统概述 中断 在主程序运行过程中 出现了特定的中断触发条件 中断源 使得CPU暂停当前正在运行的程序 转而去处理中断程序 处理完成后又返回原来被暂停的位置继续运行 中断优先级 当有多个中断源同时申请中断时 CPU会根据中断源的轻重缓急
  • Cannot read property 'newLine' of undefined

    angularjs报错 ERROR in src main ts Module build failed TypeError Cannot read property newLine of undefined at Object getNe
  • GitLab(Gitee)配置SSH key

    1 我们已经有了gitlab的账户 项目组已经将我们添加到了group 2 打开git bash 输入命令 ls al ssh 如果显示如下图 则表示生成过key 可以去执行第4个步骤 否则的话执行第三个步骤生成key 3 输入命令 ssh
  • 快乐的强化学习1——Q_Learning及其实现方法

    快乐的强化学习1 Q Learning及其实现方法 学习前言 简介 Q Learning算法的实现 具体实现代码 GITHUB下载连接 学习前言 刚刚从大学毕业 近来闲来无事 开始了机器学习的旅程 深度学习是机器学习的重要一环 其可以使得机