关于cleanRL Q-learning
内置变量
- 内置变量是由编程语言解释器或运行时环境预定义的变量。
- 它们通常用于提供程序的元信息(如文件路径、模块名称)或控制程序行为。
- 在 Python 中,内置变量通常以双下划线开头和结尾,例如 __file__、__name__。
以下是一些常见的 Python 内置变量及其用途:
- __file__:表示当前脚本的文件路径(包括文件名)。例如,/home/user/myscript.py。
(与os.path 或 pathlib 模块的使用--路径操作--相关)
- __name__:表示当前模块的名称。如果脚本直接运行,__name__ 为 "__main__";如果脚本被导入为模块,__name__ 为模块名。
- __doc__:包含模块、类或函数的文档字符串(如果定义了)。
- __package__:表示当前模块所属的包名(如果在包中)。
- __builtins__:提供对内置函数和对象的访问(如 print、len)。
dataclass类
dataclass
是 Python 3.7 引入的一个装饰器,它可以自动为类生成一些特殊方法,比如 __init__
、__repr__
和 __eq__
。这意味着你不需要手动编写这些方法,从而简化了类的定义
init
: 自动生成__init__
方法,用于初始化类实例的属性。repr
: 自动生成__repr__
方法,用于生成一个字符串表示,方便打印和调试。eq
: 自动生成__eq__
方法,用于比较两个类实例是否相等 [1]
用途:
使用 @dataclass
装饰器,可以清晰地表明 Args
类是一个用来存储实验参数的数据结构,而不是一个包含复杂逻辑的对象。
类中,每个属性都有明确的类型提示(例如 str
, int
, float
, bool
),这增加了代码的可读性和可维护性,并且方便进行静态类型检查。
tyro
这个库可以很好地与 dataclass
集成,自动根据 Args
类中定义的属性和类型来解析命令行参数。这使得命令行参数的处理变得非常方便和自动化。
Gymnasium 中的 Wrappers
将 Wrapper 理解为一个层,它位于你的智能体和原始环境之间。当智能体与环境交互时,首先经过 Wrapper 层,Wrapper 可以对智能体的动作进行修改,或者对环境返回的观测、奖励、终止信号等进行修改,然后再将处理后的信息传递给智能体。
Wrappers 提供了一种标准化的、模块化的方式来修改环境的行为,对于常见的环境预处理(尤其是在图像观测的强化学习中)具有很好的泛化性。然而,特定的 Wrapper 配置是否具有泛化性取决于环境的类型、任务的需求以及所使用的强化学习算法。对于不同的场景,你可能需要选择或自定义适合的 Wrapper。
Atari 环境的这些 Wrapper (NoopResetEnv
, MaxAndSkipEnv
, EpisodicLifeEnv
, FireResetEnv
, ClipRewardEnv
, ResizeObservation
, GrayScaleObservation
, FrameStack
) 是一套在 Atari 游戏强化学习中非常经典的预处理步骤,它们旨在标准化 Atari 环境的接口,使其更适合于像 DQN 这样的算法进行训练。
卷积层
- 特征图数量变多,尺寸变小->下采样
32 个卷积核在滑动覆盖输入特征图时,它们覆盖的区域是相同的,但它们学习到的特征是不同的。
可以这样理解:
每个卷积核:每个卷积核都有自己独特的权重。当它在输入特征图上滑动时,它会对每个覆盖的区域进行点积运算。由于每个卷积核的权重不同,它们会检测输入中不同的模式或特征,例如边缘、角点、纹理等。
TensorBoard
TensorBoard 是 TensorFlow 生态的一部分,但它也可以与 PyTorch 等其他深度学习框架一起使用,通过写入特定格式的数据到日志文件,然后用 TensorBoard 工具来读取和展示。
- Scalars: 可视化训练过程中的标量值(性能)变化,如损失 (loss)、准确率 (accuracy)、学习率 (learning rate) 等。这些值会随着训练步数或时间的变化绘制成曲线图,方便观察训练趋势。
- Graphs: 可视化模型的计算图(Computational Graph),展示模型各层之间的连接关系。这有助于理解模型结构,以及识别潜在的问题。
- Histograms: 可视化张量(如模型权重或激活值)随时间变化的分布。通过直方图,你可以观察到权重是否在训练过程中发生剧烈变化(梯度爆炸/消失),或者激活值是否集中在某个范围。
- Distributions: 以更紧凑的方式可视化张量分布随时间的变化,通常以热力图的形式展示。
- Images: 可视化训练过程中的图像数据,例如输入图像、模型生成的图像或特征图。
- Audio: 可视化训练过程中的音频数据。
- Text: 可视化训练过程中的文本数据。
- Projector: 可视化高维数据(如词嵌入或模型中间层的特征)在低维空间(2D 或 3D)的投影。
要更改配置、优化模型性能,特别是在强化学习任务中,你需要了解并调整以下几个关键参数和步骤(代码链接https://github.com/vwxyzjn/cleanrl/blob/master/cleanrl/dqn_atari.py)
1. 算法参数 (args
):
在你的代码中,Args
这个 dataclass
定义了大部分可以调整的参数。更改这些参数会直接影响模型的训练行为和性能。一些重要的参数包括:
learning_rate
: 优化器的学习率。- 影响: 决定了模型参数每次更新的步长。过大的学习率可能导致训练不稳定甚至发散,过小的学习率可能导致训练缓慢。
- 调整: 尝试不同的学习率,通常从 1e-4 或 3e-4 开始,然后可以尝试更大或更小的值(例如,乘以或除以 3 或 10)。
gamma
: 折扣因子。- 影响: 决定了未来奖励的重要性。越接近 1,未来奖励的影响越大,智能体倾向于追求长期收益;越接近 0,智能体越关注短期奖励。
- 调整: 在 Atari 游戏中,0.99 是一个常用的值。
buffer_size
: 回放缓冲区大小。- 影响: 决定了智能体存储经验的数量。更大的缓冲区可以存储更多样化的经验,有助于打破数据之间的相关性,但会占用更多内存。
- 调整: 根据可用内存和任务需求进行调整。对于 Atari 游戏,100 万通常是一个合理的大小。
batch_size
: 采样批次大小。- 影响: 每次从回放缓冲区采样多少经验用于训练。更大的批次通常可以提供更稳定的梯度估计,但也需要更多计算资源。
- 调整: 32 是一个常用的大小。可以尝试 64 或 128。
start_e
和end_e
以及exploration_fraction
: 控制 epsilon-greedy 策略的探索衰减。- 影响: 决定了智能体在训练过程中是更多地探索(随机动作)还是更多地利用(选择最优动作)。
- 调整: 调整起始、结束 epsilon 值和衰减时长,以找到探索与利用之间的最佳平衡。早期的探索有助于智能体发现更好的策略,后期的利用有助于收敛到最优策略。
target_network_frequency
: 更新目标网络的频率。- 影响: 决定了目标网络多久与 Q 网络同步一次。更频繁的更新可能导致训练不稳定,不频繁的更新可能导致目标不准确。
- 调整: 通常是一个经验值,可以尝试调整。
tau
: 目标网络的软更新率 (Soft Update Rate)。- 影响: 决定了目标网络权重更新的平滑程度。
tau = 1.0
是硬更新,将 Q 网络的权重完全复制到目标网络;小于 1.0 是软更新,以一定的比例混合新旧权重。软更新可以使训练更稳定。 - 调整: 如果使用软更新,通常会设置一个较小的值,例如 0.005 或 0.01。你的代码中使用了
tau = 1.0
,表示硬更新。
- 影响: 决定了目标网络权重更新的平滑程度。
2. 模型架构 (QNetwork
):
更改 Q 网络的结构也会显著影响模型性能。
- 卷积层: 调整卷积核大小、步长、填充和通道数。这些会影响模型提取图像特征的能力。
- 全连接层: 调整全连接层的层数和神经元数量。这会影响模型处理特征并输出 Q 值的能力。
- 激活函数: 尝试不同的激活函数(如 Leaky ReLU、ELU 等)。
- 网络深度和宽度: 增加或减少网络的层数和每层的神经元数量。更深或更宽的网络理论上可以学习更复杂的函数,但也更容易过拟合和训练困难。
3. 环境和 Wrapper 配置:
对环境的预处理和 Wrapper 配置也会影响模型的输入和训练效果。
- Wrappers 的选择和参数: 确保使用的 Wrappers 和其参数适合你的任务。例如,对于非 Atari 环境,你可能不需要所有的 Atari Wrapper。
- 观测空间的归一化: 在你的代码中,观测被除以 255.0 进行归一化。这是图像数据常用的归一化方法。对于其他类型的观测,可能需要采用不同的归一化方法。
4. 训练过程和技巧:
除了参数和模型,训练过程本身也包含可以优化的步骤和技巧。
- 优化器: 尝试不同的优化器(如 AdamW、RMSprop 等)及其参数。
- 学习率调度: 除了线性的 epsilon 调度,还可以考虑学习率调度,例如阶梯衰减、指数衰减等,以在训练的不同阶段调整学习率。
- 正则化: 添加正则化技术(如 L1 或 L2 正则化)以防止过拟合,尤其是在模型较大时。
- 梯度裁剪: 对梯度进行裁剪,防止梯度爆炸。
- 批量归一化 (Batch Normalization) 或 层归一化 (Layer Normalization): 在神经网络中添加归一化层,有助于稳定训练和加速收敛。
- 优先经验回放 (Prioritized Experience Replay): 一种改进的回放缓冲区采样策略,优先采样那些具有更高 TD Error 的经验,可以提高训练效率。
- Multi-step Learning: 在计算 TD 目标时,考虑多步的奖励,而不是仅仅下一步的奖励。
- Double DQN: 一种改进的 DQN 算法,通过解耦动作选择和 Q 值评估来解决 Q 值过估计的问题。
优化模型的步骤:
- 理解基线性能: 首先使用你的当前代码运行一个实验,并在 TensorBoard 中记录结果,作为你的基线性能。
- 逐个调整参数: 一次只修改一个或少数几个参数,然后运行实验并与基线进行比较。这有助于 isolat 不同参数的影响。
- 超参数调优: 对于重要的超参数(如学习率、epsilon 衰减参数),可以考虑使用超参数搜索技术,如网格搜索、随机搜索或更高级的优化算法(如贝叶斯优化)。
- 模型结构调整: 在对超参数进行初步调优后,可以尝试调整模型结构,并再次进行超参数调优。
- 引入高级技巧: 如果基本的 DQN 性能不佳,可以考虑引入 Double DQN、Prioritized Experience Replay 等更先进的 DQN 变种。
- 监控和分析: 在训练过程中密切关注 TensorBoard 中的指标(损失、奖励、Q 值、SPS 等),分析训练趋势,判断模型是否存在过拟合、欠拟合或训练不稳定等问题。
- 评估: 在训练完成后,使用独立的评估环境来评估模型的最终性能,而不是仅仅依赖训练过程中的奖励曲线。
优化强化学习模型性能是一个迭代的过程,需要耐心和实验。通过系统地调整参数、模型和训练技巧,并结合对训练过程的深入分析,你可以逐步提高模型的性能。