强化学习随机策略之高斯似然数原理与代码实现
一、原理介绍
使用随机策略有两个关键点
- 从策略当中进行采样,获得动作 a a a (Action)
- 计算特定动作的似然数 log π θ ( a ∣ s ) \log \pi _ { \theta } ( a | s ) logπθ(a∣s)
什么是多元高斯分布?
在多元高斯分布中,当协方差矩阵
Σ
\Sigma
Σ 只有在对角元素非零,而其余元素为 0 时,成为对角高斯分布。
多元高斯分布(Multivariate Gaussian Distribution)是一元高斯分布的在向量形式上的推广,其中向量
X
=
[
X
1
,
X
2
,
…
,
X
n
]
T
X = \left[ X _ { 1 } , X _ { 2 } , \ldots , X _ { n } \right] ^ { T }
X=[X1,X2,…,Xn]T 的均值为
μ
∈
R
n
\mu \in \mathbf { R } ^ { n }
μ∈Rn ,协方差矩阵为
Σ
∈
S
n
\Sigma \in S ^ { n }
Σ∈Sn ,概率密度函数表示为
p ( x ; μ , Σ ) = 1 ( 2 π ) n / 2 ∣ Σ ∣ 1 / 2 exp ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) p ( x ; \mu , \Sigma ) = \frac { 1 } { ( 2 \pi ) ^ { n / 2 } | \Sigma | ^ { 1 / 2 } } \exp \left( - \frac { 1 } { 2 } ( x - \mu ) ^ { T } \Sigma ^ { - 1 } ( x - \mu ) \right) p(x;μ,Σ)=(2π)n/2∣Σ∣1/21exp(−21(x−μ)TΣ−1(x−μ))
例如二元高斯多元分布可以如图所示
.
对于一对随机变量 X X X 和 Y Y Y ,它们的协方差矩阵写作
Cov [ X , Y ] = E [ ( X − E [ X ] ) ( Y − E [ Y ] ) ] = E [ X Y ] − E [ X ] E [ Y ] \operatorname { Cov } [ X , Y ] = E [ ( X - E [ X ] ) ( Y - E [ Y ] ) ] = E [ X Y ] - E [ X ] E [ Y ] Cov[X,Y]=E[(X−E[X])(Y−E[Y])]=E[XY]−E[X]E[Y]
对于多个变量的问题,用协方差矩阵 Σ ∈ S n \Sigma \in S ^ { n } Σ∈Sn 来表示各个变量之间的相关性,有
Σ = E [ ( X − μ ) ( X − μ ) T ] = E [ X X T ] − μ μ T \Sigma = E \left[ ( X - \mu ) ( X - \mu ) ^ { T } \right] = E \left[ X X ^ { T } \right] - \mu \mu ^ { T } Σ=E[(X−μ)(X−μ)T]=E[XXT]−μμT
对角多元高斯分布
特殊地,当 N 个随机变量 X = [ X 1 , X 2 , … , X n ] T X = \left[ X _ { 1 } , X _ { 2 } , \ldots , X _ { n } \right] ^ { T } X=[X1,X2,…,Xn]T 为各自独立的高斯随机变量时,协方差矩阵为对角阵,即
Σ = diag ( σ 1 2 , σ 2 2 , … , σ n 2 ) \Sigma = \operatorname { diag } \left( \sigma _ { 1 } ^ { 2 } , \sigma _ { 2 } ^ { 2 } , \ldots , \sigma _ { n } ^ { 2 } \right) Σ=diag(σ12,σ22,…,σn2)
对角高斯策略 Diagonal Gaussian Policies
由于标准差的公式
σ
=
1
N
∑
i
=
1
N
(
x
i
−
μ
)
2
\sigma = \sqrt { \frac { 1 } { N } \sum _ { i = 1 } ^ { N } \left( x _ { i } - \mu \right) ^ { 2 } }
σ=N1∑i=1N(xi−μ)2 可知
σ
\sigma
σ 始终大于等于 0 ,对标准差取 log
对数,可以将标准差映射到
(
−
∞
,
∞
)
( - \infty , \infty )
(−∞,∞),这样更有利于神经网络的训练。
-
采样:假设已知动作(Action) 的均值 μ θ ( s ) \mu _ { \theta } ( s ) μθ(s) 和标准差 σ θ ( s ) \sigma _ { \theta } ( s ) σθ(s) ,引入服从 ( z ∼ N ( 0 , I ) ) ( z \sim \mathcal { N } ( 0 , I ) ) (z∼N(0,I)) 分布的噪声 z z z ,下一步的动作采样表示为
a = μ θ ( s ) + σ θ ( s ) ⊙ z a = \mu _ { \theta } ( s ) + \sigma _ { \theta } ( s ) \odot z a=μθ(s)+σθ(s)⊙z
其中 ⊙ \odot ⊙ 表示两个向量之间的内积。 -
似然数:当均值为 μ = μ θ ( s ) \mu = \mu _ { \theta } ( s ) μ=μθ(s) ,标准差为 σ = σ θ ( s ) \sigma = \sigma _ { \theta } ( s ) σ=σθ(s) 的 k − k- k−维的动作 a a a 的似然数表示为
log π θ ( a ∣ s ) = − 1 2 ( ∑ i = 1 k ( ( a i − μ i ) 2 σ i 2 + 2 log σ i ) + k log 2 π ) \log \pi _ { \theta } ( a | s ) = - \frac { 1 } { 2 } \left( \sum _ { i = 1 } ^ { k } \left( \frac { \left( a _ { i } - \mu _ { i } \right) ^ { 2 } } { \sigma _ { i } ^ { 2 } } + 2 \log \sigma _ { i } \right) + k \log 2 \pi \right) logπθ(a∣s)=−21(i=1∑k(σi2(ai−μi)2+2logσi)+klog2π)
二、代码实现
要求
- 输入: 样本
x
,对角高斯分布的均值和标准差 - 输出:样本
x
的似然数
import tensorflow as tf
import numpy as np
EPS = 1e-8
根据上一节,似然数公式,理解公式后就很容易写出代码
# my solution
def my_gaussian_likelihood(x, mu, log_std):
"""
Args:
x: Tensor with shape [batch, dim]
mu: Tensor with shape [batch, dim]
log_std: Tensor with shape [batch, dim] or [dim]
Returns:
Tensor with shape [batch]
"""
#######################
# #
# YOUR CODE HERE #
# #
#######################
std = tf.exp(log_std)
ans = ((x - mu) / std)**2 + 2 * log_std + np.log(2 * np.pi)
ans = -0.5 * ans
# https://www.tensorflow.org/api_docs/python/tf/math/reduce_sum
sum_ans = tf.reduce_sum(ans, axis=1)
return sum_ans
# standard solution
# 代码来自 spinup/exercises/problem_set_1_solutions/exercise1_2_soln.py
def ans_gaussian_likelihood(x, mu, log_std):
pre_sum = -0.5 * (((x-mu)/(tf.exp(log_std)+EPS))**2 + 2*log_std + np.log(2*np.pi))
return tf.reduce_sum(pre_sum, axis=1)
if __name__ == '__main__':
"""
Run this file to verify your solution.
"""
sess = tf.Session()
dim = 10
x = tf.placeholder(tf.float32, shape=(None, dim))
mu = tf.placeholder(tf.float32, shape=(None, dim))
log_std = tf.placeholder(tf.float32, shape=(dim,))
your_gaussian_likelihood = my_gaussian_likelihood(x, mu, log_std)
true_gaussian_likelihood = ans_gaussian_likelihood(x, mu, log_std)
batch_size = 32
feed_dict = {x: np.random.rand(batch_size, dim),
mu: np.random.rand(batch_size, dim),
log_std: np.random.rand(dim)}
your_result, true_result = sess.run([your_gaussian_likelihood, true_gaussian_likelihood],
feed_dict=feed_dict)
correct = np.allclose(your_result, true_result)
print("Your answer is", correct)
Your answer is True