我正在为强化学习任务实施 Softmax 动作选择策略 (http://www.incompleteideas.net/book/ebook/node17.html)。
我提出了这个解决方案,但我认为还有改进的空间。
1-这里我评估概率
prob_t = [0]*3
denominator = 0
for a in range(nActions):
denominator += exp(Q[state][a] / temperature)
for a in range(nActions):
prob_t[a] = (exp(Q[state][a]/temperature))/denominator
2-这里我将]0,1[范围内的随机生成的数字与动作的概率值进行比较:
rand_action = random.random()
if rand_action < prob_t[0]:
action = 0
elif rand_action >= prob_t[0] and rand_action < prob_t[1]+prob_t[0]:
action = 1
else: #if rand_action >= prob_t[1]+prob_t[0]
action = 2
编辑:
示例:rand_action 为 0.78,prob_t[0] 为 0.25,prob_t[1] 为 0.35,prob_t[2] 为 0.4。 概率之和为 1。 0.78 大于动作 0 和 1 的概率之和 (prob_t[0] + prob_t[1]),因此选择动作 2。
有更有效的方法吗?
使用 numpy 库可以轻松完成基于概率的动作选择。
q_values = [] #array of q_values
action = np.random.choice(q_values,p=q_values)
评估每个动作的概率后,如果您有一个函数返回加权随机选择,您可以获得如下所示的所需动作:
action = weighted_choice(prob_t)
虽然我不确定这是否是你所说的“更好的方法”。
weighted_choice
可以类似于 this:
import random
def weighted_choice(weights):
totals = []
running_total = 0
for w in weights:
running_total += w
totals.append(running_total)
rnd = random.random() * running_total
for i, total in enumerate(totals):
if rnd < total:
return i
如果您有很多可用的操作,请务必检查本文中的二分搜索实现,而不是上面的线性搜索。
或者如果您有权访问 numpy:
import numpy as np
def weighted_choice(weights):
totals = np.cumsum(weights)
norm = totals[-1]
throw = np.random.rand()*norm
return np.searchsorted(totals, throw)
在使用 numpy 的建议之后,我做了一些研究,并为 soft-max 实现的第一部分提供了这个解决方案。
prob_t = [0,0,0] #initialise
for a in range(nActions):
prob_t[a] = np.exp(Q[state][a]/temperature) #calculate numerators
#numpy matrix element-wise division for denominator (sum of numerators)
prob_t = np.true_divide(prob_t,sum(prob_t))
比我最初的解决方案少了一个 for 循环。 我能体会到的唯一缺点是精度降低。
使用numpy:
[ 0.02645082 0.02645082 0.94709836]
初始二循环解决方案:
[0.02645082063629476, 0.02645082063629476, 0.9470983587274104]
如果您有包含操作 ID 的列表:
actions = [0, 1, 2]
您可以使用带有概率列表的 numpy 随机选择:
action_int = numpy.random.choice(actions, p=prob_t)
您可以通过多次迭代此语句来证明这一点:
results = []
for i in range(30):
actions = [0, 1, 2]
prob_t = [0.6, 0.1, 0.3]
action_int = np.random.choice(actions, p=prob_t)
results.append(action_int)
print(results)
你会得到这样的东西:
[0, 1, 2, 0, 0, 0, 2, 0, 2, 0, 2, 0, 1, 0, 0, 2, 2, 2, 0, 0, 1, 2, 1, 2, 2, 0, 0, 0, 0, 0]