- 2023-11-25
-
发表了日志:
一起读《深度强化学习实战》- 经验回放、目标网络优化random的Gridworld
-
发表了主题帖:
一起读《深度强化学习实战》- 经验回放、目标网络优化random的Gridworld
定义
强化学习如果只是记忆相同的步骤,那它是没有任何价值的(状态复杂、数据量变大,都将无法有效的记忆),故随机模式下损失函数将变得无法收敛(每次的游戏初始状态都是随机的)
在线训练中,不断地反向传播,从而更新权重,使其loss逐渐变小,达到学习的效果
非常相似的状态-动作对下,得到的Q值不同,会导致对相似(甚至相同的)状态-动作对之前的学习得到的权重被覆盖(白学了),称之灾难性遗忘(catastrophic forgeting)
经验回放,将过去的经验存起来(存到一个双端队列deque),反向传播时使用过去经验的随机子集(避免使用最近一条,造成灾难性遗忘),但结果仍然呈不稳定性。
更新规则中增加目标网络作为维度,以平滑不稳定性,定期同步目标网络和著网络的参数,通过它的Q网络预测的Q值用来反向传播和训练主Q网络
17. Double DQN - Deep Learning Bible - 5. Reinforcement Learning - 한글 (wikidocs.net)
实践
随机模式
将Gridworld的模式切换成random,将随机生成初始状态,再运行loss损失计算,得到如下图
game = Gridworld(size=4, mode='random')
python3 Gridworld-Q-funciton-loss.py,随机模式下的Loss损失并未收敛
灾难性遗忘
增加经验回放解决,由于是随机的状态,增大学习的epochs次数
import numpy as np
import torch
from Gridworld import Gridworld
# from IPython.display import clear_output
import random
from matplotlib import pylab as plt
import math
l1 = 64
l2 = 150
l3 = 100
l4 = 4
model = torch.nn.Sequential(
torch.nn.Linear(l1, l2),
torch.nn.ReLU(),
torch.nn.Linear(l2, l3),
torch.nn.ReLU(),
torch.nn.Linear(l3,l4)
)
loss_fn = torch.nn.MSELoss()
learning_rate = 1e-3
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
gamma = 0.9
epsilon = 0.3
action_set = {
0: 'u',
1: 'd',
2: 'l',
3: 'r',
}
from collections import deque
epochs = 5000
losses = []
mem_size = 1000 #A
batch_size = 200 #B
replay = deque(maxlen=mem_size) #C
max_moves = 50 #D
h = 0
for i in range(epochs):
game = Gridworld(size=4, mode='random')
state1_ = game.board.render_np().reshape(1,64) + np.random.rand(1,64)/100.0
state1 = torch.from_numpy(state1_).float()
status = 1
mov = 0
while(status == 1):
mov += 1
qval = model(state1) #E
qval_ = qval.data.numpy()
if (random.random() < epsilon): #F
action_ = np.random.randint(0,4)
else:
action_ = np.argmax(qval_)
action = action_set[action_]
game.makeMove(action)
state2_ = game.board.render_np().reshape(1,64) + np.random.rand(1,64)/100.0
state2 = torch.from_numpy(state2_).float()
reward = game.reward()
done = True if reward > 0 else False
exp = (state1, action_, reward, state2, done) #G
replay.append(exp) #H
state1 = state2
if len(replay) > batch_size: #I
minibatch = random.sample(replay, batch_size) #J
state1_batch = torch.cat([s1 for (s1,a,r,s2,d) in minibatch]) #K
action_batch = torch.Tensor([a for (s1,a,r,s2,d) in minibatch])
reward_batch = torch.Tensor([r for (s1,a,r,s2,d) in minibatch])
state2_batch = torch.cat([s2 for (s1,a,r,s2,d) in minibatch])
done_batch = torch.Tensor([d for (s1,a,r,s2,d) in minibatch])
Q1 = model(state1_batch) #L
with torch.no_grad():
Q2 = model(state2_batch) #M
Y = reward_batch + gamma * ((1 - done_batch) * torch.max(Q2,dim=1)[0]) #N
X = Q1.gather(dim=1,index=action_batch.long().unsqueeze(dim=1)).squeeze()
loss = loss_fn(X, Y.detach())
print(i, loss.item())
# clear_output(wait=True)
optimizer.zero_grad()
loss.backward()
losses.append(loss.item())
optimizer.step()
if reward != -1 or mov > max_moves: #O
status = 0
mov = 0
losses = np.array(losses)
plt.figure(figsize=(10,7))
plt.plot(losses)
plt.xlabel("Epochs",fontsize=22)
plt.ylabel("Loss",fontsize=22)
plt.show()
运行后,效果如下,可以看到,逐渐收敛,但仍有较大程度的震荡
目标网络
增加目标网络
import numpy as np
import torch
from Gridworld import Gridworld
# from IPython.display import clear_output
import random
from matplotlib import pylab as plt
import math
import copy
l1 = 64
l2 = 150
l3 = 100
l4 = 4
model = torch.nn.Sequential(
torch.nn.Linear(l1, l2),
torch.nn.ReLU(),
torch.nn.Linear(l2, l3),
torch.nn.ReLU(),
torch.nn.Linear(l3,l4)
)
model2 = copy.deepcopy(model) #A
model2.load_state_dict(model.state_dict()) #B
loss_fn = torch.nn.MSELoss()
learning_rate = 1e-3
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
gamma = 0.9
epsilon = 0.3
action_set = {
0: 'u',
1: 'd',
2: 'l',
3: 'r',
}
from collections import deque
epochs = 5000
losses = []
mem_size = 1000 #A经验回放内存总大小
batch_size = 200 #B小排量随机自己的大小
replay = deque(maxlen=mem_size) #C经验回放的deque双端队列
max_moves = 50 #D如果单次超过50次还未找到目标就退出
h = 0
sync_freq = 500 #A
j=0
for i in range(epochs):
game = Gridworld(size=4, mode='random')
state1_ = game.board.render_np().reshape(1,64) + np.random.rand(1,64)/100.0
state1 = torch.from_numpy(state1_).float()
status = 1
mov = 0
while(status == 1):
j+=1
mov += 1
qval = model(state1) #E
qval_ = qval.data.numpy()
if (random.random() < epsilon): #F
action_ = np.random.randint(0,4)
else:
action_ = np.argmax(qval_)
action = action_set[action_]
game.makeMove(action)
state2_ = game.board.render_np().reshape(1,64) + np.random.rand(1,64)/100.0
state2 = torch.from_numpy(state2_).float()
reward = game.reward()
done = True if reward > 0 else False
exp = (state1, action_, reward, state2, done) #G创建一条状态、动作、奖励、下一个状态的经验
replay.append(exp) #H塞进队列
state1 = state2
if len(replay) > batch_size: #I当经验列表长度大于随机自己大小,开始小批量训练
minibatch = random.sample(replay, batch_size) #J使用random.sample进行随机抽样子集
state1_batch = torch.cat([s1 for (s1,a,r,s2,d) in minibatch]) #K,将每一部分抽离成单独的张量,这里是状态张量
action_batch = torch.Tensor([a for (s1,a,r,s2,d) in minibatch]) #这里是动作张量
reward_batch = torch.Tensor([r for (s1,a,r,s2,d) in minibatch])
state2_batch = torch.cat([s2 for (s1,a,r,s2,d) in minibatch])
done_batch = torch.Tensor([d for (s1,a,r,s2,d) in minibatch])
Q1 = model(state1_batch) #L重新计算小批量的Q值,得到梯度
with torch.no_grad():
Q2 = model2(state2_batch) #M计算下一状态的Q值,不计算梯度
Y = reward_batch + gamma * ((1 - done_batch) * torch.max(Q2,dim=1)[0]) #N计算目标Q值
X = Q1.gather(dim=1,index=action_batch.long().unsqueeze(dim=1)).squeeze() #gather函数可以通过动作索引获取Q1张量的子集,这样只选择与实际被选择动作相关的Q值
loss = loss_fn(X, Y.detach())
print(i, loss.item())
# clear_output(wait=True)
optimizer.zero_grad()
loss.backward()
losses.append(loss.item())
optimizer.step()
if j % sync_freq == 0: #C
model2.load_state_dict(model.state_dict())
if reward != -1 or mov > max_moves: #O
status = 0
mov = 0
losses = np.array(losses)
plt.figure(figsize=(10,7))
plt.plot(losses)
plt.xlabel("Epochs",fontsize=22)
plt.ylabel("Loss",fontsize=22)
plt.show()
视频讲解
- 2023-11-21
-
回复了主题帖:
一起读《深度强化学习实战》- 马尔可夫决策过程MDP以及V、Q函数
chejm 发表于 2023-11-21 15:00
感谢楼主提供的技术分享,先收藏学习再发表个人意见,顶起来
感谢
-
回复了主题帖:
一起读《深度强化学习实战》- 【Q-learning】是什么、Gridworld游戏引擎
浪杯咖啡 发表于 2023-11-21 13:06
神经网络预测给定状态下每个动作的期望奖励,观察实际奖励,并相应地更新网络。
是的,后面有讲到,实际上是利用反向传播算法,求偏导更新网络中的权重,让loss逐渐变小,达到学习的效果
-
回复了主题帖:
一起读《深度强化学习实战》-Multi-armed bandit问题
chejm 发表于 2023-11-21 15:03
感谢楼主提供的技术分享,先收藏学习再发表个人意见,顶起来
一起学习
- 2023-11-20
-
发表了日志:
一起读《深度强化学习实战》- 构建Q函数神经网络,计算Loss损失
-
发表了主题帖:
一起读《深度强化学习实战》- 构建Q函数神经网络,计算Loss损失
定义
模型,需要抽象出游戏的状态向量、输入层、隐藏层、输出层(方便计算机表达的形式)。Gridworld游戏中,玩家p、目标+、坑-、墙w,这四个位置分别对应4x4的可能,4个维度再组合,则成为4x4x4大小的状态向量(64)。输出层则是给定状态下每个动作的Q值向量(移动的方向、上下左右)。
PyTorch的nn模块是一个专门为深度学习设计的模块,它提供了创建和训练神经网络的各种工具。其核心的数据结构是Module,它是一个抽象的概念,既可以表示神经网络中的某个层,也可以表示一个包含很多层的神经网络。此模块包含了各种神经网络层,例如卷积层、池化层、全连接层等等。同时,用户可以根据具体的问题对这些模块进行定制,从而充分发挥这些模块的功能。
MSE = Σ(yi - f(xi))^2 / n,均方差损失函数的值越小,代表模型的预测值越接近真实值,因此模型的鲁棒性就越好。此外,均方差损失函数还可以评价数据的变化程度,MSE的值越小,说明预测模型描述实验数据具有更好的精确度。
argmax函数用于返回数组中最大值的索引
PyTorch中的no_grad()是一个上下文管理器,用于在计算图中禁用梯度计算。当你不需要计算梯度时,可以使用它来提高性能
PyTorch中的detach()方法用于将张量从计算图中分离,使其不再参与梯度计算。这在训练过程中非常有用
PyTorch中的squeeze()方法用于移除张量中维度为1的尺寸。如果张量在某个维度上的大小为1,则该维度会被移除,并且结果张量的形状会相应地改变
添加噪声,是因为ReLU函数在0处不可微。
在PyTorch中,计算图是由节点和边组成的。节点表示参与运算的变量,比如张量或者Function。例如,在我们前面提到的线性回归模型中,输入数据x和权重w就可以被视为节点。这些节点在计算图中通过边来表示它们之间的依赖关系,例如,x和w之间的相乘操作可以由torch.mul()表示。特别需要注意的是,在神经网络中还有一种特殊的节点,称为叶子节点。这些节点是由用户创建的Variable变量,不需要再依赖其他变量进行计算。在进行网络优化时,反向传播算法会从输出开始,通过链式求导法则计算出每一个叶子节点对最终输出结果的梯度。此外,PyTorch的计算图是动态图。这意味着在前向传播过程中,每条语句都会在计算图中动态添加节点和边,并立即执行正向传播得到计算结果。一旦进行了反向传播或者计算了梯度,创建的计算图就会立即销毁,释放存储空间。因此,每次执行前向传播过程时,都需要重新构建计算图。这种动态性使得PyTorch能够更有效地处理复杂的计算任务和大规模的数据。
反向传播的主要目标是最小化损失函数。在反向传播过程中,误差是从输出层向输入层反向传播的,通过链式法则计算损失函数对各参数的梯度(该参数对损失函数的贡献(即梯度)),并更新参数。
实践
计算loss损失图
import numpy as np
import torch
from Gridworld import Gridworld
# from IPython.display import clear_output
import random
from matplotlib import pylab as plt
l1 = 64
l2 = 150
l3 = 100
l4 = 4
model = torch.nn.Sequential(
torch.nn.Linear(l1, l2),
torch.nn.ReLU(),
torch.nn.Linear(l2, l3),
torch.nn.ReLU(),
torch.nn.Linear(l3,l4)
)
loss_fn = torch.nn.MSELoss()
learning_rate = 1e-3
gamma = 0.9
epsilon = 1.0
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
action_set = {
0: 'u',
1: 'd',
2: 'l',
3: 'r',
}
epochs = 1000
losses = [] #A
for i in range(epochs): #B
game = Gridworld(size=4, mode='static') #C
state_ = game.board.render_np().reshape(1,64) + np.random.rand(1,64)/10.0 #D
# https://github.com/DeepReinforcementLearning/DeepReinforcementLearningInAction/blob/master/Chapter%203/Ch3_book.ipynb
# 如下给错了,应该是state1
state1 = torch.from_numpy(state_).float() #E
status = 1 #F
while(status == 1): #G
qval = model(state1) #H
qval_ = qval.data.numpy()
if (random.random() < epsilon): #I
action_ = np.random.randint(0,4)
else:
action_ = np.argmax(qval_)
action = action_set[action_] #J
game.makeMove(action) #K
state2_ = game.board.render_np().reshape(1,64) + np.random.rand(1,64)/10.0
state2 = torch.from_numpy(state2_).float() #L
reward = game.reward()
with torch.no_grad():
newQ = model(state2.reshape(1,64))
maxQ = torch.max(newQ) #M
if reward == -1: #N
Y = reward + (gamma * maxQ)
else:
Y = reward
Y = torch.Tensor([Y]).detach()
X = qval.squeeze()[action_] #O
loss = loss_fn(X, Y) #P
print(i, loss.item())
#不适用IPython,这个可以删除
# clear_output(wait=True)
optimizer.zero_grad()
loss.backward()
losses.append(loss.item())
optimizer.step()
state1 = state2
if reward != -1: #Q
status = 0
if epsilon > 0.1: #R
epsilon -= (1/epochs)
plt.figure(figsize=(10,7))
plt.plot(losses)
plt.xlabel("Epochs",fontsize=22)
plt.ylabel("Loss",fontsize=22)
plt.show()
视频讲解
- 2023-11-19
-
发表了主题帖:
一起读《深度强化学习实战》- 【Q-learning】是什么、Gridworld游戏引擎
定义
Q-learning
是最优动作-价值的方法中的一种。主要的思想,算法预测一个状态-动作对的值,然后将该预测值与稍后观察到的累计奖励进行比较并更新算法的参数,以便下次做出更好的预测。一句话,神经网络预测给定状态下每个动作的期望奖励,观察实际奖励,并相应地更新网络。
贴现因子
也称折现系数或折现参数,是一个介于0-1之间的数,用于将未来的现金流量折算成现值。 当利率为r时,一个承诺在T年之后支付R美元的现值就是R美元除以(1+r)^T。 因此,即使没有通货膨胀,将来的1美元的价值也小于现在的1美元的价值。必须按某一数额贴现,该数额取决于利率的高低和收到货币的时间长短。 其中的1/ (1+r) T被称为未来T时期的货币的贴现因子。 贴现因子在数值上可以理解为贴现率,它表示的是1个份额经过一段时间后所等同的如今份额。一个月后的200美元,和现在的100美元的关系就是,0.5*200=100。然后再过一个月,也就是两个月和现在100美元比的话就是,100/0.5^2=400,也就是等价于两个月后给400
为什么要有贴现因子:对未来的奖励和现在的奖励对比,未来的奖励高,那肯定先选未来的,虽然先选后选,整体奖励是相等的,但效果却不一样,较近的奖励通常比较远的奖励更有价值。
学习率
超参数,控制算法从每步中学习的速度,值比较小,则每步只会有较小的更新
Q函数
接收一个状态和动作,并返回在该状态下采取该动作产生价值(期望奖励)。
Q-learning的改造Q函数,Q函数接收一个状态,返回输出所有动作对应的期望奖励的向量,这样做的好处是可以直接选择最高预测值的动作。
损失函数
也被称为目标函数,是衡量模型预测值与真实值之间差异的一种重要工具。在编译一个神经网络模型时,损失函数和优化器是两个必不可少的要素。
损失函数的具体形式是一个非负实值函数,通常使用L(Y, f(x))来表示,其中Y代表真实值,f(x)代表模型的预测值。损失函数的值越小,代表模型的预测值越接近真实值,因此模型的鲁棒性就越好。
在机器学习中,有各种各样的损失函数可供选择。例如,均方差损失(Mean Squared Loss)和平均绝对误差损失(Mean Absolute Error Loss)是适用于回归问题的两种常见损失函数。
MSE = Σ(yi - f(xi))^2 / n,均方差损失函数的值越小,代表模型的预测值越接近真实值,因此模型的鲁棒性就越好。此外,均方差损失函数还可以评价数据的变化程度,MSE的值越小,说明预测模型描述实验数据具有更好的精确度。
超参数
在机器学习模型中,一般存在两类参数。一类是模型参数,这类参数需要从数据中学习和估计得到,比如线性回归直线的加权系数(斜率)及其偏差项(截距)。另一类则是超参数。
超参数是一种手工可配置的设置,具有未知的特性,即它不是一个已知常量。它是需要人为根据已有或现有的经验来指定“正确”的值,而不是通过系统学习得到的。具体来说,超参数是模型外部的配置,其值无法从数据中估计。它们通常用于帮助估计模型参数,由人工指定,并且经常被调整以适应特定的预测建模问题。
例如,在神经网络中,学习率就是一个典型的超参数。与模型参数不同,超参数不需要数据来驱动调整,而是在训练前或者训练中人为进行调整的参数。
超参数的重要性不容忽视,合理的超参数设置可以显著提高模型的性能。然而,确定最佳超参数值的过程往往需要反复试验和搜索。虽然我们无法知道给定问题的模型超参数的最佳值,但我们可以使用经验法则,在其他问题上使用复制值,或通过反复试验来搜索最佳值。
ReLu
全称是Rectified Linear Unit,是一种激活函数,用来连接上一层的输出和下一层的输入,如下,就是一个取最大值的函数,如果输入大于0,直接返回作为输入提供的值;如果输入是0或更小,返回值0。
def rectified(x):
return max(0.0, x)
实践
Gridworld游戏,Gridworld需要的库,也就是书中的库位置,在github中
DeepReinforcementLearningInAction/Chapter 3/GridBoard.py at master · DeepReinforcementLearning/DeepReinforcementLearningInAction (github.com)
先测试下,是否可以正常运行,书中使用的是交互式,直接运行需要像如下,加上print显示返回值,或者改写下display、reward函数
from Gridworld import Gridworld
game = Gridworld(size=4, mode='static')
#这里加上print
print(game.display())
print(game.reward())
不加print的话,就改写的地方如下图
game.board.render_np()输出当前4个状态的4x4矩阵(第一个矩阵编码了玩家位置P,第二个编码目标位置+,第三个编码坑的位置-,第四个编码墙的位置W)
视频讲解
-
发表了日志:
一起读《深度强化学习实战》- 【Q-learning】是什么、Gridworld游戏引擎
- 2023-11-12
-
回复了主题帖:
一起读《深度强化学习实战》-Multi-armed bandit问题
Jacktang 发表于 2023-11-12 08:46
是这样的
广告投放的算法那段,文中说,正在看的特定网站,这一状态”(上下文信息),有助于更 ...
就比如说,你正在看的网页卖手机,这个状态可以被用来直接关联相关的广告,卖手机壳、手机膜、耳机等广告,而不是像epsilon和softmax那样靠过往的数据以及概率来选择其他乱七八糟的广告(显然正在看手机的人,更可能会去看手机壳、而不会随机去看卖衣服的广告)
-
回复了主题帖:
一起读《深度强化学习实战》-Multi-armed bandit问题
Jacktang 发表于 2023-11-12 08:38
纯粹是算法算力问题了,有点看不懂了
如果要奖励比较准确,确实需要大量的数据支撑,大量的数据又需要算力来跑。不过了解其中的算法,可以应用在其他方面,就比如说epislon贪婪,类似大师PID算法,具体看怎么应用了
- 2023-11-11
-
发表了主题帖:
一起读《深度强化学习实战》- 马尔可夫决策过程MDP以及V、Q函数
理解
马尔可夫性质 (Markov property),不必知道过去的信息,根据当前的状态就可以做出决策(产生奖励)。
马尔可夫决策过程(Markov Decision Process, MDP),具有马尔可夫性质的控制任务称为MDP
不具备Mp性质的问题可以通过插入状态信息,转换成MDP。例如给病人看病,需要了解过往情况才能判断,但如果将完整的就诊记录作为状态,则就可以变成MDP来解决。
智能体根据t1时刻的状态s1做出的动作a1,则环境产生了t2时刻的s2,这时候产生的奖励r2(实质是因为状态s1切换s2才给的奖励,而不是a1,a1本身就会造成状态的好坏变化才是重要的)再给到智能体,状态之间切换的概率称为转移概率(transition probability)。
策略函数(policy function),该状态下可能动作产生最大奖励的概率分布。例如E贪婪策略、softmax策略。
最优策略(optimal policy),在某个状态下能够使得累积奖励最大(argmax)的行动,强化学习的目标就是找到一个最优的策略,使得智能体能够在与环境的交互中最大化累积奖励。
Q值(Q函数):它代表了智能体在某一状态下选择某个动作后,一直到最终状态的奖励总和的期望。换句话说,Q函数评估了在某个状态下采取某个动作的价值。更侧重于评估动作的价值,即在特定情境下执行某一动作的好坏
V值(价值函数):它代表了智能体在一个状态下,一直到最终状态的奖励总和的期望。简言之,价值函数评估了某个状态本身的价值。更侧重于评估状态的价值,即在某一状态下的优劣。
实践
import numpy as np
# 定义转移矩阵
P = np.array([[0.9, 0.1],
[0.5, 0.5]])
# 初始状态
state = np.array([1, 0])
# 迭代次数
n_iterations = 10
# 马尔科夫链迭代
for _ in range(n_iterations):
state = np.dot(state, P)
print(state)
视频讲解
-
发表了日志:
一起读《深度强化学习实战》- 马尔可夫决策过程MDP以及V、Q函数
-
发表了日志:
一起读《深度强化学习实战》-Multi-armed bandit问题
-
发表了主题帖:
一起读《深度强化学习实战》-Multi-armed bandit问题
实践
Epsilon贪婪算法
E概率下随机选择未知动作,1-E下基于过去已知信息选择最佳杠杆
import numpy as np
from scipy import stats
import random
import matplotlib.pyplot as plt
n = 10
probs = np.random.rand(n) #A
eps = 0.1
# 10 actions x 2 columns
# Columns: Count #, Avg Reward
record = np.zeros((n,2))
def get_reward(prob, n=10):
reward = 0;
for i in range(n):
if random.random() < prob:
reward += 1
return reward
def get_best_arm(record):
arm_index = np.argmax(record[:,1],axis=0)
return arm_index
def update_record(record,action,r):
new_r = (record[action,0] * record[action,1] + r) / (record[action,0] + 1)
record[action,0] += 1
record[action,1] = new_r
return record
fig,ax = plt.subplots(1,1)
ax.set_xlabel("Plays")
ax.set_ylabel("Avg Reward")
fig.set_size_inches(9,5)
rewards = [0]
for i in range(500):
if random.random() > 0.2:
choice = get_best_arm(record)
else:
choice = np.random.randint(10)
r = get_reward(probs[choice])
record = update_record(record,choice,r)
mean_reward = ((i+1) * rewards[-1] + r)/(i+2)
rewards.append(mean_reward)
ax.scatter(np.arange(len(rewards)),rewards)
# 要加一行这个
plt.show()
Softmax选择策略
首先,Softmax可以将一组分数转换为概率分布。更具体来说,对于某个训练样本的向量的分数是[ 2, 3, 4 ],经过Softmax函数作用后概率将会是[0.2, 0.3, 0.5],这些值都在[0,1]之间并且总和为1。
Softmax函数的形式为:
import numpy as np
from scipy import stats
import random
import matplotlib.pyplot as plt
n = 10
probs = np.random.rand(n)
record = np.zeros((n,2))
def softmax(av, tau=1.12):
softm = ( np.exp(av / tau) / np.sum( np.exp(av / tau) ) )
return softm
def get_reward(prob, n=10):
reward = 0;
for i in range(n):
if random.random() < prob:
reward += 1
return reward
def get_best_arm(record):
arm_index = np.argmax(record[:,1],axis=0)
return arm_index
def update_record(record,action,r):
new_r = (record[action,0] * record[action,1] + r) / (record[action,0] + 1)
record[action,0] += 1
record[action,1] = new_r
return record
fig,ax = plt.subplots(1,1)
ax.set_xlabel("Plays")
ax.set_ylabel("Avg Reward")
fig.set_size_inches(9,5)
rewards = [0]
for i in range(500):
p = softmax(record[:,1],tau=0.7)
choice = np.random.choice(np.arange(n),p=p)
r = get_reward(probs[choice])
record = update_record(record,choice,r)
mean_reward = ((i+1) * rewards[-1] + r)/(i+2)
rewards.append(mean_reward)
ax.scatter(np.arange(len(rewards)),rewards)
plt.show()
广告投放的算法
在浏览某个网站,希望用户看到另一个网站的广告,按照softmax和epsilon贪婪都是某种概率随机投放广告,但实际用户在浏览某个网站时,更原因看相关性的广告,而正在看的特定网站,这一状态”(上下文信息),有助于更好的投放特定的广告。
强化学习,目标时在过程中最大化奖励,那么【状态、动作、奖励】的排列组合就太庞大了,远不是像softmax、epsilon贪婪中使用【动作、奖励】这样简单的数组能用查表的方法来解决。但神经网络就能很好的处理这个难题,只保留有价值的抽象信息(数据中的组合模式和规律)
使用pytorch来解决这个问题:
import numpy as np
import torch
import random
import matplotlib.pyplot as plt
class ContextBandit:
def __init__(self, arms=10):
self.arms = arms
self.init_distribution(arms)
self.update_state()
def init_distribution(self, arms):
# Num states = Num Arms to keep things simple
self.bandit_matrix = np.random.rand(arms,arms)
#each row represents a state, each column an arm
def reward(self, prob):
reward = 0
for i in range(self.arms):
if random.random() < prob:
reward += 1
return reward
def get_state(self):
return self.state
def update_state(self):
self.state = np.random.randint(0,self.arms)
def get_reward(self,arm):
return self.reward(self.bandit_matrix[self.get_state()][arm])
def choose_arm(self, arm):
reward = self.get_reward(arm)
self.update_state()
return reward
arms = 10
N, D_in, H, D_out = 1, arms, 100, arms
env = ContextBandit(arms=10)
state = env.get_state()
reward = env.choose_arm(1)
print(state)
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.ReLU(),
torch.nn.Linear(H, D_out),
torch.nn.ReLU(),
)
loss_fn = torch.nn.MSELoss()
env = ContextBandit(arms)
def softmax(av, tau=1.12):
softm = ( np.exp(av / tau) / np.sum( np.exp(av / tau) ) )
return softm
def one_hot(N, pos, val=1):
one_hot_vec = np.zeros(N)
one_hot_vec[pos] = val
return one_hot_vec
def running_mean(x,N=50):
c = x.shape[0] - N
y = np.zeros(c)
conv = np.ones(N)
for i in range(c):
y[i] = (x[i:i+N] @ conv)/N
return y
def train(env, epochs=5000, learning_rate=1e-2):
cur_state = torch.Tensor(one_hot(arms,env.get_state())) #A
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
rewards = []
for i in range(epochs):
y_pred = model(cur_state) #B
av_softmax = softmax(y_pred.data.numpy(), tau=2.0) #C
av_softmax /= av_softmax.sum() #D
choice = np.random.choice(arms, p=av_softmax) #E
cur_reward = env.choose_arm(choice) #F
one_hot_reward = y_pred.data.numpy().copy() #G
one_hot_reward[choice] = cur_reward #H
reward = torch.Tensor(one_hot_reward)
rewards.append(cur_reward)
loss = loss_fn(y_pred, reward)
optimizer.zero_grad()
loss.backward()
optimizer.step()
cur_state = torch.Tensor(one_hot(arms,env.get_state())) #I
return np.array(rewards)
rewards = train(env)
plt.plot(running_mean(rewards,N=500))
plt.show()
定义
grad:梯度
梯度下降的方向,函数减小最快,更容易找到最小值
梯度下降法,沿着梯度下降的方向求解极小值,沿着梯度上升的方向可以求得最大值,这种方法叫梯度上升。
算法:求当前函数的导数,然后下降就是不停的循环(当前位置减去一个指定步长*导数)
Multi-armed bandit
一种游戏机,有多个拉杆,每个拉杆中奖的概率不同。
视频讲解
-
回复了主题帖:
一起读《深度强化学习实战》- gym案例
chejm 发表于 2023-11-6 07:39
感谢楼主的无私奉献,受益很大,希望楼主再接再厉
一起努力学习
- 2023-11-07
-
回复了主题帖:
【EETALK】你平时会忘事吗?项目管理软件有了解吗?看看大家怎么说
公司项目使用腾讯的coding,提供一站式研发管理平台及云原生开发工具
有看板、仓库、CICD可持续集成、制品库
最好用的几个功能:
git仓库代码提交可以绑定开发事项,方便回看提交
CICD,提交发布到制品库
和企业微信数据打通
迭代计划
- 2023-11-04
-
发表了主题帖:
一起读《深度强化学习实战》- gym案例
一起读《深度强化学习实战》-gym案例
定义
1. 深度强化学习 DRL(Deep Reinforcement Learning)属于机器学习的一个子领域,将深度学习模型(神经网络)应用于强化学习。
2. 什么是强化学习?类似大人教小孩子,训练狗,做的差不多或完全正确就给奖励,然后不停地强化。
3. 强化学习需要做出决策和采取动作(控制任务control task),通过试错学习如何最佳地匹配状态(states)和动作(actions),以期获得最大的回报(rewards)。
4. 状态是环境的“快照”(环境是连续的,状态是离散的)。
5. 动态规划Dynamic Programming,分析问题,拆解成清楚如何解决的最小单元,再逐级解决。
6. 蒙特卡洛法,对未知的场景,反复试错进行判断。
应用
强化学习,可以应用于打游戏(DeepMind的DQN算法),股票交易,广告投放等等
实践
1. 使用Python Gym库(安装pip3 install gym)提供大量可与学习算法交互的环境和接口。运行书中给的例子:
import gym
env = gym.make('CarRacing-v0')
env.reset()
env.step(action)
env.render()
2. python3运行,报错`gym.error.DeprecatedEnv: Environment version v0 for CarRacing is deprecated. Please use CarRacing-v2 instead.`表示已经不推荐弃用,换成‘CarRacing-v2’
3. 再次运行,出现新的报错‘gym.error.DependencyNotInstalled: box2D is not installed, run pip install gym[box2d]’,
4. 安装pip3 install gym[box2d],报错如下
5. 通过sudo apt install swig解决
6. 再次运行还是会报‘NameError: name 'action' is not defined’,上面确实没有定义,修改成如下:
import gym
env = gym.make("CarRacing-v2", render_mode="human")
observation, info = env.reset()
while True:
action = env.action_space.sample() # agent policy that uses the observation and info
observation, reward, terminated, truncated, info = env.step(action)
if terminated or truncated:
observation, info = env.reset()
env.close()
7. 运行的效果如下,小车会一直尝试拐弯
视频分享
-
发表了日志:
一起读《深度强化学习实战》- gym案例
- 2023-10-18
-
回复了主题帖:
【共读入选名单】一起共读《深度强化学习实战》
个人信息无误,确认可以完成