写在前面的话
想要在赌场中发家致富,要么有超能力,要么靠技术加持。
多臂老虎机也常常在游戏厅中见到,它是强化学习入门的必要问题,也是概率论中的经典。每一台老虎机的结果都服从一个概率分布,如高斯分布。如果想要从n个老虎机中实现财富自由,搞清楚每台老虎机的期望奖励,才能最大化自己的收益.
多臂老虎机英译为K-armed bandit。bandit:uk /ˈbæn.dɪt/ us /ˈbæn.dɪt/ 土匪强盗暴徒。多臂老虎机问题也警戒我们,小赌不怡情,大赌很伤身。言归正传,面对多台老虎机,我们怎么去探求每一台老虎机的奖励分布呢?
K-armed bandit
本算法会使用到贪婪的思想,即ϵ−greedy算法
在大多数情况下做出贪婪的选择,但是以一定的概率\epsilon做出随机的选择,能够保证每一个行动都能得到一定的探索,即便状态发生改变。
明确变量
输入:
- k:老虎机的数量
- num_learning_step:尝试次数
输出:
- model.q:第k个老虎机的价值估计
- model.n:选择第k个老虎机的次数
过程变量:
- model:老虎机群的规模
- reward:奖励函数
- action:选择第action个老虎机进行一次行动
import random
# 本模型中老虎机的奖励是恒定的,即不随时间的变化而变化
class Bandit:
def __init__(self, k):
# 对k个老虎机初始化,确定每一个老虎机的奖励分布函数
self.levers = [None] * k
for i in range(k):
minimum = random.random()
maximum = minimum + abs(random.random() - minimum)
lever = (minimum, maximum)
self.levers[i] = lever
def pull_lever(self, lever_index):
lever = self.levers[lever_index]
minimum, maximum = lever
return minimum + random.random() * (maximum - minimum)
def create_k_bandit(k):
return Bandit(k)
class Model:
def __init__(self, bandit):
k = len(bandit.levers)
self.q = [0] * k
self.n = [0] * k
def learn(bandit, num_learning_step):
model = Model(bandit)
Q = lambda action: model.q[action]
for learning_step_number in range(num_learning_step):
actions = tuple(range(len(bandit.levers)))
epsilon = 0.1 # 贪婪程度,便于模型进行探索,值越大探索程度越大
# TODO 修改学习率来查看不同的效果
if random.random() <= epsilon:
# 以epsilon的概率随机选择一个老虎机进行行动
action = random.choice(actions)
else:
# 以(1-epsilon)的概率在k个老虎机中选择当前收益最大的老虎机进行行动
action = argmax(actions, Q)
reward = bandit.pull_lever(action)
model.n[action] += 1
model.q[action] += 1.0 / model.n[action] * (reward - model.q[action])
return model
def argmax(values, predicate):
# 返回奖励最大的老虎机的id
return max(values, key=predicate)
# 传入命名参数key,其为一个函数,用来指定取最大值的方法
if __name__ == '__main__':
bandit = create_k_bandit(10)
model = learn(bandit, 1000)
print('bandit:', bandit)
print('model:', model)
print(model.q)
print(model.n)
print('')
在很多行业中,多臂老虎机问题有着广泛的应用。比如说广告展示,例如购物网站的推荐上,当然现在他们的算法应该更先进了.