响应曲线

什么是响应曲线

响应曲线是描述系统或过程中输入与输出关系的图形表现。 通常在二维图上绘制,输入变量在横轴 (x 轴) 上,输出变量在纵轴 (y 轴) 上。输入变量可以是任何可测量的参数,例如频率、时间、电压或温度等。 输出变量可以是任何受输入影响的参数,例如幅度、相位、功率或电阻等。

在许多领域,响应曲线被用于分析和优化系统或过程的性能。 例如,在音频工程中,扬声器的频率响应曲线显示了其对不同频率声音的输出水平变化。 通过分析这条曲线,工程师可以确定扬声器的频率范围、灵敏度和失真特性,并根据需要进行设计调整。 同样,在电子学中,响应曲线可用于分析电路或设备的性能:例如,晶体管的电流电压 (I-V) 曲线显示了其输出电流随输入电压变化的情况。 通过分析这条曲线,工程师可以确定晶体管的工作区域、增益和线性度,并为不同应用优化其性能。 响应曲线也可用于比较不同系统或过程。 例如,对比不同音频扬声器或电子设备的响应曲线,可以帮助工程师选择最适合特定应用的选项。 总之,响应曲线是分析和优化许多领域中系统和过程性能的重要工具。 通过提供输入和输出变量之间关系的图形表现,它们帮助工程师和科学家了解系统或过程的特性,并做出有根据的决策来改进它们。

用 REVIVE SDK 绘制响应曲线

REVIVE SDK 也提供了绘制响应曲线的功能。有以下两种方式调用响应曲线的绘制:

1. 在 config.json 文件中 base_config 域下配置

defaulttrue 即为开启响应曲线绘制, false 关闭。

{
   "base_config": [
         ...
      {
            "name": "plt_response_curve",
            "abbreviation": "prc",
            "description": "Whether to plot response curve at the end of venv training.",
            "type": "bool",
            "default": true
      },
         ...
   ],
   ...
   }
}

这样 REVIVE 会在环境训练结束时自动绘制双环境(训练环境与验证环境)的响应曲线, 路径位于 logs/<run_id>/venv_train/response_curve

以冰箱温控为例,生成的文件目录结构如下:

response_curve
|-- action
|   `-- action_on_temperature.png
`-- next_temperature
   |-- next_temperature_on_action.png
   |-- next_temperature_on_door_open.png
   `-- next_temperature_on_temperature.png

该目录下每个文件夹对应决策流图中一个网络节点,比如这里 actionnext_temperature 是网络节点,他们作为输出变量。 每个文件夹中有若干图片,分别代表不同输入对这个输出的响应曲线,比如 action_on_temperature.png 代表 actiontemperature 的响应曲线。 如下所示:

../_images/action_on_temperature.png

可以看到有 16 幅子图,这是从数据集中随机采样 16 个数据点所绘而成。 x 轴代表了自变量 temperature 的变化范围,y 轴代表因变量 action 的变化趋势。 红线代表训练环境的预测值,蓝线代表验证环境的预测值。 从图中可以看到:随着 temperature 逐渐升高,冰箱电机的功率(action)逐渐增大,使得冰箱内温度稳定在目标温度 -2 度左右。 并且其中训练环境与验证环境的趋势基本一致,表明两个环境的一致性还挺好。 我们还可以计算 2 个环境之间的 MAE 以及 Spearman Correlation 系数,我们可以在每个16宫格的小标题处看到这些信息。 需要说明的是 MAE 以及 Correlation 系数是在 16 个子图中,以及每个 action 上做了平均。

高维数据请看下面的例子:

2. 通过调用 REVIVE SDK 提供的脚本绘制

import pickle
from revive.data.dataset import OfflineDataset
from revive.utils.common_utils import load_data, response_curve

if __name__ == "__main__":
   dataset_path = "data/halfcheetah-medium-v2.npz"  # 替换为对应数据集路径
   yaml_path = "data/halfcheetah-medium-v2.yaml"  # 替换为对应 yaml 文件路径
   dataset = OfflineDataset(dataset_path, yaml_path).data

   venv = pickle.load(open("logs/revive/env.pkl", 'rb'), encoding='utf-8')  # 换成对应环境的路径
   save_path = "./response"  # 设置保存路径

   response_curve(save_path, venv, dataset)

以 HalfCheetah 为例,生成的文件目录结构如下:

response
|-- action
|   `-- action_on_obs.png
|-- delta_x
|   |-- delta_x_on_action.png
|   `-- delta_x_on_obs.png
`-- next_obs
   |-- next_obs_on_action.png
   |-- next_obs_on_delta_x.png
   `-- next_obs_on_obs.png

比如 next_obs_on_action.png 代表 next_obsaction 的响应曲线。 如下所示:

../_images/next_obs_on_action.png

下面我们详细解释 response curve 是如何生成。假定我们的数据有以下形式定义:

obs

Continuous(17,)

\(S^i = [s^i_0, s^i_1, ..., s^i_{16}]\)

action

Continuous(6,)

\(A^i = [a^i_0, a^i_1, ..., a^i_5]\)

next_obs

Continuous(17,)

\({NS}^i = [ns^i_0, ns^i_1, ..., ns^i_{16}]\)

首先,我们从数据集中采样 16 个数据点:\(<S^0, A^0, {NS}^0>, <S^1, A^1, {NS}^1>, ..., <S^{15}, A^{15}, {NS}^{15}>\), 比如宫格 (next_obs_dim: t , action_dim: k) 中有 16 个子图, 它们代表:我们对 \(a^i_k\) 取遍 action 第 k 维的数据范围,也即 [-1, 1] 中取遍每一个值。 同时观察 \(ns^i_t\) 的变化情况。 就是说,在给定 \(S^i\) 的情况下,观察 \(ns^i_t\)\(a^i_k\) 的响应情况。 这里 \(i \in [0, 15], t \in [0, 17], k \in [0, 5]\)

3. 多步长响应曲线

另外在REVIVE 1.0当中我们新增加了多步长响应曲线的绘制功能,在此功能下用户可以根据自己的定义对多步的响应曲线进行绘制。


import pickle
from revive.data.dataset import OfflineDataset
from revive.utils.common_utils import  rollout_response_curve

if __name__ == "__main__":
   node_name = 'cat_delta_obs_reward' #替换成需要进行画图的节点
   dataset_path = "data/halfcheetah-medium-v2.npz"  # 替换为对应数据集路径
   yaml_path = "data/halfcheetah-medium-v2.yaml"  # 替换为对应 yaml 文件路径
   venv = pickle.load(open("logs/revive/env.pkl", 'rb'), encoding='utf-8')

   expert_func_dict = {'action_0+10': {'node':'action', 'dim':0, 'func':'rollout_response_func.action_0_add_10'},
                       'action_0+20': {'node':'action', 'dim':0, 'func':'rollout_response_func.action_0_add_20'}}
   plot_path = './rollout_response'

   dataset = OfflineDataset(dataset_path, yaml_path, None)
   rollout_response_curve(dataset, venv, expert_func_dict, node_name, plot_path, 100)

其中, expert_func_dict 中用户可以根据自己的设定,对所需要修改的数据节点和维度进行修改, func 中包含了用户设定所必要的专家函数。 在示例中,我们需要对 action 节点的第0维进行加法运算,其中 action_0+10 是将第0维加10, action_0+20 是将第0维加20。 那么REVIVE则会先将随机算则的某一条轨迹 action 节点先进行用户专家函数所定义的操作,然后将结果带入到模型中进行单步推演, 得到轨迹中 node_name 所对应的结果,并绘制多步长响应曲线。

专家函数的格式如下所示:

import torch
import numpy as np

def action_0_add_10(data):
   action = data['action']
   action[..., 0 ] += 0.1
   return action


def action_0_add_20(data):
   action = data['action']
   action[..., 0 ] += 0.2
   return action

最后我们得到了根据用户设定绘制的多步长响应曲线图。

../_images/rollout_response_curve.png