参考于:Step-By-Step Tutorial
极简Qlearning教程
假设有这样的大房间,
有门表示相互连通,将房间表示为点,连通关系表示为线,则上图可以建模为:
假设有个机器人处在任意某一个房间,它的最终目标是走到房间5。为了表示能走到房间5,我们在能直接到达房间5的边权重设为100,其他不能到达的边设为0,不存在的边设为-1(比如0和2之间不在直达路径)。则该问题就抽象为:
在Qlearning中,最重要的就是“状态”和“动作”,状态表示处于图中的哪个房间,比如2房间,而动作则表示从一个节点到另一个节点的操作,如从2房间到3房间。
Q learning
- 1.S表示当前的状态
- 2.a表示当前的动作 (在本例中实际上指的是下一个状态)
- 3.s~表示下一个状态
- 4.a~表示下一个动作
- 5.λ为贪婪因子,0<λ<1,一般设置为0.8
下面是Q learning 算法步骤
当Q表学习完之后,就可以根据q表来选择最优的路径了。
例子:
首先根据上图生成一个reward矩阵:
同时我们创建一个Q表,与R同阶,Q表初始化为0矩阵。
取学习参数γ为0.8,刚开始随机选择一个状态如1,这时查看R表可知,s=1时下一步可以到达3和5,随机地,选取状态5,而状态5的下一个状态可能为1,4,5。根据状态转移方程,我们有
注意这里Q表初始化为0。
所以,Q表更新为:
这样,现在状态5变成了当前状态,一次episode结束。
下一次尝试,也就是下一个episode,随机选择一个状态s=3,其下一个为1 or 2 or 4。随机选取状态1,下一步为3 or 5。所以有:
这样,Q表为:
现在状态为1,同上,再选择3or5 ,假设选5,5的下一个状态是1,4,5。有:
q表不变。
至此第二次episode结束。若执行更过的episode,矩阵Q将最终收敛为:
一旦矩阵Q足够接近于收敛状态,agent便学习到了转移至目标函数的最佳路径。在得到Q表后,可根据下列方法得到最佳路径:
例如,假设初始状态为2,那么根据Q表,选2-3。到达s=3之后,可选的有1,2,4。根据Q表,选最大的价值,所以选3-1。到达s=1之后,再选择1-5。所以路径为2-3-1-5。
代码如下:
import numpy as np
import random
# 建立 Q 表
q = np.zeros((6, 6))
# 建立 R 表
r = np.array([[-1, -1, -1, -1, 0, -1],
[-1, -1, -1, 0, -1, 100],
[-1, -1, -1, 0, -1, -1],
[-1, 0, 0, -1, 0, -1],
[0, -1, -1, 0, -1, 100],
[-1, 0, -1, -1, 0, 100]])
# 衰减指数
gamma = 0.8
# 训练
for i in range(1000): #训练1000次
# 对每一个训练,随机选择一种状态
state = random.randint(0, 5)
while state != 5:#(这里就是每次episode,即每次尝试,直到5为止)
# 选择r表中非负的值的动作
r_pos_action = []
for action in range(6):
if r[state, action] >= 0:
r_pos_action.append(action)
next_state = r_pos_action[random.randint(0, len(r_pos_action) - 1)]
q[state, next_state] = r[state, next_state] + gamma * q[next_state].max()
state = next_state
print(q)
# 验证
for i in range(10):
print("第{}次验证".format(i + 1))
state = random.randint(0, 5)
print('机器人处于{}'.format(state))
count = 0
while state != 5:
if count > 20:
print('fail')
break
# 选择最大的q_max
q_max = q[state].max()
q_max_action = []
for action in range(6):
if q[state, action] == q_max:
q_max_action.append(action)
next_state = q_max_action[random.randint(0, len(q_max_action) - 1)]
print("the robot goes to " + str(next_state) + '.')
state = next_state
count += 1
输出结果:
[[ 0. 0. 0. 0. 80. 0. ]
[ 0. 0. 0. 64. 0. 100. ]
[ 0. 0. 0. 64. 0. 0. ]
[ 0. 80. 51.2 0. 80. 0. ]
[ 64. 0. 0. 64. 0. 100. ]
[ 0. 0. 0. 0. 0. 0. ]]
第1次验证
机器人处于0
the robot goes to 4.
the robot goes to 5.
第2次验证
机器人处于1
the robot goes to 5.
第3次验证
机器人处于5
第4次验证
机器人处于1
the robot goes to 5.
第5次验证
机器人处于2
the robot goes to 3.
the robot goes to 4.
the robot goes to 5.
第6次验证
机器人处于4
the robot goes to 5.
第7次验证
机器人处于3
the robot goes to 4.
the robot goes to 5.
第8次验证
机器人处于0
the robot goes to 4.
the robot goes to 5.
第9次验证
机器人处于0
the robot goes to 4.
the robot goes to 5.
第10次验证
机器人处于0
the robot goes to 4.
the robot goes to 5.
输出Q表和计算的q表不一致,是因为存在while !=5,即5已经是目标状态。
另一种代码
import numpy as np
import random
q= np.zeros((6, 6))
# 回报函数,在状态state采用action转移到next_state的回报,横纵坐标分别为state和next_state
reward = np.array([[-1, -1, -1, -1, 0, -1],
[-1, -1, -1, 0, -1, 100],
[-1, -1, -1, 0, -1, -1],
[-1, 0, 0, -1, 0, -1],
[0, -1, -1, 0, -1, 100],
[-1, 0, -1, -1, 0, 100]])
legal_action = [[4], #每个状态所能进行的操作
[3, 5],
[3],
[1, 2, 4],
[0, 3, 5],
[1, 4, 5]]
GAMMA = 0.8
TRAINING_STEP = 1000
for i in range(1, TRAINING_STEP + 1):
state = random.randint(0, 4) #0-5随机状态
# 百分百探索,随机产生next_state
next_state = random.choice(legal_action[state])
q[state, next_state] = reward[state, next_state] + GAMMA * q[next_state].max()
print(q)
for i in range(10):
print("第{}次验证".format(i + 1))
state = random.randint(0, 5)
print('机器人处于{}'.format(state))
count = 0
while state != 5:
if count > 20:
print('fail')
break
# 选择最大的q_max
q_max = q[state].max()
q_max_action = []
for action in range(6):
if q[state, action] == q_max:
q_max_action.append(action)
next_state = q_max_action[random.randint(0, len(q_max_action) - 1)]
print("the robot goes to " + str(next_state) + '.')
state = next_state
count += 1