强化学习零碎知识点笔记

强化学习零碎知识点笔记
坷np.array_equal
比较numpy数组尽量不用==,要用np.array_equal。
两个 numpy 数组用==时,不会像普通变量 / 列表那样返回「单个 True/False」,而是对两个数组中对应位置的元素逐一比较 ,返回一个和原数组形状完全相同的布尔数组。
1 | import numpy as np |
np.array_equal(a, b)是专门判断两个数组是否完全相等的函数,核心特性:
- 先判断两个数组的形状是否一致(比如都是 2 维、都是 N×2),形状不同直接返回 False;
- 形状一致则逐元素比较,所有元素都相等才返回单个 True,否则返回单个 False;
- 返回值是单个布尔值,可以直接用在if判断里,完美解决数组比较的问题。
1 | np.array_equal(loc1, loc2) # False(元素不全等) |
@dataclass、default_factory 与 Lambda
1. @dataclass 装饰器
来源:from dataclasses import dataclass (Python 3.7+)
定义:一个用于简化类定义的装饰器,专门用于创建主要存储数据的类(Data Class)。
核心功能:自动生成 __init__、__repr__、__eq__ 等样板代码,让代码极度简洁。
写法对比
- 传统写法(手动挡):
1
2
3
4
5
6class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point(x={self.x}, y={self.y})" - Dataclass 写法(自动挡):
1
2
3
4
class Point:
x: int
y: int
2. field(default_factory=…)
核心痛点:可变默认参数陷阱
在 Python 类中,绝对不能直接使用可变对象(如 list, dict, set)作为类变量的默认值。
错误写法:items: list = []
后果:所有该类的实例会共享同一个列表内存地址。修改 A 对象的列表,B 对象的列表也会随之改变。
为了解决共享问题,我们需要告诉 Python:不要使用现成的对象,而是每次实例化时,调用一个“工厂函数”现场创建一个新对象。
示例:
1 | taskTypes: List[str] = field(default_factory=lambda: ["search", "fire", "facility"]) |
ROS 2 与 Gazebo 桥接器 (ros_gz_bridge) 语法精讲
在 Launch 文件中配置 parameter_bridge 时,字符串格式非常严谨,核心公式为:话题名称@ROS数据类型<方向号>Gazebo数据类型
1. 符号含义:
@:分隔符,分隔话题名称和数据类型。]:单向通信,数据从 ROS 2 流向 Gazebo(例如:下发控制指令、推力)。[:单向通信,数据从 Gazebo 流向 ROS 2(例如:获取传感器数据、Odometry 里程计位置)。@或==(有些版本支持双向):双向通信。
2. 核心代码结构:
1 | from launch_ros.actions import Node |
Python 避坑笔记:为什么 VS Code 找不到代码引用/不高亮?
问题现象
在 VS Code 中选中一个函数(比如 step),但在其他类中调用它的地方(比如 self.bandit.step())却没有高亮显示。右键点击“查找所有引用”也毫无反应,让人误以为这个函数没被用过。
根本原因:Python 的“动态类型”特性
Python 是一门非常自由的语言,声明变量时不需要指定类型。
当你写下 def __init__(self, bandit): 时,VS Code 的代码分析器(Pylance/IntelliSense)并不知道传入的 bandit 到底是个什么对象(是数字?是字符串?还是老虎机?)。因为不知道身份,VS Code 为了避免报错,干脆就不进行跨文件/跨类的高亮关联。
终极解决办法:类型提示 (Type Hint)
在定义参数时,顺手给它“贴个标签”,明确告诉 VS Code 它的真实身份。
- 修改前(VS Code 无法识别):
1
def __init__(self, bandit):
- 修改后(VS Code 瞬间变聪明): (加上
1
def __init__(self, bandit: BernoulliBandit):
: BernoulliBandit后,VS Code 瞬间就能把两个类关联起来,代码高亮、Ctrl + 点击跳转、自动补全全部复活!)
备用方案:暴力搜索法
如果是在阅读别人写的老代码(没有类型提示),千万别依赖高亮来判断函数有没有被调用。请直接使用:
- 单文件搜索:
Ctrl + F - 全局搜索(最管用):
Ctrl + Shift + F,在整个工程文件夹里直接搜索函数名。
强化学习:折扣回报与贝尔曼方程核心概念
1. 折扣回报 (Discounted Return) 的理论公式:
衡量一个状态的好坏,不仅看当下,还要看未来。
$G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \dots = \sum_{k=0}^{\infty} \gamma^k R_{t+k+1}$
- $\gamma$ (Gamma):折扣率 (0 到 1 之间)。决定了智能体是“目光短浅”($\gamma$ 接近 0)还是“高瞻远瞩”($\gamma$ 接近 1)。
2. 解决“未知未来”的两大落地方法:
- 蒙特卡洛方法 (Monte Carlo):必须等一个回合 (Episode) 彻底结束,拿到所有真实的 $R$ 序列后,再反向计算 $G_t$ 进行更新。属于“事后结算”。
- 时序差分法 (Temporal Difference, TD):不需要等回合结束,走一步算一步。核心在于利用贝尔曼方程:
$$V(s_t) = \mathbb{E}[R_{t+1} + \gamma V(s_{t+1})]$$
利用【当下真实的即时奖励 $R_{t+1}$】加上【下一个状态的预估价值 $\gamma V(s_{t+1})$】,来更新【当前状态的价值 $V(s_t)$】。
核心机制:经验回放 (Experience Replay)
1. 经验元组 (Transition Tuple)
智能体与环境交互的基本记录格式:$[s, a, r, s’]$
- $s$: 当前状态 (State)
- $a$: 动作 (Action)
- $r$: 奖励 (Reward)
- $s’$: 下一状态 (Next State)
(注:有时候还会加上一个 $done$ 标志,记录游戏是否结束,变成 $[s, a, r, s’, done]$)
2. 机制流程
- 存储 (Store):智能体在探索环境时,将每一步的 $[s, a, r, s’]$ 存入一个固定容量的队列 (Memory/Buffer) 中。如果存满了,新的经验会挤掉最老的经验。
- 采样 (Sample):在训练更新网络时,从 Memory 中随机抽取 (Random Sample) 一批大小为
batch_size的经验进行学习。
3. 为什么必须随机抽样?
- 打破时间相关性 (Break Correlation):连续的样本之间高度相似,会导致神经网络训练产生震荡甚至崩溃。随机抽样能让送入网络的数据分布更加均匀。
- 提高数据利用率:过去犯下的惨痛错误(稀有经验),可以在未来被多次随机抽中并反复复习,而不是经历一次就被遗忘了。
机器学习核心概念:偏差、方差与拟合状态
在机器学习中,模型的总误差可以分解为:$Error = Bias^2 + Variance + Noise$
1. 欠拟合 (Underfitting) $\rightarrow$ 高偏差 (High Bias)
- 表现:模型在“训练集”和“测试集”上的表现都很差,准确率都不高。
- 原因:模型过于简单(如用直线拟合曲线),表达能力不足,无法捕捉数据中的真实规律。
- 形象比喻:瞄准镜歪了。预测结果集体偏离真实值。
2. 过拟合 (Overfitting) $\rightarrow$ 高方差 (High Variance)
- 表现:模型在“训练集”上表现极好(甚至 100% 准确),但在“测试集”上表现极其糟糕。
- 原因:模型过于复杂,把训练数据里的噪声和偶然特征也当成规律死记硬背了下来。泛化能力极差。
- 形象比喻:手抖得厉害。稍微改变一下训练数据,训练出的模型就会剧烈变动,极不稳定。
3. 终极目标:偏差-方差权衡 (Bias-Variance Tradeoff)
我们想要的是一个既能看懂规律(低偏差),又不过度敏感(低方差)的模型,也就是打靶时既对准靶心,手又稳(子弹密集击中靶心)。






