强化学习入门必备基础
文章目录
- 强化学习入门必备基础
- 1. 强化学习与机器学习
- 1.1 有监督学习
- 1.2 半监督学习
- 1.3 无监督学习
- 1.4 强化学习
- 1.5 深度学习
- 2. 强化学习中的一些概念
- 2.1 智能体、动作、状态
- 2.2 策略函数、奖励
- 2.3 状态转移
- 2.4 智能体与环境的交互过程
- 2.5 折扣奖励
- 2.6 动作价值函数
- 2.7 状态价值函数
- 3. Python强化学习迷宫实例
1. 强化学习与机器学习
机器学习是人工智能的一种实现方法,机器学习的方法可以归纳为经过一系列的输入数据确定整个系统的参数的过程。
机器学习可以分为有监督学习、半监督学习、无监督学习和强化学习。
1.1 有监督学习
有监督学习是一种常见的学习方法,其中模型使用带有标签的数据集进行训练。 在有监督学习中,每个数据点都由一个输入向量和一个标签组成。例如,我们可以使用有标签的图像来训练一个模型,其中每个图像被标记为包含特定的对象或类别,然后让模型学习识别相似的对象。
在有监督学习中,我们训练一个模型来学习如何将输入数据映射到正确的输出标签。训练过程中,模型通过与正确答案进行比较来调整自己的权重和参数。一旦训练完成,我们可以将模型应用于新的数据集并使用其输出来进行预测。常见的有监督学习算法包括决策树、随机森林、支持向量机、逻辑回归和神经网络等。
1.2 半监督学习
半监督学习是机器学习中的一种学习方法,它结合了有监督学习和无监督学习。在半监督学习中,我们拥有一些带有标签的数据以及一些未标记的数据,而我们的目标是使用这些数据来训练一个模型,以便我们可以对新数据进行分类或预测。
在半监督学习中,我们可以使用无监督学习算法来利用未标记的数据来发现数据中的模式和结构,从而提高模型的性能。例如,我们可以使用聚类算法来对未标记的数据进行分组,然后使用这些分组来帮助我们对带有标签的数据进行分类。另外,我们可以使用半监督学习算法来自动标记未标记的数据,并将其与已标记的数据一起用于训练模型。
半监督学习在数据集中标记数据较少或成本较高的情况下非常有用,例如,在医学图像识别或语音识别中。由于半监督学习利用了未标记数据的信息,因此可以提高模型的准确性并降低训练成本。常见的半监督学习算法包括半监督支持向量机、半监督聚类和图半监督学习等。
1.3 无监督学习
在机器学习中,无监督学习是一种学习方法,其中模型使用未标记的数据集进行训练,而无需使用标签或指示变量。在无监督学习中,我们的目标是发现数据中的结构和模式,以便我们可以更好地理解和解释数据。
在无监督学习中,我们通常使用聚类、降维、异常检测和关联规则等算法来发现数据中的模式和结构。聚类算法用于将数据点分组成具有相似特征的簇。降维算法用于将高维数据集转换为低维表示,以便我们可以更好地可视化和理解数据。异常检测算法用于识别与数据中的其他数据点不同的异常值。关联规则算法用于发现数据中的关联性,例如购物篮分析。
无监督学习在许多情况下非常有用,特别是在我们不知道正确答案或标签的情况下。它可以帮助我们发现数据中的潜在模式和结构,从而提高数据分析的效率和准确性。常见的无监督学习算法包括k-means聚类、主成分分析、自编码器、密度聚类和关联规则等。
1.4 强化学习
在机器学习中,强化学习是一种学习方法,用于训练智能体(agent)在特定环境中执行任务的能力。在强化学习中,智能体与环境进行交互,并根据执行的动作和所获得的奖励来学习。目标是使智能体学习一个策略(policy),以最大化长期奖励。
在强化学习中,我们定义一个环境,智能体通过观察环境的状态来决定执行什么动作。执行动作后,环境会给予智能体一个奖励或惩罚,以反馈其行动的好坏。通过与环境交互,智能体学习一种策略,即一组从状态到动作的映射,以最大化长期奖励。这是通过使用价值函数(value function)来计算当前状态下的预期长期奖励,并更新策略来实现的。
强化学习在许多应用场景中非常有用,例如在游戏、机器人控制、自然语言处理等方面。常见的强化学习算法包括Q学习、策略梯度、深度强化学习等。
1.5 深度学习
深度学习是一种机器学习方法,它利用人工神经网络来学习输入数据的表征,以便能够进行分类、回归、聚类、生成等任务。深度学习中的神经网络通常包含多个层次,每个层次都执行一些简单的计算,并将其结果传递给下一个层次。
深度学习的主要优势在于,它可以通过对大量标记数据进行训练,从而自动学习特征表示,并在无需手动提取特征的情况下实现高效的学习。与传统的机器学习方法相比,深度学习在处理大型、高维度数据时表现得更加出色,如图像、音频、自然语言处理等。深度学习已经被广泛应用于许多领域,如计算机视觉、语音识别、自然语言处理、机器翻译、推荐系统等。
深度学习的核心是神经网络模型,其中最常见的是卷积神经网络(CNN)和循环神经网络(RNN)。CNN主要用于处理图像和视频数据,而RNN则更适合处理序列数据,如文本和语音。另外,还有一些其他的深度学习架构,如自编码器、生成对抗网络(GAN)、变分自编码器(VAE)等,这些架构在不同领域中也有着广泛的应用。
上述四种方法的联系如图所示
2. 强化学习中的一些概念
2.1 智能体、动作、状态
以下面马里奥的游戏为例,游戏的执行主体称为智能体 ( A g e n t ) (Agent) (Agent)
下图中的一帧就是一个状态 s s s
而马里奥可以做出的动作记为 a , a ∈ { l e f t , r i g h t , u p } a,a\in \{left,right,up\} a,a∈{left,right,up}
2.2 策略函数、奖励
策略函数表征马里奥下一步执行动作的选择概率,策略函数记为
π
(
s
,
a
)
\pi(s,a)
π(s,a),其取值范围为0到1,通过观测状态的取值,对动作进行依概率随机抽样。
π
(
l
e
f
t
∣
s
)
=
P
(
A
=
a
∣
S
=
s
)
\pi(left|s)=P(A=a|S=s)
π(left∣s)=P(A=a∣S=s)
以当前场景为例
π
(
l
e
f
t
∣
s
)
=
0.2
π
(
r
i
g
h
t
∣
s
)
=
0.1
π
(
u
p
∣
s
)
=
0.7
\pi(left|s)=0.2\\ \pi(right|s)=0.1\\ \pi(up|s)=0.7
π(left∣s)=0.2π(right∣s)=0.1π(up∣s)=0.7
强化学习是以奖励作为目标的机器学习方法,其思路仿照生物的经验学习方法,其没有标签数据,所以奖励是非常重要的指标,强化学习方向的最终目标是将总奖励最大化,奖励的建模设计引导整个强化学习的走向。
在这个场景中,奖励(reward) R R R可以如此设计:
- 吃到一个金币: R = + 1 R=+1 R=+1
- 游戏获胜: R = + 10000 R=+10000 R=+10000
- 碰到敌人(非踩): R = − 10000 R=-10000 R=−10000
- 无事发生: R = 0 R=0 R=0
2.3 状态转移
从一个旧的状态变成新的状态的过程称为状态转移过程,状态的转移依赖于动作的选择,当动作随机抽样后,智能体做出动作后会造成当前状态的改变。
状态转移的过程是随机的,随机性来自于环境,记旧状态为
s
s
s,新状态为
s
′
s^{'}
s′,那么状态转移函数
p
p
p有:
p
(
s
′
∣
s
,
a
)
=
P
(
S
′
∣
S
=
s
,
A
=
a
)
p(s{'}|s,a)=P(S^{'}|S=s,A=a)
p(s′∣s,a)=P(S′∣S=s,A=a)
2.4 智能体与环境的交互过程
智能体与环境发生交互的过程可以概括为:
-
环境产生 t t t时刻的状态 s t s_t st,智能体在环境产生的状态 s t s_t st中完成后续的决策。
-
智能体在状态 s t s_t st下依概率随机抽样,做出 t t t时刻的动作 a t a_t at作用于环境参考。
-
环境得到智能体根据 t t t时刻的状态 s t s_t st所决策出的动作 a t a_t at之后,相应产生 t t t时刻的奖励 r t r_t rt和 t + 1 t+1 t+1时刻的状态的 s t + 1 s_{t+1} st+1,完成一次闭环。
那么用强化学习去玩这个游戏的过程实际上就是
- 观测一帧(state s 1 s_1 s1)
- 抽样出动作 a 1 a_1 a1(上、左、右)
- 观测新的一帧(state s 2 s_2 s2)同时获取到奖励 r e w a r d r 1 reward r_1 rewardr1
- 抽样出动作 a 2 a_2 a2
- …(循环往复)
(
s
t
a
t
e
,
a
c
t
i
o
n
,
r
e
w
a
r
d
)
(state,action,reward)
(state,action,reward)的轨迹序列为
s
1
,
a
1
,
r
1
,
s
2
,
a
2
,
r
2
,
.
.
.
,
s
T
,
a
T
,
r
T
s_1,a_1,r_1,s_2,a_2,r_2,...,s_T,a_T,r_T
s1,a1,r1,s2,a2,r2,...,sT,aT,rT
2.5 折扣奖励
累计回报 U U U定义:
U t = R t + R t + 1 + R t + 2 + R t + 3 + . . . U_t=R_t+R_{t+1}+R_{t+2}+R_{t+3}+... Ut=Rt+Rt+1+Rt+2+Rt+3+...
对于参考的重要性来说,未来时刻的奖励肯定重要性低于当前时刻,所以要给予当前(t时刻)时刻更高的权重,按照王树森老师的例子,现在给你100块钱肯定比未来给你100块钱更现实,所以上式应该添加衰减系数
γ
\gamma
γ,那么
U
U
U的定义变更为
U
t
=
R
t
+
γ
R
t
+
1
+
γ
2
R
t
+
2
+
γ
3
R
t
+
3
+
.
.
.
U_t=R_t+\gamma R_{t+1}+\gamma^2R_{t+2}+\gamma^3R_{t+3}+...
Ut=Rt+γRt+1+γ2Rt+2+γ3Rt+3+...
折扣奖励的随机性
在t时刻,累计回报 U t U_t Ut是随机的,其随机性的来源有两个:
-
动作抽样是随机的,也即
P [ A = a ∣ S = s ] = π ( a ∣ s ) P[A=a|S=s]=\pi(a|s) P[A=a∣S=s]=π(a∣s) -
新的状态的产生是随机的
P [ S ′ = s ′ ∣ S = s , A = a ] = p ( s ′ ∣ s , a ) P[S^{'}=s^{'}|S=s,A=a]=p(s^{'}|s,a) P[S′=s′∣S=s,A=a]=p(s′∣s,a)
对于任给的 i ≥ t i\geq t i≥t,奖励 R i R_i Ri取决于随机变量 S i S_i Si和 A i A_i Ai,因此给定一个状态 s t s_t st,累计回报 U t U_t Ut取决于随机变量:
A t , A t + 1 , A t + 2 , . . . A_t,A_{t+1},A_{t+2},... At,At+1,At+2,...和 S t + 1 , S t + 2 , . . . S_{t+1},S_{t+2},... St+1,St+2,...
2.6 动作价值函数
动作价值函数
Q
(
s
,
a
)
Q(s,a)
Q(s,a)的定义为:
Q
π
(
s
t
,
a
t
)
=
E
[
U
t
∣
S
t
=
s
t
,
A
t
=
a
t
]
Q_\pi(s_t,a_t)=E[U_t|S_t=s_t,A_t=a_t]
Qπ(st,at)=E[Ut∣St=st,At=at]
也就是动作价值函数是累计奖励
U
t
U_t
Ut的期望,其反映了对策略函数
π
\pi
π的评价。
最优动作价值函数 Q ∗ Q^* Q∗函数定义如下:
Q ∗ ( s t , a t ) = m a x π Q π ( s t , a t ) Q^{*}(s_t,a_t)=\mathop{max}\limits_{\pi}Q_{\pi}(s_t,a_t) Q∗(st,at)=πmaxQπ(st,at)
动作价值函数:给定策略函数 π \pi π, Q π ( s , a ) Q_{\pi}(s,a) Qπ(s,a)评价智能体在状态 s s s下抽样动作 a a a的好坏
2.7 状态价值函数
状态价值函数
V
π
V_{\pi}
Vπ的定义如下:
V
π
(
s
t
)
=
E
A
[
Q
π
(
s
t
,
A
)
]
V_{\pi}(s_t)=E_{A}[Q_{\pi}(s_t,A)]
Vπ(st)=EA[Qπ(st,A)]
进一步依据动作空间细化可分为:
- 动作空间离散
V π ( s t ) = E A [ Q π ( s t , A ) ] = ∑ a π ( a ∣ s t ) ⋅ Q π ( s t , a ) V_{\pi}(s_t)=E_{A}[Q_{\pi}(s_t,A)]=\sum_{a}\pi(a|s_t)\cdot Q_{\pi}(s_t,a) Vπ(st)=EA[Qπ(st,A)]=∑aπ(a∣st)⋅Qπ(st,a) - 动作空间连续
V π ( s t ) = E A [ Q π ( s t , A ) ] = ∫ π ( a ∣ s t ) ⋅ Q π ( s t , a ) d a V_{\pi}(s_t)=E_{A}[Q_{\pi}(s_t,A)]=\int \pi(a|s_t)\cdot Q_{\pi}(s_t,a)da Vπ(st)=EA[Qπ(st,A)]=∫π(a∣st)⋅Qπ(st,a)da
为了修正策略函数 π \pi π, V π ( s ) V_{\pi}(s) Vπ(s)评估状态 s s s的好坏
对所有的状态求期望 E S [ V π ( S ) ] E_{S}[V_{\pi}(S)] ES[Vπ(S)],可以评估策略函数 π \pi π的好坏。
3. Python强化学习迷宫实例
本节源码来自Wanghailin2019/Learing-DRL-by-PyTorch-cookbook: 本书作者是来自日本的Yutaro Ogawa(小川熊太郎),作者的github上源码是日文注释的,这个repository把它翻译成中文
出自《边做边学深度强化学习PyTorch程序设计实践》
#导入所使用的包
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#迷宫的初始位置
#声明图的大小以及图的变量名
fig = plt.figure(figsize=(5, 5))
ax = plt.gca()
#画出红色的墙壁
plt.plot([1, 1], [0, 1], color='red', linewidth=2)
plt.plot([1, 2], [2, 2], color='red', linewidth=2)
plt.plot([2, 2], [2, 1], color='red', linewidth=2)
plt.plot([2, 3], [1, 1], color='red', linewidth=2)
#画出表示状态的文字S0-S8
plt.text(0.5, 2.5, 'S0', size=14, ha='center')
plt.text(1.5, 2.5, 'S1', size=14, ha='center')
plt.text(2.5, 2.5, 'S2', size=14, ha='center')
plt.text(0.5, 1.5, 'S3', size=14, ha='center')
plt.text(1.5, 1.5, 'S4', size=14, ha='center')
plt.text(2.5, 1.5, 'S5', size=14, ha='center')
plt.text(0.5, 0.5, 'S6', size=14, ha='center')
plt.text(1.5, 0.5, 'S7', size=14, ha='center')
plt.text(2.5, 0.5, 'S8', size=14, ha='center')
plt.text(0.5, 2.3, 'START', ha='center')
plt.text(2.5, 0.3, 'GOAL', ha='center')
#设定画图的范围
ax.set_xlim(0, 3)
ax.set_ylim(0, 3)
plt.tick_params(axis='both', which='both', bottom='off', top='off',
labelbottom='off', right='off', left='off', labelleft='off')
#当前位置S0用绿色圆圈画出
line, = ax.plot([0.5], [2.5], marker="o", color='g', markersize=60)
#设定参数θ的初始值theta_0,用于确定初始方案
#行为状态0-7,列为↑,→,↓,←表示的移动方向
theta_0 = np.array([[np.nan, 1, 1, np.nan], # s0
[np.nan, 1, np.nan, 1], # s1
[np.nan, np.nan, 1, 1], # s2
[1, 1, 1, np.nan], # s3
[np.nan, np.nan, 1, 1], # s4
[1, np.nan, np.nan, np.nan], # s5
[1, np.nan, np.nan, np.nan], # s6
[1, 1, np.nan, np.nan], # s7、※s8是目标,无策略
])
#将策略参数θ转换为行动策略π的函数定义
def simple_convert_into_pi_from_theta(theta):
#简单地计算百分比
[m, n] = theta.shape # 获取θ的矩阵大小
pi = np.zeros((m, n))
for i in range(0, m):
pi[i, :] = theta[i, :] / np.nansum(theta[i, :]) # 计算百分比
pi = np.nan_to_num(pi) # 将nan转换为0
return pi
#求初始策略π
pi_0 = simple_convert_into_pi_from_theta(theta_0)
#1步移动后求得状态s的函数的定义
def get_next_s(pi, s):
direction = ["up", "right", "down", "left"]
next_direction = np.random.choice(direction, p=pi[s, :])
# 根据概率pi[s,:]选择direction
if next_direction == "up":
s_next = s - 3 # 向上移动时状态的数字减少3
elif next_direction == "right":
s_next = s + 1 # 向右移动时状态的数字增加1
elif next_direction == "down":
s_next = s + 3 # 向下移动时状态的数字增加3
elif next_direction == "left":
s_next = s - 1 # 向左移动时状态的数字减少1
return s_next
# 迷宫内使智能体移动到目标的函数的定义
def goal_maze(pi):
s = 0 # 开始地点
state_history = [0] # 记录智能体移动轨迹的列表
while (1): # 循环,直到到达目标
next_s = get_next_s(pi, s)
state_history.append(next_s) # 在记录列表中添加下一个状态(智能体的位置)
if next_s == 8: # 到达目标地点则终止
break
else:
s = next_s
return state_history
# 在迷宫内朝着目标移动
state_history = goal_maze(pi_0)
print(state_history)
print("求解迷宫路径所需的步数是 " + str(len(state_history) - 1))
# 将智能体移动的情形可视化
# 参考URL http://louistiao.me/posts/notebooks/embedding-matplotlib-animations-in-jupyter-notebooks/
from matplotlib import animation
from IPython.display import HTML
def init():
'''初始化背景图像'''
line.set_data([], [])
return (line,)
def animate(i):
'''每一帧的画面内容'''
state = state_history[i] # 画出当前的位置
x = (state % 3) + 0.5 # 状态的x坐标为状态数除以3的余数加0.5
y = 2.5 - int(state / 3) # 状态的y坐标为2.5减去状态数除以3的商
line.set_data(x, y)
return (line,)
# 用初始化函数和绘图函数来生成动画
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=len(
state_history), interval=200, repeat=False)
HTML(anim.to_jshtml())