小白一个,不会强化学习,也不会写博客,不知道从何入手。。。
先看看b站莫烦Python的视频,嘻嘻~
链接: 莫烦Python-强化学习.
Q-Learning算法
问题:
比如在x坐标轴上有5个位置:_ _ _ _ _
小人的起始点在最左边的位置,宝藏在最右侧的位置,即:x _ _ _ T ;
目的是不断训练让小人最快找到宝藏。
我的理解就是首先有一个初始的Q表,比如像下面这样:
状态/动作 | a0 | a1 |
---|---|---|
s0 | 0 | 2 |
s1 | 2 | 2 |
s2 | 2 | 1 |
s3 | 1 | 2 |
s4 | 2 | 0 |
其中s0 ,s1,… 表示状态0,状态1…,这里有5个位置对应就有5个状态;
其中a0,a1表示动作,因为只能向左和向右,所以只有两个状态。
小人的移动根据Q表中的值来进行判断,比如在状态0时,对应表里的第一行,这一状态a1的值更大,所以选择动作为a1,即向右移动。
移动后会根据奖励更新Q表的值(这里我没有搞得特别清楚)。
然后因为向右移动了一步所以状态变成了s1,然后再根据Q表选择动作…如此周而往复,不断迭代。Q表最后就变成了我们想要的,能够驱动小人以最快速度找到宝藏。
当然具体过程应该比这复杂地多,但是可以就先这么理解;
莫烦Python中给出的伪代码是这样的:
代码实现
1. 加载依赖包
#导入包
import numpy as np
import pandas as pd
import time
2. 初始化
#设置全局变量
N_STATES=5 #表示有5个状态
ACTIONS=['left','right']#可选动作
EPSILON=0.9#选择动作时以0.9的概率根据Q表进行选择,0.1的概率为随机选择
ALPHA=0.1#学习率
LAMBDA=0.9#衰减度
MAX_EPISODES=13#最大的迭代次数
FRESH_TIME=0.3#走一步花的时间
3. 创建Q表
def buildQTable(states,actions):
table=pd.DataFrame(np.zeros((states,len(actions))),columns=actions)
print(table)
return table
创建Q表如下:
其中Q表中的值都初始化为0.
4. 选择动作
#根据当前状态和Q表选择动作
def chooseAction(state,qTable):
actionName=None
stateActions=qTable.iloc[state,:]
temp=np.random.uniform()#产生一个随机数
#如果概率小于0.1时使用随机产生的动作,如果还存在0,即还没有更新无法比较,也进行随机选择
if (temp>EPSILON or stateActions.all()==0):
actionName=np.random.choice(ACTIONS)
else:#一般情况,选择Q值最大的那个动作
actionName=stateActions.idxmax()
return actionName
这个函数在初始状态下,运行结果如下:
#在初始状态下运行
actionTemp=chooseAction(0,tableTemp)
print(actionTemp)
#结果为
left
5. 构造环境
在当前状态S下采取的动作A,环境应该告诉我们下一个状态S_和获得的奖励R。
def getEnvFeedback(S,A):
if A=="right":
if S==N_STATES-2:#下一步找到宝藏
S_="terminal"
R=1
else:
S_=S+1
R=0
else:
if S==0:#如果当前状态是0,下一步继续停留在0处
S_=0
R=0
else:
S_=S-1
R=0
return S_,R
例如在状态2,执行动作"right":
sTemp,RTemp=getEnvFeedback(2,"right")
print(sTemp)
print(RTemp)
#结果为:
3
0
6. 显示环境
因为这个不重要,视频中的代码没仔细看,自己写了个。
def showEnv(s,episode,stepCount):
if s=="terminal":#已经结束
for i in range(N_STATES-1):
print("-",end="")
print("o,episode={},stepCount={}".format(episode,stepCount))
else:
for i in range(N_STATES):
if s==i:
print("o",end="")
elif i==N_STATES-1:
print("T",end="")
else:
print("-",end="")
print()
7. 主函数
def main():
QTable=buildQTable(N_STATES,ACTIONS)
for episode in range(MAX_EPISODES):
stepCount=0
S=0#初始状态为0
showEnv(S,episode,stepCount)#首先显示一下初始状态
while S!="terminal":#当没有找到宝藏时一直循环
A=chooseAction(S,QTable)#选择一个动作
S_,R=getEnvFeedback(S,A)#进行这个动作后得到下一个状态S_和奖励R
#更新Q表
if S_=="terminal":
q_target=R
else:
q_target=R+LAMBDA*QTable.iloc[S_,:].max()
QTable.loc[S,A]+=ALPHA*(q_target-QTable.loc[S,A])
S=S_
stepCount+=1
showEnv(S,episode,stepCount)#显示状态
return QTable
运行结果如下:
o---T
o---T
-o--T
o---T
-o--T
--o-T
---oT
----o,episode=0,stepCount=7
o---T
o---T
o---T
-o--T
o---T
o---T
o---T
-o--T
o---T
o---T
-o--T
o---T
-o--T
--o-T
---oT
----o,episode=1,stepCount=15
o---T
o---T
-o--T
--o-T
---oT
----o,episode=2,stepCount=5
o---T
-o--T
--o-T
-o--T
--o-T
---oT
--o-T
---oT
----o,episode=3,stepCount=8
o---T
o---T
-o--T
o---T
-o--T
--o-T
---oT
----o,episode=4,stepCount=7
o---T
o---T
-o--T
--o-T
---oT
----o,episode=5,stepCount=5
o---T
-o--T
--o-T
---oT
----o,episode=6,stepCount=4
o---T
-o--T
--o-T
---oT
----o,episode=7,stepCount=4
o---T
-o--T
--o-T
-o--T
--o-T
---oT
----o,episode=8,stepCount=6
o---T
-o--T
o---T
-o--T
--o-T
---oT
----o,episode=9,stepCount=6
o---T
-o--T
--o-T
---oT
----o,episode=10,stepCount=4
o---T
-o--T
--o-T
---oT
----o,episode=11,stepCount=4
o---T
-o--T
--o-T
---oT
----o,episode=12,stepCount=4
可以从结果中看出,开始的几次迭代用的步数较长,后来步数就非常短。
最后的Q表如下:
从中也能看出,经过多次迭代后right的概率高于left的概率,说明已经学习到了规律,能够迅速找到宝藏。