Python-DQN代码阅读(13)

目录

1.代码

1.1 代码阅读

1.2 代码分解

1.2.1 导入库

1.2.2 data = np.loadtxt('performance.txt')

1.2.3 mva = np.zeros((data.shape[0]), dtype=np.float)

1.2.4 mva[i] = data[i,1],mva[i] = alpha * data[i,1] + (1.0 - alpha) * mva[i-1]

1.2.5 plt.plot(data[:,0], data[:,1]) ,plt.plot(data[:,0], mva) 

1.2.6 mvar[i] = alpha * data[i,2] + (1.0 - alpha) * mvar[i-1]

2.问题


1.代码

1.1 代码阅读

import numpy as np
import matplotlib.pyplot as plt

# 从文件中加载性能数据
data = np.loadtxt('performance.txt')

print(data.shape)

# 计算第一个图形中的移动平均值
alpha = 0.02
mva = np.zeros((data.shape[0]), dtype=np.float)
for i in range(data.shape[0]):
   if i == 0:
     mva[i] = data[i,1]
   else:
     mva[i] = alpha * data[i,1] + (1.0 - alpha) * mva[i-1] 

# 绘制第一个图形:episode数量与时间步数的关系
plt.plot(data[:,0], data[:,1])  # 绘制原始数据
plt.plot(data[:,0], mva)  # 绘制移动平均数据
plt.xlabel('episode #', fontsize=20)  # 设置x轴标签
plt.ylabel('# of time steps', fontsize=20)  # 设置y轴标签
plt.savefig('dqn1.png')  # 保存图形到文件

# 清空绘图缓存
plt.clf()
plt.close()

# 计算第二个图形中的移动平均值
alpha = 0.02
mvar = np.zeros((data.shape[0]), dtype=np.float)
for i in range(data.shape[0]):
   if i == 0:
     mvar[i] = data[i,2]
   else:
     mvar[i] = alpha * data[i,2] + (1.0 - alpha) * mvar[i-1] 

# 绘制第二个图形:时间步数与每个episode的奖励值的关系
plt.plot(data[:,3], data[:,2])  # 绘制原始数据
plt.plot(data[:,3], mvar)  # 绘制移动平均数据
plt.xlabel('time step #', fontsize=20)  # 设置x轴标签
plt.ylabel('episode reward', fontsize=20)  # 设置y轴标签
plt.savefig('dqn2.png')  # 保存图形到文件

这段代码通过加载 "performance.txt" 文件中的性能数据,计算并绘制了两个图形,分别表示 episode 数量与时间步数的关系以及时间步数与每个 episode 的奖励值的关系。移动平均值的计算采用了指数加权平均方法,使用了参数 alpha 控制平均值的权重。最后,通过 plt.savefig() 方法将绘制的图形保存到文件 "dqn1.png" 和 "dqn2.png" 中。

1.2 代码分解

1.2.1 导入库

import numpy as np
import matplotlib.pyplot as plt

这段代码导入了 NumPy 和 Matplotlib 库,这两个库在 Python 中用于进行数值计算和绘图。

  • NumPy 是一个强大的数值计算库,提供了很多用于处理数组和矩阵的函数,包括数值计算、线性代数、傅里叶变换等。
  • Matplotlib 是一个流行的数据可视化库,提供了绘制图形的功能,包括折线图、散点图、柱状图、饼图等,可以用于创建各种类型的图形。

这两个库经常一起使用,NumPy 用于处理数据,Matplotlib 用于将数据可视化。通过导入这两个库,你可以在 Python 程序中使用它们的函数和类来进行数值计算和绘图操作。

1.2.2 data = np.loadtxt('performance.txt')

data = np.loadtxt('performance.txt')

print(data.shape)

这行代码使用 NumPy 的 loadtxt() 函数从名为 performance.txt 的文本文件中加载数据,并将数据存储到名为 data 的 NumPy 数组中。然后,通过 data.shape 打印出 data 数组的形状信息。

performance.txt 文件中的数据可能包含了程序运行过程中的性能指标或者统计数据,例如每个 episode 的时步数、总奖励等。np.loadtxt() 函数可以读取文本文件中的数据,并将其转换为 NumPy 数组,便于后续的处理和分析。

print(data.shape)输出结果将显示 data 数组的形状,即 (m, n),其中 m 是数组的行数,n 是数组的列数。这可以帮助我们了解加载的数据的维度大小,以便后续的数据处理和绘图等操作。

注意:在运行这行代码之前,需要确保当前工作目录下存在名为 performance.txt 的文件,并且文件中包含了正确格式的数据。如果文件不存在或者文件格式不正确,np.loadtxt() 函数可能会抛出异常或者加载不成功。

1.2.3 mva = np.zeros((data.shape[0]), dtype=np.float)

alpha = 0.02
mva = np.zeros((data.shape[0]), dtype=np.float)

这段代码定义了一个变量 alpha 并赋值为 0.02,然后创建了一个长度为 data.shape[0] 的零数组 mva,数据类型为浮点数 (dtype=np.float)。这将用于存储移动平均值

alpha 是用于计算移动平均值的权重,控制着历史值在计算中的权重大小。较小的 alpha会使得历史值在计算中的权重较大,从而导致移动平均值对历史数据更加敏感变化较为迅速。而较大的 alpha 值会使得历史值在计算中的权重较小,从而导致移动平均值对历史数据变化较不敏感,变化较为平滑。在这段代码中,设置 alpha 为 0.02 可以使得移动平均值对历史数据变化较为敏感,变化较为迅速。

data.shape[0] 表示 data 数据的行数,即数据矩阵的第一维度的大小。在这段代码中,data 是一个二维数组,data.shape[0] 返回的是 data 的行数,即数据的数量。这个值会用于控制循环的次数,对每一行数据进行处理。

1.2.4 mva[i] = data[i,1],mva[i] = alpha * data[i,1] + (1.0 - alpha) * mva[i-1]

for i in range(data.shape[0]):
   if i == 0:
     mva[i] = data[i,1]
   else:
     mva[i] = alpha * data[i,1] + (1.0 - alpha) * mva[i-1] 

这段代码实现了计算移动平均值(Moving Average)的操作。循环遍历 data 中的每一行数据,其中 data.shape[0] 表示数据的行数。在每一次循环中,使用当前行的第二列数据 data[i,1] 更新移动平均值 mva[i]

如果 i 等于 0,说明是第一行数据,此时直接将当前行的第二列数据赋值给 mva[i],作为初始值。

如果 i 大于 0,说明不是第一行数据,此时使用指数加权平均(Exponential Weighted Average,EMA)的方法计算移动平均值。公式为:

mva[i] = alpha * data[i,1] + (1.0 - alpha) * mva[i-1] 

alpha 是平滑系数,通常取一个小于1的值,用于控制移动平均的权重。data[i,1] 表示第 i 行数据的第二列值(索引为 1),即在 data 数据中的第二列数据mva[i-1] 表示上一个位置(索引为 i-1)的指数移动平均值。

根据指数移动平均的定义,当前位置的指数移动平均值(mva[i])等于当前位置的数据(data[i,1])乘以平滑系数 alpha,再加上上一个位置的指数移动平均值(mva[i-1])乘以 (1.0 - alpha)。这样可以实现对历史数据的加权平均,使得新数据在计算中占有较大的权重,而旧数据在计算中的权重逐渐减小。这样计算出的指数移动平均值具有较好的平滑效果,能够较好地反映数据的趋势变化

(1)问:这里的新数据是指什么,为什么在计算中占有较大的比重?

在这段代码中,新数据指的是 data 数据中的第二列值,即 data[i,1]。在指数移动平均中,新数据占有较大的比重是因为乘以了平滑系数 alpha。较小的 alpha 值会使得新数据在计算中占有较大的权重,而旧数据在计算中的权重逐渐减小。

具体地说,alpha 控制了新数据在指数移动平均中的权重,取值范围为 0 到 1 之间,通常取一个小于1的值。当 alpha 较小的时候,新数据的权重较大,而旧数据的权重较小。这样可以使得指数移动平均能够较快地反应最近的数据变化,对数据的瞬时波动更加敏感。而随着时间的推移,旧数据的权重逐渐减小,使得指数移动平均能够对数据的趋势变化更具平滑性。因此,新数据在计算中占有较大的比重,能够较好地反映数据的近期变化趋势。

(2)问:alpha较小,为何新数据权重较大?

在指数移动平均中,实际上是新数据乘以平滑系数 alpha 加上旧数据乘以剩余的权重 (1-alpha)。当 alpha 较小时,新数据乘以 alpha 的结果会比较小,但是由于是累积计算,新数据会不断地被乘以 alpha 的结果,因此在指数移动平均中新数据的权重会逐渐增大。

更具体地说,当 alpha 接近 0 时,新数据的权重接近 0,而旧数据的权重接近 1,这是因为 (1-alpha)^nn 取较大值时会趋近于 0。因此,当 alpha 较小时,新数据在指数移动平均中的权重较大,能够较好地反映数据的近期变化趋势。

1.2.5 plt.plot(data[:,0], data[:,1]) ,plt.plot(data[:,0], mva) 

plt.plot(data[:,0], data[:,1])  # 绘制原始数据
plt.plot(data[:,0], mva)  # 绘制移动平均数据
plt.xlabel('episode #', fontsize=20)  # 设置x轴标签
plt.ylabel('# of time steps', fontsize=20)  # 设置y轴标签
plt.savefig('dqn1.png') 

plt.clf()
plt.close()

这段代码用于绘制原始数据指数移动平均数据的折线图,并保存为图片文件 "dqn1.png"。

  • plt.plot(data[:,0], data[:,1]) 绘制原始数据的折线图,其中 data[:,0] 是 x 轴数据,data[:,1] 是 y 轴数据。
  • plt.plot(data[:,0], mva) 绘制指数移动平均数据的折线图,其中 data[:,0] 是 x 轴数据,mva 是 y 轴数据,即通过指数移动平均计算得到的平均值。
  • plt.xlabel('episode #', fontsize=20) 设置 x 轴标签为 "episode #",字体大小为 20。
  • plt.ylabel('# of time steps', fontsize=20) 设置 y 轴标签为 "# of time steps",字体大小为 20。
  • plt.savefig('dqn1.png') 将绘制的图保存为 "dqn1.png" 图片文件。
  • plt.clf() 是用于清除当前图像的函数,它会将当前图像中的所有绘图元素(如线条、点、文本等)清除,但不会关闭图像窗口

  • plt.close() 是用于关闭当前图像的函数,它会关闭当前图像窗口,释放相关的系统资源。这样可以避免在后续的绘图中出现不必要的重叠或混淆。

plt.plot(data[:,0], data[:,1]) 

plt.plot(data[:,0], data[:,1]) 是用于绘制原始数据的折线图。

  • data[:,0]data 数据中的第一列,表示 x 轴数据。
  • data[:,1]data 数据中的第二列,表示 y 轴数据。

这段代码将使用 data[:,0] 作为 x 轴数据,data[:,1] 作为 y 轴数据,绘制折线图。具体绘制的内容和形式取决于 data[:,0]data[:,1] 中的数据,可能表示了游戏的不同关卡或不同轮次的性能数据。

plt.plot(data[:,0], mva)

plt.plot(data[:,0], mva) 是用于绘制移动平均数据的折线图。

  • data[:,0]data 数据中的第一列,表示 x 轴数据。
  • mva 是通过计算得到的移动平均数据,作为 y 轴数据。

这段代码将使用 data[:,0] 作为 x 轴数据,mva 作为 y 轴数据,绘制移动平均折线图。移动平均线是通过对原始数据进行平滑处理得到的,用于平滑数据的波动,以便更好地观察数据的趋势和变化。具体绘制的内容和形式取决于 data[:,0]mva 中的数据,可能表示了游戏的不同关卡或不同轮次的移动平均性能数据。

plt.clf()
plt.close()

plt.clf() 是用于清除当前图像的函数,它会将当前图像中的所有绘图元素(如线条、点、文本等)清除,但不会关闭图像窗口

plt.close() 是用于关闭当前图像的函数,它会关闭当前图像窗口,释放相关的系统资源。这样可以避免在后续的绘图中出现不必要的重叠或混淆。

这两个函数通常在生成多个图像时使用,可以帮助清除之前的图像并关闭图像窗口,以便绘制新的图像或在生成图像后释放系统资源。

1.2.6 mvar[i] = alpha * data[i,2] + (1.0 - alpha) * mvar[i-1]

alpha = 0.02
mvar = np.zeros((data.shape[0]), dtype=np.float)
for i in range(data.shape[0]):
   if i == 0:
     mvar[i] = data[i,2]
   else:
     mvar[i] = alpha * data[i,2] + (1.0 - alpha) * mvar[i-1] 

# 绘制第二个图形:时间步数与每个episode的奖励值的关系
plt.plot(data[:,3], data[:,2])  # 绘制原始数据
plt.plot(data[:,3], mvar)  # 绘制移动平均数据
plt.xlabel('time step #', fontsize=20)  # 设置x轴标签
plt.ylabel('episode reward', fontsize=20)  # 设置y轴标签
plt.savefig('dqn2.png')  # 保存图形到文件

这段代码根据 data 中的第三列数据(每个 episode 的奖励值)计算了指数移动平均,并绘制了原始数据和移动平均数据的图形。

首先,创建了一个名为 mvar 的全零数组,用于存储每个时间步的移动平均值。

然后,使用循环遍历 data 中的每一行,计算移动平均值,并将结果存储在 mvar 数组中。

移动平均值的计算方式与之前的例子类似,使用了指数加权平均方法,其中 alpha 是平滑系数,控制了新数据和历史数据的权重。

最后,使用 plt.plot() 函数分别绘制了原始数据和移动平均数据的折线图,并使用 plt.xlabel()plt.ylabel() 设置了 x 轴和 y 轴的标签。最后,使用 plt.savefig() 将图形保存到文件中。

2.问题

(1)问:为何再次执行程序从第一个回合开始写入performance.txt文件,但是在内容的末尾追加,而没有覆盖原先的数据,是为什么?

 f = open("experiments/" + str(env.spec.id) + "/performance.txt", "a+") 这段代码中使用了 "a+" 模式来打开文件,表示以追加模式进行文件操作。

在 Python 中,文件操作模式通常由第二个参数来指定,其中 "a+" 表示以追加模式打开文件进行读写操作。具体解释如下:

  • 'a':追加模式(append mode),允许在文件末尾进行写入操作,如果文件不存在则创建文件。
  • '+':允许同时进行读写操作。
  • 'a+':追加模式 + 读写操作,既可以在文件末尾追加内容,也可以进行读取和写入操作。

因此,使用 "a+" 模式打开文件后,可以在文件末尾追加新的内容,而不会覆盖原先的数据。如果文件不存在,将会创建一个新的文件。在进行文件操作时,请注意谨慎操作,避免误删除或覆盖重要数据。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天寒心亦热

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值